X-Git-Url: http://plrg.eecs.uci.edu/git/?p=oota-llvm.git;a=blobdiff_plain;f=tools%2Fllvm-objdump%2FCOFFDump.cpp;h=7a0fa6e151b1246b18b9f40179f60a26ac3190ba;hp=5f0bcbbc92ddbb45165a7e9dc66a315d2c22c11c;hb=d5132f907367b43d43108bd4367dbbcb650f98ce;hpb=29552222c2e7cbeb37fcd15d247597467f7b8544 diff --git a/tools/llvm-objdump/COFFDump.cpp b/tools/llvm-objdump/COFFDump.cpp index 5f0bcbbc92d..7a0fa6e151b 100644 --- a/tools/llvm-objdump/COFFDump.cpp +++ b/tools/llvm-objdump/COFFDump.cpp @@ -10,7 +10,7 @@ /// \file /// \brief This file implements the COFF-specific dumper for llvm-objdump. /// It outputs the Win64 EH data structures as plain text. -/// The encoding of the unwind codes is decribed in MSDN: +/// The encoding of the unwind codes is described in MSDN: /// http://msdn.microsoft.com/en-us/library/ck9asaa9.aspx /// //===----------------------------------------------------------------------===// @@ -22,9 +22,9 @@ #include "llvm/Support/SourceMgr.h" #include "llvm/Support/Win64EH.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/Support/system_error.h" #include #include +#include using namespace llvm; using namespace object; @@ -94,7 +94,7 @@ static unsigned getNumUsedSlots(const UnwindCode &UnwindCode) { // slots is provided. static void printUnwindCode(ArrayRef UCs) { assert(UCs.size() >= getNumUsedSlots(UCs[0])); - outs() << format(" 0x%02x: ", unsigned(UCs[0].u.CodeOffset)) + outs() << format(" 0x%02x: ", unsigned(UCs[0].u.CodeOffset)) << getUnwindCodeTypeName(UCs[0].getUnwindOp()); switch (UCs[0].getUnwindOp()) { case UOP_PushNonVol: @@ -161,10 +161,12 @@ static error_code resolveSectionAndAddress(const COFFObjectFile *Obj, const SymbolRef &Sym, const coff_section *&ResolvedSection, uint64_t &ResolvedAddr) { - if (error_code ec = Sym.getAddress(ResolvedAddr)) return ec; - section_iterator iter(Obj->begin_sections()); - if (error_code ec = Sym.getSection(iter)) return ec; - ResolvedSection = Obj->getCOFFSection(iter); + if (error_code EC = Sym.getAddress(ResolvedAddr)) + return EC; + section_iterator iter(Obj->section_begin()); + if (error_code EC = Sym.getSection(iter)) + return EC; + ResolvedSection = Obj->getCOFFSection(*iter); return object_error::success; } @@ -176,13 +178,14 @@ static error_code resolveSymbol(const std::vector &Rels, E = Rels.end(); I != E; ++I) { uint64_t Ofs; - if (error_code ec = I->getOffset(Ofs)) return ec; + if (error_code EC = I->getOffset(Ofs)) + return EC; if (Ofs == Offset) { Sym = *I->getSymbol(); - break; + return object_error::success; } } - return object_error::success; + return object_error::parse_failed; } // Given a vector of relocations for a section and an offset into this section @@ -195,11 +198,13 @@ static error_code getSectionContents(const COFFObjectFile *Obj, ArrayRef &Contents, uint64_t &Addr) { SymbolRef Sym; - if (error_code ec = resolveSymbol(Rels, Offset, Sym)) return ec; + if (error_code EC = resolveSymbol(Rels, Offset, Sym)) + return EC; const coff_section *Section; - if (error_code ec = resolveSectionAndAddress(Obj, Sym, Section, Addr)) - return ec; - if (error_code ec = Obj->getSectionContents(Section, Contents)) return ec; + if (error_code EC = resolveSectionAndAddress(Obj, Sym, Section, Addr)) + return EC; + if (error_code EC = Obj->getSectionContents(Section, Contents)) + return EC; return object_error::success; } @@ -209,8 +214,10 @@ static error_code getSectionContents(const COFFObjectFile *Obj, static error_code resolveSymbolName(const std::vector &Rels, uint64_t Offset, StringRef &Name) { SymbolRef Sym; - if (error_code ec = resolveSymbol(Rels, Offset, Sym)) return ec; - if (error_code ec = Sym.getName(Name)) return ec; + if (error_code EC = resolveSymbol(Rels, Offset, Sym)) + return EC; + if (error_code EC = Sym.getName(Name)) + return EC; return object_error::success; } @@ -218,30 +225,95 @@ static void printCOFFSymbolAddress(llvm::raw_ostream &Out, const std::vector &Rels, uint64_t Offset, uint32_t Disp) { StringRef Sym; - if (error_code ec = resolveSymbolName(Rels, Offset, Sym)) { - error(ec); - return ; + if (!resolveSymbolName(Rels, Offset, Sym)) { + Out << Sym; + if (Disp > 0) + Out << format(" + 0x%04x", Disp); + } else { + Out << format("0x%04x", Disp); } - Out << Sym; - if (Disp > 0) - Out << format(" + 0x%04x", Disp); +} + +static void +printSEHTable(const COFFObjectFile *Obj, uint32_t TableVA, int Count) { + if (Count == 0) + return; + + const pe32_header *PE32Header; + if (error(Obj->getPE32Header(PE32Header))) + return; + uint32_t ImageBase = PE32Header->ImageBase; + uintptr_t IntPtr = 0; + if (error(Obj->getVaPtr(TableVA, IntPtr))) + return; + const support::ulittle32_t *P = (const support::ulittle32_t *)IntPtr; + outs() << "SEH Table:"; + for (int I = 0; I < Count; ++I) + outs() << format(" 0x%x", P[I] + ImageBase); + outs() << "\n\n"; +} + +static void printLoadConfiguration(const COFFObjectFile *Obj) { + // Skip if it's not executable. + const pe32_header *PE32Header; + if (error(Obj->getPE32Header(PE32Header))) + return; + if (!PE32Header) + return; + + const coff_file_header *Header; + if (error(Obj->getCOFFHeader(Header))) + return; + // Currently only x86 is supported + if (Header->Machine != COFF::IMAGE_FILE_MACHINE_I386) + return; + + const data_directory *DataDir; + if (error(Obj->getDataDirectory(COFF::LOAD_CONFIG_TABLE, DataDir))) + return; + uintptr_t IntPtr = 0; + if (DataDir->RelativeVirtualAddress == 0) + return; + if (error(Obj->getRvaPtr(DataDir->RelativeVirtualAddress, IntPtr))) + return; + + auto *LoadConf = reinterpret_cast(IntPtr); + outs() << "Load configuration:" + << "\n Timestamp: " << LoadConf->TimeDateStamp + << "\n Major Version: " << LoadConf->MajorVersion + << "\n Minor Version: " << LoadConf->MinorVersion + << "\n GlobalFlags Clear: " << LoadConf->GlobalFlagsClear + << "\n GlobalFlags Set: " << LoadConf->GlobalFlagsSet + << "\n Critical Section Default Timeout: " << LoadConf->CriticalSectionDefaultTimeout + << "\n Decommit Free Block Threshold: " << LoadConf->DeCommitFreeBlockThreshold + << "\n Decommit Total Free Threshold: " << LoadConf->DeCommitTotalFreeThreshold + << "\n Lock Prefix Table: " << LoadConf->LockPrefixTable + << "\n Maximum Allocation Size: " << LoadConf->MaximumAllocationSize + << "\n Virtual Memory Threshold: " << LoadConf->VirtualMemoryThreshold + << "\n Process Affinity Mask: " << LoadConf->ProcessAffinityMask + << "\n Process Heap Flags: " << LoadConf->ProcessHeapFlags + << "\n CSD Version: " << LoadConf->CSDVersion + << "\n Security Cookie: " << LoadConf->SecurityCookie + << "\n SEH Table: " << LoadConf->SEHandlerTable + << "\n SEH Count: " << LoadConf->SEHandlerCount + << "\n\n"; + printSEHTable(Obj, LoadConf->SEHandlerTable, LoadConf->SEHandlerCount); + outs() << "\n"; } // Prints import tables. The import table is a table containing the list of // DLL name and symbol names which will be linked by the loader. static void printImportTables(const COFFObjectFile *Obj) { + import_directory_iterator I = Obj->import_directory_begin(); + import_directory_iterator E = Obj->import_directory_end(); + if (I == E) + return; outs() << "The Import Tables:\n"; - error_code ec; - for (import_directory_iterator i = Obj->import_directory_begin(), - e = Obj->import_directory_end(); - i != e; i = i.increment(ec)) { - if (ec) - return; - + for (; I != E; I = ++I) { const import_directory_table_entry *Dir; StringRef Name; - if (i->getImportTableEntry(Dir)) return; - if (i->getName(Name)) return; + if (I->getImportTableEntry(Dir)) return; + if (I->getName(Name)) return; outs() << format(" lookup %08x time %08x fwd %08x name %08x addr %08x\n\n", static_cast(Dir->ImportLookupTableRVA), @@ -252,7 +324,7 @@ static void printImportTables(const COFFObjectFile *Obj) { outs() << " DLL Name: " << Name << "\n"; outs() << " Hint/Ord Name\n"; const import_lookup_table_entry32 *entry; - if (i->getImportLookupEntry(entry)) + if (I->getImportLookupEntry(entry)) return; for (; entry->data; ++entry) { if (entry->isOrdinal()) { @@ -269,133 +341,218 @@ static void printImportTables(const COFFObjectFile *Obj) { } } -void llvm::printCOFFUnwindInfo(const COFFObjectFile *Obj) { - const coff_file_header *Header; - if (error(Obj->getCOFFHeader(Header))) return; - - if (Header->Machine != COFF::IMAGE_FILE_MACHINE_AMD64) { - errs() << "Unsupported image machine type " - "(currently only AMD64 is supported).\n"; +// Prints export tables. The export table is a table containing the list of +// exported symbol from the DLL. +static void printExportTable(const COFFObjectFile *Obj) { + outs() << "Export Table:\n"; + export_directory_iterator I = Obj->export_directory_begin(); + export_directory_iterator E = Obj->export_directory_end(); + if (I == E) return; - } - - const coff_section *Pdata = 0; - - error_code ec; - for (section_iterator SI = Obj->begin_sections(), - SE = Obj->end_sections(); - SI != SE; SI.increment(ec)) { - if (error(ec)) return; + StringRef DllName; + uint32_t OrdinalBase; + if (I->getDllName(DllName)) + return; + if (I->getOrdinalBase(OrdinalBase)) + return; + outs() << " DLL name: " << DllName << "\n"; + outs() << " Ordinal base: " << OrdinalBase << "\n"; + outs() << " Ordinal RVA Name\n"; + for (; I != E; I = ++I) { + uint32_t Ordinal; + if (I->getOrdinal(Ordinal)) + return; + uint32_t RVA; + if (I->getExportRVA(RVA)) + return; + outs() << format(" % 4d %# 8x", Ordinal, RVA); StringRef Name; - if (error(SI->getName(Name))) continue; + if (I->getSymbolName(Name)) + continue; + if (!Name.empty()) + outs() << " " << Name; + outs() << "\n"; + } +} - if (Name != ".pdata") continue; +// Given the COFF object file, this function returns the relocations for .pdata +// and the pointer to "runtime function" structs. +static bool getPDataSection(const COFFObjectFile *Obj, + std::vector &Rels, + const RuntimeFunction *&RFStart, int &NumRFs) { + for (const SectionRef &Section : Obj->sections()) { + StringRef Name; + if (error(Section.getName(Name))) + continue; + if (Name != ".pdata") + continue; - Pdata = Obj->getCOFFSection(SI); - std::vector Rels; - for (relocation_iterator RI = SI->begin_relocations(), - RE = SI->end_relocations(); - RI != RE; RI.increment(ec)) { - if (error(ec)) break; - Rels.push_back(*RI); - } + const coff_section *Pdata = Obj->getCOFFSection(Section); + for (const RelocationRef &Reloc : Section.relocations()) + Rels.push_back(Reloc); // Sort relocations by address. std::sort(Rels.begin(), Rels.end(), RelocAddressLess); ArrayRef Contents; - if (error(Obj->getSectionContents(Pdata, Contents))) continue; - if (Contents.empty()) continue; + if (error(Obj->getSectionContents(Pdata, Contents))) + continue; + if (Contents.empty()) + continue; + + RFStart = reinterpret_cast(Contents.data()); + NumRFs = Contents.size() / sizeof(RuntimeFunction); + return true; + } + return false; +} - ArrayRef RFs( - reinterpret_cast(Contents.data()), - Contents.size() / sizeof(RuntimeFunction)); - for (const RuntimeFunction *I = RFs.begin(), *E = RFs.end(); I < E; ++I) { - const uint64_t SectionOffset = std::distance(RFs.begin(), I) - * sizeof(RuntimeFunction); +static void printWin64EHUnwindInfo(const Win64EH::UnwindInfo *UI) { + // The casts to int are required in order to output the value as number. + // Without the casts the value would be interpreted as char data (which + // results in garbage output). + outs() << " Version: " << static_cast(UI->getVersion()) << "\n"; + outs() << " Flags: " << static_cast(UI->getFlags()); + if (UI->getFlags()) { + if (UI->getFlags() & UNW_ExceptionHandler) + outs() << " UNW_ExceptionHandler"; + if (UI->getFlags() & UNW_TerminateHandler) + outs() << " UNW_TerminateHandler"; + if (UI->getFlags() & UNW_ChainInfo) + outs() << " UNW_ChainInfo"; + } + outs() << "\n"; + outs() << " Size of prolog: " << static_cast(UI->PrologSize) << "\n"; + outs() << " Number of Codes: " << static_cast(UI->NumCodes) << "\n"; + // Maybe this should move to output of UOP_SetFPReg? + if (UI->getFrameRegister()) { + outs() << " Frame register: " + << getUnwindRegisterName(UI->getFrameRegister()) << "\n"; + outs() << " Frame offset: " << 16 * UI->getFrameOffset() << "\n"; + } else { + outs() << " No frame pointer used\n"; + } + if (UI->getFlags() & (UNW_ExceptionHandler | UNW_TerminateHandler)) { + // FIXME: Output exception handler data + } else if (UI->getFlags() & UNW_ChainInfo) { + // FIXME: Output chained unwind info + } - outs() << "Function Table:\n"; + if (UI->NumCodes) + outs() << " Unwind Codes:\n"; - outs() << " Start Address: "; - printCOFFSymbolAddress(outs(), Rels, SectionOffset + + printAllUnwindCodes(ArrayRef(&UI->UnwindCodes[0], UI->NumCodes)); + + outs() << "\n"; + outs().flush(); +} + +/// Prints out the given RuntimeFunction struct for x64, assuming that Obj is +/// pointing to an executable file. +static void printRuntimeFunction(const COFFObjectFile *Obj, + const RuntimeFunction &RF) { + if (!RF.StartAddress) + return; + outs() << "Function Table:\n" + << format(" Start Address: 0x%04x\n", + static_cast(RF.StartAddress)) + << format(" End Address: 0x%04x\n", + static_cast(RF.EndAddress)) + << format(" Unwind Info Address: 0x%04x\n", + static_cast(RF.UnwindInfoOffset)); + uintptr_t addr; + if (Obj->getRvaPtr(RF.UnwindInfoOffset, addr)) + return; + printWin64EHUnwindInfo(reinterpret_cast(addr)); +} + +/// Prints out the given RuntimeFunction struct for x64, assuming that Obj is +/// pointing to an object file. Unlike executable, fields in RuntimeFunction +/// struct are filled with zeros, but instead there are relocations pointing to +/// them so that the linker will fill targets' RVAs to the fields at link +/// time. This function interprets the relocations to find the data to be used +/// in the resulting executable. +static void printRuntimeFunctionRels(const COFFObjectFile *Obj, + const RuntimeFunction &RF, + uint64_t SectionOffset, + const std::vector &Rels) { + outs() << "Function Table:\n"; + outs() << " Start Address: "; + printCOFFSymbolAddress(outs(), Rels, + SectionOffset + /*offsetof(RuntimeFunction, StartAddress)*/ 0, - I->StartAddress); - outs() << "\n"; + RF.StartAddress); + outs() << "\n"; - outs() << " End Address: "; - printCOFFSymbolAddress(outs(), Rels, SectionOffset + + outs() << " End Address: "; + printCOFFSymbolAddress(outs(), Rels, + SectionOffset + /*offsetof(RuntimeFunction, EndAddress)*/ 4, - I->EndAddress); - outs() << "\n"; + RF.EndAddress); + outs() << "\n"; - outs() << " Unwind Info Address: "; - printCOFFSymbolAddress(outs(), Rels, SectionOffset + + outs() << " Unwind Info Address: "; + printCOFFSymbolAddress(outs(), Rels, + SectionOffset + /*offsetof(RuntimeFunction, UnwindInfoOffset)*/ 8, - I->UnwindInfoOffset); - outs() << "\n"; - - ArrayRef XContents; - uint64_t UnwindInfoOffset = 0; - if (error(getSectionContents(Obj, Rels, SectionOffset + - /*offsetof(RuntimeFunction, UnwindInfoOffset)*/ 8, - XContents, UnwindInfoOffset))) continue; - if (XContents.empty()) continue; - - UnwindInfoOffset += I->UnwindInfoOffset; - if (UnwindInfoOffset > XContents.size()) continue; - - const Win64EH::UnwindInfo *UI = - reinterpret_cast - (XContents.data() + UnwindInfoOffset); - - // The casts to int are required in order to output the value as number. - // Without the casts the value would be interpreted as char data (which - // results in garbage output). - outs() << " Version: " << static_cast(UI->getVersion()) << "\n"; - outs() << " Flags: " << static_cast(UI->getFlags()); - if (UI->getFlags()) { - if (UI->getFlags() & UNW_ExceptionHandler) - outs() << " UNW_ExceptionHandler"; - if (UI->getFlags() & UNW_TerminateHandler) - outs() << " UNW_TerminateHandler"; - if (UI->getFlags() & UNW_ChainInfo) - outs() << " UNW_ChainInfo"; - } - outs() << "\n"; - outs() << " Size of prolog: " - << static_cast(UI->PrologSize) << "\n"; - outs() << " Number of Codes: " - << static_cast(UI->NumCodes) << "\n"; - // Maybe this should move to output of UOP_SetFPReg? - if (UI->getFrameRegister()) { - outs() << " Frame register: " - << getUnwindRegisterName(UI->getFrameRegister()) - << "\n"; - outs() << " Frame offset: " - << 16 * UI->getFrameOffset() - << "\n"; - } else { - outs() << " No frame pointer used\n"; - } - if (UI->getFlags() & (UNW_ExceptionHandler | UNW_TerminateHandler)) { - // FIXME: Output exception handler data - } else if (UI->getFlags() & UNW_ChainInfo) { - // FIXME: Output chained unwind info - } + RF.UnwindInfoOffset); + outs() << "\n"; - if (UI->NumCodes) - outs() << " Unwind Codes:\n"; + ArrayRef XContents; + uint64_t UnwindInfoOffset = 0; + if (error(getSectionContents( + Obj, Rels, SectionOffset + + /*offsetof(RuntimeFunction, UnwindInfoOffset)*/ 8, + XContents, UnwindInfoOffset))) + return; + if (XContents.empty()) + return; - printAllUnwindCodes(ArrayRef(&UI->UnwindCodes[0], - UI->NumCodes)); + UnwindInfoOffset += RF.UnwindInfoOffset; + if (UnwindInfoOffset > XContents.size()) + return; - outs() << "\n\n"; - outs().flush(); - } + auto *UI = reinterpret_cast(XContents.data() + + UnwindInfoOffset); + printWin64EHUnwindInfo(UI); +} + +void llvm::printCOFFUnwindInfo(const COFFObjectFile *Obj) { + const coff_file_header *Header; + if (error(Obj->getCOFFHeader(Header))) + return; + + if (Header->Machine != COFF::IMAGE_FILE_MACHINE_AMD64) { + errs() << "Unsupported image machine type " + "(currently only AMD64 is supported).\n"; + return; + } + + std::vector Rels; + const RuntimeFunction *RFStart; + int NumRFs; + if (!getPDataSection(Obj, Rels, RFStart, NumRFs)) + return; + ArrayRef RFs(RFStart, NumRFs); + + bool IsExecutable = Rels.empty(); + if (IsExecutable) { + for (const RuntimeFunction &RF : RFs) + printRuntimeFunction(Obj, RF); + return; + } + + for (const RuntimeFunction &RF : RFs) { + uint64_t SectionOffset = + std::distance(RFs.begin(), &RF) * sizeof(RuntimeFunction); + printRuntimeFunctionRels(Obj, RF, SectionOffset, Rels); } } void llvm::printCOFFFileHeader(const object::ObjectFile *Obj) { - printImportTables(dyn_cast(Obj)); + const COFFObjectFile *file = dyn_cast(Obj); + printLoadConfiguration(file); + printImportTables(file); + printExportTable(file); }