aboutsummaryrefslogtreecommitdiffstats
path: root/tools/llvm-objdump/COFFDump.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tools/llvm-objdump/COFFDump.cpp')
-rw-r--r--tools/llvm-objdump/COFFDump.cpp427
1 files changed, 292 insertions, 135 deletions
diff --git a/tools/llvm-objdump/COFFDump.cpp b/tools/llvm-objdump/COFFDump.cpp
index 5f0bcbb..49f2755 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
///
//===----------------------------------------------------------------------===//
@@ -94,7 +94,7 @@ static unsigned getNumUsedSlots(const UnwindCode &UnwindCode) {
// slots is provided.
static void printUnwindCode(ArrayRef<UnwindCode> 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<RelocationRef> &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<uint8_t> &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<RelocationRef> &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<RelocationRef> &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<const coff_load_configuration32 *>(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<uint32_t>(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<RelocationRef> &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<RelocationRef> 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<uint8_t> 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<const RuntimeFunction *>(Contents.data());
+ NumRFs = Contents.size() / sizeof(RuntimeFunction);
+ return true;
+ }
+ return false;
+}
- ArrayRef<RuntimeFunction> RFs(
- reinterpret_cast<const RuntimeFunction *>(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<int>(UI->getVersion()) << "\n";
+ outs() << " Flags: " << static_cast<int>(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<int>(UI->PrologSize) << "\n";
+ outs() << " Number of Codes: " << static_cast<int>(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<UnwindCode>(&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<uint32_t>(RF.StartAddress))
+ << format(" End Address: 0x%04x\n",
+ static_cast<uint32_t>(RF.EndAddress))
+ << format(" Unwind Info Address: 0x%04x\n",
+ static_cast<uint32_t>(RF.UnwindInfoOffset));
+ uintptr_t addr;
+ if (Obj->getRvaPtr(RF.UnwindInfoOffset, addr))
+ return;
+ printWin64EHUnwindInfo(reinterpret_cast<const Win64EH::UnwindInfo *>(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<RelocationRef> &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<uint8_t> 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<const Win64EH::UnwindInfo *>
- (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<int>(UI->getVersion()) << "\n";
- outs() << " Flags: " << static_cast<int>(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<int>(UI->PrologSize) << "\n";
- outs() << " Number of Codes: "
- << static_cast<int>(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<uint8_t> XContents;
+ uint64_t UnwindInfoOffset = 0;
+ if (error(getSectionContents(
+ Obj, Rels, SectionOffset +
+ /*offsetof(RuntimeFunction, UnwindInfoOffset)*/ 8,
+ XContents, UnwindInfoOffset)))
+ return;
+ if (XContents.empty())
+ return;
- printAllUnwindCodes(ArrayRef<UnwindCode>(&UI->UnwindCodes[0],
- UI->NumCodes));
+ UnwindInfoOffset += RF.UnwindInfoOffset;
+ if (UnwindInfoOffset > XContents.size())
+ return;
- outs() << "\n\n";
- outs().flush();
- }
+ auto *UI = reinterpret_cast<const Win64EH::UnwindInfo *>(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<RelocationRef> Rels;
+ const RuntimeFunction *RFStart;
+ int NumRFs;
+ if (!getPDataSection(Obj, Rels, RFStart, NumRFs))
+ return;
+ ArrayRef<RuntimeFunction> 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<const COFFObjectFile>(Obj));
+ const COFFObjectFile *file = dyn_cast<const COFFObjectFile>(Obj);
+ printLoadConfiguration(file);
+ printImportTables(file);
+ printExportTable(file);
}