123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114 |
- //===------ utils/archive2yaml.cpp - obj2yaml conversion tool ---*- C++ -*-===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- #include "obj2yaml.h"
- #include "llvm/BinaryFormat/Magic.h"
- #include "llvm/ObjectYAML/ArchiveYAML.h"
- using namespace llvm;
- namespace {
- class ArchiveDumper {
- public:
- Expected<ArchYAML::Archive *> dump(MemoryBufferRef Source) {
- StringRef Buffer = Source.getBuffer();
- assert(file_magic::archive == identify_magic(Buffer));
- std::unique_ptr<ArchYAML::Archive> Obj =
- std::make_unique<ArchYAML::Archive>();
- StringRef Magic = "!<arch>\n";
- if (!Buffer.startswith(Magic))
- return createStringError(std::errc::not_supported,
- "only regular archives are supported");
- Obj->Magic = Magic;
- Buffer = Buffer.drop_front(Magic.size());
- Obj->Members.emplace();
- while (!Buffer.empty()) {
- uint64_t Offset = Buffer.data() - Source.getBuffer().data();
- if (Buffer.size() < sizeof(ArchiveHeader))
- return createStringError(
- std::errc::illegal_byte_sequence,
- "unable to read the header of a child at offset 0x%" PRIx64,
- Offset);
- const ArchiveHeader &Hdr =
- *reinterpret_cast<const ArchiveHeader *>(Buffer.data());
- Buffer = Buffer.drop_front(sizeof(ArchiveHeader));
- auto ToString = [](ArrayRef<char> V) {
- // We don't want to dump excessive spaces.
- return StringRef(V.data(), V.size()).rtrim(' ');
- };
- ArchYAML::Archive::Child C;
- C.Fields["Name"].Value = ToString(Hdr.Name);
- C.Fields["LastModified"].Value = ToString(Hdr.LastModified);
- C.Fields["UID"].Value = ToString(Hdr.UID);
- C.Fields["GID"].Value = ToString(Hdr.GID);
- C.Fields["AccessMode"].Value = ToString(Hdr.AccessMode);
- StringRef SizeStr = ToString(Hdr.Size);
- C.Fields["Size"].Value = SizeStr;
- C.Fields["Terminator"].Value = ToString(Hdr.Terminator);
- uint64_t Size;
- if (SizeStr.getAsInteger(10, Size))
- return createStringError(
- std::errc::illegal_byte_sequence,
- "unable to read the size of a child at offset 0x%" PRIx64
- " as integer: \"%s\"",
- Offset, SizeStr.str().c_str());
- if (Buffer.size() < Size)
- return createStringError(
- std::errc::illegal_byte_sequence,
- "unable to read the data of a child at offset 0x%" PRIx64
- " of size %" PRId64 ": the remaining archive size is %zu",
- Offset, Size, Buffer.size());
- if (!Buffer.empty())
- C.Content = arrayRefFromStringRef(Buffer.take_front(Size));
- const bool HasPaddingByte = (Size & 1) && Buffer.size() > Size;
- if (HasPaddingByte)
- C.PaddingByte = Buffer[Size];
- Obj->Members->push_back(C);
- // If the size is odd, consume a padding byte.
- Buffer = Buffer.drop_front(HasPaddingByte ? Size + 1 : Size);
- }
- return Obj.release();
- }
- private:
- struct ArchiveHeader {
- char Name[16];
- char LastModified[12];
- char UID[6];
- char GID[6];
- char AccessMode[8];
- char Size[10];
- char Terminator[2];
- };
- };
- } // namespace
- Error archive2yaml(raw_ostream &Out, MemoryBufferRef Source) {
- ArchiveDumper Dumper;
- Expected<ArchYAML::Archive *> YAMLOrErr = Dumper.dump(Source);
- if (!YAMLOrErr)
- return YAMLOrErr.takeError();
- std::unique_ptr<ArchYAML::Archive> YAML(YAMLOrErr.get());
- yaml::Output Yout(Out);
- Yout << *YAML;
- return Error::success();
- }
|