X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=tools%2Fllvm-objdump%2FCOFFDump.cpp;h=001e352c8d0b8f31cdd2067cfd782a0ea393ea20;hb=fdb838f3f8a8b6896bbbd5285555874eb3b748eb;hp=883786d4f6645c7baf54645080a9a8432e07bec3;hpb=b7e1ab795944263b663593085f7fee404f72475f;p=oota-llvm.git diff --git a/tools/llvm-objdump/COFFDump.cpp b/tools/llvm-objdump/COFFDump.cpp index 883786d4f66..001e352c8d0 100644 --- a/tools/llvm-objdump/COFFDump.cpp +++ b/tools/llvm-objdump/COFFDump.cpp @@ -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: @@ -151,107 +151,126 @@ static void printAllUnwindCodes(ArrayRef UCs) { << " remaining in buffer"; return ; } - printUnwindCode(ArrayRef(I, E)); + printUnwindCode(makeArrayRef(I, E)); I += UsedSlots; } } // Given a symbol sym this functions returns the address and section of it. -static error_code resolveSectionAndAddress(const COFFObjectFile *Obj, - const SymbolRef &Sym, - const coff_section *&ResolvedSection, - uint64_t &ResolvedAddr) { - if (error_code EC = Sym.getAddress(ResolvedAddr)) +static std::error_code +resolveSectionAndAddress(const COFFObjectFile *Obj, const SymbolRef &Sym, + const coff_section *&ResolvedSection, + uint64_t &ResolvedAddr) { + ErrorOr ResolvedAddrOrErr = Sym.getAddress(); + if (std::error_code EC = ResolvedAddrOrErr.getError()) return EC; - section_iterator iter(Obj->section_begin()); - if (error_code EC = Sym.getSection(iter)) + ResolvedAddr = *ResolvedAddrOrErr; + ErrorOr Iter = Sym.getSection(); + if (std::error_code EC = Iter.getError()) return EC; - ResolvedSection = Obj->getCOFFSection(iter); - return object_error::success; + ResolvedSection = Obj->getCOFFSection(**Iter); + return std::error_code(); } // Given a vector of relocations for a section and an offset into this section // the function returns the symbol used for the relocation at the offset. -static error_code resolveSymbol(const std::vector &Rels, - uint64_t Offset, SymbolRef &Sym) { +static std::error_code resolveSymbol(const std::vector &Rels, + uint64_t Offset, SymbolRef &Sym) { for (std::vector::const_iterator I = Rels.begin(), E = Rels.end(); I != E; ++I) { - uint64_t Ofs; - if (error_code EC = I->getOffset(Ofs)) - return EC; + uint64_t Ofs = I->getOffset(); if (Ofs == Offset) { Sym = *I->getSymbol(); - break; + return std::error_code(); } } - return object_error::success; + return object_error::parse_failed; } // Given a vector of relocations for a section and an offset into this section // the function resolves the symbol used for the relocation at the offset and // returns the section content and the address inside the content pointed to // by the symbol. -static error_code getSectionContents(const COFFObjectFile *Obj, - const std::vector &Rels, - uint64_t Offset, - ArrayRef &Contents, - uint64_t &Addr) { +static std::error_code +getSectionContents(const COFFObjectFile *Obj, + const std::vector &Rels, uint64_t Offset, + ArrayRef &Contents, uint64_t &Addr) { SymbolRef Sym; - if (error_code ec = resolveSymbol(Rels, Offset, Sym)) return ec; + if (std::error_code EC = resolveSymbol(Rels, Offset, Sym)) + return EC; const coff_section *Section; - if (error_code EC = resolveSectionAndAddress(Obj, Sym, Section, Addr)) + if (std::error_code EC = resolveSectionAndAddress(Obj, Sym, Section, Addr)) return EC; - if (error_code EC = Obj->getSectionContents(Section, Contents)) + if (std::error_code EC = Obj->getSectionContents(Section, Contents)) return EC; - return object_error::success; + return std::error_code(); } // Given a vector of relocations for a section and an offset into this section // the function returns the name of the symbol used for the relocation at the // offset. -static error_code resolveSymbolName(const std::vector &Rels, - uint64_t Offset, StringRef &Name) { +static std::error_code resolveSymbolName(const std::vector &Rels, + uint64_t Offset, StringRef &Name) { SymbolRef Sym; - if (error_code EC = resolveSymbol(Rels, Offset, Sym)) + if (std::error_code EC = resolveSymbol(Rels, Offset, Sym)) return EC; - if (error_code EC = Sym.getName(Name)) + ErrorOr NameOrErr = Sym.getName(); + if (std::error_code EC = NameOrErr.getError()) return EC; - return object_error::success; + Name = *NameOrErr; + return std::error_code(); } 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; + error(Obj->getPE32Header(PE32Header)); + uint32_t ImageBase = PE32Header->ImageBase; + uintptr_t IntPtr = 0; + error(Obj->getVaPtr(TableVA, IntPtr)); + 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) { - const coff_file_header *Header; - if (error(Obj->getCOFFHeader(Header))) + // Skip if it's not executable. + const pe32_header *PE32Header; + error(Obj->getPE32Header(PE32Header)); + if (!PE32Header) return; + // Currently only x86 is supported - if (Header->Machine != COFF::IMAGE_FILE_MACHINE_I386) + if (Obj->getMachine() != COFF::IMAGE_FILE_MACHINE_I386) return; const data_directory *DataDir; - if (error(Obj->getDataDirectory(COFF::LOAD_CONFIG_TABLE, DataDir))) - return; + error(Obj->getDataDirectory(COFF::LOAD_CONFIG_TABLE, DataDir)); uintptr_t IntPtr = 0; if (DataDir->RelativeVirtualAddress == 0) return; - if (error(Obj->getRvaPtr(DataDir->RelativeVirtualAddress, IntPtr))) - return; - const coff_load_configuration32 *LoadConf = - reinterpret_cast(IntPtr); + error(Obj->getRvaPtr(DataDir->RelativeVirtualAddress, IntPtr)); + auto *LoadConf = reinterpret_cast(IntPtr); outs() << "Load configuration:" << "\n Timestamp: " << LoadConf->TimeDateStamp << "\n Major Version: " << LoadConf->MajorVersion @@ -271,6 +290,8 @@ static void printLoadConfiguration(const COFFObjectFile *Obj) { << "\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 @@ -298,7 +319,7 @@ static void printImportTables(const COFFObjectFile *Obj) { const import_lookup_table_entry32 *entry; if (I->getImportLookupEntry(entry)) return; - for (; entry->data; ++entry) { + for (; entry->Data; ++entry) { if (entry->isOrdinal()) { outs() << format(" % 6d\n", entry->getOrdinal()); continue; @@ -348,124 +369,170 @@ static void printExportTable(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"; - return; - } - - const coff_section *Pdata = 0; - - for (section_iterator SI = Obj->section_begin(), SE = Obj->section_end(); - SI != SE; ++SI) { +// 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(SI->getName(Name))) continue; - - if (Name != ".pdata") continue; + error(Section.getName(Name)); + if (Name != ".pdata") + continue; - Pdata = Obj->getCOFFSection(SI); - std::vector Rels; - for (relocation_iterator RI = SI->relocation_begin(), - RE = SI->relocation_end(); - RI != RE; ++RI) - 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; + error(Obj->getSectionContents(Pdata, Contents)); + if (Contents.empty()) + continue; + + RFStart = reinterpret_cast(Contents.data()); + NumRFs = Contents.size() / sizeof(RuntimeFunction); + return true; + } + return false; +} + +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 + } - 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); + if (UI->NumCodes) + outs() << " Unwind Codes:\n"; - outs() << "Function Table:\n"; + printAllUnwindCodes(makeArrayRef(&UI->UnwindCodes[0], UI->NumCodes)); - outs() << " Start Address: "; - printCOFFSymbolAddress(outs(), Rels, SectionOffset + + 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; + error(getSectionContents( + Obj, Rels, SectionOffset + + /*offsetof(RuntimeFunction, UnwindInfoOffset)*/ 8, + XContents, UnwindInfoOffset)); + 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) { + if (Obj->getMachine() != 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); } }