From b21ed75e107b10e7b82aa3da87c918214a4f0c0d Mon Sep 17 00:00:00 2001 From: Esme-Yi Date: Thu, 26 Aug 2021 07:17:06 +0000 Subject: [PATCH] [llvm-readobj][XCOFF] Add support for `--needed-libs` option. Summary: This patch is trying to add support for llvm-readobj --needed-libs option under XCOFF. For XCOFF, the needed libraries can be found from the Import File ID Name Table of the Loader Section. Currently, I am using binary inputs in the test since yaml2obj does not yet support for writing the Loader Section and the import file table. Reviewed By: jhenderson Differential Revision: https://reviews.llvm.org/D106643 --- llvm/include/llvm/Object/XCOFFObjectFile.h | 29 ++++++++ llvm/lib/Object/XCOFFObjectFile.cpp | 73 +++++++++++++++++++++ .../llvm-readobj/XCOFF/Inputs/needed-libs-32.o | Bin 0 -> 5583 bytes .../llvm-readobj/XCOFF/Inputs/needed-libs-64.o | Bin 0 -> 6660 bytes .../llvm-readobj/XCOFF/Inputs/needed-libs-empty.o | Bin 0 -> 1033 bytes .../test/tools/llvm-readobj/XCOFF/needed-libs.test | 29 ++++++++ llvm/tools/llvm-readobj/XCOFFDumper.cpp | 39 ++++++++++- 7 files changed, 169 insertions(+), 1 deletion(-) create mode 100755 llvm/test/tools/llvm-readobj/XCOFF/Inputs/needed-libs-32.o create mode 100755 llvm/test/tools/llvm-readobj/XCOFF/Inputs/needed-libs-64.o create mode 100644 llvm/test/tools/llvm-readobj/XCOFF/Inputs/needed-libs-empty.o create mode 100644 llvm/test/tools/llvm-readobj/XCOFF/needed-libs.test diff --git a/llvm/include/llvm/Object/XCOFFObjectFile.h b/llvm/include/llvm/Object/XCOFFObjectFile.h index c51c438..8765832 100644 --- a/llvm/include/llvm/Object/XCOFFObjectFile.h +++ b/llvm/include/llvm/Object/XCOFFObjectFile.h @@ -97,6 +97,31 @@ struct XCOFFSectionHeader64 : XCOFFSectionHeader { char Padding[4]; }; +struct LoaderSectionHeader32 { + support::ubig32_t Version; + support::ubig32_t NumberOfSymTabEnt; + support::ubig32_t NumberOfRelTabEnt; + support::ubig32_t LengthOfImpidStrTbl; + support::ubig32_t NumberOfImpid; + support::big32_t OffsetToImpid; + support::ubig32_t LengthOfStrTbl; + support::big32_t OffsetToStrTbl; +}; + +struct LoaderSectionHeader64 { + support::ubig32_t Version; + support::ubig32_t NumberOfSymTabEnt; + support::ubig32_t NumberOfRelTabEnt; + support::ubig32_t LengthOfImpidStrTbl; + support::ubig32_t NumberOfImpid; + support::ubig32_t LengthOfStrTbl; + support::big64_t OffsetToImpid; + support::big64_t OffsetToStrTbl; + support::big64_t OffsetToSymTbl; + char Padding[16]; + support::big32_t OffsetToRelEnt; +}; + struct XCOFFStringTable { uint32_t Size; const char *Data; @@ -290,6 +315,7 @@ private: const XCOFFSectionHeader64 *toSection64(DataRefImpl Ref) const; uintptr_t getSectionHeaderTableAddress() const; uintptr_t getEndOfSymbolTableAddress() const; + Expected getLoaderSectionAddress() const; // This returns a pointer to the start of the storage for the name field of // the 32-bit or 64-bit SectionHeader struct. This string is *not* necessarily @@ -429,6 +455,9 @@ public: template Expected> relocations(const Shdr &Sec) const; + // Loader section related interfaces. + Expected getImportFileTable() const; + // This function returns string table entry. Expected getStringTableEntry(uint32_t Offset) const; diff --git a/llvm/lib/Object/XCOFFObjectFile.cpp b/llvm/lib/Object/XCOFFObjectFile.cpp index 7ec418c..dfb48e6 100644 --- a/llvm/lib/Object/XCOFFObjectFile.cpp +++ b/llvm/lib/Object/XCOFFObjectFile.cpp @@ -307,6 +307,38 @@ uint64_t XCOFFObjectFile::getSectionAlignment(DataRefImpl Sec) const { return Result; } +Expected XCOFFObjectFile::getLoaderSectionAddress() const { + uint64_t OffsetToLoaderSection = 0; + uint64_t SizeOfLoaderSection = 0; + + if (is64Bit()) { + for (const auto &Sec64 : sections64()) + if (Sec64.getSectionType() == XCOFF::STYP_LOADER) { + OffsetToLoaderSection = Sec64.FileOffsetToRawData; + SizeOfLoaderSection = Sec64.SectionSize; + break; + } + } else { + for (const auto &Sec32 : sections32()) + if (Sec32.getSectionType() == XCOFF::STYP_LOADER) { + OffsetToLoaderSection = Sec32.FileOffsetToRawData; + SizeOfLoaderSection = Sec32.SectionSize; + break; + } + } + + // No loader section is not an error. + if (!SizeOfLoaderSection) + return 0; + + uintptr_t LoderSectionStart = + reinterpret_cast(base() + OffsetToLoaderSection); + if (Error E = + Binary::checkOffset(Data, LoderSectionStart, SizeOfLoaderSection)) + return std::move(E); + return LoderSectionStart; +} + bool XCOFFObjectFile::isSectionCompressed(DataRefImpl Sec) const { return false; } @@ -794,6 +826,47 @@ XCOFFObjectFile::parseStringTable(const XCOFFObjectFile *Obj, uint64_t Offset) { return XCOFFStringTable{Size, StringTablePtr}; } +// This function returns the import file table. Each entry in the import file +// table consists of: "path_name\0base_name\0archive_member_name\0". +Expected XCOFFObjectFile::getImportFileTable() const { + Expected LoaderSectionAddrOrError = getLoaderSectionAddress(); + if (!LoaderSectionAddrOrError) + return LoaderSectionAddrOrError.takeError(); + + uintptr_t LoaderSectionAddr = LoaderSectionAddrOrError.get(); + if (!LoaderSectionAddr) + return StringRef(); + + uint64_t OffsetToImportFileTable = 0; + uint64_t LengthOfImportFileTable = 0; + if (is64Bit()) { + const LoaderSectionHeader64 *LoaderSec64 = + viewAs(LoaderSectionAddr); + OffsetToImportFileTable = LoaderSec64->OffsetToImpid; + LengthOfImportFileTable = LoaderSec64->LengthOfImpidStrTbl; + } else { + const LoaderSectionHeader32 *LoaderSec32 = + viewAs(LoaderSectionAddr); + OffsetToImportFileTable = LoaderSec32->OffsetToImpid; + LengthOfImportFileTable = LoaderSec32->LengthOfImpidStrTbl; + } + + auto ImportTableOrErr = getObject( + Data, + reinterpret_cast(LoaderSectionAddr + OffsetToImportFileTable), + LengthOfImportFileTable); + if (Error E = ImportTableOrErr.takeError()) + return std::move(E); + + const char *ImportTablePtr = ImportTableOrErr.get(); + if (ImportTablePtr[LengthOfImportFileTable - 1] != '\0') + return createStringError( + object_error::parse_failed, + "the import file table must end with a null terminator"); + + return StringRef(ImportTablePtr, LengthOfImportFileTable); +} + Expected> XCOFFObjectFile::create(unsigned Type, MemoryBufferRef MBR) { // Can't use std::make_unique because of the private constructor. diff --git a/llvm/test/tools/llvm-readobj/XCOFF/Inputs/needed-libs-32.o b/llvm/test/tools/llvm-readobj/XCOFF/Inputs/needed-libs-32.o new file mode 100755 index 0000000000000000000000000000000000000000..6137aee2a48dc774463b17b7a5f5c46284fac793 GIT binary patch literal 5583 zcmb_gO>7(25uW8zGNq`I)Ch$e3-vm-1H~qGxs)Z#>>m{chMdZd+o*vH6kStGN@7fr z41Wv;RSQbFS`=tcL4m49Pd(&N6ge114>|OZgAX|vsA1&LLs9h5LjxFAznS-z zKtFk*3=4d2yGNKzS?P)1qa&VIZ{%tm>u77oD3OHl@-A7+MCY!w5k6^rzo{V66g}&Cjm=sim#=%p za}Nwx(-Df5TduojLhZde*XBd)~6@HQ!mQ)SYI%=JZTG?SC1BqYko(+mUC%C6Fpj| z2xJW)XTHeSD_t)&AC-kDsGNw^hZH-(eoE6ZF^=PY;QJ5;nCBi-a@>Qa@t?XJwg0sI zZjW5nL(B102y_myPOX3FG4QbBpx6=(Y0S?$%^6Mrk7zk610^)(huRU1r+`h3xju|) zJPjOYY&#ieqn>kWjVgE5TIJ1x->5q+r&aQ|s%xdZQ)`x;n>oK)b@GLqPOjK;^0{K^ zZEX0|f;%sXf@Jt#)l{kt=hDlUVRkE5uR9lPq>UsW49>g%KkdHb&Ih_PUFR_agoM!f zc8=t@-)F`o?DQ%^MiR*~#;^DtTSSkKqD!z2bY#dZFfl zSS%OvUOBf_5N5aDk9u7E*#@7H&Op)pxCvwfeO1s!peaGG0)6eZ=P-H&$QIcTfKq~Z z0@H$afxaQ=7SJ2Neja!H1}H7EJ)m=f?f?~K^bt`0eb|k$2MV!`Ws&hQ>QzB}7F!YY zXP_&B{u#*38K75=kE0H;r$>3zyb4rj8|HgJ*Jbp#K+lh3G|v0B%%gGk*%H|wfL<6k zb@tiEQNtwnE(+o-Szsi2_o5)qx(Pua0c8c=iT(88RzeYd|v~589{#;kp^&aMeN!*U$(@ z>ru?^Ik=y#aBYp~(YCZ6U1tyEoYCCA^U`B;eL33J>T7s(pkW>PU4m}(#Ai}_5cmwv z;|@ok_9vxs2No!fHGsofPk+vLWn~ZM%z=|QM9&#;#tz|(gM(!1?@zGq;7kqT1p5b^ zqk}lX-T-HM5XZvvLPzQJ{*%wmjUZ(F6wmBG8H2>u4?t9j8D`5`{7w-kH9yLcJ@%p+ z#5ARapQC#Ja0a1GhW9Gg0_Tk&K1t2dd!y>Lai|y8 zU*BNPzYpX<-gdOZx*%ec-GqL)+`{N2|aOZ@qc68GxB_CURkSu#I|=V6BvSyOd~aUPt{4&ht|=kJGb zJaGOoh|{wc*VJ0LwyzwB{59Uzes$!=FBHU7I}J}T$ux;iTZ#1nlx+Q~q&aFWRuw1E z(c{m0@7^%@IU8!m=j!sXy=D zi1WvtIQL!m*bCr1=y3G9PwHIWC>6^$Z27EnLsukS+7Pijomued0&P+r)Hwb`II`<> zd5dXIkLIe@tP3kNw+CvDa71&7Z6g#B&HLP>it6z>MD>F~nxh=i{Fat#&9Jf9bCf*b zASowDb>QqCBKZ}{laFbPc;_LqgAb#gx8&h~-zaVsysCUaYF5d%ou~f~crkwZ1(sHu z1#7XnVYv&IdoJU;nbd-nPPurt;(%{mTd|g`^-9fJymT#Ty-}#uiveW!9 z3Vnl$T|mm(4`?-xA3vQ^DB!XuaA2D^<< z0jb$cI-P;X=~UY7y6r5TJ=@21d7rRT{lkVp4v1XjlLD=7HpTv|YjMm{c+=;wp&Z)b QZ$#a7@5~cX>bz3?7Z8aR=Kufz literal 0 HcmV?d00001 diff --git a/llvm/test/tools/llvm-readobj/XCOFF/Inputs/needed-libs-64.o b/llvm/test/tools/llvm-readobj/XCOFF/Inputs/needed-libs-64.o new file mode 100755 index 0000000000000000000000000000000000000000..98504eb02e46b516b4963d7ac6ea244c779f2a6b GIT binary patch literal 6660 zcmb_gU2Ggz6+Sy&dpC*WIBh6)TcQbxDkm{BJL{ipRzU4ILJq`kXccE@n8iJ1rVqYJX8oIE8-zY2$d)Lz(W=Bu;Gb5;R3Sx&Ye4V zc6Pm4)8;1YJKs6qoO{pD+_`r`|Dtf}=#)mH_1vdQFJHeN+D9Q*#(iiL*P&kOeBbRO zG14H{@Gndq6rm35ykv{6;{z9o`}i`7AMWq^rz>y$*C=NyWmm1nmE%L&Xt%q&&eG@P zwa&efPL)%xpl;q`{*Zd}^6>uKE>-;fjJzJ>-k2+uB!->HeO!Azi`lPst;z%=mrtcL z#TMM~Syv(Kx8U@)kbg39?HuJ)QP6nNS`Dco~{xQH@4FuuJGp&_1JcKv6xAvOLlfSt4yv&wL6LW zcHqPs>@m7I4Z_H2H-TuSZwzu!P&gTV9x& zdoMn#Ka2bZHFJ?;gg8%e&Kk$xVZ1@w@1$}$yHH*Xgk24Unwk|gh9|jpo}wHF#9J4H z?sbpX=UqJR-t$lTwZeYY;Nxnv;||BRuAUG_ta(JoD7=))E=kg_UrBpN>r)1``bNoZn#RF&Z z17|pcx+@#h!95j^>7!=cGGnK7Ya|&@Bu9AJAhtVd?Xe82wOz*y*040~V7Rn0o-pIW z_E0i*IvKC8aCqds&+r}-In_3}N8A{D4LnhYjdD-#^{oFi^@;nv_mF4u6ZM>_z4+n% z75X}QtYmZ*KQyi4_8ot8d*b>)3k|rv_^ToMoh+=A@g;1IvE4@bXIsb*x3Ket7V=Xq zF~^ei?@7E*;th#A4Kryjlu~A~T;Q%y%wNhl<&s%3D>-MWFqcc4#g%3A zO3En|%yj08naWnobSj&B9S?sjVU3DK0}I2aHIpxt&2wj_FziyQR5DK+SVF`?gaJpb z$7kI!tx?Z*(w{s$Kxhb^W2C6GShPonjl2+e%b=833JW8?GBxLaxgiz9p3jG-9C58T6uM6{&GWq-g{Kd?|Y_rc}hKGS(^X3vR z0Hqak4e03ua%P=;ekpp)PSzb$x?cc2=OX!rh~uflc)VVr|EfYC0)5d#UA(4uDa0$_ z357O+p70PaCUjOI_Q==u0nI6$9?*>e%`066Xs<$5pqN6}fqE6X0o0?=J3zcH3XdY| z=)(%#1?pDlT_8=N_kc*D4FK0$7IWh@jWlFMHFx#@kHQ$2uLB%j*@@~oJuC=tn(g%O zg2S~Rw9`D+$z5=UcEOo$;xy0sl_riqA71NY&^!Egyj&N(2X-`Z-;6IR}IFlYsQQ%8qy%iJo-r$+04Q=l2yS>e_iG$SFYjw≪ zhtKgpX~T(ub6atC9_v0hzvE-F@ZID1enCyxkJ4YZw@6!X>zwGXEEes*ZWrQrAR0pM zNqBTLgq0;wXdCD*c=-y=LW(95Eps6`GvMfAK4)AGY;cn~6|ayqb41>E;2@_rFxGc? zaKRBzK8nuwi=Snf485%4(;Jl?cUVM55*URaP;QXi!=OQ@2Y{Qua=l74` z@SxwsPv*ih9G3Xai@eNET`oRyNeG9`1qZ^<1yxT<#G5`KZ& z(8Q|GDz6f>ZwbVS_h#5s8(}>#pIP^gU~Mo*dri$pa_Z)ToOa29!Gh2-aLEGv$%Twp`EOIqHRtuHTX%R{9j3+;x(ahqCn8lE#TQPhpOO6b4 h7*FYB1i!EPb)&pp$Yq!LaEUq*rD$-KBC_gC_&?TOh7kY& literal 0 HcmV?d00001 diff --git a/llvm/test/tools/llvm-readobj/XCOFF/Inputs/needed-libs-empty.o b/llvm/test/tools/llvm-readobj/XCOFF/Inputs/needed-libs-empty.o new file mode 100644 index 0000000000000000000000000000000000000000..98f2ce1a26c6df42606e42b8a325223cdbdbbd9c GIT binary patch literal 1033 zcmdr~Jx{_=6uoU3h!TawI2a?3=!U7Z7)2(Km`D^^jA67Y5TeoqYU04~1_nn47ykgi z!++whaJAl#s>Lumd7Jm%>AB~f*LQo3H?X|TW){FK0l+G(0~m{l05py?fmmoeXg>xq z0-?qoI84zRoK*IW7kCWW2lM1*;$p5bZSh>OuZBZL025qk%nLn_{14nHX-=PW;p@bJ zROI{Ew8`lgb>mgj5ma#ZkXvOlvpIwd`}UPCf-Z9i8X1E z4vJJWeS{g-d^^kmc+Rby#mR#&pLl5vP$p>>BuU>(ao(&6pf5#|eIh2aEFfkxCJp;g zWic|5Urh7k6ICk{-Old#zU-2jed2`RqlVvC)rYQfi>gp87v1vizH$q$qo97+P_0u{ c+o|RAs^bq-wcgrR7wy5YhkKko+rg&*pJLxen*aa+ literal 0 HcmV?d00001 diff --git a/llvm/test/tools/llvm-readobj/XCOFF/needed-libs.test b/llvm/test/tools/llvm-readobj/XCOFF/needed-libs.test new file mode 100644 index 0000000..3dea70a --- /dev/null +++ b/llvm/test/tools/llvm-readobj/XCOFF/needed-libs.test @@ -0,0 +1,29 @@ +## In this test we check the --needed-libs option. + +# RUN: llvm-readobj --needed-libs %p/Inputs/needed-libs-32.o \ +# RUN: %p/Inputs/needed-libs-64.o %p/Inputs/needed-libs-empty.o |\ +# RUN: FileCheck %s --strict-whitespace --match-full-lines + +## Check 32-bit. + +# CHECK:NeededLibraries [ +# CHECK-NEXT: BASE MEMBER +# CHECK-NEXT: libc.a shr.o +# CHECK-NEXT: libpthreads.a shr_xpg5.o +# CHECK-NEXT: libabcdefghijk.a +# CHECK-NEXT:] + +## Check 64-bit. + +# CHECK:NeededLibraries [ +# CHECK-NEXT: BASE MEMBER +# CHECK-NEXT: libc.a shr_64.o +# CHECK-NEXT: libpthreads.a shr_xpg5_64.o +# CHECK-NEXT: libabcdefghijk64.a +# CHECK-NEXT:] + +## Check no lib. + +# CHECK:NeededLibraries [ +# CHECK-NEXT: BASE MEMBER +# CHECK-NEXT:] diff --git a/llvm/tools/llvm-readobj/XCOFFDumper.cpp b/llvm/tools/llvm-readobj/XCOFFDumper.cpp index 9371901..3d9e9e6 100644 --- a/llvm/tools/llvm-readobj/XCOFFDumper.cpp +++ b/llvm/tools/llvm-readobj/XCOFFDumper.cpp @@ -13,6 +13,7 @@ #include "ObjDumper.h" #include "llvm-readobj.h" #include "llvm/Object/XCOFFObjectFile.h" +#include "llvm/Support/FormattedStream.h" #include "llvm/Support/ScopedPrinter.h" using namespace llvm; @@ -494,7 +495,43 @@ void XCOFFDumper::printStackMap() const { } void XCOFFDumper::printNeededLibraries() { - llvm_unreachable("Unimplemented functionality for XCOFFDumper"); + ListScope D(W, "NeededLibraries"); + auto ImportFilesOrError = Obj.getImportFileTable(); + if (!ImportFilesOrError) { + reportUniqueWarning(ImportFilesOrError.takeError()); + return; + } + + StringRef ImportFileTable = ImportFilesOrError.get(); + const char *CurrentStr = ImportFileTable.data(); + const char *TableEnd = ImportFileTable.end(); + // Default column width for names is 13 even if no names are that long. + size_t BaseWidth = 13; + + // Get the max width of BASE columns. + for (size_t StrIndex = 0; CurrentStr < TableEnd; ++StrIndex) { + size_t CurrentLen = strlen(CurrentStr); + CurrentStr += strlen(CurrentStr) + 1; + if (StrIndex % 3 == 1) + BaseWidth = std::max(BaseWidth, CurrentLen); + } + + auto &OS = static_cast(W.startLine()); + // Each entry consists of 3 strings: the path_name, base_name and + // archive_member_name. The first entry is a default LIBPATH value and other + // entries have no path_name. We just dump the base_name and + // archive_member_name here. + OS << left_justify("BASE", BaseWidth) << " MEMBER\n"; + CurrentStr = ImportFileTable.data(); + for (size_t StrIndex = 0; CurrentStr < TableEnd; + ++StrIndex, CurrentStr += strlen(CurrentStr) + 1) { + if (StrIndex >= 3 && StrIndex % 3 != 0) { + if (StrIndex % 3 == 1) + OS << " " << left_justify(CurrentStr, BaseWidth) << " "; + else + OS << CurrentStr << "\n"; + } + } } static const EnumEntry SectionTypeFlagsNames[] = { -- 2.7.4