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