llvm-readobj: print COFF delay-load import table
authorRui Ueyama <ruiu@google.com>
Fri, 3 Oct 2014 00:41:58 +0000 (00:41 +0000)
committerRui Ueyama <ruiu@google.com>
Fri, 3 Oct 2014 00:41:58 +0000 (00:41 +0000)
This patch adds another iterator to access the delay-load import table
and use it from llvm-readobj.

http://reviews.llvm.org/D5594

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@218933 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/Object/COFF.h
lib/Object/COFFObjectFile.cpp
test/tools/llvm-readobj/Inputs/imports.exe.coff-i386
test/tools/llvm-readobj/Inputs/imports.exe.coff-x86-64
test/tools/llvm-readobj/imports.test
tools/llvm-readobj/COFFDumper.cpp

index 8dc4d52bb5d7a01527bfa2b6d3ad36210d5e9350..c7fe2926bfa2a3fb945506d7250708ba98d2715e 100644 (file)
@@ -25,9 +25,12 @@ template <typename T> class ArrayRef;
 
 namespace object {
 class ImportDirectoryEntryRef;
+class DelayImportDirectoryEntryRef;
 class ExportDirectoryEntryRef;
 class ImportedSymbolRef;
 typedef content_iterator<ImportDirectoryEntryRef> import_directory_iterator;
+typedef content_iterator<DelayImportDirectoryEntryRef>
+    delay_import_directory_iterator;
 typedef content_iterator<ExportDirectoryEntryRef> export_directory_iterator;
 typedef content_iterator<ImportedSymbolRef> imported_symbol_iterator;
 
@@ -184,6 +187,18 @@ typedef import_lookup_table_entry<support::little32_t>
 typedef import_lookup_table_entry<support::little64_t>
     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:
index f533d5e21e64101b2a94bf4b49060b4bbf13b033..e4ff074945d3f163efbcec93d4f5e7e301905049 100644 (file)
@@ -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<const import_lookup_table_entry32 *>(Ptr);
-    return imported_symbol_iterator(ImportedSymbolRef(P, Index, OwningObject));
+    return imported_symbol_iterator(ImportedSymbolRef(P, Index, Object));
   }
   auto *P = reinterpret_cast<const import_lookup_table_entry64 *>(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<ulittle32_t *>(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<const char *>(IntPtr));
+  return object_error::success;
+}
+
 bool ExportDirectoryEntryRef::
 operator==(const ExportDirectoryEntryRef &Other) const {
   return ExportTable == Other.ExportTable && Index == Other.Index;
index 7f38438d0e5d020634b6f194a73a0eaa47c9a138..72077adaebefd57c1a2a61ef662bb2c8003e0a22 100644 (file)
Binary files a/test/tools/llvm-readobj/Inputs/imports.exe.coff-i386 and b/test/tools/llvm-readobj/Inputs/imports.exe.coff-i386 differ
index 9ab582486ad3a48076e4f1e6a1c9b454a5bda1a7..5ee198e4a2e2ee6a7adbfe00476ec14d676dc357 100644 (file)
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
index faa9cd26436f91f91f50f3f17ac5407a3b008738..531fb32561af483732af1e4662b754f1f2973456 100644 (file)
@@ -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: }
index 3653afaec665fa9e635d0d4e365ffec3a7370543..1697a55b718b06f5224c27359dc766853d87a350 100644 (file)
@@ -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<const coff_section*, std::vector<RelocationRef> > 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());
   }
 }