aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/llvm/Object/COFF.h40
-rw-r--r--lib/Object/COFFObjectFile.cpp196
-rw-r--r--test/tools/llvm-objdump/Inputs/nop.exe.coff-i386bin0 -> 7680 bytes
-rw-r--r--test/tools/llvm-objdump/Inputs/trivial.obj.elf-i386bin0 -> 449 bytes
-rw-r--r--test/tools/llvm-objdump/Inputs/win64-unwind.exe.coff-x86_64bin0 -> 698 bytes
-rw-r--r--test/tools/llvm-objdump/Inputs/win64-unwind.exe.coff-x86_64.asm53
-rw-r--r--test/tools/llvm-objdump/coff-private-headers.test9
-rw-r--r--test/tools/llvm-objdump/disassembly-show-raw.s15
-rw-r--r--test/tools/llvm-objdump/disassembly-show-raw.test14
-rw-r--r--test/tools/llvm-objdump/lit.local.cfg4
-rw-r--r--test/tools/llvm-objdump/win64-unwind-data.s106
-rw-r--r--test/tools/llvm-objdump/win64-unwind-data.test52
-rw-r--r--tools/llvm-objdump/COFFDump.cpp46
-rw-r--r--tools/llvm-objdump/llvm-objdump.cpp12
-rw-r--r--tools/llvm-objdump/llvm-objdump.h3
15 files changed, 390 insertions, 160 deletions
diff --git a/include/llvm/Object/COFF.h b/include/llvm/Object/COFF.h
index cb464ab..e9ea547 100644
--- a/include/llvm/Object/COFF.h
+++ b/include/llvm/Object/COFF.h
@@ -23,6 +23,8 @@ namespace llvm {
class ArrayRef;
namespace object {
+class ImportDirectoryEntryRef;
+typedef content_iterator<ImportDirectoryEntryRef> import_directory_iterator;
/// The DOS compatible header at the front of all PE/COFF executables.
struct dos_header {
@@ -202,6 +204,7 @@ struct coff_aux_section_definition {
class COFFObjectFile : public ObjectFile {
private:
+ friend class ImportDirectoryEntryRef;
const coff_file_header *COFFHeader;
const pe32_header *PE32Header;
const data_directory *DataDirectory;
@@ -209,6 +212,8 @@ private:
const coff_symbol *SymbolTable;
const char *StringTable;
uint32_t StringTableSize;
+ const import_directory_table_entry *ImportDirectory;
+ uint32_t NumberOfImportDirectory;
error_code getString(uint32_t offset, StringRef &Res) const;
@@ -216,6 +221,9 @@ private:
const coff_section *toSec(DataRefImpl Sec) const;
const coff_relocation *toRel(DataRefImpl Rel) const;
+ error_code initSymbolTablePtr();
+ error_code initImportTablePtr();
+
protected:
virtual error_code getSymbolNext(DataRefImpl Symb, SymbolRef &Res) const;
virtual error_code getSymbolName(DataRefImpl Symb, StringRef &Res) const;
@@ -287,6 +295,9 @@ public:
virtual unsigned getArch() const;
virtual StringRef getLoadName() const;
+ import_directory_iterator getImportDirectoryBegin() const;
+ import_directory_iterator getImportDirectoryEnd() const;
+
error_code getHeader(const coff_file_header *&Res) const;
error_code getCOFFHeader(const coff_file_header *&Res) const;
error_code getPE32Header(const pe32_header *&Res) const;
@@ -307,12 +318,37 @@ public:
error_code getSectionContents(const coff_section *Sec,
ArrayRef<uint8_t> &Res) const;
+ error_code getRvaPtr(uint32_t Rva, uintptr_t &Res) const;
+ error_code getHintName(uint32_t Rva, uint16_t &Hint, StringRef &Name) const;
+
static inline bool classof(const Binary *v) {
return v->isCOFF();
}
};
-}
-}
+// The iterator for the import directory table.
+class ImportDirectoryEntryRef {
+public:
+ ImportDirectoryEntryRef() : OwningObject(0) {}
+ ImportDirectoryEntryRef(DataRefImpl ImportDirectory,
+ const COFFObjectFile *Owner)
+ : ImportDirectoryPimpl(ImportDirectory), OwningObject(Owner) {}
+
+ bool operator==(const ImportDirectoryEntryRef &Other) const;
+ error_code getNext(ImportDirectoryEntryRef &Result) const;
+ error_code getName(StringRef &Result) const;
+
+ error_code
+ getImportTableEntry(const import_directory_table_entry *&Result) const;
+
+ error_code
+ getImportLookupEntry(const COFF::ImportLookupTableEntry32 *&Result) const;
+
+private:
+ DataRefImpl ImportDirectoryPimpl;
+ const COFFObjectFile *OwningObject;
+};
+} // end namespace object
+} // end namespace llvm
#endif
diff --git a/lib/Object/COFFObjectFile.cpp b/lib/Object/COFFObjectFile.cpp
index f3f2532..1429241 100644
--- a/lib/Object/COFFObjectFile.cpp
+++ b/lib/Object/COFFObjectFile.cpp
@@ -16,6 +16,8 @@
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Triple.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/raw_ostream.h"
using namespace llvm;
using namespace object;
@@ -429,6 +431,94 @@ relocation_iterator COFFObjectFile::getSectionRelEnd(DataRefImpl Sec) const {
return relocation_iterator(RelocationRef(ret, this));
}
+// Initialize the pointer to the symbol table.
+error_code COFFObjectFile::initSymbolTablePtr() {
+ if (error_code ec = getObject(
+ SymbolTable, Data, base() + COFFHeader->PointerToSymbolTable,
+ COFFHeader->NumberOfSymbols * sizeof(coff_symbol)))
+ return ec;
+
+ // Find string table. The first four byte of the string table contains the
+ // total size of the string table, including the size field itself. If the
+ // string table is empty, the value of the first four byte would be 4.
+ const uint8_t *StringTableAddr =
+ base() + COFFHeader->PointerToSymbolTable +
+ COFFHeader->NumberOfSymbols * sizeof(coff_symbol);
+ const ulittle32_t *StringTableSizePtr;
+ if (error_code ec = getObject(StringTableSizePtr, Data, StringTableAddr))
+ return ec;
+ StringTableSize = *StringTableSizePtr;
+ if (error_code ec =
+ getObject(StringTable, Data, StringTableAddr, StringTableSize))
+ return ec;
+
+ // Check that the string table is null terminated if has any in it.
+ if (StringTableSize < 4 ||
+ (StringTableSize > 4 && StringTable[StringTableSize - 1] != 0))
+ return object_error::parse_failed;
+ return object_error::success;
+}
+
+// Returns the file offset for the given RVA.
+error_code COFFObjectFile::getRvaPtr(uint32_t Rva, uintptr_t &Res) const {
+ error_code ec;
+ for (section_iterator i = begin_sections(), e = end_sections(); i != e;
+ i.increment(ec)) {
+ if (ec)
+ return ec;
+ const coff_section *Section = getCOFFSection(i);
+ uint32_t SectionStart = Section->VirtualAddress;
+ uint32_t SectionEnd = Section->VirtualAddress + Section->VirtualSize;
+ if (SectionStart <= Rva && Rva < SectionEnd) {
+ uint32_t Offset = Rva - SectionStart;
+ Res = uintptr_t(base()) + Section->PointerToRawData + Offset;
+ return object_error::success;
+ }
+ }
+ return object_error::parse_failed;
+}
+
+// Returns hint and name fields, assuming \p Rva is pointing to a Hint/Name
+// table entry.
+error_code COFFObjectFile::
+getHintName(uint32_t Rva, uint16_t &Hint, StringRef &Name) const {
+ uintptr_t IntPtr = 0;
+ if (error_code ec = getRvaPtr(Rva, IntPtr))
+ return ec;
+ const uint8_t *Ptr = reinterpret_cast<const uint8_t *>(IntPtr);
+ Hint = *reinterpret_cast<const ulittle16_t *>(Ptr);
+ Name = StringRef(reinterpret_cast<const char *>(Ptr + 2));
+ return object_error::success;
+}
+
+// Find the import table.
+error_code COFFObjectFile::initImportTablePtr() {
+ // First, we get the RVA of the import table. If the file lacks a pointer to
+ // the import table, do nothing.
+ const data_directory *DataEntry;
+ if (getDataDirectory(COFF::IMPORT_TABLE, DataEntry))
+ return object_error::success;
+
+ // Do nothing if the pointer to import table is NULL.
+ if (DataEntry->RelativeVirtualAddress == 0)
+ return object_error::success;
+
+ uint32_t ImportTableRva = DataEntry->RelativeVirtualAddress;
+ NumberOfImportDirectory = DataEntry->Size /
+ sizeof(import_directory_table_entry);
+
+ // Find the section that contains the RVA. This is needed because the RVA is
+ // the import table's memory address which is different from its file offset.
+ uintptr_t IntPtr = 0;
+ if (error_code ec = getRvaPtr(ImportTableRva, IntPtr))
+ return ec;
+ ImportDirectory = reinterpret_cast<
+ const import_directory_table_entry *>(IntPtr);
+
+ // It's an error if there's no section containing the Import Table RVA.
+ return object_error::parse_failed;
+}
+
COFFObjectFile::COFFObjectFile(MemoryBuffer *Object, error_code &ec)
: ObjectFile(Binary::ID_COFF, Object)
, COFFHeader(0)
@@ -437,7 +527,9 @@ COFFObjectFile::COFFObjectFile(MemoryBuffer *Object, error_code &ec)
, SectionTable(0)
, SymbolTable(0)
, StringTable(0)
- , StringTableSize(0) {
+ , StringTableSize(0)
+ , ImportDirectory(0)
+ , NumberOfImportDirectory(0) {
// Check that we at least have enough room for a header.
if (!checkSize(Data, ec, sizeof(coff_file_header))) return;
@@ -488,45 +580,28 @@ COFFObjectFile::COFFObjectFile(MemoryBuffer *Object, error_code &ec)
COFFHeader->NumberOfSections * sizeof(coff_section))))
return;
- if (COFFHeader->PointerToSymbolTable != 0) {
- if ((ec = getObject(SymbolTable, Data,
- base() + COFFHeader->PointerToSymbolTable,
- COFFHeader->NumberOfSymbols * sizeof(coff_symbol))))
+ // Initialize the pointer to the symbol table.
+ if (COFFHeader->PointerToSymbolTable != 0)
+ if ((ec = initSymbolTablePtr()))
return;
- // Find string table. The first four byte of the string table contains the
- // total size of the string table, including the size field itself. If the
- // string table is empty, the value of the first four byte would be 4.
- const uint8_t *StringTableAddr = base() + COFFHeader->PointerToSymbolTable
- + COFFHeader->NumberOfSymbols * sizeof(coff_symbol);
- const ulittle32_t *StringTableSizePtr;
- if ((ec = getObject(StringTableSizePtr, Data, StringTableAddr)))
- return;
- StringTableSize = *StringTableSizePtr;
- if ((ec = getObject(StringTable, Data, StringTableAddr, StringTableSize)))
- return;
-
- // Check that the string table is null terminated if has any in it.
- if (StringTableSize < 4
- || (StringTableSize > 4 && StringTable[StringTableSize - 1] != 0)) {
- ec = object_error::parse_failed;
- return;
- }
- }
+ // Initialize the pointer to the beginning of the import table.
+ if ((ec = initImportTablePtr()))
+ return;
ec = object_error::success;
}
symbol_iterator COFFObjectFile::begin_symbols() const {
DataRefImpl ret;
- ret.p = reinterpret_cast<intptr_t>(SymbolTable);
+ ret.p = reinterpret_cast<uintptr_t>(SymbolTable);
return symbol_iterator(SymbolRef(ret, this));
}
symbol_iterator COFFObjectFile::end_symbols() const {
// The symbol table ends where the string table begins.
DataRefImpl ret;
- ret.p = reinterpret_cast<intptr_t>(StringTable);
+ ret.p = reinterpret_cast<uintptr_t>(StringTable);
return symbol_iterator(SymbolRef(ret, this));
}
@@ -555,16 +630,32 @@ StringRef COFFObjectFile::getLoadName() const {
return "";
}
+import_directory_iterator COFFObjectFile::getImportDirectoryBegin() const {
+ DataRefImpl Imp;
+ Imp.p = reinterpret_cast<uintptr_t>(ImportDirectory);
+ return import_directory_iterator(ImportDirectoryEntryRef(Imp, this));
+}
+
+import_directory_iterator COFFObjectFile::getImportDirectoryEnd() const {
+ DataRefImpl Imp;
+ if (ImportDirectory) {
+ Imp.p = reinterpret_cast<uintptr_t>(
+ ImportDirectory + (NumberOfImportDirectory - 1));
+ } else {
+ Imp.p = 0;
+ }
+ return import_directory_iterator(ImportDirectoryEntryRef(Imp, this));
+}
section_iterator COFFObjectFile::begin_sections() const {
DataRefImpl ret;
- ret.p = reinterpret_cast<intptr_t>(SectionTable);
+ ret.p = reinterpret_cast<uintptr_t>(SectionTable);
return section_iterator(SectionRef(ret, this));
}
section_iterator COFFObjectFile::end_sections() const {
DataRefImpl ret;
- ret.p = reinterpret_cast<intptr_t>(SectionTable + COFFHeader->NumberOfSections);
+ ret.p = reinterpret_cast<uintptr_t>(SectionTable + COFFHeader->NumberOfSections);
return section_iterator(SectionRef(ret, this));
}
@@ -676,7 +767,7 @@ error_code COFFObjectFile::getSymbolName(const coff_symbol *symbol,
ArrayRef<uint8_t> COFFObjectFile::getSymbolAuxData(
const coff_symbol *symbol) const {
const uint8_t *aux = NULL;
-
+
if ( symbol->NumberOfAuxSymbols > 0 ) {
// AUX data comes immediately after the symbol in COFF
aux = reinterpret_cast<const uint8_t *>(symbol + 1);
@@ -777,7 +868,6 @@ const coff_relocation *COFFObjectFile::getCOFFRelocation(
return toRel(It->getRawDataRefImpl());
}
-
#define LLVM_COFF_SWITCH_RELOC_TYPE_NAME(enum) \
case COFF::enum: res = #enum; break;
@@ -858,6 +948,52 @@ error_code COFFObjectFile::getLibraryPath(DataRefImpl LibData,
report_fatal_error("getLibraryPath not implemented in COFFObjectFile");
}
+bool ImportDirectoryEntryRef::
+operator==(const ImportDirectoryEntryRef &Other) const {
+ return ImportDirectoryPimpl == Other.ImportDirectoryPimpl;
+}
+
+static const import_directory_table_entry *toImportEntry(DataRefImpl Imp) {
+ return reinterpret_cast<const import_directory_table_entry *>(Imp.p);
+}
+
+error_code
+ImportDirectoryEntryRef::getNext(ImportDirectoryEntryRef &Result) const {
+ const import_directory_table_entry *Dir = toImportEntry(ImportDirectoryPimpl);
+ Dir += 1;
+ DataRefImpl Next;
+ Next.p = reinterpret_cast<uintptr_t>(Dir);
+ Result = ImportDirectoryEntryRef(Next, OwningObject);
+ return object_error::success;
+}
+
+error_code ImportDirectoryEntryRef::
+getImportTableEntry(const import_directory_table_entry *&Result) const {
+ Result = toImportEntry(ImportDirectoryPimpl);
+ return object_error::success;
+}
+
+error_code ImportDirectoryEntryRef::getName(StringRef &Result) const {
+ const import_directory_table_entry *Dir = toImportEntry(ImportDirectoryPimpl);
+ uintptr_t IntPtr = 0;
+ if (error_code ec = OwningObject->getRvaPtr(Dir->NameRVA, IntPtr))
+ return ec;
+ const char *Ptr = reinterpret_cast<const char *>(IntPtr);
+ Result = StringRef(Ptr);
+ return object_error::success;
+}
+
+error_code ImportDirectoryEntryRef::getImportLookupEntry(
+ const COFF::ImportLookupTableEntry32 *&Result) const {
+ const import_directory_table_entry *Dir = toImportEntry(ImportDirectoryPimpl);
+ uintptr_t IntPtr = 0;
+ if (error_code ec = OwningObject->getRvaPtr(
+ Dir->ImportLookupTableRVA, IntPtr))
+ return ec;
+ Result = reinterpret_cast<const COFF::ImportLookupTableEntry32 *>(IntPtr);
+ return object_error::success;
+}
+
namespace llvm {
ObjectFile *ObjectFile::createCOFFObjectFile(MemoryBuffer *Object) {
diff --git a/test/tools/llvm-objdump/Inputs/nop.exe.coff-i386 b/test/tools/llvm-objdump/Inputs/nop.exe.coff-i386
new file mode 100644
index 0000000..68c9d3d
--- /dev/null
+++ b/test/tools/llvm-objdump/Inputs/nop.exe.coff-i386
Binary files differ
diff --git a/test/tools/llvm-objdump/Inputs/trivial.obj.elf-i386 b/test/tools/llvm-objdump/Inputs/trivial.obj.elf-i386
new file mode 100644
index 0000000..fdc4874
--- /dev/null
+++ b/test/tools/llvm-objdump/Inputs/trivial.obj.elf-i386
Binary files differ
diff --git a/test/tools/llvm-objdump/Inputs/win64-unwind.exe.coff-x86_64 b/test/tools/llvm-objdump/Inputs/win64-unwind.exe.coff-x86_64
new file mode 100644
index 0000000..63460e7
--- /dev/null
+++ b/test/tools/llvm-objdump/Inputs/win64-unwind.exe.coff-x86_64
Binary files differ
diff --git a/test/tools/llvm-objdump/Inputs/win64-unwind.exe.coff-x86_64.asm b/test/tools/llvm-objdump/Inputs/win64-unwind.exe.coff-x86_64.asm
new file mode 100644
index 0000000..4d47fa4
--- /dev/null
+++ b/test/tools/llvm-objdump/Inputs/win64-unwind.exe.coff-x86_64.asm
@@ -0,0 +1,53 @@
+ .text
+ .globl func
+ .def func; .scl 2; .type 32; .endef
+ .seh_proc func
+func:
+ .seh_pushframe @code
+ subq $24, %rsp
+ .seh_stackalloc 24
+ movq %rsi, 16(%rsp)
+ .seh_savereg %rsi, 16
+ movups %xmm8, (%rsp)
+ .seh_savexmm %xmm8, 0
+ pushq %rbx
+ .seh_pushreg 3
+ mov %rsp, %rbx
+ .seh_setframe 3, 0
+ .seh_endprologue
+ .seh_handler __C_specific_handler, @except
+ .seh_handlerdata
+ .long 0
+ .text
+ .seh_startchained
+ .seh_endprologue
+ .seh_endchained
+ lea (%rbx), %rsp
+ pop %rbx
+ addq $24, %rsp
+ ret
+ .seh_endproc
+
+// Test emission of small functions.
+ .globl smallFunc
+ .def smallFunc; .scl 2; .type 32; .endef
+ .seh_proc smallFunc
+smallFunc:
+ ret
+ .seh_endproc
+
+// Function with big stack allocation.
+ .globl allocFunc
+ .def allocFunc; .scl 2; .type 32; .endef
+ .seh_proc allocFunc
+allocFunc:
+ .seh_pushframe @code
+ subq $65520, %rsp
+ .seh_stackalloc 65520
+ sub $8454128, %rsp
+ .seh_stackalloc 8454128
+ .seh_endprologue
+ add $8454128, %rsp
+ addq $65520, %rsp
+ ret
+ .seh_endproc
diff --git a/test/tools/llvm-objdump/coff-private-headers.test b/test/tools/llvm-objdump/coff-private-headers.test
new file mode 100644
index 0000000..d36c148
--- /dev/null
+++ b/test/tools/llvm-objdump/coff-private-headers.test
@@ -0,0 +1,9 @@
+// RUN: llvm-objdump -p %p/Inputs/nop.exe.coff-i386 | FileCheck %s
+
+CHECK: The Import Tables:
+CHECK-NEXT: lookup 00005028 time 00000000 fwd 00000000 name 00005096 addr 00005058
+CHECK: DLL Name: KERNEL32.dll
+CHECK-NEXT: Hint/Ord Name
+CHECK-NEXT: 365 ExitProcess
+
+
diff --git a/test/tools/llvm-objdump/disassembly-show-raw.s b/test/tools/llvm-objdump/disassembly-show-raw.s
deleted file mode 100644
index 32fcad4..0000000
--- a/test/tools/llvm-objdump/disassembly-show-raw.s
+++ /dev/null
@@ -1,15 +0,0 @@
-// RUN: llvm-mc -filetype=obj -arch=x86 %s | llvm-objdump -d - \
-// RUN: | FileCheck %s -check-prefix=WITHRAW
-// RUN: llvm-mc -filetype=obj -arch=x86 %s | llvm-objdump -d -no-show-raw-insn - \
-// RUN: | FileCheck %s -check-prefix=NORAW
-
-// Expect to find the raw incoding when run with raw output (default), but not
-// when run explicitly with -no-show-raw-insn
-
-movl 0, %eax
-// WITHRAW: a1 00 00 00 00 movl
-
-// NORAW: movl
-// NORAW-NOT: a1 00
-
-
diff --git a/test/tools/llvm-objdump/disassembly-show-raw.test b/test/tools/llvm-objdump/disassembly-show-raw.test
new file mode 100644
index 0000000..e9956a5
--- /dev/null
+++ b/test/tools/llvm-objdump/disassembly-show-raw.test
@@ -0,0 +1,14 @@
+// RUN: llvm-objdump -d %p/Inputs/trivial.obj.elf-i386 \
+// RUN: | FileCheck %s -check-prefix=WITHRAW
+// RUN: llvm-objdump -d -no-show-raw-insn %p/Inputs/trivial.obj.elf-i386 \
+// RUN: | FileCheck %s -check-prefix=NORAW
+
+// Expect to find the raw incoding when run with raw output (default), but not
+// when run explicitly with -no-show-raw-insn
+
+WITHRAW: a1 00 00 00 00 movl
+
+NORAW: movl
+NORAW-NOT: a1 00
+
+
diff --git a/test/tools/llvm-objdump/lit.local.cfg b/test/tools/llvm-objdump/lit.local.cfg
deleted file mode 100644
index ba763cf..0000000
--- a/test/tools/llvm-objdump/lit.local.cfg
+++ /dev/null
@@ -1,4 +0,0 @@
-targets = set(config.root.targets_to_build.split())
-if not 'X86' in targets:
- config.unsupported = True
-
diff --git a/test/tools/llvm-objdump/win64-unwind-data.s b/test/tools/llvm-objdump/win64-unwind-data.s
deleted file mode 100644
index f8463fb..0000000
--- a/test/tools/llvm-objdump/win64-unwind-data.s
+++ /dev/null
@@ -1,106 +0,0 @@
-// This test checks that the unwind data is dumped by llvm-objdump.
-// RUN: llvm-mc -triple x86_64-pc-win32 -filetype=obj %s | llvm-objdump -u - | FileCheck %s
-
-// CHECK: Unwind info:
-// CHECK: Function Table:
-// CHECK-NEXT: Start Address: func
-// CHECK-NEXT: End Address: func + 0x001b
-// CHECK-NEXT: Unwind Info Address: .xdata
-// CHECK-NEXT: Version: 1
-// CHECK-NEXT: Flags: 1 UNW_ExceptionHandler
-// CHECK-NEXT: Size of prolog: 18
-// CHECK-NEXT: Number of Codes: 8
-// CHECK-NEXT: Frame register: RBX
-// CHECK-NEXT: Frame offset: 0
-// CHECK-NEXT: Unwind Codes:
-// CHECK-NEXT: 0x12: UOP_SetFPReg
-// CHECK-NEXT: 0x0f: UOP_PushNonVol RBX
-// CHECK-NEXT: 0x0e: UOP_SaveXMM128 XMM8 [0x0000]
-// CHECK-NEXT: 0x09: UOP_SaveNonVol RSI [0x0010]
-// CHECK-NEXT: 0x04: UOP_AllocSmall 24
-// CHECK-NEXT: 0x00: UOP_PushMachFrame w/o error code
-// CHECK: Function Table:
-// CHECK-NEXT: Start Address: func + 0x0012
-// CHECK-NEXT: End Address: func + 0x0012
-// CHECK-NEXT: Unwind Info Address: .xdata + 0x001c
-// CHECK-NEXT: Version: 1
-// CHECK-NEXT: Flags: 4 UNW_ChainInfo
-// CHECK-NEXT: Size of prolog: 0
-// CHECK-NEXT: Number of Codes: 0
-// CHECK-NEXT: No frame pointer used
-// CHECK: Function Table:
-// CHECK-NEXT: Start Address: smallFunc
-// CHECK-NEXT: End Address: smallFunc + 0x0001
-// CHECK-NEXT: Unwind Info Address: .xdata + 0x002c
-// CHECK-NEXT: Version: 1
-// CHECK-NEXT: Flags: 0
-// CHECK-NEXT: Size of prolog: 0
-// CHECK-NEXT: Number of Codes: 0
-// CHECK-NEXT: No frame pointer used
-// CHECK: Function Table:
-// CHECK-NEXT: Start Address: allocFunc
-// CHECK-NEXT: End Address: allocFunc + 0x001d
-// CHECK-NEXT: Unwind Info Address: .xdata + 0x0034
-// CHECK-NEXT: Version: 1
-// CHECK-NEXT: Flags: 0
-// CHECK-NEXT: Size of prolog: 14
-// CHECK-NEXT: Number of Codes: 6
-// CHECK-NEXT: No frame pointer used
-// CHECK-NEXT: Unwind Codes:
-// CHECK-NEXT: 0x0e: UOP_AllocLarge 8454128
-// CHECK-NEXT: 0x07: UOP_AllocLarge 8190
-// CHECK-NEXT: 0x00: UOP_PushMachFrame w/o error code
-
- .text
- .globl func
- .def func; .scl 2; .type 32; .endef
- .seh_proc func
-func:
- .seh_pushframe @code
- subq $24, %rsp
- .seh_stackalloc 24
- movq %rsi, 16(%rsp)
- .seh_savereg %rsi, 16
- movups %xmm8, (%rsp)
- .seh_savexmm %xmm8, 0
- pushq %rbx
- .seh_pushreg 3
- mov %rsp, %rbx
- .seh_setframe 3, 0
- .seh_endprologue
- .seh_handler __C_specific_handler, @except
- .seh_handlerdata
- .long 0
- .text
- .seh_startchained
- .seh_endprologue
- .seh_endchained
- lea (%rbx), %rsp
- pop %rbx
- addq $24, %rsp
- ret
- .seh_endproc
-
-// Test emission of small functions.
- .globl smallFunc
- .def smallFunc; .scl 2; .type 32; .endef
- .seh_proc smallFunc
-smallFunc:
- ret
- .seh_endproc
-
-// Function with big stack allocation.
- .globl allocFunc
- .def allocFunc; .scl 2; .type 32; .endef
- .seh_proc allocFunc
-allocFunc:
- .seh_pushframe @code
- subq $65520, %rsp
- .seh_stackalloc 65520
- sub $8454128, %rsp
- .seh_stackalloc 8454128
- .seh_endprologue
- add $8454128, %rsp
- addq $65520, %rsp
- ret
- .seh_endproc
diff --git a/test/tools/llvm-objdump/win64-unwind-data.test b/test/tools/llvm-objdump/win64-unwind-data.test
new file mode 100644
index 0000000..a723ffe
--- /dev/null
+++ b/test/tools/llvm-objdump/win64-unwind-data.test
@@ -0,0 +1,52 @@
+// This test checks that the unwind data is dumped by llvm-objdump.
+// RUN: llvm-objdump -u %p/Inputs/win64-unwind.exe.coff-x86_64 | FileCheck %s
+
+CHECK: Unwind info:
+CHECK: Function Table:
+CHECK-NEXT: Start Address: func
+CHECK-NEXT: End Address: func + 0x001b
+CHECK-NEXT: Unwind Info Address: .xdata
+CHECK-NEXT: Version: 1
+CHECK-NEXT: Flags: 1 UNW_ExceptionHandler
+CHECK-NEXT: Size of prolog: 18
+CHECK-NEXT: Number of Codes: 8
+CHECK-NEXT: Frame register: RBX
+CHECK-NEXT: Frame offset: 0
+CHECK-NEXT: Unwind Codes:
+CHECK-NEXT: 0x12: UOP_SetFPReg
+CHECK-NEXT: 0x0f: UOP_PushNonVol RBX
+CHECK-NEXT: 0x0e: UOP_SaveXMM128 XMM8 [0x0000]
+CHECK-NEXT: 0x09: UOP_SaveNonVol RSI [0x0010]
+CHECK-NEXT: 0x04: UOP_AllocSmall 24
+CHECK-NEXT: 0x00: UOP_PushMachFrame w/o error code
+CHECK: Function Table:
+CHECK-NEXT: Start Address: func + 0x0012
+CHECK-NEXT: End Address: func + 0x0012
+CHECK-NEXT: Unwind Info Address: .xdata + 0x001c
+CHECK-NEXT: Version: 1
+CHECK-NEXT: Flags: 4 UNW_ChainInfo
+CHECK-NEXT: Size of prolog: 0
+CHECK-NEXT: Number of Codes: 0
+CHECK-NEXT: No frame pointer used
+CHECK: Function Table:
+CHECK-NEXT: Start Address: smallFunc
+CHECK-NEXT: End Address: smallFunc + 0x0001
+CHECK-NEXT: Unwind Info Address: .xdata + 0x002c
+CHECK-NEXT: Version: 1
+CHECK-NEXT: Flags: 0
+CHECK-NEXT: Size of prolog: 0
+CHECK-NEXT: Number of Codes: 0
+CHECK-NEXT: No frame pointer used
+CHECK: Function Table:
+CHECK-NEXT: Start Address: allocFunc
+CHECK-NEXT: End Address: allocFunc + 0x001d
+CHECK-NEXT: Unwind Info Address: .xdata + 0x0034
+CHECK-NEXT: Version: 1
+CHECK-NEXT: Flags: 0
+CHECK-NEXT: Size of prolog: 14
+CHECK-NEXT: Number of Codes: 6
+CHECK-NEXT: No frame pointer used
+CHECK-NEXT: Unwind Codes:
+CHECK-NEXT: 0x0e: UOP_AllocLarge 8454128
+CHECK-NEXT: 0x07: UOP_AllocLarge 8190
+CHECK-NEXT: 0x00: UOP_PushMachFrame w/o error code
diff --git a/tools/llvm-objdump/COFFDump.cpp b/tools/llvm-objdump/COFFDump.cpp
index bca6fc9..968e20c 100644
--- a/tools/llvm-objdump/COFFDump.cpp
+++ b/tools/llvm-objdump/COFFDump.cpp
@@ -227,6 +227,48 @@ static void printCOFFSymbolAddress(llvm::raw_ostream &Out,
Out << format(" + 0x%04x", Disp);
}
+// 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) {
+ outs() << "The Import Tables:\n";
+ error_code ec;
+ for (import_directory_iterator i = Obj->getImportDirectoryBegin(),
+ e = Obj->getImportDirectoryEnd();
+ i != e; i = i.increment(ec)) {
+ if (ec)
+ return;
+
+ const import_directory_table_entry *Dir;
+ StringRef Name;
+ if (i->getImportTableEntry(Dir)) return;
+ if (i->getName(Name)) return;
+
+ outs() << format(" lookup %08x", Dir->ImportLookupTableRVA);
+ outs() << format(" time %08x", Dir->TimeDateStamp);
+ outs() << format(" fwd %08x", Dir->ForwarderChain);
+ outs() << format(" name %08x", Dir->NameRVA);
+ outs() << format(" addr %08x\n\n", Dir->ImportAddressTableRVA);
+
+ outs() << " DLL Name: " << Name << "\n";
+ outs() << " Hint/Ord Name\n";
+ const COFF::ImportLookupTableEntry32 *entry;
+ if (i->getImportLookupEntry(entry))
+ return;
+ for (; entry->data; ++entry) {
+ if (entry->isOrdinal()) {
+ outs() << format(" % 6d\n", entry->getOrdinal());
+ continue;
+ }
+ uint16_t Hint;
+ StringRef Name;
+ if (Obj->getHintName(entry->getHintNameRVA(), Hint, Name))
+ return;
+ outs() << format(" % 6d %s\n", Hint, Name);
+ }
+ outs() << "\n";
+ }
+}
+
void llvm::printCOFFUnwindInfo(const COFFObjectFile *Obj) {
const coff_file_header *Header;
if (error(Obj->getCOFFHeader(Header))) return;
@@ -353,3 +395,7 @@ void llvm::printCOFFUnwindInfo(const COFFObjectFile *Obj) {
}
}
}
+
+void llvm::printCOFFFileHeader(const object::ObjectFile *Obj) {
+ printImportTables(dyn_cast<const COFFObjectFile>(Obj));
+}
diff --git a/tools/llvm-objdump/llvm-objdump.cpp b/tools/llvm-objdump/llvm-objdump.cpp
index 8065787..9bc092e 100644
--- a/tools/llvm-objdump/llvm-objdump.cpp
+++ b/tools/llvm-objdump/llvm-objdump.cpp
@@ -770,6 +770,14 @@ static void PrintUnwindInfo(const ObjectFile *o) {
}
}
+static void printPrivateFileHeader(const ObjectFile *o) {
+ if (o->isELF()) {
+ printELFFileHeader(o);
+ } else if (o->isCOFF()) {
+ printCOFFFileHeader(o);
+ }
+}
+
static void DumpObject(const ObjectFile *o) {
outs() << '\n';
outs() << o->getFileName()
@@ -787,8 +795,8 @@ static void DumpObject(const ObjectFile *o) {
PrintSymbolTable(o);
if (UnwindInfo)
PrintUnwindInfo(o);
- if (PrivateHeaders && o->isELF())
- printELFFileHeader(o);
+ if (PrivateHeaders)
+ printPrivateFileHeader(o);
}
/// @brief Dump each object file in \a a;
diff --git a/tools/llvm-objdump/llvm-objdump.h b/tools/llvm-objdump/llvm-objdump.h
index 87f19ba..b716a26 100644
--- a/tools/llvm-objdump/llvm-objdump.h
+++ b/tools/llvm-objdump/llvm-objdump.h
@@ -34,7 +34,8 @@ void DumpBytes(StringRef bytes);
void DisassembleInputMachO(StringRef Filename);
void printCOFFUnwindInfo(const object::COFFObjectFile* o);
void printELFFileHeader(const object::ObjectFile *o);
+void printCOFFFileHeader(const object::ObjectFile *o);
-}
+} // end namespace llvm
#endif