brintos

brintos / llvm-project-archived public Read only

0
0
Text · 3.7 KiB · 35bcd43 Raw
115 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9#include "obj2yaml.h"10#include "llvm/BinaryFormat/Magic.h"11#include "llvm/ObjectYAML/ArchiveYAML.h"12 13using namespace llvm;14 15namespace {16 17class ArchiveDumper {18public:19  Expected<ArchYAML::Archive *> dump(MemoryBufferRef Source) {20    StringRef Buffer = Source.getBuffer();21    assert(file_magic::archive == identify_magic(Buffer));22 23    std::unique_ptr<ArchYAML::Archive> Obj =24        std::make_unique<ArchYAML::Archive>();25 26    StringRef Magic = "!<arch>\n";27    if (!Buffer.starts_with(Magic))28      return createStringError(std::errc::not_supported,29                               "only regular archives are supported");30    Obj->Magic = Magic;31    Buffer = Buffer.drop_front(Magic.size());32 33    Obj->Members.emplace();34    while (!Buffer.empty()) {35      uint64_t Offset = Buffer.data() - Source.getBuffer().data();36      if (Buffer.size() < sizeof(ArchiveHeader))37        return createStringError(38            std::errc::illegal_byte_sequence,39            "unable to read the header of a child at offset 0x%" PRIx64,40            Offset);41 42      const ArchiveHeader &Hdr =43          *reinterpret_cast<const ArchiveHeader *>(Buffer.data());44      Buffer = Buffer.drop_front(sizeof(ArchiveHeader));45 46      auto ToString = [](ArrayRef<char> V) {47        // We don't want to dump excessive spaces.48        return StringRef(V.data(), V.size()).rtrim(' ');49      };50 51      ArchYAML::Archive::Child C;52      C.Fields["Name"].Value = ToString(Hdr.Name);53      C.Fields["LastModified"].Value = ToString(Hdr.LastModified);54      C.Fields["UID"].Value = ToString(Hdr.UID);55      C.Fields["GID"].Value = ToString(Hdr.GID);56      C.Fields["AccessMode"].Value = ToString(Hdr.AccessMode);57      StringRef SizeStr = ToString(Hdr.Size);58      C.Fields["Size"].Value = SizeStr;59      C.Fields["Terminator"].Value = ToString(Hdr.Terminator);60 61      uint64_t Size;62      if (SizeStr.getAsInteger(10, Size))63        return createStringError(64            std::errc::illegal_byte_sequence,65            "unable to read the size of a child at offset 0x%" PRIx6466            " as integer: \"%s\"",67            Offset, SizeStr.str().c_str());68      if (Buffer.size() < Size)69        return createStringError(70            std::errc::illegal_byte_sequence,71            "unable to read the data of a child at offset 0x%" PRIx6472            " of size %" PRId64 ": the remaining archive size is %zu",73            Offset, Size, Buffer.size());74      if (!Buffer.empty())75        C.Content = arrayRefFromStringRef(Buffer.take_front(Size));76 77      const bool HasPaddingByte = (Size & 1) && Buffer.size() > Size;78      if (HasPaddingByte)79        C.PaddingByte = Buffer[Size];80 81      Obj->Members->push_back(C);82      // If the size is odd, consume a padding byte.83      Buffer = Buffer.drop_front(HasPaddingByte ? Size + 1 : Size);84    }85 86    return Obj.release();87  }88 89private:90  struct ArchiveHeader {91    char Name[16];92    char LastModified[12];93    char UID[6];94    char GID[6];95    char AccessMode[8];96    char Size[10];97    char Terminator[2];98  };99};100 101} // namespace102 103Error archive2yaml(raw_ostream &Out, MemoryBufferRef Source) {104  ArchiveDumper Dumper;105  Expected<ArchYAML::Archive *> YAMLOrErr = Dumper.dump(Source);106  if (!YAMLOrErr)107    return YAMLOrErr.takeError();108 109  std::unique_ptr<ArchYAML::Archive> YAML(YAMLOrErr.get());110  yaml::Output Yout(Out);111  Yout << *YAML;112 113  return Error::success();114}115