llvm.org GIT mirror llvm / fb432ac
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. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@199358 91177308-0d34-0410-b5e6-96231b3b80d8 Rui Ueyama 6 years ago
5 changed file(s) with 170 addition(s) and 12 deletion(s). Raw diff Collapse all Expand all
2323
2424 namespace object {
2525 class ImportDirectoryEntryRef;
26 class ExportDirectoryEntryRef;
2627 typedef content_iterator import_directory_iterator;
28 typedef content_iterator export_directory_iterator;
2729
2830 /// The DOS compatible header at the front of all PE/COFF executables.
2931 struct dos_header {
244246 class COFFObjectFile : public ObjectFile {
245247 private:
246248 friend class ImportDirectoryEntryRef;
249 friend class ExportDirectoryEntryRef;
247250 const coff_file_header *COFFHeader;
248251 const pe32_header *PE32Header;
249252 const data_directory *DataDirectory;
253256 uint32_t StringTableSize;
254257 const import_directory_table_entry *ImportDirectory;
255258 uint32_t NumberOfImportDirectory;
259 const export_directory_table_entry *ExportDirectory;
256260
257261 error_code getString(uint32_t offset, StringRef &Res) const;
258262
262266
263267 error_code initSymbolTablePtr();
264268 error_code initImportTablePtr();
269 error_code initExportTablePtr();
265270
266271 protected:
267272 virtual error_code getSymbolNext(DataRefImpl Symb, SymbolRef &Res) const;
335340
336341 import_directory_iterator import_directory_begin() const;
337342 import_directory_iterator import_directory_end() const;
343 export_directory_iterator export_directory_begin() const;
344 export_directory_iterator export_directory_end() const;
338345
339346 error_code getHeader(const coff_file_header *&Res) const;
340347 error_code getCOFFHeader(const coff_file_header *&Res) const;
387394 uint32_t Index;
388395 const COFFObjectFile *OwningObject;
389396 };
397
398 // The iterator for the export directory table entry.
399 class ExportDirectoryEntryRef {
400 public:
401 ExportDirectoryEntryRef() : OwningObject(0) {}
402 ExportDirectoryEntryRef(const export_directory_table_entry *Table, uint32_t I,
403 const COFFObjectFile *Owner)
404 : ExportTable(Table), Index(I), OwningObject(Owner) {}
405
406 bool operator==(const ExportDirectoryEntryRef &Other) const;
407 error_code getNext(ExportDirectoryEntryRef &Result) const;
408 error_code getOrdinal(uint32_t &Result) const;
409 error_code getExportRVA(uint32_t &Result) const;
410 error_code getName(StringRef &Result) const;
411
412 private:
413 const export_directory_table_entry *ExportTable;
414 uint32_t Index;
415 const COFFObjectFile *OwningObject;
416 };
390417 } // end namespace object
391418 } // end namespace llvm
392419
444444 return ec;
445445 ImportDirectory = reinterpret_cast<
446446 const import_directory_table_entry *>(IntPtr);
447
448 // It's an error if there's no section containing the Import Table RVA.
449 return object_error::parse_failed;
447 return object_error::success;
448 }
449
450 // Find the export table.
451 error_code COFFObjectFile::initExportTablePtr() {
452 // First, we get the RVA of the export table. If the file lacks a pointer to
453 // the export table, do nothing.
454 const data_directory *DataEntry;
455 if (getDataDirectory(COFF::EXPORT_TABLE, DataEntry))
456 return object_error::success;
457
458 // Do nothing if the pointer to export table is NULL.
459 if (DataEntry->RelativeVirtualAddress == 0)
460 return object_error::success;
461
462 uint32_t ExportTableRva = DataEntry->RelativeVirtualAddress;
463 uintptr_t IntPtr = 0;
464 if (error_code EC = getRvaPtr(ExportTableRva, IntPtr))
465 return EC;
466 ExportDirectory = reinterpret_cast(IntPtr);
467 return object_error::success;
450468 }
451469
452470 COFFObjectFile::COFFObjectFile(MemoryBuffer *Object, error_code &ec)
459477 , StringTable(0)
460478 , StringTableSize(0)
461479 , ImportDirectory(0)
462 , NumberOfImportDirectory(0) {
480 , NumberOfImportDirectory(0)
481 , ExportDirectory(0) {
463482 // Check that we at least have enough room for a header.
464483 if (!checkSize(Data, ec, sizeof(coff_file_header))) return;
465484
520539 if ((ec = initImportTablePtr()))
521540 return;
522541
542 // Initialize the pointer to the export table.
543 if ((ec = initExportTablePtr()))
544 return;
545
523546 ec = object_error::success;
524547 }
525548
569592 import_directory_iterator COFFObjectFile::import_directory_end() const {
570593 return import_directory_iterator(
571594 ImportDirectoryEntryRef(ImportDirectory, NumberOfImportDirectory, this));
595 }
596
597 export_directory_iterator COFFObjectFile::export_directory_begin() const {
598 return export_directory_iterator(
599 ExportDirectoryEntryRef(ExportDirectory, 0, this));
600 }
601
602 export_directory_iterator COFFObjectFile::export_directory_end() const {
603 if (ExportDirectory == 0)
604 return export_directory_iterator(ExportDirectoryEntryRef(0, 0, this));
605 ExportDirectoryEntryRef ref(ExportDirectory,
606 ExportDirectory->AddressTableEntries, this);
607 return export_directory_iterator(ref);
572608 }
573609
574610 section_iterator COFFObjectFile::begin_sections() const {
909945 return object_error::success;
910946 }
911947
948 bool ExportDirectoryEntryRef::
949 operator==(const ExportDirectoryEntryRef &Other) const {
950 return ExportTable == Other.ExportTable && Index == Other.Index;
951 }
952
953 error_code
954 ExportDirectoryEntryRef::getNext(ExportDirectoryEntryRef &Result) const {
955 Result = ExportDirectoryEntryRef(ExportTable, Index + 1, OwningObject);
956 return object_error::success;
957 }
958
959 // Returns the export ordinal of the current export symbol.
960 error_code ExportDirectoryEntryRef::getOrdinal(uint32_t &Result) const {
961 Result = ExportTable->OrdinalBase + Index;
962 return object_error::success;
963 }
964
965 // Returns the address of the current export symbol.
966 error_code ExportDirectoryEntryRef::getExportRVA(uint32_t &Result) const {
967 uintptr_t IntPtr = 0;
968 if (error_code EC = OwningObject->getRvaPtr(
969 ExportTable->ExportAddressTableRVA, IntPtr))
970 return EC;
971 const export_address_table_entry *entry = reinterpret_cast(IntPtr);
972 Result = entry[Index].ExportRVA;
973 return object_error::success;
974 }
975
976 // Returns the name of the current export symbol. If the symbol is exported only
977 // by ordinal, the empty string is set as a result.
978 error_code ExportDirectoryEntryRef::getName(StringRef &Result) const {
979 uintptr_t IntPtr = 0;
980 if (error_code EC = OwningObject->getRvaPtr(
981 ExportTable->OrdinalTableRVA, IntPtr))
982 return EC;
983 const ulittle16_t *Start = reinterpret_cast(IntPtr);
984
985 uint32_t NumEntries = ExportTable->NumberOfNamePointers;
986 int Offset = 0;
987 for (const ulittle16_t *I = Start, *E = Start + NumEntries;
988 I < E; ++I, ++Offset) {
989 if (*I != Index)
990 continue;
991 if (error_code EC = OwningObject->getRvaPtr(
992 ExportTable->NamePointerRVA, IntPtr))
993 return EC;
994 const ulittle32_t *NamePtr = reinterpret_cast(IntPtr);
995 if (error_code EC = OwningObject->getRvaPtr(NamePtr[Offset], IntPtr))
996 return EC;
997 Result = StringRef(reinterpret_cast(IntPtr));
998 return object_error::success;
999 }
1000 Result = "";
1001 return object_error::success;
1002 }
1003
9121004 namespace llvm {
9131005 ObjectFile *ObjectFile::createCOFFObjectFile(MemoryBuffer *Object) {
9141006 error_code ec;
None // RUN: llvm-objdump -p %p/Inputs/nop.exe.coff-i386 | FileCheck %s
0 // RUN: llvm-objdump -p %p/Inputs/nop.exe.coff-i386 | \
1 // RUN: FileCheck -check-prefix=IMPORT %s
12
2 CHECK: The Import Tables:
3 CHECK-NEXT: lookup 00005028 time 00000000 fwd 00000000 name 00005096 addr 00005058
4 CHECK: DLL Name: KERNEL32.dll
5 CHECK-NEXT: Hint/Ord Name
6 CHECK-NEXT: 365 ExitProcess
3 IMPORT: The Import Tables:
4 IMPORT-NEXT: lookup 00005028 time 00000000 fwd 00000000 name 00005096 addr 00005058
5 IMPORT: DLL Name: KERNEL32.dll
6 IMPORT-NEXT: Hint/Ord Name
7 IMPORT-NEXT: 365 ExitProcess
78
9 // RUN: llvm-objdump -p %p/Inputs/export.dll.coff-i386 | \
10 // RUN: FileCheck -check-prefix=EXPORT %s
811
12 EXPORT: Export Table:
13 EXPORT-NEXT: Ordinal RVA Name
14 EXPORT-NEXT: 5 0x2008
15 EXPORT-NEXT: 6 0x2010 exportfn2
266266 return;
267267 outs() << format(" % 6d ", Hint) << Name << "\n";
268268 }
269 outs() << "\n";
270 }
271 }
272
273 // Prints export tables. The export table is a table containing the list of
274 // exported symbol from the DLL.
275 static void printExportTable(const COFFObjectFile *Obj) {
276 outs() << "Export Table:\n";
277 export_directory_iterator I = Obj->export_directory_begin();
278 export_directory_iterator E = Obj->export_directory_end();
279 if (I == E)
280 return;
281 outs() << " Ordinal RVA Name\n";
282 error_code EC;
283 for (; I != E; I = I.increment(EC)) {
284 if (EC)
285 return;
286 uint32_t Ordinal;
287 if (I->getOrdinal(Ordinal))
288 return;
289 uint32_t RVA;
290 if (I->getExportRVA(RVA))
291 return;
292 outs() << format(" % 4d %# 8x", Ordinal, RVA);
293
294 StringRef Name;
295 if (I->getName(Name))
296 continue;
297 if (!Name.empty())
298 outs() << " " << Name;
269299 outs() << "\n";
270300 }
271301 }
398428 }
399429
400430 void llvm::printCOFFFileHeader(const object::ObjectFile *Obj) {
401 printImportTables(dyn_cast(Obj));
402 }
431 const COFFObjectFile *file = dyn_cast(Obj);
432 printImportTables(file);
433 printExportTable(file);
434 }