From 582c4d2babbb93271485cc4fee837b6b880c7610 Mon Sep 17 00:00:00 2001 From: "Michael J. Spencer" Date: Thu, 11 Feb 2016 04:59:45 +0000 Subject: [PATCH] [readobj] Handle ELF files with no section table or with no program headers. This adds support for finding the dynamic table and dynamic symbol table via the section table or the program header table. If there's no section table an attempt is made to figure out the length of the dynamic symbol table. llvm-svn: 260488 --- llvm/include/llvm/Object/ELF.h | 17 +- .../corrupt-invalid-virtual-addr.elf.x86-64 | Bin 1720 -> 0 bytes llvm/test/Object/corrupt.test | 11 +- llvm/test/Object/invalid.test | 4 +- .../Inputs/dynamic-table-exe-no-phdrs.x86 | Bin 0 -> 6555 bytes .../Inputs/dynamic-table-exe-no-shdrs.x86 | Bin 0 -> 6555 bytes .../tools/llvm-readobj/dynamic-symbols.test | 198 ++++++++++++++ llvm/tools/llvm-readobj/ELFDumper.cpp | 247 +++++++++++------- llvm/tools/llvm-readobj/llvm-readobj.h | 6 + 9 files changed, 375 insertions(+), 108 deletions(-) delete mode 100755 llvm/test/Object/Inputs/corrupt-invalid-virtual-addr.elf.x86-64 create mode 100644 llvm/test/tools/llvm-readobj/Inputs/dynamic-table-exe-no-phdrs.x86 create mode 100644 llvm/test/tools/llvm-readobj/Inputs/dynamic-table-exe-no-shdrs.x86 create mode 100644 llvm/test/tools/llvm-readobj/dynamic-symbols.test diff --git a/llvm/include/llvm/Object/ELF.h b/llvm/include/llvm/Object/ELF.h index b0eaa3f5ed4d..abd95861ad9a 100644 --- a/llvm/include/llvm/Object/ELF.h +++ b/llvm/include/llvm/Object/ELF.h @@ -62,6 +62,8 @@ public: return reinterpret_cast(Buf.data()); } + size_t getBufSize() const { return Buf.size(); } + private: StringRef Buf; @@ -200,6 +202,9 @@ public: uint32_t getExtendedSymbolTableIndex(const Elf_Sym *Sym, const Elf_Shdr *SymTab, ArrayRef ShndxTable) const; + uint32_t getExtendedSymbolTableIndex(const Elf_Sym *Sym, + const Elf_Sym *FirstSym, + ArrayRef ShndxTable) const; const Elf_Ehdr *getHeader() const { return Header; } ErrorOr getSection(const Elf_Sym *Sym, const Elf_Shdr *SymTab, @@ -225,8 +230,15 @@ template uint32_t ELFFile::getExtendedSymbolTableIndex( const Elf_Sym *Sym, const Elf_Shdr *SymTab, ArrayRef ShndxTable) const { + return getExtendedSymbolTableIndex(Sym, symbol_begin(SymTab), ShndxTable); +} + +template +uint32_t ELFFile::getExtendedSymbolTableIndex( + const Elf_Sym *Sym, const Elf_Sym *FirstSym, + ArrayRef ShndxTable) const { assert(Sym->st_shndx == ELF::SHN_XINDEX); - unsigned Index = Sym - symbol_begin(SymTab); + unsigned Index = Sym - FirstSym; // The size of the table was checked in getSHNDXTable. return ShndxTable[Index]; @@ -238,7 +250,8 @@ ELFFile::getSection(const Elf_Sym *Sym, const Elf_Shdr *SymTab, ArrayRef ShndxTable) const { uint32_t Index = Sym->st_shndx; if (Index == ELF::SHN_XINDEX) - return getSection(getExtendedSymbolTableIndex(Sym, SymTab, ShndxTable)); + return getSection( + getExtendedSymbolTableIndex(Sym, symbol_begin(SymTab), ShndxTable)); if (Index == ELF::SHN_UNDEF || Index >= ELF::SHN_LORESERVE) return nullptr; diff --git a/llvm/test/Object/Inputs/corrupt-invalid-virtual-addr.elf.x86-64 b/llvm/test/Object/Inputs/corrupt-invalid-virtual-addr.elf.x86-64 deleted file mode 100755 index 58d995933ecadffe435c6044763bc67adaa41d63..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1720 zcmcIky-piJ5FY=KKuqDF6dk3zZdnr}@U6z_WP`avL)7*LdX*_Y!=7_Oi<06>YA&643?ME1n(i zi+C909z}*Xfvwy9YJMuKhJ5Sk)Dw@4Uo%7u*x2-bc7MN!x1=BN-Qg!W>3{94H(aA} zOGtmbYMOs8$Gexx3zE+#(p;1eyh{=PYz{BX&F<&J*9Y%+=I6~N;V==W=@i!)MR76^ z7xk0SokV92*W5f02k~h?^6pVjTsMfjvsutPJr);tRg?s69T7*p*?d+idcwQg3*7=W z!g^xe5WiRm`0?iaKd_#bmCM%ScdHvB>&mv7?ZGi{OFz^k^#9r}0rQF!1-%NVNz>J^R3r0`+ArAOE2`vFHEl(NC~P z-WdOB&XJG*QT;_ny)^Q|^ym{fBk#}r?;CH+Qh06`+DI8c$fxCv(!6_i=?5d*SyIP& F{cnshZSw#C diff --git a/llvm/test/Object/corrupt.test b/llvm/test/Object/corrupt.test index 0d9aad378f88..005f86fb7446 100644 --- a/llvm/test/Object/corrupt.test +++ b/llvm/test/Object/corrupt.test @@ -38,24 +38,17 @@ RUN: FileCheck --check-prefix=PHENTSIZE %s PHENTSIZE: Invalid program header size -RUN: not llvm-readobj -dynamic-table \ -RUN: %p/Inputs/corrupt-invalid-virtual-addr.elf.x86-64 2>&1 | \ -RUN: FileCheck --check-prefix=VIRTADDR %s - -VIRTADDR: Virtual address is not in any segment - - RUN: not llvm-readobj -dyn-relocations \ RUN: %p/Inputs/corrupt-invalid-relocation-size.elf.x86-64 2>&1 | \ RUN: FileCheck --check-prefix=RELOC %s -RELOC: Invalid relocation entry size +RELOC: Invalid entity size RUN: not llvm-readobj -dyn-relocations \ RUN: %p/Inputs/corrupt-invalid-dynamic-table-size.elf.x86-64 2>&1 | \ RUN: FileCheck --check-prefix=DYN-TABLE-SIZE %s -DYN-TABLE-SIZE: Invalid dynamic table size +DYN-TABLE-SIZE: Invalid entity size RUN: not llvm-readobj -dyn-relocations \ diff --git a/llvm/test/Object/invalid.test b/llvm/test/Object/invalid.test index cc5cd68304c6..a32c621cca61 100644 --- a/llvm/test/Object/invalid.test +++ b/llvm/test/Object/invalid.test @@ -35,9 +35,11 @@ SECTION-NEXT: AddressAlignment: SECTION-NEXT: EntrySize: 32 RUN: not llvm-readobj -t %p/Inputs/invalid-sh_entsize.elf 2>&1 | FileCheck --check-prefix=INVALID-SYM-SIZE %s -RUN: not llvm-readobj --dyn-symbols %p/Inputs/invalid-sh_entsize.elf 2>&1 | FileCheck --check-prefix=INVALID-SYM-SIZE %s INVALID-SYM-SIZE: Invalid symbol size +RUN: not llvm-readobj --dyn-symbols %p/Inputs/invalid-sh_entsize.elf 2>&1 | FileCheck --check-prefix=INVALID-DYNSYM-SIZE %s +INVALID-DYNSYM-SIZE: Invalid entity size + RUN: not llvm-readobj -t %p/Inputs/invalid-section-index.elf 2>&1 | FileCheck --check-prefix=INVALID-SECTION-INDEX %s INVALID-SECTION-INDEX: Invalid section index diff --git a/llvm/test/tools/llvm-readobj/Inputs/dynamic-table-exe-no-phdrs.x86 b/llvm/test/tools/llvm-readobj/Inputs/dynamic-table-exe-no-phdrs.x86 new file mode 100644 index 0000000000000000000000000000000000000000..1571da9f650b377433c1f9c42fc13750998023c2 GIT binary patch literal 6555 zcmd^DeQZ?65#O^9;sjz0AqfSioajLzffpMbAO$Hl_5lV1#+Z+Ugw6Tx+4stQxcANL={(ie} z&GUt{Nd2>8&D))w+1cIMnYr~m6Kh)=3WbD$N>M3DU7jpN1KP7wHK##D&{>G@1A5^9 z`1^3$>3TSwT#|OOg+9y8Sxbco!yYw2+HT$E?aDe8_`-~0Hjw<8z)B$bcUHYqzxuiF zF6%hHBHFm;_rDy8eEm1%O$Xiyq^>DI1Jp~P40TNcQa`WfZeSH~8j$PV0VGrd?*eiT z<*0-6s*++6Y4Qm_dGEx*=GZ%9-{1J&&>z0Et9I`*-#n-}H@}N-cHsj;tSX})H5oL!c$?1Zc|tpp2ehrtef4|Kl?H!GQcc@b-XC&CxqizL%1}%juX z$t7)`wkMI0E)QETO}LdT}^9RWxcgbtZQps0}{gxx-XYn zOP0kgO12@#Q6EGd?}Pz5W?ZGcj;{ zG5nJ4(|(Jtf+PkjfQQ&3sE@HlfPafE0{a|R4FP9i-ejy*%N9u?!WNDlWs8$6WQ!B8 zMtcY38rdQ#w6KM~^=zTPjV*MyvxVMHwpeEuTg=~n^n-21vG52txBKw$HRQ8_lOv^4 z>Bw8&q!C8luH6@g)z-&9r8A7M(rKtwP&&=blVX4L&zM>|O$(>U9=)h&X2}!>M~4(W zi!?u@FDts1bcFPaie@*pko0jyM@jPEl9;$_S~GUQ!8Ix||j_~GcFw?Nr&t(26ZgAw$F>pvyc{03@k>%1s~y?)F_fOWh;0uRe}(U&H_n$Tj+DG;{nde3 z4UAYd5SvO{4#c=p>8ocbReU}4=#Bil#n)xCz~{qQ;c+@Se^Z$^#CA7t zwKxgS+L_BIT@jj7xr)vTj;O&l)Lr0=eV}Io384cWB6P4SG-ql!`~vJ0!5F>zZ5ZP? zT2WoKwtDJ@X;Zv#pLlHcst1=w=aEkc9cXV;v-OYsoS+VR{vjNMzggk?@oB2AI#RLb z?nxD!evYLufJiKbs_t2`PHaG4sKJE{X+0|cVJoU-u4JD%j?uapIf8GD2<{E3OE7;S zB_KoUw+-_c_eYv|4Dd5$^}g1I5k|3u3@{4c=wKouWz zKJ0_S=Yd}Xz6AUc@O9wtfPV!NnA7pY_Jzp87Q4%dXCn>P3Tx?-M;7T$ISz*yGZGf@q9ksuXULI7ZaF><>DD9fq6MBfsduu)ob9XAgn|#ld-d& zHtcPD>7#Hpsl5a~At$Rm6X$S|Pqt;ZlSg1!Oz6`>wz_ACzNk5a*$9*5x>HFOc!XK4Xe_2z{>0bwDaOfG<*mn!^|+GDeL)${}<_5oqKX z)5J!MQI7e=$Q?tUd*wKD4{-td2F$u&#(Uc!KpYljTc82lC1sZ*PyUv1hm)no~_*X!VzYTSeTZ}OSlu-y}M&FZ=dlGV7 z$ACH0T@d0p&%yr%laMn!%9{Q(Utb*u0hC**yXwoei2O}bwo{`*d>eAJ$ne2**#_KA zoW;Z!vDjRUTR^T$AH+3H(AS9{w{?L9j6R5c0+`zfx_YB?n5Om0%vGA!3Yn8MtxwI| zqiF;sfH{Uxscux~5=}Gug~}P4)|O^&&@@k>bAYD#i?3r{(=ZZ%F-@rSJ(#hpX=VZ) zqnf5C3l)o+rpM}-)3lCW#+IgeD>{ZW%@>1?6;1130LF!;`O*ORzw4F$izGZw>lcRk z-LLdB0{xay>3c5yQ`1^8{ZP|dk*PgYs+W`IX@0HpB{LF6t%5Oa)(?sM)SIhLn;m{s zt$e08KsP~tC_wK7&GmStA*|Pp)|@Yd^9_RJ+mAqf-#}~Z5yH#sRmIUC?#FixH9&d@ zy)ob3A-u?b4LZ2rKY}*)2tocbXtO?Fb}ToV^+?YIZR|_=2S6M9MKEz8=$ElydM0Zz zD?u}d6G%S>+CT)I&1G~KXy$0TC~G|qXy$gp3}nDuK%U-WVuSn$@O$6~YelaF% zwApVB_WLgAjlO+nR8)&Apw0bHuYf-Uk^$FS4Vv#n0{N|=hcN#M&^+Jcpv`>Nvh1?? zXF&&RT|X}4UnrY@v5fyw8GUCU=gh+%=7XMX?1l5J2FE-gSj2HR@o`1b* z+q09_BP*7n$aO0r)}0*vtVB)8%l8ZYG))#VnSM+OP?9g&38Jh{SqbiWZAa6ln2c?1 zVfjv-!0)eX+p?yqO>SAcc3Z4db~dePi&0{Ns^r80RrwOKmwp2lmD-^0WZC@%OwS8#SNT8-IeK2wgrK(y;leX$Z)GAQf!l)q87F7w`@0+>T zUTbkuDfOj#`CELGLkRf13BO)if{j!q}}sO(p;Og)44&z$r$Uj zE~ci|wr$s5rOSCz2h&uxtHJ3T%IB58U%%zc-&@~#YGb7F&>wy^5&p(+DO&`>)VNGB zALJJ-M-}$rJn1Xi=k`1bDhDkDalA)BEEOQQNsY;Vv_ZXcQ>-SYoaJX9zHzKM`u@}p zc6>PY$1m-#IsD4Ej%mrv@0yva2&2Ba1V86b5baeU&fhO#RCfCSoY*eH?Ek|Oyt2gJ znfE`q$XMBWPA0jKVPyb5xGJ$GC) z{`Aw_@C`z?b?=m>m9_e8$F;KEJDZc4wACH!Nm@e6zEmbH9XFPBr4(}efb8`8H78?^ zV>w#={>m@y>T>HFdSZ?pmv*n?X02GNEsnPOcp{dSZZ>ASPFp-0ZK;nAaIC>W*>7c? zOgfgd-61(pC*%X$Xs(ZT?4a@WvMuAt-ThWNl`$=@wl5x+4i{T5lbCk}2Em%^{NX6{5kd_&9V-WN>j&4U&+7#QG zo8@|=PBib|-?X(&)*I`^w)VEIfM{;eb-B)%Zb!XNZ?O6jc+P{Ug>c5_;;j3BJof?d zH}vG041+pW4dK(8BjVU&mH@O^rJNRj_oKu3OhV!?8rkNqegh{VC*9!^j^c|~E~k_k3Wjw!s9m_L(mDa@NX5hnhQ!mK80iBBmUA?7wt z9#@#6#3tf?;QE_~PW~l-?Nr<(EbcpU~D%^$y6D0GbGPm%3;v2gYy^qr9SxieA| z89y~$=!1zWIB|IVpLo;qQ`MvSjW9lXx&gndujKE}Ju)}{PW8c;$4BzFpnqb_y>+rW zQn+$sa@1X=d^qtgx(<)O?dwz1*S~PL?Bsw)xqI0U^6%6f zJS4GwYTxOPqB9@D2nTq``402m5PO}h(PGD4V_zm~IwG(bh1sJ*}%2Z5_W zEPD=#P>Bs0({|MT zhp8yeyOMR@ar|1>;ErI75yrmZ>QXTot_0kWI=10G#`zJGUWeY_?-erFz!`7U!dWmO zmcl8FN8Us`V;g?ti$N^(XB~{vZ;c@Oim?!vF$E*6o8a)jcnyTJsqV}r;4Gg3acnF< za}5=^JVTrK1T$m6{{rV6{-45lfH9|E24L_jps$0z3;HqWBIx&^zk*nJr{iJ!T)4Ky z>ak<#aD%bYShx1s)w)tDgLLgW%1{x)aE4NDtOwl9YM$_Gb{bJfzcA7n*D~;2u61L5 z9_mZyjGmm00M#~yL6nF&31OH+Y1q@;&1%U20tY*jo&_XiSu4r@y3(I?g<+>{{JPd4 ze(|{55M|UmZdeJ~n~kL`nJ}U0BbY=0VGYKueph1hh>MgB8Ovs4L)wO4|6&}97%rBw zcjoTs;Ot1!2T9sg#v=wPPRtKJ>st4?Oh1Lk}nqFxSGOvo|{Tp)p@nM8MN> zzKZ&dCJ(AtQwYA*8uP{0Z?(qyA>$jau?`scrfSTn4*Js=K>`ZjYL=jS@%0<7F<*Wi zQ)tWx1Mj5wUIta9q4Q5#uCo-3Jv3gZ_@-&hC_?9Q$b%|UK)z^N&WHi_rZFQ29m9|Z z{iw`)*MnX}5}L+3!tmeypo&QJ|6E$1(VmW7G-iY(#OE0xp#)X-XD0U$6rMnfA+J%f zmItvLw+r-$KYloAUe_Kt%Q%;NtoI37D}QO91_Eu`(SuRSTvY z{qY#-RRjC}W&bCDegB1_SPT3X=F1~hh52p*W`2@|_<3Nzgi+a5f_s2@UU)sx1HisMb6Hl2{yE^{T-Q%aby+#~ap6$(@vc0XV8=0_~e3^7p zGR};dBm68_QInKrM)oB$J+Y)T-AvYzvD~0Q_}8DbT+1|`-MAh}uKRUj-pSTsC2~q` zc1Y;Z)Xb$)Lr^I~k`e8!uFOsuan8B5vuS5kMt8L^eWzC7)wi|p-rCeIcel27MZ0Bp z)7JJVd(1Lr&TdedFCkkF>}uNC)+`v$`dKfX8jCwQHEl87{J+zOz5OzAM0jeY8Meko zl{ZuQvHzN class DumpStyle; +/// \brief Represents a region described by entries in the .dynamic table. +struct DynRegionInfo { + DynRegionInfo() : Addr(nullptr), Size(0), EntSize(0) {} + DynRegionInfo(const void *A, uint64_t S, uint64_t ES) + : Addr(A), Size(S), EntSize(ES) {} + /// \brief Address in current address space. + const void *Addr; + /// \brief Size in bytes of the region. + uint64_t Size; + /// \brief Size of each entity in the region. + uint64_t EntSize; + + template iterator_range getAsRange() const { + const Type *Start = reinterpret_cast(Addr); + if (Size == 0) + return {Start, Start}; + if (EntSize != sizeof(Type) || Size % EntSize) + reportError("Invalid entity size"); + return {Start, Start + (Size / EntSize)}; + } +}; + template class ELFDumper : public ObjDumper { public: @@ -82,6 +104,7 @@ private: typedef ELFFile ELFO; typedef typename ELFO::Elf_Shdr Elf_Shdr; typedef typename ELFO::Elf_Sym Elf_Sym; + typedef typename ELFO::Elf_Sym_Range Elf_Sym_Range; typedef typename ELFO::Elf_Dyn Elf_Dyn; typedef typename ELFO::Elf_Dyn_Range Elf_Dyn_Range; typedef typename ELFO::Elf_Rel Elf_Rel; @@ -101,21 +124,25 @@ private: typedef typename ELFO::Elf_Verdef Elf_Verdef; typedef typename ELFO::Elf_Verdaux Elf_Verdaux; - /// \brief Represents a region described by entries in the .dynamic table. - struct DynRegionInfo { - DynRegionInfo() : Addr(nullptr), Size(0), EntSize(0) {} - /// \brief Address in current address space. - const void *Addr; - /// \brief Size in bytes of the region. - uintX_t Size; - /// \brief Size of each entity in the region. - uintX_t EntSize; - }; + DynRegionInfo checkDRI(DynRegionInfo DRI) { + if (DRI.Addr < Obj->base() || + (const uint8_t *)DRI.Addr + DRI.Size > Obj->base() + Obj->getBufSize()) + error(llvm::object::object_error::parse_failed); + return DRI; + } + + DynRegionInfo createDRIFrom(const Elf_Phdr *P, uintX_t EntSize) { + return checkDRI({Obj->base() + P->p_offset, P->p_filesz, EntSize}); + } + + DynRegionInfo createDRIFrom(const Elf_Shdr *S) { + return checkDRI({Obj->base() + S->sh_offset, S->sh_size, S->sh_entsize}); + } void parseDynamicTable(ArrayRef LoadSegments); void printSymbolsHelper(bool IsDynamic); - void printSymbol(const Elf_Sym *Symbol, const Elf_Shdr *SymTab, + void printSymbol(const Elf_Sym *Symbol, const Elf_Sym *FirstSym, StringRef StrTable, bool IsDynamic); void printDynamicRelocation(Elf_Rela Rel); @@ -123,23 +150,9 @@ private: void printRelocation(Elf_Rela Rel, const Elf_Shdr *SymTab); void printValue(uint64_t Type, uint64_t Value); - template - static const REL *dyn_rel_begin(const DynRegionInfo ®ion); - template - static const REL *dyn_rel_end(const DynRegionInfo ®ion); Elf_Rel_Range dyn_rels() const; Elf_Rela_Range dyn_relas() const; StringRef getDynamicString(uint64_t Offset) const; - const Elf_Dyn *dynamic_table_begin() const { - ErrorOr Ret = Obj->dynamic_table_begin(DynamicProgHeader); - error(Ret.getError()); - return *Ret; - } - const Elf_Dyn *dynamic_table_end() const { - ErrorOr Ret = Obj->dynamic_table_end(DynamicProgHeader); - error(Ret.getError()); - return *Ret; - } StringRef getSymbolVersion(StringRef StrTab, const Elf_Sym *symb, bool &IsDefault); void LoadVersionMap(); @@ -147,15 +160,17 @@ private: void LoadVersionDefs(const Elf_Shdr *sec) const; const ELFO *Obj; + DynRegionInfo DynamicTable; + + // Dynamic relocation info. DynRegionInfo DynRelRegion; DynRegionInfo DynRelaRegion; - const Elf_Phdr *DynamicProgHeader = nullptr; + + DynRegionInfo DynSymRegion; StringRef DynamicStringTable; - const Elf_Sym *DynSymStart = nullptr; StringRef SOName; const Elf_Hash *HashTable = nullptr; const Elf_GnuHash *GnuHashTable = nullptr; - const Elf_Shdr *DotDynSymSec = nullptr; const Elf_Shdr *DotSymtabSec = nullptr; ArrayRef ShndxTable; @@ -188,16 +203,18 @@ private: public: Elf_Dyn_Range dynamic_table() const { - ErrorOr Ret = Obj->dynamic_table(DynamicProgHeader); - error(Ret.getError()); - return *Ret; + return DynamicTable.getAsRange(); + } + + Elf_Sym_Range dynamic_symbols() const { + return DynSymRegion.getAsRange(); } std::string getFullSymbolName(const Elf_Sym *Symbol, StringRef StrTable, bool IsDynamic); - const Elf_Shdr *getDotDynSymSec() const { return DotDynSymSec; } const Elf_Shdr *getDotSymtabSec() const { return DotSymtabSec; } ArrayRef getShndxTable() { return ShndxTable; } + StringRef getDynamicStringTable() const { return DynamicStringTable; } }; template class DumpStyle { @@ -340,7 +357,7 @@ void ELFDumper::LoadVersionDefs(const Elf_Shdr *sec) const { template void ELFDumper::LoadVersionMap() { // If there is no dynamic symtab or version table, there is nothing to do. - if (!DynSymStart || !dot_gnu_version_sec) + if (!DynSymRegion.Addr || !dot_gnu_version_sec) return; // Has the VersionMap already been loaded? @@ -374,18 +391,15 @@ static void printVersionSymbolSection(ELFDumper *Dumper, W.printHex("Offset", Sec->sh_offset); W.printNumber("Link", Sec->sh_link); - const typename ELFO::Elf_Shdr *DynSymSec = Dumper->getDotDynSymSec(); const uint8_t *P = (const uint8_t *)Obj->base() + Sec->sh_offset; - ErrorOr StrTableOrErr = - Obj->getStringTableForSymtab(*DynSymSec); - error(StrTableOrErr.getError()); + StringRef StrTable = Dumper->getDynamicStringTable(); // Same number of entries in the dynamic symbol table (DT_SYMTAB). ListScope Syms(W, "Symbols"); - for (const typename ELFO::Elf_Sym &Sym : Obj->symbols(DynSymSec)) { + for (const typename ELFO::Elf_Sym &Sym : Dumper->dynamic_symbols()) { DictScope S(W, "Symbol"); std::string FullSymbolName = - Dumper->getFullSymbolName(&Sym, *StrTableOrErr, true /* IsDynamic */); + Dumper->getFullSymbolName(&Sym, StrTable, true /* IsDynamic */); W.printNumber("Version", *P); W.printString("Name", FullSymbolName); P += sizeof(typename ELFO::Elf_Half); @@ -461,7 +475,7 @@ StringRef ELFDumper::getSymbolVersion(StringRef StrTab, // Determine the position in the symbol table of this entry. size_t entry_index = (reinterpret_cast(symb) - - reinterpret_cast(DynSymStart)) / + reinterpret_cast(DynSymRegion.Addr)) / sizeof(Elf_Sym); // Get the corresponding version index entry @@ -517,7 +531,7 @@ std::string ELFDumper::getFullSymbolName(const Elf_Sym *Symbol, template static void getSectionNameIndex(const ELFO &Obj, const typename ELFO::Elf_Sym *Symbol, - const typename ELFO::Elf_Shdr *SymTab, + const typename ELFO::Elf_Sym *FirstSym, ArrayRef ShndxTable, StringRef &SectionName, unsigned &SectionIndex) { SectionIndex = Symbol->st_shndx; @@ -536,7 +550,7 @@ getSectionNameIndex(const ELFO &Obj, const typename ELFO::Elf_Sym *Symbol, else { if (SectionIndex == SHN_XINDEX) SectionIndex = - Obj.getExtendedSymbolTableIndex(Symbol, SymTab, ShndxTable); + Obj.getExtendedSymbolTableIndex(Symbol, FirstSym, ShndxTable); ErrorOr Sec = Obj.getSection(SectionIndex); error(Sec.getError()); SectionName = errorOrDefault(Obj.getSectionName(*Sec)); @@ -990,7 +1004,7 @@ ELFDumper::ELFDumper(const ELFFile *Obj, StreamWriter &Writer) SmallVector LoadSegments; for (const Elf_Phdr &Phdr : Obj->program_headers()) { if (Phdr.p_type == ELF::PT_DYNAMIC) { - DynamicProgHeader = &Phdr; + DynamicTable = createDRIFrom(&Phdr, sizeof(Elf_Dyn)); continue; } if (Phdr.p_type != ELF::PT_LOAD || Phdr.p_filesz == 0) @@ -1005,10 +1019,17 @@ ELFDumper::ELFDumper(const ELFFile *Obj, StreamWriter &Writer) reportError("Multilpe SHT_SYMTAB"); DotSymtabSec = &Sec; break; + case ELF::SHT_DYNAMIC: { + if (DynamicTable.Addr == nullptr) + DynamicTable = createDRIFrom(&Sec); + const Elf_Shdr *DynStrSec = unwrapOrError(Obj->getSection(Sec.sh_link)); + DynamicStringTable = unwrapOrError(Obj->getStringTable(DynStrSec)); + break; + } case ELF::SHT_DYNSYM: - if (DotDynSymSec != nullptr) - reportError("Multilpe SHT_DYNSYM"); - DotDynSymSec = &Sec; + // The dynamic table does not contain the size of the dynamic symbol + // table, so get that from the section table if present. + DynSymRegion = createDRIFrom(&Sec); break; case ELF::SHT_SYMTAB_SHNDX: { ErrorOr> TableOrErr = Obj->getSHNDXTable(Sec); @@ -1049,12 +1070,12 @@ void ELFDumper::parseDynamicTable( const Elf_Phdr *const *I = std::upper_bound( LoadSegments.begin(), LoadSegments.end(), VAddr, compareAddr); if (I == LoadSegments.begin()) - report_fatal_error("Virtual address is not in any segment"); + return nullptr; --I; const Elf_Phdr &Phdr = **I; uint64_t Delta = VAddr - Phdr.p_vaddr; if (Delta >= Phdr.p_filesz) - report_fatal_error("Virtual address is not in any segment"); + return nullptr; return Obj->base() + Phdr.p_offset + Delta; }; @@ -1078,8 +1099,11 @@ void ELFDumper::parseDynamicTable( StringTableSize = Dyn.getVal(); break; case ELF::DT_SYMTAB: - DynSymStart = - reinterpret_cast(toMappedAddr(Dyn.getPtr())); + if (DynSymRegion.Addr) + break; + DynSymRegion.Addr = toMappedAddr(Dyn.getPtr()); + DynSymRegion.EntSize = sizeof(Elf_Sym); + // Figure out the size once we have scanned the entire dynamic table. break; case ELF::DT_RELA: DynRelaRegion.Addr = toMappedAddr(Dyn.getPtr()); @@ -1108,35 +1132,59 @@ void ELFDumper::parseDynamicTable( DynamicStringTable = StringRef(StringTableBegin, StringTableSize); if (SONameOffset) SOName = getDynamicString(SONameOffset); -} + if (DynSymRegion.Addr && !DynSymRegion.Size) { + // There was no section table entry for the dynamic section, and there is + // no DT entry describing its size, so attempt to guess at its size. + // Initally guess that it ends at the end of the file. + const void *Start = DynSymRegion.Addr; + const void *End = Obj->base() + Obj->getBufSize(); -template -template -const REL *ELFDumper::dyn_rel_begin(const DynRegionInfo &Region) { - if (Region.Size && Region.EntSize != sizeof(REL)) - report_fatal_error("Invalid relocation entry size"); - return reinterpret_cast(Region.Addr); -} + // Check all the sections we know about. + for (const Elf_Shdr &Sec : Obj->sections()) { + const void *Addr = Obj->base() + Sec.sh_offset; + if (Addr >= Start && Addr < End) + End = Addr; + } + + // Check all the dynamic regions we know about. + auto CheckDRI = [&](DynRegionInfo DRI) { + if (DRI.Addr >= Start && DRI.Addr < End) + End = DRI.Addr; + }; -template -template -const REL *ELFDumper::dyn_rel_end(const DynRegionInfo &Region) { - uint64_t Size = Region.Size; - if (Size % sizeof(REL)) - report_fatal_error("Invalid relocation table size"); - return dyn_rel_begin(Region) + Size / sizeof(REL); + CheckDRI(DynamicTable); + CheckDRI(DynRelRegion); + CheckDRI(DynRelaRegion); + + if (DynamicStringTable.data() >= Start && DynamicStringTable.data() < End) + End = DynamicStringTable.data(); + + // Scan to the first invalid symbol. + auto SymI = reinterpret_cast(Start); + for (; ((const char *)SymI + sizeof(Elf_Sym)) <= End; ++SymI) { + uint32_t NameOffset = SymI->st_name; + if (SymI > Start && !NameOffset) + break; + if (NameOffset >= DynamicStringTable.size()) + break; + uint16_t SectionIndex = SymI->st_shndx; + if ((Obj->getNumSections() && SectionIndex >= Obj->getNumSections()) && + SectionIndex < SHN_LORESERVE) + break; + } + End = SymI; + DynSymRegion.Size = (const char *)End - (const char *)Start; + } } template typename ELFDumper::Elf_Rel_Range ELFDumper::dyn_rels() const { - return make_range(dyn_rel_begin(DynRelRegion), - dyn_rel_end(DynRelRegion)); + return DynRelRegion.getAsRange(); } template typename ELFDumper::Elf_Rela_Range ELFDumper::dyn_relas() const { - return make_range(dyn_rel_begin(DynRelaRegion), - dyn_rel_end(DynRelaRegion)); + return DynRelaRegion.getAsRange(); } template @@ -1211,7 +1259,7 @@ void ELFDumper::printSections() { if (!SymSec) continue; if (*SymSec == &Sec) - printSymbol(&Sym, Symtab, StrTable, false); + printSymbol(&Sym, Obj->symbol_begin(Symtab), StrTable, false); } } @@ -1328,7 +1376,8 @@ void ELFDumper::printDynamicRelocation(Elf_Rela Rel) { Obj->getRelocationTypeName(Rel.getType(Obj->isMips64EL()), RelocName); StringRef SymbolName; uint32_t SymIndex = Rel.getSymbol(Obj->isMips64EL()); - const Elf_Sym *Sym = DynSymStart + SymIndex; + const Elf_Sym *Sym = + DynSymRegion.getAsRange().begin() + SymIndex; SymbolName = errorOrDefault(Sym->getName(DynamicStringTable)); if (opts::ExpandRelocs) { DictScope Group(W, "Relocation"); @@ -1346,14 +1395,21 @@ void ELFDumper::printDynamicRelocation(Elf_Rela Rel) { template void ELFDumper::printSymbolsHelper(bool IsDynamic) { - const Elf_Shdr *Symtab = (IsDynamic) ? DotDynSymSec : DotSymtabSec; - if (!Symtab) - return; - ErrorOr StrTableOrErr = Obj->getStringTableForSymtab(*Symtab); - error(StrTableOrErr.getError()); - StringRef StrTable = *StrTableOrErr; - for (const Elf_Sym &Sym : Obj->symbols(Symtab)) - printSymbol(&Sym, Symtab, StrTable, IsDynamic); + StringRef StrTable = DynamicStringTable; + Elf_Sym_Range Syms(nullptr, nullptr); + if (IsDynamic) + Syms = DynSymRegion.getAsRange(); + else { + if (!DotSymtabSec) + return; + ErrorOr StrTableOrErr = + Obj->getStringTableForSymtab(*DotSymtabSec); + error(StrTableOrErr.getError()); + StrTable = *StrTableOrErr; + Syms = Obj->symbols(DotSymtabSec); + } + for (const Elf_Sym &Sym : Syms) + printSymbol(&Sym, Syms.begin(), StrTable, IsDynamic); } template @@ -1369,11 +1425,12 @@ void ELFDumper::printDynamicSymbols() { } template -void ELFDumper::printSymbol(const Elf_Sym *Symbol, const Elf_Shdr *SymTab, - StringRef StrTable, bool IsDynamic) { +void ELFDumper::printSymbol(const Elf_Sym *Symbol, + const Elf_Sym *FirstSym, StringRef StrTable, + bool IsDynamic) { unsigned SectionIndex = 0; StringRef SectionName; - getSectionNameIndex(*Obj, Symbol, SymTab, ShndxTable, SectionName, + getSectionNameIndex(*Obj, Symbol, FirstSym, ShndxTable, SectionName, SectionIndex); std::string FullSymbolName = getFullSymbolName(Symbol, StrTable, IsDynamic); unsigned char SymbolType = Symbol->getType(); @@ -1650,8 +1707,8 @@ template <> void ELFDumper>::printUnwindInfo() { template void ELFDumper::printDynamicTable() { - auto I = dynamic_table_begin(); - auto E = dynamic_table_end(); + auto I = dynamic_table().begin(); + auto E = dynamic_table().end(); if (I == E) return; @@ -1747,10 +1804,10 @@ void ELFDumper::printGnuHashTable() { W.printNumber("Shift Count", GnuHashTable->shift2); W.printHexList("Bloom Filter", GnuHashTable->filter()); W.printList("Buckets", GnuHashTable->buckets()); - if (!DotDynSymSec) + if (!DynSymRegion.Size || !DynSymRegion.EntSize) reportError("No dynamic symbol section"); - W.printHexList("Values", - GnuHashTable->values(DotDynSymSec->getEntityCount())); + W.printHexList( + "Values", GnuHashTable->values(DynSymRegion.Size / DynSymRegion.EntSize)); } template void ELFDumper::printLoadName() { @@ -1878,11 +1935,9 @@ template void MipsGOTParser::parseGOT() { return; } - const Elf_Shdr *DynSymSec = Dumper->getDotDynSymSec(); - ErrorOr StrTable = Obj->getStringTableForSymtab(*DynSymSec); - error(StrTable.getError()); - const Elf_Sym *DynSymBegin = Obj->symbol_begin(DynSymSec); - const Elf_Sym *DynSymEnd = Obj->symbol_end(DynSymSec); + StringRef StrTable = Dumper->getDynamicStringTable(); + const Elf_Sym *DynSymBegin = Dumper->dynamic_symbols().begin(); + const Elf_Sym *DynSymEnd = Dumper->dynamic_symbols().end(); std::size_t DynSymTotal = std::size_t(std::distance(DynSymBegin, DynSymEnd)); if (*DtGotSym > DynSymTotal) @@ -1942,8 +1997,8 @@ template void MipsGOTParser::parseGOT() { const Elf_Sym *GotDynSym = DynSymBegin + *DtGotSym; for (; It != GotGlobalEnd; ++It) { DictScope D(W, "Entry"); - printGlobalGotEntry(GOTShdr->sh_addr, GotBegin, It, GotDynSym++, - *StrTable, true); + printGlobalGotEntry(GOTShdr->sh_addr, GotBegin, It, GotDynSym++, StrTable, + true); } } @@ -2046,7 +2101,7 @@ void MipsGOTParser::printGlobalGotEntry( unsigned SectionIndex = 0; StringRef SectionName; - getSectionNameIndex(*Obj, Sym, Dumper->getDotDynSymSec(), + getSectionNameIndex(*Obj, Sym, Dumper->dynamic_symbols().begin(), Dumper->getShndxTable(), SectionName, SectionIndex); W.printHex("Section", SectionName, SectionIndex); @@ -2080,7 +2135,7 @@ void MipsGOTParser::printPLTEntry(uint64_t PLTAddr, unsigned SectionIndex = 0; StringRef SectionName; - getSectionNameIndex(*Obj, Sym, Dumper->getDotDynSymSec(), + getSectionNameIndex(*Obj, Sym, Dumper->dynamic_symbols().begin(), Dumper->getShndxTable(), SectionName, SectionIndex); W.printHex("Section", SectionName, SectionIndex); diff --git a/llvm/tools/llvm-readobj/llvm-readobj.h b/llvm/tools/llvm-readobj/llvm-readobj.h index 39af47810278..3eb21e434b7f 100644 --- a/llvm/tools/llvm-readobj/llvm-readobj.h +++ b/llvm/tools/llvm-readobj/llvm-readobj.h @@ -12,6 +12,7 @@ #include "llvm/Support/CommandLine.h" #include "llvm/Support/Compiler.h" +#include "llvm/Support/ErrorOr.h" #include namespace llvm { @@ -22,6 +23,11 @@ namespace llvm { // Various helper functions. LLVM_ATTRIBUTE_NORETURN void reportError(Twine Msg); void error(std::error_code ec); + template T unwrapOrError(ErrorOr EO) { + if (EO) + return *EO; + reportError(EO.getError().message()); + } bool relocAddressLess(object::RelocationRef A, object::RelocationRef B); } // namespace llvm