[llvm] r199358 - llmv-objdump/COFF: Print export table contents.

Rui Ueyama ruiu at google.com
Wed Jan 15 23:05:50 PST 2014


Author: ruiu
Date: Thu Jan 16 01:05:49 2014
New Revision: 199358

URL: http://llvm.org/viewvc/llvm-project?rev=199358&view=rev
Log:
llmv-objdump/COFF: Print export table contents.

This patch adds the capability to dump export table contents. An example
output is this:

  Export Table:
   Ordinal      RVA  Name
         5   0x2008  exportfn1
         6   0x2010  exportfn2

By adding this feature to llvm-objdump, we will be able to use it to check
export table contents in LLD's tests. Currently we are doing binary
comparison in the tests, which is fragile and not readable to humans.

Added:
    llvm/trunk/test/tools/llvm-objdump/Inputs/export.dll.coff-i386
Modified:
    llvm/trunk/include/llvm/Object/COFF.h
    llvm/trunk/lib/Object/COFFObjectFile.cpp
    llvm/trunk/test/tools/llvm-objdump/coff-private-headers.test
    llvm/trunk/tools/llvm-objdump/COFFDump.cpp

Modified: llvm/trunk/include/llvm/Object/COFF.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Object/COFF.h?rev=199358&r1=199357&r2=199358&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Object/COFF.h (original)
+++ llvm/trunk/include/llvm/Object/COFF.h Thu Jan 16 01:05:49 2014
@@ -24,7 +24,9 @@ namespace llvm {
 
 namespace object {
 class ImportDirectoryEntryRef;
+class ExportDirectoryEntryRef;
 typedef content_iterator<ImportDirectoryEntryRef> import_directory_iterator;
+typedef content_iterator<ExportDirectoryEntryRef> export_directory_iterator;
 
 /// The DOS compatible header at the front of all PE/COFF executables.
 struct dos_header {
@@ -245,6 +247,7 @@ struct coff_aux_section_definition {
 class COFFObjectFile : public ObjectFile {
 private:
   friend class ImportDirectoryEntryRef;
+  friend class ExportDirectoryEntryRef;
   const coff_file_header *COFFHeader;
   const pe32_header      *PE32Header;
   const data_directory   *DataDirectory;
@@ -254,6 +257,7 @@ private:
         uint32_t          StringTableSize;
   const import_directory_table_entry *ImportDirectory;
         uint32_t          NumberOfImportDirectory;
+  const export_directory_table_entry *ExportDirectory;
 
         error_code        getString(uint32_t offset, StringRef &Res) const;
 
@@ -263,6 +267,7 @@ private:
 
         error_code        initSymbolTablePtr();
         error_code        initImportTablePtr();
+        error_code        initExportTablePtr();
 
 protected:
   virtual error_code getSymbolNext(DataRefImpl Symb, SymbolRef &Res) const;
@@ -336,6 +341,8 @@ public:
 
   import_directory_iterator import_directory_begin() const;
   import_directory_iterator import_directory_end() const;
+  export_directory_iterator export_directory_begin() const;
+  export_directory_iterator export_directory_end() const;
 
   error_code getHeader(const coff_file_header *&Res) const;
   error_code getCOFFHeader(const coff_file_header *&Res) const;
@@ -388,6 +395,26 @@ private:
   uint32_t Index;
   const COFFObjectFile *OwningObject;
 };
+
+// The iterator for the export directory table entry.
+class ExportDirectoryEntryRef {
+public:
+  ExportDirectoryEntryRef() : OwningObject(0) {}
+  ExportDirectoryEntryRef(const export_directory_table_entry *Table, uint32_t I,
+                          const COFFObjectFile *Owner)
+      : ExportTable(Table), Index(I), OwningObject(Owner) {}
+
+  bool operator==(const ExportDirectoryEntryRef &Other) const;
+  error_code getNext(ExportDirectoryEntryRef &Result) const;
+  error_code getOrdinal(uint32_t &Result) const;
+  error_code getExportRVA(uint32_t &Result) const;
+  error_code getName(StringRef &Result) const;
+
+private:
+  const export_directory_table_entry *ExportTable;
+  uint32_t Index;
+  const COFFObjectFile *OwningObject;
+};
 } // end namespace object
 } // end namespace llvm
 

Modified: llvm/trunk/lib/Object/COFFObjectFile.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Object/COFFObjectFile.cpp?rev=199358&r1=199357&r2=199358&view=diff
==============================================================================
--- llvm/trunk/lib/Object/COFFObjectFile.cpp (original)
+++ llvm/trunk/lib/Object/COFFObjectFile.cpp Thu Jan 16 01:05:49 2014
@@ -445,9 +445,27 @@ error_code COFFObjectFile::initImportTab
     return ec;
   ImportDirectory = reinterpret_cast<
       const import_directory_table_entry *>(IntPtr);
+  return object_error::success;
+}
+
+// Find the export table.
+error_code COFFObjectFile::initExportTablePtr() {
+  // First, we get the RVA of the export table. If the file lacks a pointer to
+  // the export table, do nothing.
+  const data_directory *DataEntry;
+  if (getDataDirectory(COFF::EXPORT_TABLE, DataEntry))
+    return object_error::success;
+
+  // Do nothing if the pointer to export table is NULL.
+  if (DataEntry->RelativeVirtualAddress == 0)
+    return object_error::success;
 
-  // It's an error if there's no section containing the Import Table RVA.
-  return object_error::parse_failed;
+  uint32_t ExportTableRva = DataEntry->RelativeVirtualAddress;
+  uintptr_t IntPtr = 0;
+  if (error_code EC = getRvaPtr(ExportTableRva, IntPtr))
+    return EC;
+  ExportDirectory = reinterpret_cast<const export_directory_table_entry *>(IntPtr);
+  return object_error::success;
 }
 
 COFFObjectFile::COFFObjectFile(MemoryBuffer *Object, error_code &ec)
@@ -460,7 +478,8 @@ COFFObjectFile::COFFObjectFile(MemoryBuf
   , StringTable(0)
   , StringTableSize(0)
   , ImportDirectory(0)
-  , NumberOfImportDirectory(0) {
+  , NumberOfImportDirectory(0)
+  , ExportDirectory(0) {
   // Check that we at least have enough room for a header.
   if (!checkSize(Data, ec, sizeof(coff_file_header))) return;
 
@@ -521,6 +540,10 @@ COFFObjectFile::COFFObjectFile(MemoryBuf
   if ((ec = initImportTablePtr()))
     return;
 
+  // Initialize the pointer to the export table.
+  if ((ec = initExportTablePtr()))
+    return;
+
   ec = object_error::success;
 }
 
@@ -572,6 +595,19 @@ import_directory_iterator COFFObjectFile
       ImportDirectoryEntryRef(ImportDirectory, NumberOfImportDirectory, this));
 }
 
+export_directory_iterator COFFObjectFile::export_directory_begin() const {
+  return export_directory_iterator(
+      ExportDirectoryEntryRef(ExportDirectory, 0, this));
+}
+
+export_directory_iterator COFFObjectFile::export_directory_end() const {
+  if (ExportDirectory == 0)
+    return export_directory_iterator(ExportDirectoryEntryRef(0, 0, this));
+  ExportDirectoryEntryRef ref(ExportDirectory,
+                              ExportDirectory->AddressTableEntries, this);
+  return export_directory_iterator(ref);
+}
+
 section_iterator COFFObjectFile::begin_sections() const {
   DataRefImpl ret;
   ret.p = reinterpret_cast<uintptr_t>(SectionTable);
@@ -910,6 +946,62 @@ error_code ImportDirectoryEntryRef::getI
   return object_error::success;
 }
 
+bool ExportDirectoryEntryRef::
+operator==(const ExportDirectoryEntryRef &Other) const {
+  return ExportTable == Other.ExportTable && Index == Other.Index;
+}
+
+error_code
+ExportDirectoryEntryRef::getNext(ExportDirectoryEntryRef &Result) const {
+  Result = ExportDirectoryEntryRef(ExportTable, Index + 1, OwningObject);
+  return object_error::success;
+}
+
+// Returns the export ordinal of the current export symbol.
+error_code ExportDirectoryEntryRef::getOrdinal(uint32_t &Result) const {
+  Result = ExportTable->OrdinalBase + Index;
+  return object_error::success;
+}
+
+// Returns the address of the current export symbol.
+error_code ExportDirectoryEntryRef::getExportRVA(uint32_t &Result) const {
+  uintptr_t IntPtr = 0;
+  if (error_code EC = OwningObject->getRvaPtr(
+          ExportTable->ExportAddressTableRVA, IntPtr))
+    return EC;
+  const export_address_table_entry *entry = reinterpret_cast<const export_address_table_entry *>(IntPtr);
+  Result = entry[Index].ExportRVA;
+  return object_error::success;
+}
+
+// Returns the name of the current export symbol. If the symbol is exported only
+// by ordinal, the empty string is set as a result.
+error_code ExportDirectoryEntryRef::getName(StringRef &Result) const {
+  uintptr_t IntPtr = 0;
+  if (error_code EC = OwningObject->getRvaPtr(
+          ExportTable->OrdinalTableRVA, IntPtr))
+    return EC;
+  const ulittle16_t *Start = reinterpret_cast<const ulittle16_t *>(IntPtr);
+
+  uint32_t NumEntries = ExportTable->NumberOfNamePointers;
+  int Offset = 0;
+  for (const ulittle16_t *I = Start, *E = Start + NumEntries;
+       I < E; ++I, ++Offset) {
+    if (*I != Index)
+      continue;
+    if (error_code EC = OwningObject->getRvaPtr(
+            ExportTable->NamePointerRVA, IntPtr))
+      return EC;
+    const ulittle32_t *NamePtr = reinterpret_cast<const ulittle32_t *>(IntPtr);
+    if (error_code EC = OwningObject->getRvaPtr(NamePtr[Offset], IntPtr))
+      return EC;
+    Result = StringRef(reinterpret_cast<const char *>(IntPtr));
+    return object_error::success;
+  }
+  Result = "";
+  return object_error::success;
+}
+
 namespace llvm {
 ObjectFile *ObjectFile::createCOFFObjectFile(MemoryBuffer *Object) {
   error_code ec;

Added: llvm/trunk/test/tools/llvm-objdump/Inputs/export.dll.coff-i386
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-objdump/Inputs/export.dll.coff-i386?rev=199358&view=auto
==============================================================================
Binary files llvm/trunk/test/tools/llvm-objdump/Inputs/export.dll.coff-i386 (added) and llvm/trunk/test/tools/llvm-objdump/Inputs/export.dll.coff-i386 Thu Jan 16 01:05:49 2014 differ

Modified: llvm/trunk/test/tools/llvm-objdump/coff-private-headers.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-objdump/coff-private-headers.test?rev=199358&r1=199357&r2=199358&view=diff
==============================================================================
--- llvm/trunk/test/tools/llvm-objdump/coff-private-headers.test (original)
+++ llvm/trunk/test/tools/llvm-objdump/coff-private-headers.test Thu Jan 16 01:05:49 2014
@@ -1,9 +1,16 @@
-// RUN: llvm-objdump -p %p/Inputs/nop.exe.coff-i386 | FileCheck %s
+// RUN: llvm-objdump -p %p/Inputs/nop.exe.coff-i386 | \
+// RUN:   FileCheck -check-prefix=IMPORT %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
+IMPORT:       The Import Tables:
+IMPORT-NEXT:  lookup 00005028 time 00000000 fwd 00000000 name 00005096 addr 00005058
+IMPORT:       DLL Name: KERNEL32.dll
+IMPORT-NEXT:     Hint/Ord  Name
+IMPORT-NEXT:          365  ExitProcess
 
+// RUN: llvm-objdump -p %p/Inputs/export.dll.coff-i386 | \
+// RUN:   FileCheck -check-prefix=EXPORT %s
 
+EXPORT:      Export Table:
+EXPORT-NEXT:  Ordinal      RVA  Name
+EXPORT-NEXT:        5   0x2008
+EXPORT-NEXT:        6   0x2010  exportfn2

Modified: llvm/trunk/tools/llvm-objdump/COFFDump.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-objdump/COFFDump.cpp?rev=199358&r1=199357&r2=199358&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-objdump/COFFDump.cpp (original)
+++ llvm/trunk/tools/llvm-objdump/COFFDump.cpp Thu Jan 16 01:05:49 2014
@@ -271,6 +271,36 @@ static void printImportTables(const COFF
   }
 }
 
+// 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;
+  outs() << " Ordinal      RVA  Name\n";
+  error_code EC;
+  for (; I != E; I = I.increment(EC)) {
+    if (EC)
+      return;
+    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 (I->getName(Name))
+      continue;
+    if (!Name.empty())
+      outs() << "  " << Name;
+    outs() << "\n";
+  }
+}
+
 void llvm::printCOFFUnwindInfo(const COFFObjectFile *Obj) {
   const coff_file_header *Header;
   if (error(Obj->getCOFFHeader(Header))) return;
@@ -399,5 +429,7 @@ void llvm::printCOFFUnwindInfo(const COF
 }
 
 void llvm::printCOFFFileHeader(const object::ObjectFile *Obj) {
-  printImportTables(dyn_cast<const COFFObjectFile>(Obj));
+  const COFFObjectFile *file = dyn_cast<const COFFObjectFile>(Obj);
+  printImportTables(file);
+  printExportTable(file);
 }





More information about the llvm-commits mailing list