Path: blob/main/contrib/llvm-project/llvm/tools/llvm-objdump/COFFDump.cpp
35231 views
//===-- COFFDump.cpp - COFF-specific dumper ---------------------*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7///8/// \file9/// This file implements the COFF-specific dumper for llvm-objdump.10/// It outputs the Win64 EH data structures as plain text.11/// The encoding of the unwind codes is described in MSDN:12/// https://docs.microsoft.com/en-us/cpp/build/exception-handling-x6413///14//===----------------------------------------------------------------------===//1516#include "COFFDump.h"1718#include "llvm-objdump.h"19#include "llvm/Demangle/Demangle.h"20#include "llvm/Object/COFF.h"21#include "llvm/Object/COFFImportFile.h"22#include "llvm/Object/ObjectFile.h"23#include "llvm/Support/Format.h"24#include "llvm/Support/Win64EH.h"25#include "llvm/Support/WithColor.h"26#include "llvm/Support/raw_ostream.h"2728using namespace llvm;29using namespace llvm::objdump;30using namespace llvm::object;31using namespace llvm::Win64EH;3233namespace {34template <typename T> struct EnumEntry {35T Value;36StringRef Name;37};3839class COFFDumper : public Dumper {40public:41explicit COFFDumper(const llvm::object::COFFObjectFile &O)42: Dumper(O), Obj(O) {43Is64 = !Obj.getPE32Header();44}4546template <class PEHeader> void printPEHeader(const PEHeader &Hdr) const;47void printPrivateHeaders() override;4849private:50template <typename T> FormattedNumber formatAddr(T V) const {51return format_hex_no_prefix(V, Is64 ? 16 : 8);52}5354uint32_t getBaseOfData(const void *Hdr) const {55return Is64 ? 0 : static_cast<const pe32_header *>(Hdr)->BaseOfData;56}5758const llvm::object::COFFObjectFile &Obj;59bool Is64;60};61} // namespace6263std::unique_ptr<Dumper>64objdump::createCOFFDumper(const object::COFFObjectFile &Obj) {65return std::make_unique<COFFDumper>(Obj);66}6768constexpr EnumEntry<uint16_t> PEHeaderMagic[] = {69{uint16_t(COFF::PE32Header::PE32), "PE32"},70{uint16_t(COFF::PE32Header::PE32_PLUS), "PE32+"},71};7273constexpr EnumEntry<COFF::WindowsSubsystem> PEWindowsSubsystem[] = {74{COFF::IMAGE_SUBSYSTEM_UNKNOWN, "unspecified"},75{COFF::IMAGE_SUBSYSTEM_NATIVE, "NT native"},76{COFF::IMAGE_SUBSYSTEM_WINDOWS_GUI, "Windows GUI"},77{COFF::IMAGE_SUBSYSTEM_WINDOWS_CUI, "Windows CUI"},78{COFF::IMAGE_SUBSYSTEM_POSIX_CUI, "POSIX CUI"},79{COFF::IMAGE_SUBSYSTEM_WINDOWS_CE_GUI, "Wince CUI"},80{COFF::IMAGE_SUBSYSTEM_EFI_APPLICATION, "EFI application"},81{COFF::IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER, "EFI boot service driver"},82{COFF::IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER, "EFI runtime driver"},83{COFF::IMAGE_SUBSYSTEM_EFI_ROM, "SAL runtime driver"},84{COFF::IMAGE_SUBSYSTEM_XBOX, "XBOX"},85};8687template <typename T, typename TEnum>88static void printOptionalEnumName(T Value,89ArrayRef<EnumEntry<TEnum>> EnumValues) {90for (const EnumEntry<TEnum> &I : EnumValues)91if (I.Value == Value) {92outs() << "\t(" << I.Name << ')';93return;94}95}9697template <class PEHeader>98void COFFDumper::printPEHeader(const PEHeader &Hdr) const {99auto print = [](const char *K, auto V, const char *Fmt = "%d\n") {100outs() << format("%-23s ", K) << format(Fmt, V);101};102auto printU16 = [&](const char *K, support::ulittle16_t V,103const char *Fmt = "%d\n") { print(K, uint16_t(V), Fmt); };104auto printU32 = [&](const char *K, support::ulittle32_t V,105const char *Fmt = "%d\n") { print(K, uint32_t(V), Fmt); };106auto printAddr = [=](const char *K, uint64_t V) {107outs() << format("%-23s ", K) << formatAddr(V) << '\n';108};109110printU16("Magic", Hdr.Magic, "%04x");111printOptionalEnumName(Hdr.Magic, ArrayRef(PEHeaderMagic));112outs() << '\n';113print("MajorLinkerVersion", Hdr.MajorLinkerVersion);114print("MinorLinkerVersion", Hdr.MinorLinkerVersion);115printAddr("SizeOfCode", Hdr.SizeOfCode);116printAddr("SizeOfInitializedData", Hdr.SizeOfInitializedData);117printAddr("SizeOfUninitializedData", Hdr.SizeOfUninitializedData);118printAddr("AddressOfEntryPoint", Hdr.AddressOfEntryPoint);119printAddr("BaseOfCode", Hdr.BaseOfCode);120if (!Is64)121printAddr("BaseOfData", getBaseOfData(&Hdr));122printAddr("ImageBase", Hdr.ImageBase);123printU32("SectionAlignment", Hdr.SectionAlignment, "%08x\n");124printU32("FileAlignment", Hdr.FileAlignment, "%08x\n");125printU16("MajorOSystemVersion", Hdr.MajorOperatingSystemVersion);126printU16("MinorOSystemVersion", Hdr.MinorOperatingSystemVersion);127printU16("MajorImageVersion", Hdr.MajorImageVersion);128printU16("MinorImageVersion", Hdr.MinorImageVersion);129printU16("MajorSubsystemVersion", Hdr.MajorSubsystemVersion);130printU16("MinorSubsystemVersion", Hdr.MinorSubsystemVersion);131printU32("Win32Version", Hdr.Win32VersionValue, "%08x\n");132printU32("SizeOfImage", Hdr.SizeOfImage, "%08x\n");133printU32("SizeOfHeaders", Hdr.SizeOfHeaders, "%08x\n");134printU32("CheckSum", Hdr.CheckSum, "%08x\n");135printU16("Subsystem", Hdr.Subsystem, "%08x");136printOptionalEnumName(Hdr.Subsystem, ArrayRef(PEWindowsSubsystem));137outs() << '\n';138139printU16("DllCharacteristics", Hdr.DLLCharacteristics, "%08x\n");140#define FLAG(Name) \141if (Hdr.DLLCharacteristics & COFF::IMAGE_DLL_CHARACTERISTICS_##Name) \142outs() << "\t\t\t\t\t" << #Name << '\n';143FLAG(HIGH_ENTROPY_VA);144FLAG(DYNAMIC_BASE);145FLAG(FORCE_INTEGRITY);146FLAG(NX_COMPAT);147FLAG(NO_ISOLATION);148FLAG(NO_SEH);149FLAG(NO_BIND);150FLAG(APPCONTAINER);151FLAG(WDM_DRIVER);152FLAG(GUARD_CF);153FLAG(TERMINAL_SERVER_AWARE);154#undef FLAG155156printAddr("SizeOfStackReserve", Hdr.SizeOfStackReserve);157printAddr("SizeOfStackCommit", Hdr.SizeOfStackCommit);158printAddr("SizeOfHeapReserve", Hdr.SizeOfHeapReserve);159printAddr("SizeOfHeapCommit", Hdr.SizeOfHeapCommit);160printU32("LoaderFlags", Hdr.LoaderFlags, "%08x\n");161printU32("NumberOfRvaAndSizes", Hdr.NumberOfRvaAndSize, "%08x\n");162163static const char *DirName[COFF::NUM_DATA_DIRECTORIES + 1] = {164"Export Directory [.edata (or where ever we found it)]",165"Import Directory [parts of .idata]",166"Resource Directory [.rsrc]",167"Exception Directory [.pdata]",168"Security Directory",169"Base Relocation Directory [.reloc]",170"Debug Directory",171"Description Directory",172"Special Directory",173"Thread Storage Directory [.tls]",174"Load Configuration Directory",175"Bound Import Directory",176"Import Address Table Directory",177"Delay Import Directory",178"CLR Runtime Header",179"Reserved",180};181outs() << "\nThe Data Directory\n";182for (uint32_t I = 0; I != std::size(DirName); ++I) {183uint32_t Addr = 0, Size = 0;184if (const data_directory *Data = Obj.getDataDirectory(I)) {185Addr = Data->RelativeVirtualAddress;186Size = Data->Size;187}188outs() << format("Entry %x ", I) << formatAddr(Addr)189<< format(" %08x %s\n", uint32_t(Size), DirName[I]);190}191}192193// Returns the name of the unwind code.194static StringRef getUnwindCodeTypeName(uint8_t Code) {195switch(Code) {196default: llvm_unreachable("Invalid unwind code");197case UOP_PushNonVol: return "UOP_PushNonVol";198case UOP_AllocLarge: return "UOP_AllocLarge";199case UOP_AllocSmall: return "UOP_AllocSmall";200case UOP_SetFPReg: return "UOP_SetFPReg";201case UOP_SaveNonVol: return "UOP_SaveNonVol";202case UOP_SaveNonVolBig: return "UOP_SaveNonVolBig";203case UOP_Epilog: return "UOP_Epilog";204case UOP_SpareCode: return "UOP_SpareCode";205case UOP_SaveXMM128: return "UOP_SaveXMM128";206case UOP_SaveXMM128Big: return "UOP_SaveXMM128Big";207case UOP_PushMachFrame: return "UOP_PushMachFrame";208}209}210211// Returns the name of a referenced register.212static StringRef getUnwindRegisterName(uint8_t Reg) {213switch(Reg) {214default: llvm_unreachable("Invalid register");215case 0: return "RAX";216case 1: return "RCX";217case 2: return "RDX";218case 3: return "RBX";219case 4: return "RSP";220case 5: return "RBP";221case 6: return "RSI";222case 7: return "RDI";223case 8: return "R8";224case 9: return "R9";225case 10: return "R10";226case 11: return "R11";227case 12: return "R12";228case 13: return "R13";229case 14: return "R14";230case 15: return "R15";231}232}233234// Calculates the number of array slots required for the unwind code.235static unsigned getNumUsedSlots(const UnwindCode &UnwindCode) {236switch (UnwindCode.getUnwindOp()) {237default: llvm_unreachable("Invalid unwind code");238case UOP_PushNonVol:239case UOP_AllocSmall:240case UOP_SetFPReg:241case UOP_PushMachFrame:242return 1;243case UOP_SaveNonVol:244case UOP_SaveXMM128:245case UOP_Epilog:246return 2;247case UOP_SaveNonVolBig:248case UOP_SaveXMM128Big:249case UOP_SpareCode:250return 3;251case UOP_AllocLarge:252return (UnwindCode.getOpInfo() == 0) ? 2 : 3;253}254}255256// Prints one unwind code. Because an unwind code can occupy up to 3 slots in257// the unwind codes array, this function requires that the correct number of258// slots is provided.259static void printUnwindCode(ArrayRef<UnwindCode> UCs) {260assert(UCs.size() >= getNumUsedSlots(UCs[0]));261outs() << format(" 0x%02x: ", unsigned(UCs[0].u.CodeOffset))262<< getUnwindCodeTypeName(UCs[0].getUnwindOp());263switch (UCs[0].getUnwindOp()) {264case UOP_PushNonVol:265outs() << " " << getUnwindRegisterName(UCs[0].getOpInfo());266break;267case UOP_AllocLarge:268if (UCs[0].getOpInfo() == 0) {269outs() << " " << UCs[1].FrameOffset;270} else {271outs() << " " << UCs[1].FrameOffset272+ (static_cast<uint32_t>(UCs[2].FrameOffset) << 16);273}274break;275case UOP_AllocSmall:276outs() << " " << ((UCs[0].getOpInfo() + 1) * 8);277break;278case UOP_SetFPReg:279outs() << " ";280break;281case UOP_SaveNonVol:282outs() << " " << getUnwindRegisterName(UCs[0].getOpInfo())283<< format(" [0x%04x]", 8 * UCs[1].FrameOffset);284break;285case UOP_SaveNonVolBig:286outs() << " " << getUnwindRegisterName(UCs[0].getOpInfo())287<< format(" [0x%08x]", UCs[1].FrameOffset288+ (static_cast<uint32_t>(UCs[2].FrameOffset) << 16));289break;290case UOP_SaveXMM128:291outs() << " XMM" << static_cast<uint32_t>(UCs[0].getOpInfo())292<< format(" [0x%04x]", 16 * UCs[1].FrameOffset);293break;294case UOP_SaveXMM128Big:295outs() << " XMM" << UCs[0].getOpInfo()296<< format(" [0x%08x]", UCs[1].FrameOffset297+ (static_cast<uint32_t>(UCs[2].FrameOffset) << 16));298break;299case UOP_PushMachFrame:300outs() << " " << (UCs[0].getOpInfo() ? "w/o" : "w")301<< " error code";302break;303}304outs() << "\n";305}306307static void printAllUnwindCodes(ArrayRef<UnwindCode> UCs) {308for (const UnwindCode *I = UCs.begin(), *E = UCs.end(); I < E; ) {309unsigned UsedSlots = getNumUsedSlots(*I);310if (UsedSlots > UCs.size()) {311outs() << "Unwind data corrupted: Encountered unwind op "312<< getUnwindCodeTypeName((*I).getUnwindOp())313<< " which requires " << UsedSlots314<< " slots, but only " << UCs.size()315<< " remaining in buffer";316return ;317}318printUnwindCode(ArrayRef(I, E));319I += UsedSlots;320}321}322323// Given a symbol sym this functions returns the address and section of it.324static Error resolveSectionAndAddress(const COFFObjectFile *Obj,325const SymbolRef &Sym,326const coff_section *&ResolvedSection,327uint64_t &ResolvedAddr) {328Expected<uint64_t> ResolvedAddrOrErr = Sym.getAddress();329if (!ResolvedAddrOrErr)330return ResolvedAddrOrErr.takeError();331ResolvedAddr = *ResolvedAddrOrErr;332Expected<section_iterator> Iter = Sym.getSection();333if (!Iter)334return Iter.takeError();335ResolvedSection = Obj->getCOFFSection(**Iter);336return Error::success();337}338339// Given a vector of relocations for a section and an offset into this section340// the function returns the symbol used for the relocation at the offset.341static Error resolveSymbol(const std::vector<RelocationRef> &Rels,342uint64_t Offset, SymbolRef &Sym) {343for (auto &R : Rels) {344uint64_t Ofs = R.getOffset();345if (Ofs == Offset) {346Sym = *R.getSymbol();347return Error::success();348}349}350return make_error<BinaryError>();351}352353// Given a vector of relocations for a section and an offset into this section354// the function resolves the symbol used for the relocation at the offset and355// returns the section content and the address inside the content pointed to356// by the symbol.357static Error358getSectionContents(const COFFObjectFile *Obj,359const std::vector<RelocationRef> &Rels, uint64_t Offset,360ArrayRef<uint8_t> &Contents, uint64_t &Addr) {361SymbolRef Sym;362if (Error E = resolveSymbol(Rels, Offset, Sym))363return E;364const coff_section *Section;365if (Error E = resolveSectionAndAddress(Obj, Sym, Section, Addr))366return E;367return Obj->getSectionContents(Section, Contents);368}369370// Given a vector of relocations for a section and an offset into this section371// the function returns the name of the symbol used for the relocation at the372// offset.373static Error resolveSymbolName(const std::vector<RelocationRef> &Rels,374uint64_t Offset, StringRef &Name) {375SymbolRef Sym;376if (Error EC = resolveSymbol(Rels, Offset, Sym))377return EC;378Expected<StringRef> NameOrErr = Sym.getName();379if (!NameOrErr)380return NameOrErr.takeError();381Name = *NameOrErr;382return Error::success();383}384385static void printCOFFSymbolAddress(raw_ostream &Out,386const std::vector<RelocationRef> &Rels,387uint64_t Offset, uint32_t Disp) {388StringRef Sym;389if (!resolveSymbolName(Rels, Offset, Sym)) {390Out << Sym;391if (Disp > 0)392Out << format(" + 0x%04x", Disp);393} else {394Out << format("0x%04x", Disp);395}396}397398static void399printSEHTable(const COFFObjectFile *Obj, uint32_t TableVA, int Count) {400if (Count == 0)401return;402403uintptr_t IntPtr = 0;404if (Error E = Obj->getVaPtr(TableVA, IntPtr))405reportError(std::move(E), Obj->getFileName());406407const support::ulittle32_t *P = (const support::ulittle32_t *)IntPtr;408outs() << "SEH Table:";409for (int I = 0; I < Count; ++I)410outs() << format(" 0x%x", P[I] + Obj->getPE32Header()->ImageBase);411outs() << "\n\n";412}413414template <typename T>415static void printTLSDirectoryT(const coff_tls_directory<T> *TLSDir) {416size_t FormatWidth = sizeof(T) * 2;417outs() << "TLS directory:"418<< "\n StartAddressOfRawData: "419<< format_hex(TLSDir->StartAddressOfRawData, FormatWidth)420<< "\n EndAddressOfRawData: "421<< format_hex(TLSDir->EndAddressOfRawData, FormatWidth)422<< "\n AddressOfIndex: "423<< format_hex(TLSDir->AddressOfIndex, FormatWidth)424<< "\n AddressOfCallBacks: "425<< format_hex(TLSDir->AddressOfCallBacks, FormatWidth)426<< "\n SizeOfZeroFill: "427<< TLSDir->SizeOfZeroFill428<< "\n Characteristics: "429<< TLSDir->Characteristics430<< "\n Alignment: "431<< TLSDir->getAlignment()432<< "\n\n";433}434435static void printTLSDirectory(const COFFObjectFile *Obj) {436const pe32_header *PE32Header = Obj->getPE32Header();437const pe32plus_header *PE32PlusHeader = Obj->getPE32PlusHeader();438439// Skip if it's not executable.440if (!PE32Header && !PE32PlusHeader)441return;442443if (PE32Header) {444if (auto *TLSDir = Obj->getTLSDirectory32())445printTLSDirectoryT(TLSDir);446} else {447if (auto *TLSDir = Obj->getTLSDirectory64())448printTLSDirectoryT(TLSDir);449}450451outs() << "\n";452}453454static void printLoadConfiguration(const COFFObjectFile *Obj) {455// Skip if it's not executable.456if (!Obj->getPE32Header())457return;458459// Currently only x86 is supported460if (Obj->getMachine() != COFF::IMAGE_FILE_MACHINE_I386)461return;462463auto *LoadConf = Obj->getLoadConfig32();464if (!LoadConf)465return;466467outs() << "Load configuration:"468<< "\n Timestamp: " << LoadConf->TimeDateStamp469<< "\n Major Version: " << LoadConf->MajorVersion470<< "\n Minor Version: " << LoadConf->MinorVersion471<< "\n GlobalFlags Clear: " << LoadConf->GlobalFlagsClear472<< "\n GlobalFlags Set: " << LoadConf->GlobalFlagsSet473<< "\n Critical Section Default Timeout: " << LoadConf->CriticalSectionDefaultTimeout474<< "\n Decommit Free Block Threshold: " << LoadConf->DeCommitFreeBlockThreshold475<< "\n Decommit Total Free Threshold: " << LoadConf->DeCommitTotalFreeThreshold476<< "\n Lock Prefix Table: " << LoadConf->LockPrefixTable477<< "\n Maximum Allocation Size: " << LoadConf->MaximumAllocationSize478<< "\n Virtual Memory Threshold: " << LoadConf->VirtualMemoryThreshold479<< "\n Process Affinity Mask: " << LoadConf->ProcessAffinityMask480<< "\n Process Heap Flags: " << LoadConf->ProcessHeapFlags481<< "\n CSD Version: " << LoadConf->CSDVersion482<< "\n Security Cookie: " << LoadConf->SecurityCookie483<< "\n SEH Table: " << LoadConf->SEHandlerTable484<< "\n SEH Count: " << LoadConf->SEHandlerCount485<< "\n\n";486printSEHTable(Obj, LoadConf->SEHandlerTable, LoadConf->SEHandlerCount);487outs() << "\n";488}489490// Prints import tables. The import table is a table containing the list of491// DLL name and symbol names which will be linked by the loader.492static void printImportTables(const COFFObjectFile *Obj) {493import_directory_iterator I = Obj->import_directory_begin();494import_directory_iterator E = Obj->import_directory_end();495if (I == E)496return;497outs() << "The Import Tables:\n";498for (const ImportDirectoryEntryRef &DirRef : Obj->import_directories()) {499const coff_import_directory_table_entry *Dir;500StringRef Name;501if (DirRef.getImportTableEntry(Dir)) return;502if (DirRef.getName(Name)) return;503504outs() << format(" lookup %08x time %08x fwd %08x name %08x addr %08x\n\n",505static_cast<uint32_t>(Dir->ImportLookupTableRVA),506static_cast<uint32_t>(Dir->TimeDateStamp),507static_cast<uint32_t>(Dir->ForwarderChain),508static_cast<uint32_t>(Dir->NameRVA),509static_cast<uint32_t>(Dir->ImportAddressTableRVA));510outs() << " DLL Name: " << Name << "\n";511outs() << " Hint/Ord Name\n";512for (const ImportedSymbolRef &Entry : DirRef.imported_symbols()) {513bool IsOrdinal;514if (Entry.isOrdinal(IsOrdinal))515return;516if (IsOrdinal) {517uint16_t Ordinal;518if (Entry.getOrdinal(Ordinal))519return;520outs() << format(" % 6d\n", Ordinal);521continue;522}523uint32_t HintNameRVA;524if (Entry.getHintNameRVA(HintNameRVA))525return;526uint16_t Hint;527StringRef Name;528if (Obj->getHintName(HintNameRVA, Hint, Name))529return;530outs() << format(" % 6d ", Hint) << Name << "\n";531}532outs() << "\n";533}534}535536// Prints export tables. The export table is a table containing the list of537// exported symbol from the DLL.538static void printExportTable(const COFFObjectFile *Obj) {539export_directory_iterator I = Obj->export_directory_begin();540export_directory_iterator E = Obj->export_directory_end();541if (I == E)542return;543outs() << "Export Table:\n";544StringRef DllName;545uint32_t OrdinalBase;546if (I->getDllName(DllName))547return;548if (I->getOrdinalBase(OrdinalBase))549return;550outs() << " DLL name: " << DllName << "\n";551outs() << " Ordinal base: " << OrdinalBase << "\n";552outs() << " Ordinal RVA Name\n";553for (; I != E; I = ++I) {554uint32_t RVA;555if (I->getExportRVA(RVA))556return;557StringRef Name;558if (I->getSymbolName(Name))559continue;560if (!RVA && Name.empty())561continue;562563uint32_t Ordinal;564if (I->getOrdinal(Ordinal))565return;566bool IsForwarder;567if (I->isForwarder(IsForwarder))568return;569570if (IsForwarder) {571// Export table entries can be used to re-export symbols that572// this COFF file is imported from some DLLs. This is rare.573// In most cases IsForwarder is false.574outs() << format(" %5d ", Ordinal);575} else {576outs() << format(" %5d %# 8x", Ordinal, RVA);577}578579if (!Name.empty())580outs() << " " << Name;581if (IsForwarder) {582StringRef S;583if (I->getForwardTo(S))584return;585outs() << " (forwarded to " << S << ")";586}587outs() << "\n";588}589}590591// Given the COFF object file, this function returns the relocations for .pdata592// and the pointer to "runtime function" structs.593static bool getPDataSection(const COFFObjectFile *Obj,594std::vector<RelocationRef> &Rels,595const RuntimeFunction *&RFStart, int &NumRFs) {596for (const SectionRef &Section : Obj->sections()) {597StringRef Name = unwrapOrError(Section.getName(), Obj->getFileName());598if (Name != ".pdata")599continue;600601const coff_section *Pdata = Obj->getCOFFSection(Section);602append_range(Rels, Section.relocations());603604// Sort relocations by address.605llvm::sort(Rels, isRelocAddressLess);606607ArrayRef<uint8_t> Contents;608if (Error E = Obj->getSectionContents(Pdata, Contents))609reportError(std::move(E), Obj->getFileName());610611if (Contents.empty())612continue;613614RFStart = reinterpret_cast<const RuntimeFunction *>(Contents.data());615NumRFs = Contents.size() / sizeof(RuntimeFunction);616return true;617}618return false;619}620621Error objdump::getCOFFRelocationValueString(const COFFObjectFile *Obj,622const RelocationRef &Rel,623SmallVectorImpl<char> &Result) {624symbol_iterator SymI = Rel.getSymbol();625Expected<StringRef> SymNameOrErr = SymI->getName();626if (!SymNameOrErr)627return SymNameOrErr.takeError();628StringRef SymName = *SymNameOrErr;629Result.append(SymName.begin(), SymName.end());630return Error::success();631}632633static void printWin64EHUnwindInfo(const Win64EH::UnwindInfo *UI) {634// The casts to int are required in order to output the value as number.635// Without the casts the value would be interpreted as char data (which636// results in garbage output).637outs() << " Version: " << static_cast<int>(UI->getVersion()) << "\n";638outs() << " Flags: " << static_cast<int>(UI->getFlags());639if (UI->getFlags()) {640if (UI->getFlags() & UNW_ExceptionHandler)641outs() << " UNW_ExceptionHandler";642if (UI->getFlags() & UNW_TerminateHandler)643outs() << " UNW_TerminateHandler";644if (UI->getFlags() & UNW_ChainInfo)645outs() << " UNW_ChainInfo";646}647outs() << "\n";648outs() << " Size of prolog: " << static_cast<int>(UI->PrologSize) << "\n";649outs() << " Number of Codes: " << static_cast<int>(UI->NumCodes) << "\n";650// Maybe this should move to output of UOP_SetFPReg?651if (UI->getFrameRegister()) {652outs() << " Frame register: "653<< getUnwindRegisterName(UI->getFrameRegister()) << "\n";654outs() << " Frame offset: " << 16 * UI->getFrameOffset() << "\n";655} else {656outs() << " No frame pointer used\n";657}658if (UI->getFlags() & (UNW_ExceptionHandler | UNW_TerminateHandler)) {659// FIXME: Output exception handler data660} else if (UI->getFlags() & UNW_ChainInfo) {661// FIXME: Output chained unwind info662}663664if (UI->NumCodes)665outs() << " Unwind Codes:\n";666667printAllUnwindCodes(ArrayRef(&UI->UnwindCodes[0], UI->NumCodes));668669outs() << "\n";670outs().flush();671}672673/// Prints out the given RuntimeFunction struct for x64, assuming that Obj is674/// pointing to an executable file.675static void printRuntimeFunction(const COFFObjectFile *Obj,676const RuntimeFunction &RF) {677if (!RF.StartAddress)678return;679outs() << "Function Table:\n"680<< format(" Start Address: 0x%04x\n",681static_cast<uint32_t>(RF.StartAddress))682<< format(" End Address: 0x%04x\n",683static_cast<uint32_t>(RF.EndAddress))684<< format(" Unwind Info Address: 0x%04x\n",685static_cast<uint32_t>(RF.UnwindInfoOffset));686uintptr_t addr;687if (Obj->getRvaPtr(RF.UnwindInfoOffset, addr))688return;689printWin64EHUnwindInfo(reinterpret_cast<const Win64EH::UnwindInfo *>(addr));690}691692/// Prints out the given RuntimeFunction struct for x64, assuming that Obj is693/// pointing to an object file. Unlike executable, fields in RuntimeFunction694/// struct are filled with zeros, but instead there are relocations pointing to695/// them so that the linker will fill targets' RVAs to the fields at link696/// time. This function interprets the relocations to find the data to be used697/// in the resulting executable.698static void printRuntimeFunctionRels(const COFFObjectFile *Obj,699const RuntimeFunction &RF,700uint64_t SectionOffset,701const std::vector<RelocationRef> &Rels) {702outs() << "Function Table:\n";703outs() << " Start Address: ";704printCOFFSymbolAddress(outs(), Rels,705SectionOffset +706/*offsetof(RuntimeFunction, StartAddress)*/ 0,707RF.StartAddress);708outs() << "\n";709710outs() << " End Address: ";711printCOFFSymbolAddress(outs(), Rels,712SectionOffset +713/*offsetof(RuntimeFunction, EndAddress)*/ 4,714RF.EndAddress);715outs() << "\n";716717outs() << " Unwind Info Address: ";718printCOFFSymbolAddress(outs(), Rels,719SectionOffset +720/*offsetof(RuntimeFunction, UnwindInfoOffset)*/ 8,721RF.UnwindInfoOffset);722outs() << "\n";723724ArrayRef<uint8_t> XContents;725uint64_t UnwindInfoOffset = 0;726if (Error E = getSectionContents(727Obj, Rels,728SectionOffset +729/*offsetof(RuntimeFunction, UnwindInfoOffset)*/ 8,730XContents, UnwindInfoOffset))731reportError(std::move(E), Obj->getFileName());732if (XContents.empty())733return;734735UnwindInfoOffset += RF.UnwindInfoOffset;736if (UnwindInfoOffset > XContents.size())737return;738739auto *UI = reinterpret_cast<const Win64EH::UnwindInfo *>(XContents.data() +740UnwindInfoOffset);741printWin64EHUnwindInfo(UI);742}743744void objdump::printCOFFUnwindInfo(const COFFObjectFile *Obj) {745if (Obj->getMachine() != COFF::IMAGE_FILE_MACHINE_AMD64) {746WithColor::error(errs(), "llvm-objdump")747<< "unsupported image machine type "748"(currently only AMD64 is supported).\n";749return;750}751752std::vector<RelocationRef> Rels;753const RuntimeFunction *RFStart;754int NumRFs;755if (!getPDataSection(Obj, Rels, RFStart, NumRFs))756return;757ArrayRef<RuntimeFunction> RFs(RFStart, NumRFs);758759bool IsExecutable = Rels.empty();760if (IsExecutable) {761for (const RuntimeFunction &RF : RFs)762printRuntimeFunction(Obj, RF);763return;764}765766for (const RuntimeFunction &RF : RFs) {767uint64_t SectionOffset =768std::distance(RFs.begin(), &RF) * sizeof(RuntimeFunction);769printRuntimeFunctionRels(Obj, RF, SectionOffset, Rels);770}771}772773void COFFDumper::printPrivateHeaders() {774COFFDumper CD(Obj);775const uint16_t Cha = Obj.getCharacteristics();776outs() << "Characteristics 0x" << Twine::utohexstr(Cha) << '\n';777#define FLAG(F, Name) \778if (Cha & F) \779outs() << '\t' << Name << '\n';780FLAG(COFF::IMAGE_FILE_RELOCS_STRIPPED, "relocations stripped");781FLAG(COFF::IMAGE_FILE_EXECUTABLE_IMAGE, "executable");782FLAG(COFF::IMAGE_FILE_LINE_NUMS_STRIPPED, "line numbers stripped");783FLAG(COFF::IMAGE_FILE_LOCAL_SYMS_STRIPPED, "symbols stripped");784FLAG(COFF::IMAGE_FILE_LARGE_ADDRESS_AWARE, "large address aware");785FLAG(COFF::IMAGE_FILE_BYTES_REVERSED_LO, "little endian");786FLAG(COFF::IMAGE_FILE_32BIT_MACHINE, "32 bit words");787FLAG(COFF::IMAGE_FILE_DEBUG_STRIPPED, "debugging information removed");788FLAG(COFF::IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP,789"copy to swap file if on removable media");790FLAG(COFF::IMAGE_FILE_NET_RUN_FROM_SWAP,791"copy to swap file if on network media");792FLAG(COFF::IMAGE_FILE_SYSTEM, "system file");793FLAG(COFF::IMAGE_FILE_DLL, "DLL");794FLAG(COFF::IMAGE_FILE_UP_SYSTEM_ONLY, "run only on uniprocessor machine");795FLAG(COFF::IMAGE_FILE_BYTES_REVERSED_HI, "big endian");796#undef FLAG797798// TODO Support PE_IMAGE_DEBUG_TYPE_REPRO.799// Since ctime(3) returns a 26 character string of the form:800// "Sun Sep 16 01:03:52 1973\n\0"801// just print 24 characters.802const time_t Timestamp = Obj.getTimeDateStamp();803outs() << format("\nTime/Date %.24s\n", ctime(&Timestamp));804805if (const pe32_header *Hdr = Obj.getPE32Header())806CD.printPEHeader<pe32_header>(*Hdr);807else if (const pe32plus_header *Hdr = Obj.getPE32PlusHeader())808CD.printPEHeader<pe32plus_header>(*Hdr);809810printTLSDirectory(&Obj);811printLoadConfiguration(&Obj);812printImportTables(&Obj);813printExportTable(&Obj);814}815816void objdump::printCOFFSymbolTable(const object::COFFImportFile &i) {817unsigned Index = 0;818bool IsCode = i.getCOFFImportHeader()->getType() == COFF::IMPORT_CODE;819820for (const object::BasicSymbolRef &Sym : i.symbols()) {821std::string Name;822raw_string_ostream NS(Name);823824cantFail(Sym.printName(NS));825NS.flush();826827outs() << "[" << format("%2d", Index) << "]"828<< "(sec " << format("%2d", 0) << ")"829<< "(fl 0x00)" // Flag bits, which COFF doesn't have.830<< "(ty " << format("%3x", (IsCode && Index) ? 32 : 0) << ")"831<< "(scl " << format("%3x", 0) << ") "832<< "(nx " << 0 << ") "833<< "0x" << format("%08x", 0) << " " << Name << '\n';834835++Index;836}837}838839void objdump::printCOFFSymbolTable(const COFFObjectFile &coff) {840for (unsigned SI = 0, SE = coff.getNumberOfSymbols(); SI != SE; ++SI) {841Expected<COFFSymbolRef> Symbol = coff.getSymbol(SI);842if (!Symbol)843reportError(Symbol.takeError(), coff.getFileName());844845Expected<StringRef> NameOrErr = coff.getSymbolName(*Symbol);846if (!NameOrErr)847reportError(NameOrErr.takeError(), coff.getFileName());848StringRef Name = *NameOrErr;849850outs() << "[" << format("%2d", SI) << "]"851<< "(sec " << format("%2d", int(Symbol->getSectionNumber())) << ")"852<< "(fl 0x00)" // Flag bits, which COFF doesn't have.853<< "(ty " << format("%3x", unsigned(Symbol->getType())) << ")"854<< "(scl " << format("%3x", unsigned(Symbol->getStorageClass()))855<< ") "856<< "(nx " << unsigned(Symbol->getNumberOfAuxSymbols()) << ") "857<< "0x" << format("%08x", unsigned(Symbol->getValue())) << " "858<< Name;859if (Demangle && Name.starts_with("?")) {860int Status = -1;861char *DemangledSymbol = microsoftDemangle(Name, nullptr, &Status);862863if (Status == 0 && DemangledSymbol) {864outs() << " (" << StringRef(DemangledSymbol) << ")";865std::free(DemangledSymbol);866} else {867outs() << " (invalid mangled name)";868}869}870outs() << "\n";871872for (unsigned AI = 0, AE = Symbol->getNumberOfAuxSymbols(); AI < AE; ++AI, ++SI) {873if (Symbol->isSectionDefinition()) {874const coff_aux_section_definition *asd;875if (Error E =876coff.getAuxSymbol<coff_aux_section_definition>(SI + 1, asd))877reportError(std::move(E), coff.getFileName());878879int32_t AuxNumber = asd->getNumber(Symbol->isBigObj());880881outs() << "AUX "882<< format("scnlen 0x%x nreloc %d nlnno %d checksum 0x%x "883, unsigned(asd->Length)884, unsigned(asd->NumberOfRelocations)885, unsigned(asd->NumberOfLinenumbers)886, unsigned(asd->CheckSum))887<< format("assoc %d comdat %d\n"888, unsigned(AuxNumber)889, unsigned(asd->Selection));890} else if (Symbol->isFileRecord()) {891const char *FileName;892if (Error E = coff.getAuxSymbol<char>(SI + 1, FileName))893reportError(std::move(E), coff.getFileName());894895StringRef Name(FileName, Symbol->getNumberOfAuxSymbols() *896coff.getSymbolTableEntrySize());897outs() << "AUX " << Name.rtrim(StringRef("\0", 1)) << '\n';898899SI = SI + Symbol->getNumberOfAuxSymbols();900break;901} else if (Symbol->isWeakExternal()) {902const coff_aux_weak_external *awe;903if (Error E = coff.getAuxSymbol<coff_aux_weak_external>(SI + 1, awe))904reportError(std::move(E), coff.getFileName());905906outs() << "AUX " << format("indx %d srch %d\n",907static_cast<uint32_t>(awe->TagIndex),908static_cast<uint32_t>(awe->Characteristics));909} else {910outs() << "AUX Unknown\n";911}912}913}914}915916917