brintos

brintos / llvm-project-archived public Read only

0
0
Text · 13.8 KiB · 2f80e62 Raw
367 lines · cpp
1//===------ utils/obj2yaml.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/ADT/StringMap.h"11#include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h"12#include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h"13#include "llvm/DebugInfo/CodeView/StringsAndChecksums.h"14#include "llvm/Object/COFF.h"15#include "llvm/ObjectYAML/COFFYAML.h"16#include "llvm/ObjectYAML/CodeViewYAMLTypes.h"17#include "llvm/Support/ErrorHandling.h"18#include "llvm/Support/YAMLTraits.h"19 20using namespace llvm;21 22namespace {23 24class COFFDumper {25  const object::COFFObjectFile &Obj;26  COFFYAML::Object YAMLObj;27  template <typename T>28  void dumpOptionalHeader(T OptionalHeader);29  void dumpHeader();30  void dumpSections(unsigned numSections);31  void dumpSymbols(unsigned numSymbols);32 33public:34  COFFDumper(const object::COFFObjectFile &Obj);35  COFFYAML::Object &getYAMLObj();36};37 38}39 40COFFDumper::COFFDumper(const object::COFFObjectFile &Obj) : Obj(Obj) {41  if (const object::pe32_header *PE32Header = Obj.getPE32Header())42    dumpOptionalHeader(PE32Header);43  else if (const object::pe32plus_header *PE32PlusHeader =44               Obj.getPE32PlusHeader())45    dumpOptionalHeader(PE32PlusHeader);46 47  dumpHeader();48  dumpSections(Obj.getNumberOfSections());49  dumpSymbols(Obj.getNumberOfSymbols());50}51 52template <typename T> void COFFDumper::dumpOptionalHeader(T OptionalHeader) {53  YAMLObj.OptionalHeader = COFFYAML::PEHeader();54  YAMLObj.OptionalHeader->Header.AddressOfEntryPoint =55      OptionalHeader->AddressOfEntryPoint;56  YAMLObj.OptionalHeader->Header.ImageBase = OptionalHeader->ImageBase;57  YAMLObj.OptionalHeader->Header.SectionAlignment =58      OptionalHeader->SectionAlignment;59  YAMLObj.OptionalHeader->Header.FileAlignment = OptionalHeader->FileAlignment;60  YAMLObj.OptionalHeader->Header.MajorOperatingSystemVersion =61      OptionalHeader->MajorOperatingSystemVersion;62  YAMLObj.OptionalHeader->Header.MinorOperatingSystemVersion =63      OptionalHeader->MinorOperatingSystemVersion;64  YAMLObj.OptionalHeader->Header.MajorImageVersion =65      OptionalHeader->MajorImageVersion;66  YAMLObj.OptionalHeader->Header.MinorImageVersion =67      OptionalHeader->MinorImageVersion;68  YAMLObj.OptionalHeader->Header.MajorSubsystemVersion =69      OptionalHeader->MajorSubsystemVersion;70  YAMLObj.OptionalHeader->Header.MinorSubsystemVersion =71      OptionalHeader->MinorSubsystemVersion;72  YAMLObj.OptionalHeader->Header.Subsystem = OptionalHeader->Subsystem;73  YAMLObj.OptionalHeader->Header.DLLCharacteristics =74      OptionalHeader->DLLCharacteristics;75  YAMLObj.OptionalHeader->Header.SizeOfStackReserve =76      OptionalHeader->SizeOfStackReserve;77  YAMLObj.OptionalHeader->Header.SizeOfStackCommit =78      OptionalHeader->SizeOfStackCommit;79  YAMLObj.OptionalHeader->Header.SizeOfHeapReserve =80      OptionalHeader->SizeOfHeapReserve;81  YAMLObj.OptionalHeader->Header.SizeOfHeapCommit =82      OptionalHeader->SizeOfHeapCommit;83  YAMLObj.OptionalHeader->Header.NumberOfRvaAndSize =84      OptionalHeader->NumberOfRvaAndSize;85  unsigned I = 0;86  for (auto &DestDD : YAMLObj.OptionalHeader->DataDirectories) {87    const object::data_directory *DD = Obj.getDataDirectory(I++);88    if (!DD)89      continue;90    DestDD = COFF::DataDirectory();91    DestDD->RelativeVirtualAddress = DD->RelativeVirtualAddress;92    DestDD->Size = DD->Size;93  }94}95 96void COFFDumper::dumpHeader() {97  YAMLObj.Header.Machine = Obj.getMachine();98  YAMLObj.Header.Characteristics = Obj.getCharacteristics();99}100 101static void102initializeFileAndStringTable(const llvm::object::COFFObjectFile &Obj,103                             codeview::StringsAndChecksumsRef &SC) {104 105  ExitOnError Err("invalid .debug$S section");106  // Iterate all .debug$S sections looking for the checksums and string table.107  // Exit as soon as both sections are found.108  for (const auto &S : Obj.sections()) {109    if (SC.hasStrings() && SC.hasChecksums())110      break;111 112    Expected<StringRef> SectionNameOrErr = S.getName();113    if (!SectionNameOrErr) {114      consumeError(SectionNameOrErr.takeError());115      continue;116    }117 118    ArrayRef<uint8_t> sectionData;119    if ((*SectionNameOrErr) != ".debug$S")120      continue;121 122    const object::coff_section *COFFSection = Obj.getCOFFSection(S);123 124    cantFail(Obj.getSectionContents(COFFSection, sectionData));125 126    BinaryStreamReader Reader(sectionData, llvm::endianness::little);127    uint32_t Magic;128 129    Err(Reader.readInteger(Magic));130    assert(Magic == COFF::DEBUG_SECTION_MAGIC && "Invalid .debug$S section!");131 132    codeview::DebugSubsectionArray Subsections;133    Err(Reader.readArray(Subsections, Reader.bytesRemaining()));134 135    SC.initialize(Subsections);136  }137}138 139void COFFDumper::dumpSections(unsigned NumSections) {140  std::vector<COFFYAML::Section> &YAMLSections = YAMLObj.Sections;141  codeview::StringsAndChecksumsRef SC;142  initializeFileAndStringTable(Obj, SC);143 144  ExitOnError Err("invalid section table");145  StringMap<bool> SymbolUnique;146  for (const auto &S : Obj.symbols()) {147    StringRef Name = Err(Obj.getSymbolName(Obj.getCOFFSymbol(S)));148    StringMap<bool>::iterator It;149    bool Inserted;150    std::tie(It, Inserted) = SymbolUnique.insert(std::make_pair(Name, true));151    if (!Inserted)152      It->second = false;153  }154 155  for (const auto &ObjSection : Obj.sections()) {156    const object::coff_section *COFFSection = Obj.getCOFFSection(ObjSection);157    COFFYAML::Section NewYAMLSection;158 159    if (Expected<StringRef> NameOrErr = ObjSection.getName())160      NewYAMLSection.Name = *NameOrErr;161    else162      consumeError(NameOrErr.takeError());163 164    NewYAMLSection.Header.Characteristics = COFFSection->Characteristics;165    NewYAMLSection.Header.VirtualAddress = COFFSection->VirtualAddress;166    NewYAMLSection.Header.VirtualSize = COFFSection->VirtualSize;167    NewYAMLSection.Header.NumberOfLineNumbers =168        COFFSection->NumberOfLinenumbers;169    NewYAMLSection.Header.NumberOfRelocations =170        COFFSection->NumberOfRelocations;171    NewYAMLSection.Header.PointerToLineNumbers =172        COFFSection->PointerToLinenumbers;173    NewYAMLSection.Header.PointerToRawData = COFFSection->PointerToRawData;174    NewYAMLSection.Header.PointerToRelocations =175        COFFSection->PointerToRelocations;176    NewYAMLSection.Header.SizeOfRawData = COFFSection->SizeOfRawData;177    uint32_t Shift = (COFFSection->Characteristics >> 20) & 0xF;178    NewYAMLSection.Alignment = (1U << Shift) >> 1;179    assert(NewYAMLSection.Alignment <= 8192);180 181    ArrayRef<uint8_t> sectionData;182    if (!ObjSection.isBSS())183      cantFail(Obj.getSectionContents(COFFSection, sectionData));184    NewYAMLSection.SectionData = yaml::BinaryRef(sectionData);185 186    if (NewYAMLSection.Name == ".debug$S")187      NewYAMLSection.DebugS = CodeViewYAML::fromDebugS(sectionData, SC);188    else if (NewYAMLSection.Name == ".debug$T")189      NewYAMLSection.DebugT = CodeViewYAML::fromDebugT(sectionData,190                                                       NewYAMLSection.Name);191    else if (NewYAMLSection.Name == ".debug$P")192      NewYAMLSection.DebugP = CodeViewYAML::fromDebugT(sectionData,193                                                       NewYAMLSection.Name);194    else if (NewYAMLSection.Name == ".debug$H")195      NewYAMLSection.DebugH = CodeViewYAML::fromDebugH(sectionData);196 197    std::vector<COFFYAML::Relocation> Relocations;198    for (const auto &Reloc : ObjSection.relocations()) {199      const object::coff_relocation *reloc = Obj.getCOFFRelocation(Reloc);200      COFFYAML::Relocation Rel;201      object::symbol_iterator Sym = Reloc.getSymbol();202      Expected<StringRef> SymbolNameOrErr = Sym->getName();203      if (!SymbolNameOrErr) {204       std::string Buf;205       raw_string_ostream OS(Buf);206       logAllUnhandledErrors(SymbolNameOrErr.takeError(), OS);207       report_fatal_error(Twine(OS.str()));208      }209      if (SymbolUnique.lookup(*SymbolNameOrErr))210        Rel.SymbolName = *SymbolNameOrErr;211      else212        Rel.SymbolTableIndex = reloc->SymbolTableIndex;213      Rel.VirtualAddress = reloc->VirtualAddress;214      Rel.Type = reloc->Type;215      Relocations.push_back(Rel);216    }217    NewYAMLSection.Relocations = Relocations;218    YAMLSections.push_back(NewYAMLSection);219  }220}221 222static void223dumpFunctionDefinition(COFFYAML::Symbol *Sym,224                       const object::coff_aux_function_definition *ObjFD) {225  COFF::AuxiliaryFunctionDefinition YAMLFD;226  YAMLFD.TagIndex = ObjFD->TagIndex;227  YAMLFD.TotalSize = ObjFD->TotalSize;228  YAMLFD.PointerToLinenumber = ObjFD->PointerToLinenumber;229  YAMLFD.PointerToNextFunction = ObjFD->PointerToNextFunction;230 231  Sym->FunctionDefinition = YAMLFD;232}233 234static void235dumpbfAndEfLineInfo(COFFYAML::Symbol *Sym,236                    const object::coff_aux_bf_and_ef_symbol *ObjBES) {237  COFF::AuxiliarybfAndefSymbol YAMLAAS;238  YAMLAAS.Linenumber = ObjBES->Linenumber;239  YAMLAAS.PointerToNextFunction = ObjBES->PointerToNextFunction;240 241  Sym->bfAndefSymbol = YAMLAAS;242}243 244static void dumpWeakExternal(COFFYAML::Symbol *Sym,245                             const object::coff_aux_weak_external *ObjWE) {246  COFF::AuxiliaryWeakExternal YAMLWE;247  YAMLWE.TagIndex = ObjWE->TagIndex;248  YAMLWE.Characteristics = ObjWE->Characteristics;249 250  Sym->WeakExternal = YAMLWE;251}252 253static void254dumpSectionDefinition(COFFYAML::Symbol *Sym,255                      const object::coff_aux_section_definition *ObjSD,256                      bool IsBigObj) {257  COFF::AuxiliarySectionDefinition YAMLASD;258  int32_t AuxNumber = ObjSD->getNumber(IsBigObj);259  YAMLASD.Length = ObjSD->Length;260  YAMLASD.NumberOfRelocations = ObjSD->NumberOfRelocations;261  YAMLASD.NumberOfLinenumbers = ObjSD->NumberOfLinenumbers;262  YAMLASD.CheckSum = ObjSD->CheckSum;263  YAMLASD.Number = AuxNumber;264  YAMLASD.Selection = ObjSD->Selection;265 266  Sym->SectionDefinition = YAMLASD;267}268 269static void270dumpCLRTokenDefinition(COFFYAML::Symbol *Sym,271                       const object::coff_aux_clr_token *ObjCLRToken) {272  COFF::AuxiliaryCLRToken YAMLCLRToken;273  YAMLCLRToken.AuxType = ObjCLRToken->AuxType;274  YAMLCLRToken.SymbolTableIndex = ObjCLRToken->SymbolTableIndex;275 276  Sym->CLRToken = YAMLCLRToken;277}278 279void COFFDumper::dumpSymbols(unsigned NumSymbols) {280  ExitOnError Err("invalid symbol table");281 282  std::vector<COFFYAML::Symbol> &Symbols = YAMLObj.Symbols;283  for (const auto &S : Obj.symbols()) {284    object::COFFSymbolRef Symbol = Obj.getCOFFSymbol(S);285    COFFYAML::Symbol Sym;286    Sym.Name = Err(Obj.getSymbolName(Symbol));287    Sym.SimpleType = COFF::SymbolBaseType(Symbol.getBaseType());288    Sym.ComplexType = COFF::SymbolComplexType(Symbol.getComplexType());289    Sym.Header.StorageClass = Symbol.getStorageClass();290    Sym.Header.Value = Symbol.getValue();291    Sym.Header.SectionNumber = Symbol.getSectionNumber();292    Sym.Header.NumberOfAuxSymbols = Symbol.getNumberOfAuxSymbols();293 294    if (Symbol.getNumberOfAuxSymbols() > 0) {295      ArrayRef<uint8_t> AuxData = Obj.getSymbolAuxData(Symbol);296      if (Symbol.isFunctionDefinition()) {297        // This symbol represents a function definition.298        assert(Symbol.getNumberOfAuxSymbols() == 1 &&299               "Expected a single aux symbol to describe this function!");300 301        const object::coff_aux_function_definition *ObjFD =302            reinterpret_cast<const object::coff_aux_function_definition *>(303                AuxData.data());304        dumpFunctionDefinition(&Sym, ObjFD);305      } else if (Symbol.isFunctionLineInfo()) {306        // This symbol describes function line number information.307        assert(Symbol.getNumberOfAuxSymbols() == 1 &&308               "Expected a single aux symbol to describe this function!");309 310        const object::coff_aux_bf_and_ef_symbol *ObjBES =311            reinterpret_cast<const object::coff_aux_bf_and_ef_symbol *>(312                AuxData.data());313        dumpbfAndEfLineInfo(&Sym, ObjBES);314      } else if (Symbol.isAnyUndefined()) {315        // This symbol represents a weak external definition.316        assert(Symbol.getNumberOfAuxSymbols() == 1 &&317               "Expected a single aux symbol to describe this weak symbol!");318 319        const object::coff_aux_weak_external *ObjWE =320            reinterpret_cast<const object::coff_aux_weak_external *>(321                AuxData.data());322        dumpWeakExternal(&Sym, ObjWE);323      } else if (Symbol.isFileRecord()) {324        // This symbol represents a file record.325        Sym.File = StringRef(reinterpret_cast<const char *>(AuxData.data()),326                             Symbol.getNumberOfAuxSymbols() *327                                 Obj.getSymbolTableEntrySize())328                       .rtrim(StringRef("\0", /*length=*/1));329      } else if (Symbol.isSectionDefinition()) {330        // This symbol represents a section definition.331        assert(Symbol.getNumberOfAuxSymbols() == 1 &&332               "Expected a single aux symbol to describe this section!");333 334        const object::coff_aux_section_definition *ObjSD =335            reinterpret_cast<const object::coff_aux_section_definition *>(336                AuxData.data());337        dumpSectionDefinition(&Sym, ObjSD, Symbol.isBigObj());338      } else if (Symbol.isCLRToken()) {339        // This symbol represents a CLR token definition.340        assert(Symbol.getNumberOfAuxSymbols() == 1 &&341               "Expected a single aux symbol to describe this CLR Token!");342 343        const object::coff_aux_clr_token *ObjCLRToken =344            reinterpret_cast<const object::coff_aux_clr_token *>(345                AuxData.data());346        dumpCLRTokenDefinition(&Sym, ObjCLRToken);347      } else {348        llvm_unreachable("Unhandled auxiliary symbol!");349      }350    }351    Symbols.push_back(Sym);352  }353}354 355COFFYAML::Object &COFFDumper::getYAMLObj() {356  return YAMLObj;357}358 359std::error_code coff2yaml(raw_ostream &Out, const object::COFFObjectFile &Obj) {360  COFFDumper Dumper(Obj);361 362  yaml::Output Yout(Out);363  Yout << Dumper.getYAMLObj();364 365  return std::error_code();366}367