934 lines · cpp
1//===-- COFFDump.cpp - COFF-specific dumper ---------------------*- 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/// \file10/// This file implements the COFF-specific dumper for llvm-objdump.11/// It outputs the Win64 EH data structures as plain text.12/// The encoding of the unwind codes is described in MSDN:13/// https://docs.microsoft.com/en-us/cpp/build/exception-handling-x6414///15//===----------------------------------------------------------------------===//16 17#include "COFFDump.h"18 19#include "llvm-objdump.h"20#include "llvm/Demangle/Demangle.h"21#include "llvm/Object/COFF.h"22#include "llvm/Object/COFFImportFile.h"23#include "llvm/Object/ObjectFile.h"24#include "llvm/Support/Format.h"25#include "llvm/Support/Win64EH.h"26#include "llvm/Support/WithColor.h"27#include "llvm/Support/raw_ostream.h"28 29using namespace llvm;30using namespace llvm::objdump;31using namespace llvm::object;32using namespace llvm::Win64EH;33 34namespace {35template <typename T> struct EnumEntry {36 T Value;37 StringRef Name;38};39 40class COFFDumper : public Dumper {41public:42 explicit COFFDumper(const llvm::object::COFFObjectFile &O)43 : Dumper(O), Obj(O) {44 Is64 = !Obj.getPE32Header();45 }46 47 template <class PEHeader> void printPEHeader(const PEHeader &Hdr) const;48 void printPrivateHeaders() override;49 50private:51 template <typename T> FormattedNumber formatAddr(T V) const {52 return format_hex_no_prefix(V, Is64 ? 16 : 8);53 }54 55 uint32_t getBaseOfData(const void *Hdr) const {56 return Is64 ? 0 : static_cast<const pe32_header *>(Hdr)->BaseOfData;57 }58 59 const llvm::object::COFFObjectFile &Obj;60 bool Is64;61};62} // namespace63 64std::unique_ptr<Dumper>65objdump::createCOFFDumper(const object::COFFObjectFile &Obj) {66 return std::make_unique<COFFDumper>(Obj);67}68 69constexpr EnumEntry<uint16_t> PEHeaderMagic[] = {70 {uint16_t(COFF::PE32Header::PE32), "PE32"},71 {uint16_t(COFF::PE32Header::PE32_PLUS), "PE32+"},72};73 74constexpr EnumEntry<COFF::WindowsSubsystem> PEWindowsSubsystem[] = {75 {COFF::IMAGE_SUBSYSTEM_UNKNOWN, "unspecified"},76 {COFF::IMAGE_SUBSYSTEM_NATIVE, "NT native"},77 {COFF::IMAGE_SUBSYSTEM_WINDOWS_GUI, "Windows GUI"},78 {COFF::IMAGE_SUBSYSTEM_WINDOWS_CUI, "Windows CUI"},79 {COFF::IMAGE_SUBSYSTEM_POSIX_CUI, "POSIX CUI"},80 {COFF::IMAGE_SUBSYSTEM_WINDOWS_CE_GUI, "Wince CUI"},81 {COFF::IMAGE_SUBSYSTEM_EFI_APPLICATION, "EFI application"},82 {COFF::IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER, "EFI boot service driver"},83 {COFF::IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER, "EFI runtime driver"},84 {COFF::IMAGE_SUBSYSTEM_EFI_ROM, "SAL runtime driver"},85 {COFF::IMAGE_SUBSYSTEM_XBOX, "XBOX"},86};87 88template <typename T, typename TEnum>89static void printOptionalEnumName(T Value,90 ArrayRef<EnumEntry<TEnum>> EnumValues) {91 for (const EnumEntry<TEnum> &I : EnumValues)92 if (I.Value == Value) {93 outs() << "\t(" << I.Name << ')';94 return;95 }96}97 98template <class PEHeader>99void COFFDumper::printPEHeader(const PEHeader &Hdr) const {100 auto print = [](const char *K, auto V, const char *Fmt = "%d\n") {101 outs() << format("%-23s ", K) << format(Fmt, V);102 };103 auto printU16 = [&](const char *K, support::ulittle16_t V,104 const char *Fmt = "%d\n") { print(K, uint16_t(V), Fmt); };105 auto printU32 = [&](const char *K, support::ulittle32_t V,106 const char *Fmt = "%d\n") { print(K, uint32_t(V), Fmt); };107 auto printAddr = [=](const char *K, uint64_t V) {108 outs() << format("%-23s ", K) << formatAddr(V) << '\n';109 };110 111 printU16("Magic", Hdr.Magic, "%04x");112 printOptionalEnumName(Hdr.Magic, ArrayRef(PEHeaderMagic));113 outs() << '\n';114 print("MajorLinkerVersion", Hdr.MajorLinkerVersion);115 print("MinorLinkerVersion", Hdr.MinorLinkerVersion);116 printAddr("SizeOfCode", Hdr.SizeOfCode);117 printAddr("SizeOfInitializedData", Hdr.SizeOfInitializedData);118 printAddr("SizeOfUninitializedData", Hdr.SizeOfUninitializedData);119 printAddr("AddressOfEntryPoint", Hdr.AddressOfEntryPoint);120 printAddr("BaseOfCode", Hdr.BaseOfCode);121 if (!Is64)122 printAddr("BaseOfData", getBaseOfData(&Hdr));123 printAddr("ImageBase", Hdr.ImageBase);124 printU32("SectionAlignment", Hdr.SectionAlignment, "%08x\n");125 printU32("FileAlignment", Hdr.FileAlignment, "%08x\n");126 printU16("MajorOSystemVersion", Hdr.MajorOperatingSystemVersion);127 printU16("MinorOSystemVersion", Hdr.MinorOperatingSystemVersion);128 printU16("MajorImageVersion", Hdr.MajorImageVersion);129 printU16("MinorImageVersion", Hdr.MinorImageVersion);130 printU16("MajorSubsystemVersion", Hdr.MajorSubsystemVersion);131 printU16("MinorSubsystemVersion", Hdr.MinorSubsystemVersion);132 printU32("Win32Version", Hdr.Win32VersionValue, "%08x\n");133 printU32("SizeOfImage", Hdr.SizeOfImage, "%08x\n");134 printU32("SizeOfHeaders", Hdr.SizeOfHeaders, "%08x\n");135 printU32("CheckSum", Hdr.CheckSum, "%08x\n");136 printU16("Subsystem", Hdr.Subsystem, "%08x");137 printOptionalEnumName(Hdr.Subsystem, ArrayRef(PEWindowsSubsystem));138 outs() << '\n';139 140 printU16("DllCharacteristics", Hdr.DLLCharacteristics, "%08x\n");141#define FLAG(Name) \142 if (Hdr.DLLCharacteristics & COFF::IMAGE_DLL_CHARACTERISTICS_##Name) \143 outs() << "\t\t\t\t\t" << #Name << '\n';144 FLAG(HIGH_ENTROPY_VA);145 FLAG(DYNAMIC_BASE);146 FLAG(FORCE_INTEGRITY);147 FLAG(NX_COMPAT);148 FLAG(NO_ISOLATION);149 FLAG(NO_SEH);150 FLAG(NO_BIND);151 FLAG(APPCONTAINER);152 FLAG(WDM_DRIVER);153 FLAG(GUARD_CF);154 FLAG(TERMINAL_SERVER_AWARE);155#undef FLAG156 157 printAddr("SizeOfStackReserve", Hdr.SizeOfStackReserve);158 printAddr("SizeOfStackCommit", Hdr.SizeOfStackCommit);159 printAddr("SizeOfHeapReserve", Hdr.SizeOfHeapReserve);160 printAddr("SizeOfHeapCommit", Hdr.SizeOfHeapCommit);161 printU32("LoaderFlags", Hdr.LoaderFlags, "%08x\n");162 printU32("NumberOfRvaAndSizes", Hdr.NumberOfRvaAndSize, "%08x\n");163 164 static const char *DirName[COFF::NUM_DATA_DIRECTORIES + 1] = {165 "Export Directory [.edata (or where ever we found it)]",166 "Import Directory [parts of .idata]",167 "Resource Directory [.rsrc]",168 "Exception Directory [.pdata]",169 "Security Directory",170 "Base Relocation Directory [.reloc]",171 "Debug Directory",172 "Description Directory",173 "Special Directory",174 "Thread Storage Directory [.tls]",175 "Load Configuration Directory",176 "Bound Import Directory",177 "Import Address Table Directory",178 "Delay Import Directory",179 "CLR Runtime Header",180 "Reserved",181 };182 outs() << "\nThe Data Directory\n";183 for (uint32_t I = 0; I != std::size(DirName); ++I) {184 uint32_t Addr = 0, Size = 0;185 if (const data_directory *Data = Obj.getDataDirectory(I)) {186 Addr = Data->RelativeVirtualAddress;187 Size = Data->Size;188 }189 outs() << format("Entry %x ", I) << formatAddr(Addr)190 << format(" %08x %s\n", Size, DirName[I]);191 }192}193 194// Returns the name of the unwind code.195static StringRef getUnwindCodeTypeName(uint8_t Code) {196 switch(Code) {197 default: llvm_unreachable("Invalid unwind code");198 case UOP_PushNonVol: return "UOP_PushNonVol";199 case UOP_AllocLarge: return "UOP_AllocLarge";200 case UOP_AllocSmall: return "UOP_AllocSmall";201 case UOP_SetFPReg: return "UOP_SetFPReg";202 case UOP_SaveNonVol: return "UOP_SaveNonVol";203 case UOP_SaveNonVolBig: return "UOP_SaveNonVolBig";204 case UOP_Epilog: return "UOP_Epilog";205 case UOP_SpareCode: return "UOP_SpareCode";206 case UOP_SaveXMM128: return "UOP_SaveXMM128";207 case UOP_SaveXMM128Big: return "UOP_SaveXMM128Big";208 case UOP_PushMachFrame: return "UOP_PushMachFrame";209 }210}211 212// Returns the name of a referenced register.213static StringRef getUnwindRegisterName(uint8_t Reg) {214 switch(Reg) {215 default: llvm_unreachable("Invalid register");216 case 0: return "RAX";217 case 1: return "RCX";218 case 2: return "RDX";219 case 3: return "RBX";220 case 4: return "RSP";221 case 5: return "RBP";222 case 6: return "RSI";223 case 7: return "RDI";224 case 8: return "R8";225 case 9: return "R9";226 case 10: return "R10";227 case 11: return "R11";228 case 12: return "R12";229 case 13: return "R13";230 case 14: return "R14";231 case 15: return "R15";232 }233}234 235// Calculates the number of array slots required for the unwind code.236static unsigned getNumUsedSlots(const UnwindCode &UnwindCode) {237 switch (UnwindCode.getUnwindOp()) {238 default: llvm_unreachable("Invalid unwind code");239 case UOP_PushNonVol:240 case UOP_AllocSmall:241 case UOP_SetFPReg:242 case UOP_PushMachFrame:243 case UOP_Epilog:244 return 1;245 case UOP_SaveNonVol:246 case UOP_SaveXMM128:247 return 2;248 case UOP_SaveNonVolBig:249 case UOP_SaveXMM128Big:250 case UOP_SpareCode:251 return 3;252 case UOP_AllocLarge:253 return (UnwindCode.getOpInfo() == 0) ? 2 : 3;254 }255}256 257// Prints one unwind code. Because an unwind code can occupy up to 3 slots in258// the unwind codes array, this function requires that the correct number of259// slots is provided.260static void printUnwindCode(ArrayRef<UnwindCode> UCs, bool &SeenFirstEpilog) {261 assert(UCs.size() >= getNumUsedSlots(UCs[0]));262 outs() << format(" 0x%02x: ", unsigned(UCs[0].u.CodeOffset))263 << getUnwindCodeTypeName(UCs[0].getUnwindOp());264 switch (UCs[0].getUnwindOp()) {265 case UOP_PushNonVol:266 outs() << " " << getUnwindRegisterName(UCs[0].getOpInfo());267 break;268 case UOP_AllocLarge:269 if (UCs[0].getOpInfo() == 0) {270 outs() << " " << UCs[1].FrameOffset;271 } else {272 outs() << " " << UCs[1].FrameOffset273 + (static_cast<uint32_t>(UCs[2].FrameOffset) << 16);274 }275 break;276 case UOP_AllocSmall:277 outs() << " " << ((UCs[0].getOpInfo() + 1) * 8);278 break;279 case UOP_SetFPReg:280 outs() << " ";281 break;282 case UOP_SaveNonVol:283 outs() << " " << getUnwindRegisterName(UCs[0].getOpInfo())284 << format(" [0x%04x]", 8 * UCs[1].FrameOffset);285 break;286 case UOP_SaveNonVolBig:287 outs() << " " << getUnwindRegisterName(UCs[0].getOpInfo())288 << format(" [0x%08x]", UCs[1].FrameOffset289 + (static_cast<uint32_t>(UCs[2].FrameOffset) << 16));290 break;291 case UOP_SaveXMM128:292 outs() << " XMM" << static_cast<uint32_t>(UCs[0].getOpInfo())293 << format(" [0x%04x]", 16 * UCs[1].FrameOffset);294 break;295 case UOP_SaveXMM128Big:296 outs() << " XMM" << UCs[0].getOpInfo()297 << format(" [0x%08x]", UCs[1].FrameOffset298 + (static_cast<uint32_t>(UCs[2].FrameOffset) << 16));299 break;300 case UOP_PushMachFrame:301 outs() << " " << (UCs[0].getOpInfo() ? "w/o" : "w")302 << " error code";303 break;304 305 case UOP_Epilog:306 if (SeenFirstEpilog) {307 uint32_t Offset = UCs[0].getEpilogOffset();308 if (Offset == 0) {309 outs() << " padding";310 } else {311 outs() << " offset=" << format("0x%X", Offset);312 }313 } else {314 SeenFirstEpilog = true;315 bool AtEnd = (UCs[0].getOpInfo() & 0x1) != 0;316 uint32_t Length = UCs[0].u.CodeOffset;317 outs() << " atend=" << (AtEnd ? "yes" : "no")318 << ", length=" << format("0x%X", Length);319 }320 break;321 }322 outs() << "\n";323}324 325static void printAllUnwindCodes(ArrayRef<UnwindCode> UCs) {326 bool SeenFirstEpilog = false;327 for (const UnwindCode *I = UCs.begin(), *E = UCs.end(); I < E; ) {328 unsigned UsedSlots = getNumUsedSlots(*I);329 if (UsedSlots > UCs.size()) {330 outs() << "Unwind data corrupted: Encountered unwind op "331 << getUnwindCodeTypeName((*I).getUnwindOp())332 << " which requires " << UsedSlots333 << " slots, but only " << UCs.size()334 << " remaining in buffer";335 return ;336 }337 printUnwindCode(ArrayRef(I, E), SeenFirstEpilog);338 I += UsedSlots;339 }340}341 342// Given a symbol sym this functions returns the address and section of it.343static Error resolveSectionAndAddress(const COFFObjectFile *Obj,344 const SymbolRef &Sym,345 const coff_section *&ResolvedSection,346 uint64_t &ResolvedAddr) {347 Expected<uint64_t> ResolvedAddrOrErr = Sym.getAddress();348 if (!ResolvedAddrOrErr)349 return ResolvedAddrOrErr.takeError();350 ResolvedAddr = *ResolvedAddrOrErr;351 Expected<section_iterator> Iter = Sym.getSection();352 if (!Iter)353 return Iter.takeError();354 ResolvedSection = Obj->getCOFFSection(**Iter);355 return Error::success();356}357 358// Given a vector of relocations for a section and an offset into this section359// the function returns the symbol used for the relocation at the offset.360static Error resolveSymbol(const std::vector<RelocationRef> &Rels,361 uint64_t Offset, SymbolRef &Sym) {362 for (auto &R : Rels) {363 uint64_t Ofs = R.getOffset();364 if (Ofs == Offset) {365 Sym = *R.getSymbol();366 return Error::success();367 }368 }369 return make_error<BinaryError>();370}371 372// Given a vector of relocations for a section and an offset into this section373// the function resolves the symbol used for the relocation at the offset and374// returns the section content and the address inside the content pointed to375// by the symbol.376static Error377getSectionContents(const COFFObjectFile *Obj,378 const std::vector<RelocationRef> &Rels, uint64_t Offset,379 ArrayRef<uint8_t> &Contents, uint64_t &Addr) {380 SymbolRef Sym;381 if (Error E = resolveSymbol(Rels, Offset, Sym))382 return E;383 const coff_section *Section;384 if (Error E = resolveSectionAndAddress(Obj, Sym, Section, Addr))385 return E;386 return Obj->getSectionContents(Section, Contents);387}388 389// Given a vector of relocations for a section and an offset into this section390// the function returns the name of the symbol used for the relocation at the391// offset.392static Error resolveSymbolName(const std::vector<RelocationRef> &Rels,393 uint64_t Offset, StringRef &Name) {394 SymbolRef Sym;395 if (Error EC = resolveSymbol(Rels, Offset, Sym))396 return EC;397 Expected<StringRef> NameOrErr = Sym.getName();398 if (!NameOrErr)399 return NameOrErr.takeError();400 Name = *NameOrErr;401 return Error::success();402}403 404static void printCOFFSymbolAddress(raw_ostream &Out,405 const std::vector<RelocationRef> &Rels,406 uint64_t Offset, uint32_t Disp) {407 StringRef Sym;408 if (!resolveSymbolName(Rels, Offset, Sym)) {409 Out << Sym;410 if (Disp > 0)411 Out << format(" + 0x%04x", Disp);412 } else {413 Out << format("0x%04x", Disp);414 }415}416 417static void418printSEHTable(const COFFObjectFile *Obj, uint32_t TableVA, int Count) {419 if (Count == 0)420 return;421 422 uintptr_t IntPtr = 0;423 if (Error E = Obj->getVaPtr(TableVA, IntPtr))424 reportError(std::move(E), Obj->getFileName());425 426 const support::ulittle32_t *P = (const support::ulittle32_t *)IntPtr;427 outs() << "SEH Table:";428 for (int I = 0; I < Count; ++I)429 outs() << format(" 0x%x", P[I] + Obj->getPE32Header()->ImageBase);430 outs() << "\n\n";431}432 433template <typename T>434static void printTLSDirectoryT(const coff_tls_directory<T> *TLSDir) {435 size_t FormatWidth = sizeof(T) * 2;436 outs() << "TLS directory:"437 << "\n StartAddressOfRawData: "438 << format_hex(TLSDir->StartAddressOfRawData, FormatWidth)439 << "\n EndAddressOfRawData: "440 << format_hex(TLSDir->EndAddressOfRawData, FormatWidth)441 << "\n AddressOfIndex: "442 << format_hex(TLSDir->AddressOfIndex, FormatWidth)443 << "\n AddressOfCallBacks: "444 << format_hex(TLSDir->AddressOfCallBacks, FormatWidth)445 << "\n SizeOfZeroFill: "446 << TLSDir->SizeOfZeroFill447 << "\n Characteristics: "448 << TLSDir->Characteristics449 << "\n Alignment: "450 << TLSDir->getAlignment()451 << "\n\n";452}453 454static void printTLSDirectory(const COFFObjectFile *Obj) {455 const pe32_header *PE32Header = Obj->getPE32Header();456 const pe32plus_header *PE32PlusHeader = Obj->getPE32PlusHeader();457 458 // Skip if it's not executable.459 if (!PE32Header && !PE32PlusHeader)460 return;461 462 if (PE32Header) {463 if (auto *TLSDir = Obj->getTLSDirectory32())464 printTLSDirectoryT(TLSDir);465 } else {466 if (auto *TLSDir = Obj->getTLSDirectory64())467 printTLSDirectoryT(TLSDir);468 }469 470 outs() << "\n";471}472 473static void printLoadConfiguration(const COFFObjectFile *Obj) {474 // Skip if it's not executable.475 if (!Obj->getPE32Header())476 return;477 478 // Currently only x86 is supported479 if (Obj->getMachine() != COFF::IMAGE_FILE_MACHINE_I386)480 return;481 482 auto *LoadConf = Obj->getLoadConfig32();483 if (!LoadConf)484 return;485 486 outs() << "Load configuration:"487 << "\n Timestamp: " << LoadConf->TimeDateStamp488 << "\n Major Version: " << LoadConf->MajorVersion489 << "\n Minor Version: " << LoadConf->MinorVersion490 << "\n GlobalFlags Clear: " << LoadConf->GlobalFlagsClear491 << "\n GlobalFlags Set: " << LoadConf->GlobalFlagsSet492 << "\n Critical Section Default Timeout: " << LoadConf->CriticalSectionDefaultTimeout493 << "\n Decommit Free Block Threshold: " << LoadConf->DeCommitFreeBlockThreshold494 << "\n Decommit Total Free Threshold: " << LoadConf->DeCommitTotalFreeThreshold495 << "\n Lock Prefix Table: " << LoadConf->LockPrefixTable496 << "\n Maximum Allocation Size: " << LoadConf->MaximumAllocationSize497 << "\n Virtual Memory Threshold: " << LoadConf->VirtualMemoryThreshold498 << "\n Process Affinity Mask: " << LoadConf->ProcessAffinityMask499 << "\n Process Heap Flags: " << LoadConf->ProcessHeapFlags500 << "\n CSD Version: " << LoadConf->CSDVersion501 << "\n Security Cookie: " << LoadConf->SecurityCookie502 << "\n SEH Table: " << LoadConf->SEHandlerTable503 << "\n SEH Count: " << LoadConf->SEHandlerCount504 << "\n\n";505 printSEHTable(Obj, LoadConf->SEHandlerTable, LoadConf->SEHandlerCount);506 outs() << "\n";507}508 509// Prints import tables. The import table is a table containing the list of510// DLL name and symbol names which will be linked by the loader.511static void printImportTables(const COFFObjectFile *Obj) {512 import_directory_iterator I = Obj->import_directory_begin();513 import_directory_iterator E = Obj->import_directory_end();514 if (I == E)515 return;516 outs() << "The Import Tables:\n";517 for (const ImportDirectoryEntryRef &DirRef : Obj->import_directories()) {518 const coff_import_directory_table_entry *Dir;519 StringRef Name;520 if (DirRef.getImportTableEntry(Dir)) return;521 if (DirRef.getName(Name)) return;522 523 outs() << format(" lookup %08x time %08x fwd %08x name %08x addr %08x\n\n",524 static_cast<uint32_t>(Dir->ImportLookupTableRVA),525 static_cast<uint32_t>(Dir->TimeDateStamp),526 static_cast<uint32_t>(Dir->ForwarderChain),527 static_cast<uint32_t>(Dir->NameRVA),528 static_cast<uint32_t>(Dir->ImportAddressTableRVA));529 outs() << " DLL Name: " << Name << "\n";530 outs() << " Hint/Ord Name\n";531 for (const ImportedSymbolRef &Entry : DirRef.imported_symbols()) {532 bool IsOrdinal;533 if (Entry.isOrdinal(IsOrdinal))534 return;535 if (IsOrdinal) {536 uint16_t Ordinal;537 if (Entry.getOrdinal(Ordinal))538 return;539 outs() << format(" % 6d\n", Ordinal);540 continue;541 }542 uint32_t HintNameRVA;543 if (Entry.getHintNameRVA(HintNameRVA))544 return;545 uint16_t Hint;546 StringRef Name;547 if (Obj->getHintName(HintNameRVA, Hint, Name))548 return;549 outs() << format(" % 6d ", Hint) << Name << "\n";550 }551 outs() << "\n";552 }553}554 555// Prints export tables. The export table is a table containing the list of556// exported symbol from the DLL.557static void printExportTable(const COFFObjectFile *Obj) {558 export_directory_iterator I = Obj->export_directory_begin();559 export_directory_iterator E = Obj->export_directory_end();560 if (I == E)561 return;562 outs() << "Export Table:\n";563 StringRef DllName;564 uint32_t OrdinalBase;565 if (I->getDllName(DllName))566 return;567 if (I->getOrdinalBase(OrdinalBase))568 return;569 outs() << " DLL name: " << DllName << "\n";570 outs() << " Ordinal base: " << OrdinalBase << "\n";571 outs() << " Ordinal RVA Name\n";572 for (; I != E; I = ++I) {573 uint32_t RVA;574 if (I->getExportRVA(RVA))575 return;576 StringRef Name;577 if (I->getSymbolName(Name))578 continue;579 if (!RVA && Name.empty())580 continue;581 582 uint32_t Ordinal;583 if (I->getOrdinal(Ordinal))584 return;585 bool IsForwarder;586 if (I->isForwarder(IsForwarder))587 return;588 589 if (IsForwarder) {590 // Export table entries can be used to re-export symbols that591 // this COFF file is imported from some DLLs. This is rare.592 // In most cases IsForwarder is false.593 outs() << format(" %5d ", Ordinal);594 } else {595 outs() << format(" %5d %# 8x", Ordinal, RVA);596 }597 598 if (!Name.empty())599 outs() << " " << Name;600 if (IsForwarder) {601 StringRef S;602 if (I->getForwardTo(S))603 return;604 outs() << " (forwarded to " << S << ")";605 }606 outs() << "\n";607 }608}609 610// Given the COFF object file, this function returns the relocations for .pdata611// and the pointer to "runtime function" structs.612static bool getPDataSection(const COFFObjectFile *Obj,613 std::vector<RelocationRef> &Rels,614 const RuntimeFunction *&RFStart, int &NumRFs) {615 for (const SectionRef &Section : Obj->sections()) {616 StringRef Name = unwrapOrError(Section.getName(), Obj->getFileName());617 if (Name != ".pdata")618 continue;619 620 const coff_section *Pdata = Obj->getCOFFSection(Section);621 append_range(Rels, Section.relocations());622 623 // Sort relocations by address.624 llvm::sort(Rels, isRelocAddressLess);625 626 ArrayRef<uint8_t> Contents;627 if (Error E = Obj->getSectionContents(Pdata, Contents))628 reportError(std::move(E), Obj->getFileName());629 630 if (Contents.empty())631 continue;632 633 RFStart = reinterpret_cast<const RuntimeFunction *>(Contents.data());634 NumRFs = Contents.size() / sizeof(RuntimeFunction);635 return true;636 }637 return false;638}639 640Error objdump::getCOFFRelocationValueString(const COFFObjectFile *Obj,641 const RelocationRef &Rel,642 SmallVectorImpl<char> &Result) {643 symbol_iterator SymI = Rel.getSymbol();644 Expected<StringRef> SymNameOrErr = SymI->getName();645 if (!SymNameOrErr)646 return SymNameOrErr.takeError();647 StringRef SymName = *SymNameOrErr;648 Result.append(SymName.begin(), SymName.end());649 return Error::success();650}651 652static void printWin64EHUnwindInfo(const Win64EH::UnwindInfo *UI) {653 // The casts to int are required in order to output the value as number.654 // Without the casts the value would be interpreted as char data (which655 // results in garbage output).656 outs() << " Version: " << static_cast<int>(UI->getVersion()) << "\n";657 outs() << " Flags: " << static_cast<int>(UI->getFlags());658 if (UI->getFlags()) {659 if (UI->getFlags() & UNW_ExceptionHandler)660 outs() << " UNW_ExceptionHandler";661 if (UI->getFlags() & UNW_TerminateHandler)662 outs() << " UNW_TerminateHandler";663 if (UI->getFlags() & UNW_ChainInfo)664 outs() << " UNW_ChainInfo";665 }666 outs() << "\n";667 outs() << " Size of prolog: " << static_cast<int>(UI->PrologSize) << "\n";668 outs() << " Number of Codes: " << static_cast<int>(UI->NumCodes) << "\n";669 // Maybe this should move to output of UOP_SetFPReg?670 if (UI->getFrameRegister()) {671 outs() << " Frame register: "672 << getUnwindRegisterName(UI->getFrameRegister()) << "\n";673 outs() << " Frame offset: " << 16 * UI->getFrameOffset() << "\n";674 } else {675 outs() << " No frame pointer used\n";676 }677 if (UI->getFlags() & (UNW_ExceptionHandler | UNW_TerminateHandler)) {678 // FIXME: Output exception handler data679 } else if (UI->getFlags() & UNW_ChainInfo) {680 // FIXME: Output chained unwind info681 }682 683 if (UI->NumCodes)684 outs() << " Unwind Codes:\n";685 686 printAllUnwindCodes(ArrayRef(&UI->UnwindCodes[0], UI->NumCodes));687 688 outs() << "\n";689 outs().flush();690}691 692/// Prints out the given RuntimeFunction struct for x64, assuming that Obj is693/// pointing to an executable file.694static void printRuntimeFunction(const COFFObjectFile *Obj,695 const RuntimeFunction &RF) {696 if (!RF.StartAddress)697 return;698 outs() << "Function Table:\n"699 << format(" Start Address: 0x%04x\n",700 static_cast<uint32_t>(RF.StartAddress))701 << format(" End Address: 0x%04x\n",702 static_cast<uint32_t>(RF.EndAddress))703 << format(" Unwind Info Address: 0x%04x\n",704 static_cast<uint32_t>(RF.UnwindInfoOffset));705 uintptr_t addr;706 if (Obj->getRvaPtr(RF.UnwindInfoOffset, addr))707 return;708 printWin64EHUnwindInfo(reinterpret_cast<const Win64EH::UnwindInfo *>(addr));709}710 711/// Prints out the given RuntimeFunction struct for x64, assuming that Obj is712/// pointing to an object file. Unlike executable, fields in RuntimeFunction713/// struct are filled with zeros, but instead there are relocations pointing to714/// them so that the linker will fill targets' RVAs to the fields at link715/// time. This function interprets the relocations to find the data to be used716/// in the resulting executable.717static void printRuntimeFunctionRels(const COFFObjectFile *Obj,718 const RuntimeFunction &RF,719 uint64_t SectionOffset,720 const std::vector<RelocationRef> &Rels) {721 outs() << "Function Table:\n";722 outs() << " Start Address: ";723 printCOFFSymbolAddress(outs(), Rels,724 SectionOffset +725 /*offsetof(RuntimeFunction, StartAddress)*/ 0,726 RF.StartAddress);727 outs() << "\n";728 729 outs() << " End Address: ";730 printCOFFSymbolAddress(outs(), Rels,731 SectionOffset +732 /*offsetof(RuntimeFunction, EndAddress)*/ 4,733 RF.EndAddress);734 outs() << "\n";735 736 outs() << " Unwind Info Address: ";737 printCOFFSymbolAddress(outs(), Rels,738 SectionOffset +739 /*offsetof(RuntimeFunction, UnwindInfoOffset)*/ 8,740 RF.UnwindInfoOffset);741 outs() << "\n";742 743 ArrayRef<uint8_t> XContents;744 uint64_t UnwindInfoOffset = 0;745 if (Error E = getSectionContents(746 Obj, Rels,747 SectionOffset +748 /*offsetof(RuntimeFunction, UnwindInfoOffset)*/ 8,749 XContents, UnwindInfoOffset))750 reportError(std::move(E), Obj->getFileName());751 if (XContents.empty())752 return;753 754 UnwindInfoOffset += RF.UnwindInfoOffset;755 if (UnwindInfoOffset > XContents.size())756 return;757 758 auto *UI = reinterpret_cast<const Win64EH::UnwindInfo *>(XContents.data() +759 UnwindInfoOffset);760 printWin64EHUnwindInfo(UI);761}762 763void objdump::printCOFFUnwindInfo(const COFFObjectFile *Obj) {764 if (Obj->getMachine() != COFF::IMAGE_FILE_MACHINE_AMD64) {765 WithColor::error(errs(), "llvm-objdump")766 << "unsupported image machine type "767 "(currently only AMD64 is supported).\n";768 return;769 }770 771 std::vector<RelocationRef> Rels;772 const RuntimeFunction *RFStart;773 int NumRFs;774 if (!getPDataSection(Obj, Rels, RFStart, NumRFs))775 return;776 ArrayRef<RuntimeFunction> RFs(RFStart, NumRFs);777 778 bool IsExecutable = Rels.empty();779 if (IsExecutable) {780 for (const RuntimeFunction &RF : RFs)781 printRuntimeFunction(Obj, RF);782 return;783 }784 785 for (const RuntimeFunction &RF : RFs) {786 uint64_t SectionOffset =787 std::distance(RFs.begin(), &RF) * sizeof(RuntimeFunction);788 printRuntimeFunctionRels(Obj, RF, SectionOffset, Rels);789 }790}791 792void COFFDumper::printPrivateHeaders() {793 COFFDumper CD(Obj);794 const uint16_t Cha = Obj.getCharacteristics();795 outs() << "Characteristics 0x" << Twine::utohexstr(Cha) << '\n';796#define FLAG(F, Name) \797 if (Cha & F) \798 outs() << '\t' << Name << '\n';799 FLAG(COFF::IMAGE_FILE_RELOCS_STRIPPED, "relocations stripped");800 FLAG(COFF::IMAGE_FILE_EXECUTABLE_IMAGE, "executable");801 FLAG(COFF::IMAGE_FILE_LINE_NUMS_STRIPPED, "line numbers stripped");802 FLAG(COFF::IMAGE_FILE_LOCAL_SYMS_STRIPPED, "symbols stripped");803 FLAG(COFF::IMAGE_FILE_LARGE_ADDRESS_AWARE, "large address aware");804 FLAG(COFF::IMAGE_FILE_BYTES_REVERSED_LO, "little endian");805 FLAG(COFF::IMAGE_FILE_32BIT_MACHINE, "32 bit words");806 FLAG(COFF::IMAGE_FILE_DEBUG_STRIPPED, "debugging information removed");807 FLAG(COFF::IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP,808 "copy to swap file if on removable media");809 FLAG(COFF::IMAGE_FILE_NET_RUN_FROM_SWAP,810 "copy to swap file if on network media");811 FLAG(COFF::IMAGE_FILE_SYSTEM, "system file");812 FLAG(COFF::IMAGE_FILE_DLL, "DLL");813 FLAG(COFF::IMAGE_FILE_UP_SYSTEM_ONLY, "run only on uniprocessor machine");814 FLAG(COFF::IMAGE_FILE_BYTES_REVERSED_HI, "big endian");815#undef FLAG816 817 // TODO Support PE_IMAGE_DEBUG_TYPE_REPRO.818 // Since ctime(3) returns a 26 character string of the form:819 // "Sun Sep 16 01:03:52 1973\n\0"820 // just print 24 characters.821 const time_t Timestamp = Obj.getTimeDateStamp();822 outs() << format("\nTime/Date %.24s\n", ctime(&Timestamp));823 824 if (const pe32_header *Hdr = Obj.getPE32Header())825 CD.printPEHeader<pe32_header>(*Hdr);826 else if (const pe32plus_header *Hdr = Obj.getPE32PlusHeader())827 CD.printPEHeader<pe32plus_header>(*Hdr);828 829 printTLSDirectory(&Obj);830 printLoadConfiguration(&Obj);831 printImportTables(&Obj);832 printExportTable(&Obj);833}834 835void objdump::printCOFFSymbolTable(const object::COFFImportFile &i) {836 unsigned Index = 0;837 bool IsCode = i.getCOFFImportHeader()->getType() == COFF::IMPORT_CODE;838 839 for (const object::BasicSymbolRef &Sym : i.symbols()) {840 std::string Name;841 raw_string_ostream NS(Name);842 843 cantFail(Sym.printName(NS));844 NS.flush();845 846 outs() << "[" << format("%2d", Index) << "]"847 << "(sec " << format("%2d", 0) << ")"848 << "(fl 0x00)" // Flag bits, which COFF doesn't have.849 << "(ty " << format("%3x", (IsCode && Index) ? 32 : 0) << ")"850 << "(scl " << format("%3x", 0) << ") "851 << "(nx " << 0 << ") "852 << "0x" << format("%08x", 0) << " " << Name << '\n';853 854 ++Index;855 }856}857 858void objdump::printCOFFSymbolTable(const COFFObjectFile &coff) {859 for (unsigned SI = 0, SE = coff.getNumberOfSymbols(); SI != SE; ++SI) {860 Expected<COFFSymbolRef> Symbol = coff.getSymbol(SI);861 if (!Symbol)862 reportError(Symbol.takeError(), coff.getFileName());863 864 Expected<StringRef> NameOrErr = coff.getSymbolName(*Symbol);865 if (!NameOrErr)866 reportError(NameOrErr.takeError(), coff.getFileName());867 StringRef Name = *NameOrErr;868 869 outs() << "[" << format("%2d", SI) << "]"870 << "(sec " << format("%2d", int(Symbol->getSectionNumber())) << ")"871 << "(fl 0x00)" // Flag bits, which COFF doesn't have.872 << "(ty " << format("%3x", unsigned(Symbol->getType())) << ")"873 << "(scl " << format("%3x", unsigned(Symbol->getStorageClass()))874 << ") "875 << "(nx " << unsigned(Symbol->getNumberOfAuxSymbols()) << ") "876 << "0x" << format("%08x", unsigned(Symbol->getValue())) << " "877 << Name;878 if (Demangle && Name.starts_with("?")) {879 int Status = -1;880 char *DemangledSymbol = microsoftDemangle(Name, nullptr, &Status);881 882 if (Status == 0 && DemangledSymbol) {883 outs() << " (" << StringRef(DemangledSymbol) << ")";884 std::free(DemangledSymbol);885 } else {886 outs() << " (invalid mangled name)";887 }888 }889 outs() << "\n";890 891 for (unsigned AI = 0, AE = Symbol->getNumberOfAuxSymbols(); AI < AE; ++AI, ++SI) {892 if (Symbol->isSectionDefinition()) {893 const coff_aux_section_definition *asd;894 if (Error E =895 coff.getAuxSymbol<coff_aux_section_definition>(SI + 1, asd))896 reportError(std::move(E), coff.getFileName());897 898 int32_t AuxNumber = asd->getNumber(Symbol->isBigObj());899 900 outs() << "AUX "901 << format("scnlen 0x%x nreloc %d nlnno %d checksum 0x%x "902 , unsigned(asd->Length)903 , unsigned(asd->NumberOfRelocations)904 , unsigned(asd->NumberOfLinenumbers)905 , unsigned(asd->CheckSum))906 << format("assoc %d comdat %d\n"907 , unsigned(AuxNumber)908 , unsigned(asd->Selection));909 } else if (Symbol->isFileRecord()) {910 const char *FileName;911 if (Error E = coff.getAuxSymbol<char>(SI + 1, FileName))912 reportError(std::move(E), coff.getFileName());913 914 StringRef Name(FileName, Symbol->getNumberOfAuxSymbols() *915 coff.getSymbolTableEntrySize());916 outs() << "AUX " << Name.rtrim(StringRef("\0", 1)) << '\n';917 918 SI = SI + Symbol->getNumberOfAuxSymbols();919 break;920 } else if (Symbol->isWeakExternal()) {921 const coff_aux_weak_external *awe;922 if (Error E = coff.getAuxSymbol<coff_aux_weak_external>(SI + 1, awe))923 reportError(std::move(E), coff.getFileName());924 925 outs() << "AUX " << format("indx %d srch %d\n",926 static_cast<uint32_t>(awe->TagIndex),927 static_cast<uint32_t>(awe->Characteristics));928 } else {929 outs() << "AUX Unknown\n";930 }931 }932 }933}934