diff --git a/include/llvm/Object/COFF.h b/include/llvm/Object/COFF.h index 8dc4d52bb5d..c7fe2926bfa 100644 --- a/include/llvm/Object/COFF.h +++ b/include/llvm/Object/COFF.h @@ -25,9 +25,12 @@ template class ArrayRef; namespace object { class ImportDirectoryEntryRef; +class DelayImportDirectoryEntryRef; class ExportDirectoryEntryRef; class ImportedSymbolRef; typedef content_iterator import_directory_iterator; +typedef content_iterator + delay_import_directory_iterator; typedef content_iterator export_directory_iterator; typedef content_iterator imported_symbol_iterator; @@ -184,6 +187,18 @@ typedef import_lookup_table_entry typedef import_lookup_table_entry import_lookup_table_entry64; +struct delay_import_directory_table_entry { + // dumpbin reports this field as "Characteristics" instead of "Attributes". + support::ulittle32_t Attributes; + support::ulittle32_t Name; + support::ulittle32_t ModuleHandle; + support::ulittle32_t DelayImportAddressTable; + support::ulittle32_t DelayImportNameTable; + support::ulittle32_t BoundDelayImportTable; + support::ulittle32_t UnloadDelayImportTable; + support::ulittle32_t TimeStamp; +}; + struct export_directory_table_entry { support::ulittle32_t ExportFlags; support::ulittle32_t TimeDateStamp; @@ -440,6 +455,8 @@ private: uint32_t StringTableSize; const import_directory_table_entry *ImportDirectory; uint32_t NumberOfImportDirectory; + const delay_import_directory_table_entry *DelayImportDirectory; + uint32_t NumberOfDelayImportDirectory; const export_directory_table_entry *ExportDirectory; std::error_code getString(uint32_t offset, StringRef &Res) const; @@ -451,6 +468,7 @@ private: std::error_code initSymbolTablePtr(); std::error_code initImportTablePtr(); + std::error_code initDelayImportTablePtr(); std::error_code initExportTablePtr(); public: @@ -582,6 +600,8 @@ public: import_directory_iterator import_directory_begin() const; import_directory_iterator import_directory_end() const; + delay_import_directory_iterator delay_import_directory_begin() const; + delay_import_directory_iterator delay_import_directory_end() const; export_directory_iterator export_directory_begin() const; export_directory_iterator export_directory_end() const; @@ -678,6 +698,27 @@ private: const COFFObjectFile *OwningObject; }; +class DelayImportDirectoryEntryRef { +public: + DelayImportDirectoryEntryRef() : OwningObject(nullptr) {} + DelayImportDirectoryEntryRef(const delay_import_directory_table_entry *T, + uint32_t I, const COFFObjectFile *Owner) + : Table(T), Index(I), OwningObject(Owner) {} + + bool operator==(const DelayImportDirectoryEntryRef &Other) const; + void moveNext(); + + imported_symbol_iterator imported_symbol_begin() const; + imported_symbol_iterator imported_symbol_end() const; + + std::error_code getName(StringRef &Result) const; + +private: + const delay_import_directory_table_entry *Table; + uint32_t Index; + const COFFObjectFile *OwningObject; +}; + // The iterator for the export directory table entry. class ExportDirectoryEntryRef { public: diff --git a/lib/Object/COFFObjectFile.cpp b/lib/Object/COFFObjectFile.cpp index f533d5e21e6..e4ff074945d 100644 --- a/lib/Object/COFFObjectFile.cpp +++ b/lib/Object/COFFObjectFile.cpp @@ -506,6 +506,26 @@ std::error_code COFFObjectFile::initImportTablePtr() { return object_error::success; } +// Initializes DelayImportDirectory and NumberOfDelayImportDirectory. +std::error_code COFFObjectFile::initDelayImportTablePtr() { + const data_directory *DataEntry; + if (getDataDirectory(COFF::DELAY_IMPORT_DESCRIPTOR, DataEntry)) + return object_error::success; + if (DataEntry->RelativeVirtualAddress == 0) + return object_error::success; + + uint32_t RVA = DataEntry->RelativeVirtualAddress; + NumberOfDelayImportDirectory = DataEntry->Size / + sizeof(delay_import_directory_table_entry) - 1; + + uintptr_t IntPtr = 0; + if (std::error_code EC = getRvaPtr(RVA, IntPtr)) + return EC; + DelayImportDirectory = reinterpret_cast< + const delay_import_directory_table_entry *>(IntPtr); + return object_error::success; +} + // Find the export table. std::error_code COFFObjectFile::initExportTablePtr() { // First, we get the RVA of the export table. If the file lacks a pointer to @@ -533,6 +553,7 @@ COFFObjectFile::COFFObjectFile(MemoryBufferRef Object, std::error_code &EC) DataDirectory(nullptr), SectionTable(nullptr), SymbolTable16(nullptr), SymbolTable32(nullptr), StringTable(nullptr), StringTableSize(0), ImportDirectory(nullptr), NumberOfImportDirectory(0), + DelayImportDirectory(nullptr), NumberOfDelayImportDirectory(0), ExportDirectory(nullptr) { // Check that we at least have enough room for a header. if (!checkSize(Data, EC, sizeof(coff_file_header))) @@ -631,6 +652,8 @@ COFFObjectFile::COFFObjectFile(MemoryBufferRef Object, std::error_code &EC) // Initialize the pointer to the beginning of the import table. if ((EC = initImportTablePtr())) return; + if ((EC = initDelayImportTablePtr())) + return; // Initialize the pointer to the export table. if ((EC = initExportTablePtr())) @@ -662,6 +685,19 @@ import_directory_iterator COFFObjectFile::import_directory_end() const { ImportDirectoryEntryRef(ImportDirectory, NumberOfImportDirectory, this)); } +delay_import_directory_iterator +COFFObjectFile::delay_import_directory_begin() const { + return delay_import_directory_iterator( + DelayImportDirectoryEntryRef(DelayImportDirectory, 0, this)); +} + +delay_import_directory_iterator +COFFObjectFile::delay_import_directory_end() const { + return delay_import_directory_iterator( + DelayImportDirectoryEntryRef( + DelayImportDirectory, NumberOfDelayImportDirectory, this)); +} + export_directory_iterator COFFObjectFile::export_directory_begin() const { return export_directory_iterator( ExportDirectoryEntryRef(ExportDirectory, 0, this)); @@ -1036,30 +1072,30 @@ std::error_code ImportDirectoryEntryRef::getImportTableEntry( } static imported_symbol_iterator -makeImportedSymbolIterator(const COFFObjectFile *OwningObject, +makeImportedSymbolIterator(const COFFObjectFile *Object, uintptr_t Ptr, int Index) { - if (OwningObject->getBytesInAddress() == 4) { + if (Object->getBytesInAddress() == 4) { auto *P = reinterpret_cast(Ptr); - return imported_symbol_iterator(ImportedSymbolRef(P, Index, OwningObject)); + return imported_symbol_iterator(ImportedSymbolRef(P, Index, Object)); } auto *P = reinterpret_cast(Ptr); - return imported_symbol_iterator(ImportedSymbolRef(P, Index, OwningObject)); + return imported_symbol_iterator(ImportedSymbolRef(P, Index, Object)); } -imported_symbol_iterator -ImportDirectoryEntryRef::imported_symbol_begin() const { +static imported_symbol_iterator +importedSymbolBegin(uint32_t RVA, const COFFObjectFile *Object) { uintptr_t IntPtr = 0; - OwningObject->getRvaPtr(ImportTable[Index].ImportLookupTableRVA, IntPtr); - return makeImportedSymbolIterator(OwningObject, IntPtr, 0); + Object->getRvaPtr(RVA, IntPtr); + return makeImportedSymbolIterator(Object, IntPtr, 0); } -imported_symbol_iterator -ImportDirectoryEntryRef::imported_symbol_end() const { +static imported_symbol_iterator +importedSymbolEnd(uint32_t RVA, const COFFObjectFile *Object) { uintptr_t IntPtr = 0; - OwningObject->getRvaPtr(ImportTable[Index].ImportLookupTableRVA, IntPtr); + Object->getRvaPtr(RVA, IntPtr); // Forward the pointer to the last entry which is null. int Index = 0; - if (OwningObject->getBytesInAddress() == 4) { + if (Object->getBytesInAddress() == 4) { auto *Entry = reinterpret_cast(IntPtr); while (*Entry++) ++Index; @@ -1068,7 +1104,19 @@ ImportDirectoryEntryRef::imported_symbol_end() const { while (*Entry++) ++Index; } - return makeImportedSymbolIterator(OwningObject, IntPtr, Index); + return makeImportedSymbolIterator(Object, IntPtr, Index); +} + +imported_symbol_iterator +ImportDirectoryEntryRef::imported_symbol_begin() const { + return importedSymbolBegin(ImportTable[Index].ImportLookupTableRVA, + OwningObject); +} + +imported_symbol_iterator +ImportDirectoryEntryRef::imported_symbol_end() const { + return importedSymbolEnd(ImportTable[Index].ImportLookupTableRVA, + OwningObject); } std::error_code ImportDirectoryEntryRef::getName(StringRef &Result) const { @@ -1102,6 +1150,35 @@ std::error_code ImportDirectoryEntryRef::getImportLookupEntry( return object_error::success; } +bool DelayImportDirectoryEntryRef:: +operator==(const DelayImportDirectoryEntryRef &Other) const { + return Table == Other.Table && Index == Other.Index; +} + +void DelayImportDirectoryEntryRef::moveNext() { + ++Index; +} + +imported_symbol_iterator +DelayImportDirectoryEntryRef::imported_symbol_begin() const { + return importedSymbolBegin(Table[Index].DelayImportNameTable, + OwningObject); +} + +imported_symbol_iterator +DelayImportDirectoryEntryRef::imported_symbol_end() const { + return importedSymbolEnd(Table[Index].DelayImportNameTable, + OwningObject); +} + +std::error_code DelayImportDirectoryEntryRef::getName(StringRef &Result) const { + uintptr_t IntPtr = 0; + if (std::error_code EC = OwningObject->getRvaPtr(Table[Index].Name, IntPtr)) + return EC; + Result = StringRef(reinterpret_cast(IntPtr)); + return object_error::success; +} + bool ExportDirectoryEntryRef:: operator==(const ExportDirectoryEntryRef &Other) const { return ExportTable == Other.ExportTable && Index == Other.Index; diff --git a/test/tools/llvm-readobj/Inputs/imports.exe.coff-i386 b/test/tools/llvm-readobj/Inputs/imports.exe.coff-i386 index 7f38438d0e5..72077adaebe 100644 Binary files a/test/tools/llvm-readobj/Inputs/imports.exe.coff-i386 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 index 9ab582486ad..5ee198e4a2e 100644 Binary files a/test/tools/llvm-readobj/Inputs/imports.exe.coff-x86-64 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 index faa9cd26436..531fb32561a 100644 --- a/test/tools/llvm-readobj/imports.test +++ b/test/tools/llvm-readobj/imports.test @@ -3,42 +3,62 @@ RUN: llvm-readobj --coff-imports %p/Inputs/imports.exe.coff-x86-64 | FileCheck - X86: Import { X86-NEXT: Name: KERNEL32.dll -X86-NEXT: ImportLookupTableRVA: 0x2070 +X86-NEXT: ImportLookupTableRVA: 0x2108 X86-NEXT: ImportAddressTableRVA: 0x2000 X86-NEXT: Symbol: ExitProcess (337) +X86-NEXT: Symbol: GetProcAddress (669) +X86-NEXT: Symbol: FreeLibrary (414) +X86-NEXT: Symbol: GetLastError (592) +X86-NEXT: Symbol: RaiseException (1087) +X86-NEXT: Symbol: LoadLibraryExA (934) X86-NEXT: } X86-NEXT: Import { X86-NEXT: Name: USER32.dll -X86-NEXT: ImportLookupTableRVA: 0x2078 -X86-NEXT: ImportAddressTableRVA: 0x2008 +X86-NEXT: ImportLookupTableRVA: 0x2124 +X86-NEXT: ImportAddressTableRVA: 0x201C X86-NEXT: Symbol: MessageBoxA (582) X86-NEXT: } X86-NEXT: Import { X86-NEXT: Name: mydll.dll -X86-NEXT: ImportLookupTableRVA: 0x2080 -X86-NEXT: ImportAddressTableRVA: 0x2010 +X86-NEXT: ImportLookupTableRVA: 0x212C +X86-NEXT: ImportAddressTableRVA: 0x2024 +X86-NEXT: Symbol: Func1 (0) X86-NEXT: Symbol: Func2 (1) X86-NEXT: Symbol: (3) -X86-NEXT: Symbol: Func1 (0) +X86-NEXT: } +X86-NEXT: DelayImport { +X86-NEXT: Name: lazyload.dll +X86-NEXT: Symbol: Func5 (0) +X86-NEXT: Symbol: Func4 (0) X86-NEXT: } X64: Import { X64-NEXT: Name: KERNEL32.dll -X64-NEXT: ImportLookupTableRVA: 0x2090 +X64-NEXT: ImportLookupTableRVA: 0x2170 X64-NEXT: ImportAddressTableRVA: 0x2000 X64-NEXT: Symbol: ExitProcess (343) +X64-NEXT: Symbol: GetProcAddress (676) +X64-NEXT: Symbol: FreeLibrary (420) +X64-NEXT: Symbol: GetLastError (598) +X64-NEXT: Symbol: RaiseException (1091) +X64-NEXT: Symbol: LoadLibraryExA (937) X64-NEXT: } X64-NEXT: Import { X64-NEXT: Name: USER32.dll -X64-NEXT: ImportLookupTableRVA: 0x20A0 -X64-NEXT: ImportAddressTableRVA: 0x2010 +X64-NEXT: ImportLookupTableRVA: 0x21A8 +X64-NEXT: ImportAddressTableRVA: 0x2038 X64-NEXT: Symbol: MessageBoxA (586) X64-NEXT: } X64-NEXT: Import { X64-NEXT: Name: mydll.dll -X64-NEXT: ImportLookupTableRVA: 0x20B0 -X64-NEXT: ImportAddressTableRVA: 0x2020 +X64-NEXT: ImportLookupTableRVA: 0x21B8 +X64-NEXT: ImportAddressTableRVA: 0x2048 +X64-NEXT: Symbol: Func1 (0) X64-NEXT: Symbol: Func2 (1) X64-NEXT: Symbol: (3) -X64-NEXT: Symbol: Func1 (0) +X64-NEXT: } +X64-NEXT: DelayImport { +X64-NEXT: Name: lazyload.dll +X64-NEXT: Symbol: Func5 (0) +X64-NEXT: Symbol: Func4 (0) X64-NEXT: } diff --git a/tools/llvm-readobj/COFFDumper.cpp b/tools/llvm-readobj/COFFDumper.cpp index 3653afaec66..1697a55b718 100644 --- a/tools/llvm-readobj/COFFDumper.cpp +++ b/tools/llvm-readobj/COFFDumper.cpp @@ -75,6 +75,9 @@ private: std::error_code resolveSymbolName(const coff_section *Section, uint64_t Offset, StringRef &Name); + void printImportedSymbols(imported_symbol_iterator I, + imported_symbol_iterator E); + typedef DenseMap > RelocMapTy; const llvm::object::COFFObjectFile *Obj; @@ -883,7 +886,19 @@ void COFFDumper::printUnwindInfo() { } } +void COFFDumper::printImportedSymbols(imported_symbol_iterator I, + imported_symbol_iterator E) { + for (; I != E; ++I) { + StringRef Sym; + if (error(I->getSymbolName(Sym))) return; + uint16_t Ordinal; + if (error(I->getOrdinal(Ordinal))) return; + W.printNumber("Symbol", Sym, Ordinal); + } +} + void COFFDumper::printCOFFImports() { + // Regular imports for (auto I = Obj->import_directory_begin(), E = Obj->import_directory_end(); I != E; ++I) { DictScope Import(W, "Import"); @@ -895,13 +910,17 @@ void COFFDumper::printCOFFImports() { W.printHex("ImportLookupTableRVA", Addr); if (error(I->getImportAddressTableRVA(Addr))) return; W.printHex("ImportAddressTableRVA", Addr); - for (auto J = I->imported_symbol_begin(), F = I->imported_symbol_end(); - J != F; ++J) { - StringRef Sym; - if (error(J->getSymbolName(Sym))) return; - uint16_t Ordinal; - if (error(J->getOrdinal(Ordinal))) return; - W.printNumber("Symbol", Sym, Ordinal); - } + printImportedSymbols(I->imported_symbol_begin(), I->imported_symbol_end()); + } + + // Delay imports + for (auto I = Obj->delay_import_directory_begin(), + E = Obj->delay_import_directory_end(); + I != E; ++I) { + DictScope Import(W, "DelayImport"); + StringRef Name; + if (error(I->getName(Name))) return; + W.printString("Name", Name); + printImportedSymbols(I->imported_symbol_begin(), I->imported_symbol_end()); } }