diff --git a/include/llvm/Object/COFF.h b/include/llvm/Object/COFF.h index d7beac307a4..f7a578315c1 100644 --- a/include/llvm/Object/COFF.h +++ b/include/llvm/Object/COFF.h @@ -651,6 +651,8 @@ public: bool operator==(const ImportDirectoryEntryRef &Other) const; void moveNext(); std::error_code getName(StringRef &Result) const; + std::error_code getImportLookupTableRVA(uint32_t &Result) const; + std::error_code getImportAddressTableRVA(uint32_t &Result) const; std::error_code getImportTableEntry(const import_directory_table_entry *&Result) const; diff --git a/lib/Object/COFFObjectFile.cpp b/lib/Object/COFFObjectFile.cpp index 45de4341b3f..d77238c6add 100644 --- a/lib/Object/COFFObjectFile.cpp +++ b/lib/Object/COFFObjectFile.cpp @@ -491,8 +491,9 @@ std::error_code COFFObjectFile::initImportTablePtr() { return object_error::success; uint32_t ImportTableRva = DataEntry->RelativeVirtualAddress; + // -1 because the last entry is the null entry. NumberOfImportDirectory = DataEntry->Size / - sizeof(import_directory_table_entry); + sizeof(import_directory_table_entry) - 1; // 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. @@ -1029,24 +1030,36 @@ void ImportDirectoryEntryRef::moveNext() { std::error_code ImportDirectoryEntryRef::getImportTableEntry( const import_directory_table_entry *&Result) const { - Result = ImportTable; + Result = ImportTable + Index; return object_error::success; } std::error_code ImportDirectoryEntryRef::getName(StringRef &Result) const { uintptr_t IntPtr = 0; if (std::error_code EC = - OwningObject->getRvaPtr(ImportTable->NameRVA, IntPtr)) + OwningObject->getRvaPtr(ImportTable[Index].NameRVA, IntPtr)) return EC; Result = StringRef(reinterpret_cast(IntPtr)); return object_error::success; } +std::error_code +ImportDirectoryEntryRef::getImportLookupTableRVA(uint32_t &Result) const { + Result = ImportTable[Index].ImportLookupTableRVA; + return object_error::success; +} + +std::error_code +ImportDirectoryEntryRef::getImportAddressTableRVA(uint32_t &Result) const { + Result = ImportTable[Index].ImportAddressTableRVA; + return object_error::success; +} + std::error_code ImportDirectoryEntryRef::getImportLookupEntry( const import_lookup_table_entry32 *&Result) const { uintptr_t IntPtr = 0; - if (std::error_code EC = - OwningObject->getRvaPtr(ImportTable->ImportLookupTableRVA, IntPtr)) + uint32_t RVA = ImportTable[Index].ImportLookupTableRVA; + if (std::error_code EC = OwningObject->getRvaPtr(RVA, IntPtr)) return EC; Result = reinterpret_cast(IntPtr); return object_error::success; diff --git a/test/tools/llvm-readobj/Inputs/imports.exe.coff-i386 b/test/tools/llvm-readobj/Inputs/imports.exe.coff-i386 new file mode 100644 index 00000000000..a42be04ddd2 Binary files /dev/null and b/test/tools/llvm-readobj/Inputs/imports.exe.coff-i386 differ diff --git a/test/tools/llvm-readobj/Inputs/imports.exe.coff-x86-64 b/test/tools/llvm-readobj/Inputs/imports.exe.coff-x86-64 new file mode 100644 index 00000000000..e2abfd8954b Binary files /dev/null and b/test/tools/llvm-readobj/Inputs/imports.exe.coff-x86-64 differ diff --git a/test/tools/llvm-readobj/imports.test b/test/tools/llvm-readobj/imports.test new file mode 100644 index 00000000000..62f0d1457c4 --- /dev/null +++ b/test/tools/llvm-readobj/imports.test @@ -0,0 +1,24 @@ +RUN: llvm-readobj --coff-imports %p/Inputs/imports.exe.coff-i386 | FileCheck -check-prefix=X86 %s +RUN: llvm-readobj --coff-imports %p/Inputs/imports.exe.coff-x86-64 | FileCheck -check-prefix=X64 %s + +X86: Import { +X86-NEXT: Name: KERNEL32.dll +X86-NEXT: ImportLookupTableRVA: 0x204C +X86-NEXT: ImportAddressTableRVA: 0x2000 +X86-NEXT: } +X86-NEXT: Import { +X86-NEXT: Name: USER32.dll +X86-NEXT: ImportLookupTableRVA: 0x2054 +X86-NEXT: ImportAddressTableRVA: 0x2008 +X86-NEXT: } + +X64: Import { +X64-NEXT: Name: KERNEL32.dll +X64-NEXT: ImportLookupTableRVA: 0x2060 +X64-NEXT: ImportAddressTableRVA: 0x2000 +X64-NEXT: } +X64-NEXT: Import { +X64-NEXT: Name: USER32.dll +X64-NEXT: ImportLookupTableRVA: 0x2070 +X64-NEXT: ImportAddressTableRVA: 0x2010 +X64-NEXT: } diff --git a/tools/llvm-readobj/COFFDumper.cpp b/tools/llvm-readobj/COFFDumper.cpp index 3d71d832f99..a3692af41fe 100644 --- a/tools/llvm-readobj/COFFDumper.cpp +++ b/tools/llvm-readobj/COFFDumper.cpp @@ -55,6 +55,7 @@ public: void printSymbols() override; void printDynamicSymbols() override; void printUnwindInfo() override; + void printCOFFImports() override; private: void printSymbol(const SymbolRef &Sym); @@ -882,3 +883,17 @@ void COFFDumper::printUnwindInfo() { } } +void COFFDumper::printCOFFImports() { + for (auto I = Obj->import_directory_begin(), E = Obj->import_directory_end(); + I != E; ++I) { + DictScope Import(W, "Import"); + StringRef Name; + if (error(I->getName(Name))) return; + W.printString("Name", Name); + uint32_t Addr; + if (error(I->getImportLookupTableRVA(Addr))) return; + W.printHex("ImportLookupTableRVA", Addr); + if (error(I->getImportAddressTableRVA(Addr))) return; + W.printHex("ImportAddressTableRVA", Addr); + } +} diff --git a/tools/llvm-readobj/ObjDumper.h b/tools/llvm-readobj/ObjDumper.h index 7adf76a6946..8f0c171233e 100644 --- a/tools/llvm-readobj/ObjDumper.h +++ b/tools/llvm-readobj/ObjDumper.h @@ -43,6 +43,9 @@ public: // Only implemented for MIPS ELF at this time. virtual void printMipsPLTGOT() { } + // Only implemented for PE/COFF. + virtual void printCOFFImports() { } + protected: StreamWriter& W; }; diff --git a/tools/llvm-readobj/llvm-readobj.cpp b/tools/llvm-readobj/llvm-readobj.cpp index a20164a3c23..31a011d2b9e 100644 --- a/tools/llvm-readobj/llvm-readobj.cpp +++ b/tools/llvm-readobj/llvm-readobj.cpp @@ -141,6 +141,10 @@ namespace opts { cl::opt MipsPLTGOT("mips-plt-got", cl::desc("Display the MIPS GOT and PLT GOT sections")); + + // -coff-imports + cl::opt + COFFImports("coff-imports", cl::desc("Display the PE/COFF import table")); } // namespace opts static int ReturnValue = EXIT_SUCCESS; @@ -266,6 +270,8 @@ static void dumpObject(const ObjectFile *Obj) { if (isMipsArch(Obj->getArch()) && Obj->isELF()) if (opts::MipsPLTGOT) Dumper->printMipsPLTGOT(); + if (opts::COFFImports) + Dumper->printCOFFImports(); }