From 820664686a8a5c5dfd46d76c24b54a694709f89b Mon Sep 17 00:00:00 2001 From: Rui Ueyama Date: Fri, 3 Oct 2014 00:41:58 +0000 Subject: [PATCH] llvm-readobj: print COFF delay-load import table 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 | 41 +++++++ lib/Object/COFFObjectFile.cpp | 103 +++++++++++++++--- .../llvm-readobj/Inputs/imports.exe.coff-i386 | Bin 2560 -> 3072 bytes .../Inputs/imports.exe.coff-x86-64 | Bin 2560 -> 4096 bytes test/tools/llvm-readobj/imports.test | 44 ++++++-- tools/llvm-readobj/COFFDumper.cpp | 35 ++++-- 6 files changed, 190 insertions(+), 33 deletions(-) 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 7f38438d0e5d020634b6f194a73a0eaa47c9a138..72077adaebefd57c1a2a61ef662bb2c8003e0a22 100644 GIT binary patch literal 3072 zcmeHJUuauZ82@f=rq`NwK@$~?_7+mDbPIK@(6XYbdOF#XnI`SBbym%i>ynTrqsX&!|6Ffb1lQpiIeM%#zM^*blY8ixN6eGvP> z_vd{7&hLEZ-rV?SFMtRDR%FuzD57TMd#4>3AY5pHVZX z)yTXYjil2VO+KZ_s-Bh;Y59ehLh^hjrg*x$yWFkTj}BgLoH+b#sm;BQ43=hbJ^j#w zrIV=N{!A#n%;VpcX1L#3I?lC&>tG@pXSHpl0RrF?MELOf{^_=_2BL7UU~3+d9h8y1 z#WGuXn`;ZeU2KWe)_f4H8VoP-L{`fhaD7`bClqCX0Jr{Ofqh4?WdOAo^_}F=lm!i) z?;%Kzi(zh`wUsObyyj735iJ5x6VQncVEGbq2YGP|Pcsb$n12YF<#n;e4tW7qcUHUB ze{lkZJuu{jFB$YuAP}lQjz;|nCfLo_pJW1GDX6oDI#g#*%~i7>WG|TgE-u|%4sf{- zWzm5R*D(*Kf`NDdJ@toiF?+(Snf)wQw6lbtO{9KiQgenjRvJSgIwu_qPk&8NUgAB!Toe`@8@NMtPO8ok`Z`*RePY|uTC8^t8^p3xi|k9wrNI8J%`aA z7EKBm-p-r)bP|$a>NiZM19#=F3Dapq+aMd4+|7o~60ud%*NHg^@$Y&s=u#sT25asMv9zoiLJKR=drX#2;qE^UAw8ebY8WxtiWi~4Vk`9>xE z{)2Cfj_BP~-=^dy9r-lBsryWQ4ZB(yTs)vY{yT83tsPt(u2dirju_#-xdT^k;Czjt z_T27UQ8s|1+rw^1Z(xUSUVY^x{bla!JARGukh}D+O<=qa;49=$kUv0v7x{Z+M#o!P zMST_-|0le~105n2IlGw3L}H#;D#hFavR4Lh;WxvMd;#r`k^d@P#@zRjn>4AXqwK54 z^wVu8*An7s(_v=I0PYUo>u9^sx39yujJ6wnzeRs%4pRbINN52y6IHTVI6{I)iEsEo za}tvlKRP3)mFF@G6EG7Z!FHs1nx}A5>{JI}ei28M0!T5*CK|0%twq*56V!Z delta 419 zcmZpWXb_oT!+2t%t#exL!i~Q*58Ph?!zz=QR%iqHU+hIz=zzuVfoYXV3@bE%e3eOz zU^*x>IRm7J0SW?K85n#RnHkEj=!U?=9xyO7ax?NUFfdJgm&B+rIgl}W@<$Hwi3Y4f zdL^k9B|vo^AhiNO%ryBHqr5JNrvTysF&hvg0S5*K2fdWUl0={wFG$>A@;^q&&Gt+O z87CTWOkxo*mjMdCkOdKPAVMBU1ixSel4t&_GAKAO{8!}wlM-N308EM~IBa%g+Q}F> zK>?@`2-YZoDTZ@Enwf#2;TV)(0Hr~)^FVAMt^m6N}uosmALG!tX#@lq1QB?xb@183*)7=Zgu1MZq&oI ztH$@BJo2e+yo>q29FH)&d%Tm$8YWv4u|9gXRB1>Ah`;58Z@%6TF4^wD6R^y_+-$Pk zvR0#{3tP2OPWN_zN9Z1@Bq4+f9S)KmxWlDG)>*WgK}v$+EDPNN=K&UiDU|sEYUh-H zu;Bpu@c0KP{U{fbHzQ{=XndbuTv`zA!RiBdj5vTEuNseLq5uc6cR&NflxBn~B|rXo zO_-Uh35^twBb`rvfPyz|0$Gn}V7RLJC^O#umPPHqngAKT)j%dr)AS_ozP%1WV2=Rd z6g5pZQuY*O8z}Qqc9JrBf()N)&?l#DxV>o9f8xR?Nd5PW-)8&{<9CsheA!1B`UWC_ z_l(bwxb6yQ1J65oV8%=?jd@gbs5k$mMWMwxEIiBA(f%x5M22tR~KNq>hwiW1B0y9q|os9%pYU@5h<6wN@Yuf**|f26IwLkJ5I zpAR%dP-hA{k{Z9*I+G>hYm zMr#hg&fWDC7eiMH+zQTN{_s^$O~)kq*p*h&n`& z5yLfdoc4sk6%?4?WuwS@XwYIrZz+hrg7327zFtWWF|%a2CsE6Z(-`I3HTNBM%pHDm zuH8=7?i*&iore287D_DMn5BvJiQwBy$mR*Hg6Llv?q23BJ4D0gUZ(|Ts%TxO=u^n* z;i_xo7;3_%y)~H)$m=reNo@O;!&{o^J3)I)Zy}qc=5lQX*?h3MNn0A!yMDqBuWDUH zk6?3{<`;aRne))L8}46GGuv_9*UnC7X=<8huALs%&LOj%9>aZ(h3YN_b9Fop6#!@Zjl+$IQ|BxG8s7@;OU3 zSn^d%mMWUH&Xx2k%m1h)>1zjRi1B$W8GUUqsYK)6crr=Nwptt1ov9?cA;}lPtVJB zo$fh+(RnsI_S=lMv3a(&Xd`I*Gy1pY-C+~6iA+dUV)DQM>=avH5+&b8bLuVV4!!7XjV1{p}eAe^9HnqG*knz=yO&vBqOs}p`a)~ zy(lqPAvrNGFTX?~DOI7UG*2NjPr=1MSRpq*B~_1?mrDg|bne29zcmlsUjf4^lbBX$ z1NmRl}QXMG=O}SNsM4RC^I<&qzC5009OWvls0Atv8%cvFtHB|$_(60 zJPZs>KoO7!K|lbCfnH>U@qzMeAT|)dXm9{P^)N9gG(t226@c`E0h9sfBS`_}9TXTC z0w4;hO9IVxz+<9bNoqw2P(B8v2IMwmzk|epK!JfFL9Zw!u_O`5W`qcU)xkXvQU$ih zK@XygffpoT0K_2kI6xc(aA06KfZ&a?hEfQ4G{4dCIDQc1WRG6ack&Djj^HA|aVJRV zg(8Sh0ujm}0+ee#nvZC7pLhXEH)sB+{^lA~bohrk5|R5!js z`$ zQ|g{@M%RkWl7OQ8 > 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()); } }