archive2yaml.cpp 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. //===------ utils/archive2yaml.cpp - obj2yaml conversion tool ---*- C++ -*-===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. #include "obj2yaml.h"
  9. #include "llvm/BinaryFormat/Magic.h"
  10. #include "llvm/ObjectYAML/ArchiveYAML.h"
  11. using namespace llvm;
  12. namespace {
  13. class ArchiveDumper {
  14. public:
  15. Expected<ArchYAML::Archive *> dump(MemoryBufferRef Source) {
  16. StringRef Buffer = Source.getBuffer();
  17. assert(file_magic::archive == identify_magic(Buffer));
  18. std::unique_ptr<ArchYAML::Archive> Obj =
  19. std::make_unique<ArchYAML::Archive>();
  20. StringRef Magic = "!<arch>\n";
  21. if (!Buffer.startswith(Magic))
  22. return createStringError(std::errc::not_supported,
  23. "only regular archives are supported");
  24. Obj->Magic = Magic;
  25. Buffer = Buffer.drop_front(Magic.size());
  26. Obj->Members.emplace();
  27. while (!Buffer.empty()) {
  28. uint64_t Offset = Buffer.data() - Source.getBuffer().data();
  29. if (Buffer.size() < sizeof(ArchiveHeader))
  30. return createStringError(
  31. std::errc::illegal_byte_sequence,
  32. "unable to read the header of a child at offset 0x%" PRIx64,
  33. Offset);
  34. const ArchiveHeader &Hdr =
  35. *reinterpret_cast<const ArchiveHeader *>(Buffer.data());
  36. Buffer = Buffer.drop_front(sizeof(ArchiveHeader));
  37. auto ToString = [](ArrayRef<char> V) {
  38. // We don't want to dump excessive spaces.
  39. return StringRef(V.data(), V.size()).rtrim(' ');
  40. };
  41. ArchYAML::Archive::Child C;
  42. C.Fields["Name"].Value = ToString(Hdr.Name);
  43. C.Fields["LastModified"].Value = ToString(Hdr.LastModified);
  44. C.Fields["UID"].Value = ToString(Hdr.UID);
  45. C.Fields["GID"].Value = ToString(Hdr.GID);
  46. C.Fields["AccessMode"].Value = ToString(Hdr.AccessMode);
  47. StringRef SizeStr = ToString(Hdr.Size);
  48. C.Fields["Size"].Value = SizeStr;
  49. C.Fields["Terminator"].Value = ToString(Hdr.Terminator);
  50. uint64_t Size;
  51. if (SizeStr.getAsInteger(10, Size))
  52. return createStringError(
  53. std::errc::illegal_byte_sequence,
  54. "unable to read the size of a child at offset 0x%" PRIx64
  55. " as integer: \"%s\"",
  56. Offset, SizeStr.str().c_str());
  57. if (Buffer.size() < Size)
  58. return createStringError(
  59. std::errc::illegal_byte_sequence,
  60. "unable to read the data of a child at offset 0x%" PRIx64
  61. " of size %" PRId64 ": the remaining archive size is %zu",
  62. Offset, Size, Buffer.size());
  63. if (!Buffer.empty())
  64. C.Content = arrayRefFromStringRef(Buffer.take_front(Size));
  65. const bool HasPaddingByte = (Size & 1) && Buffer.size() > Size;
  66. if (HasPaddingByte)
  67. C.PaddingByte = Buffer[Size];
  68. Obj->Members->push_back(C);
  69. // If the size is odd, consume a padding byte.
  70. Buffer = Buffer.drop_front(HasPaddingByte ? Size + 1 : Size);
  71. }
  72. return Obj.release();
  73. }
  74. private:
  75. struct ArchiveHeader {
  76. char Name[16];
  77. char LastModified[12];
  78. char UID[6];
  79. char GID[6];
  80. char AccessMode[8];
  81. char Size[10];
  82. char Terminator[2];
  83. };
  84. };
  85. } // namespace
  86. Error archive2yaml(raw_ostream &Out, MemoryBufferRef Source) {
  87. ArchiveDumper Dumper;
  88. Expected<ArchYAML::Archive *> YAMLOrErr = Dumper.dump(Source);
  89. if (!YAMLOrErr)
  90. return YAMLOrErr.takeError();
  91. std::unique_ptr<ArchYAML::Archive> YAML(YAMLOrErr.get());
  92. yaml::Output Yout(Out);
  93. Yout << *YAML;
  94. return Error::success();
  95. }