From 158083f0de033dec4f4f9a68f558da6e68d30c35 Mon Sep 17 00:00:00 2001 From: zhijian Date: Tue, 26 Oct 2021 10:40:25 -0400 Subject: [PATCH] [AIX][XCOFF] parsing xcoff object file auxiliary header Summary: The patch supports parsing the xcoff object file auxiliary header with llvm-readobj with option "auxiliary-headers" the format of auxiliary header as https://www.ibm.com/support/knowledgecenter/en/ssw_aix_72/filesreference/XCOFF.html#XCOFF__fyovh386shar Reviewers: James Henderson, Jason Liu, Hubert Tong, Esme yi, Sean Fertile. Differential Revision: https://reviews.llvm.org/D82549 --- llvm/docs/CommandGuide/llvm-readobj.rst | 9 + llvm/include/llvm/Object/XCOFFObjectFile.h | 99 ++++++++++ llvm/lib/Object/XCOFFObjectFile.cpp | 21 +- .../XCOFF/Inputs/xcoff-32-xlc-exec | Bin 0 -> 4813 bytes .../XCOFF/Inputs/xcoff-32-xlc-obj-malform.o | Bin 0 -> 1691 bytes .../XCOFF/Inputs/xcoff-32-xlc-obj.o | Bin 0 -> 1690 bytes .../XCOFF/Inputs/xcoff-64-xlc-exec | Bin 0 -> 5659 bytes .../tools/llvm-readobj/XCOFF/lit.local.cfg | 2 + .../XCOFF/xcoff-auxiliary-header.test | 125 ++++++++++++ llvm/tools/llvm-readobj/ObjDumper.h | 3 + llvm/tools/llvm-readobj/Opts.td | 4 + llvm/tools/llvm-readobj/XCOFFDumper.cpp | 182 ++++++++++++++++++ llvm/tools/llvm-readobj/llvm-readobj.cpp | 11 ++ 13 files changed, 454 insertions(+), 2 deletions(-) create mode 100755 llvm/test/tools/llvm-readobj/XCOFF/Inputs/xcoff-32-xlc-exec create mode 100644 llvm/test/tools/llvm-readobj/XCOFF/Inputs/xcoff-32-xlc-obj-malform.o create mode 100644 llvm/test/tools/llvm-readobj/XCOFF/Inputs/xcoff-32-xlc-obj.o create mode 100755 llvm/test/tools/llvm-readobj/XCOFF/Inputs/xcoff-64-xlc-exec create mode 100644 llvm/test/tools/llvm-readobj/XCOFF/lit.local.cfg create mode 100644 llvm/test/tools/llvm-readobj/XCOFF/xcoff-auxiliary-header.test diff --git a/llvm/docs/CommandGuide/llvm-readobj.rst b/llvm/docs/CommandGuide/llvm-readobj.rst index 2fb639fc30092..068808e42c4dd 100644 --- a/llvm/docs/CommandGuide/llvm-readobj.rst +++ b/llvm/docs/CommandGuide/llvm-readobj.rst @@ -311,6 +311,15 @@ The following options are implemented only for the PE/COFF file format. Display the .rsrc section. +XCOFF SPECIFIC OPTIONS +---------------------- + +The following options are implemented only for the XCOFF file format. + +.. option:: --auxiliary-header + + Display XCOFF Auxiliary header. + EXIT STATUS ----------- diff --git a/llvm/include/llvm/Object/XCOFFObjectFile.h b/llvm/include/llvm/Object/XCOFFObjectFile.h index 4b195f13e5091..94136afc45ea2 100644 --- a/llvm/include/llvm/Object/XCOFFObjectFile.h +++ b/llvm/include/llvm/Object/XCOFFObjectFile.h @@ -51,6 +51,101 @@ struct XCOFFFileHeader64 { support::ubig32_t NumberOfSymTableEntries; }; +template struct XCOFFAuxiliaryHeader { + static constexpr uint8_t AuxiHeaderFlagMask = 0xF0; + static constexpr uint8_t AuxiHeaderTDataAlignmentMask = 0x0F; + +public: + uint8_t getFlag() const { + return static_cast(this)->FlagAndTDataAlignment & + AuxiHeaderFlagMask; + } + uint8_t getTDataAlignment() const { + return static_cast(this)->FlagAndTDataAlignment & + AuxiHeaderTDataAlignmentMask; + } +}; + +struct XCOFFAuxiliaryHeader32 : XCOFFAuxiliaryHeader { + support::ubig16_t + AuxMagic; ///< If the value of the o_vstamp field is greater than 1, the + ///< o_mflags field is reserved for future use and it should + ///< contain 0. Otherwise, this field is not used. + support::ubig16_t + Version; ///< The valid values are 1 and 2. When the o_vstamp field is 2 + ///< in an XCOFF32 file, the new interpretation of the n_type + ///< field in the symbol table entry is used. + support::ubig32_t TextSize; + support::ubig32_t InitDataSize; + support::ubig32_t BssDataSize; + support::ubig32_t EntryPointAddr; + support::ubig32_t TextStartAddr; + support::ubig32_t DataStartAddr; + support::ubig32_t TOCAnchorAddr; + support::ubig16_t SecNumOfEntryPoint; + support::ubig16_t SecNumOfText; + support::ubig16_t SecNumOfData; + support::ubig16_t SecNumOfTOC; + support::ubig16_t SecNumOfLoader; + support::ubig16_t SecNumOfBSS; + support::ubig16_t MaxAlignOfText; + support::ubig16_t MaxAlignOfData; + support::ubig16_t ModuleType; + uint8_t CpuFlag; + uint8_t CpuType; + support::ubig32_t MaxStackSize; ///< If the value is 0, the system default + ///< maximum stack size is used. + support::ubig32_t MaxDataSize; ///< If the value is 0, the system default + ///< maximum data size is used. + support::ubig32_t + ReservedForDebugger; ///< This field should contain 0. When a loaded + ///< program is being debugged, the memory image of + ///< this field may be modified by a debugger to + ///< insert a trap instruction. + uint8_t TextPageSize; ///< Specifies the size of pages for the exec text. The + ///< default value is 0 (system-selected page size). + uint8_t DataPageSize; ///< Specifies the size of pages for the exec data. The + ///< default value is 0 (system-selected page size). + uint8_t StackPageSize; ///< Specifies the size of pages for the stack. The + ///< default value is 0 (system-selected page size). + uint8_t FlagAndTDataAlignment; + support::ubig16_t SecNumOfTData; + support::ubig16_t SecNumOfTBSS; +}; + +struct XCOFFAuxiliaryHeader64 : XCOFFAuxiliaryHeader { + support::ubig16_t AuxMagic; + support::ubig16_t Version; + support::ubig32_t ReservedForDebugger; + support::ubig64_t TextStartAddr; + support::ubig64_t DataStartAddr; + support::ubig64_t TOCAnchorAddr; + support::ubig16_t SecNumOfEntryPoint; + support::ubig16_t SecNumOfText; + support::ubig16_t SecNumOfData; + support::ubig16_t SecNumOfTOC; + support::ubig16_t SecNumOfLoader; + support::ubig16_t SecNumOfBSS; + support::ubig16_t MaxAlignOfText; + support::ubig16_t MaxAlignOfData; + support::ubig16_t ModuleType; + uint8_t CpuFlag; + uint8_t CpuType; + uint8_t TextPageSize; + uint8_t DataPageSize; + uint8_t StackPageSize; + uint8_t FlagAndTDataAlignment; + support::ubig64_t TextSize; + support::ubig64_t InitDataSize; + support::ubig64_t BssDataSize; + support::ubig64_t EntryPointAddr; + support::ubig64_t MaxStackSize; + support::ubig64_t MaxDataSize; + support::ubig16_t SecNumOfTData; + support::ubig16_t SecNumOfTBSS; + support::ubig16_t XCOFF64Flag; +}; + template struct XCOFFSectionHeader { // Least significant 3 bits are reserved. static constexpr unsigned SectionFlagsReservedMask = 0x7; @@ -296,6 +391,7 @@ class XCOFFSymbolRef; class XCOFFObjectFile : public ObjectFile { private: const void *FileHeader = nullptr; + const void *AuxiliaryHeader = nullptr; const void *SectionHeaderTable = nullptr; const void *SymbolTblPtr = nullptr; @@ -402,6 +498,9 @@ class XCOFFObjectFile : public ObjectFile { // Below here is the non-inherited interface. bool is64Bit() const; + const XCOFFAuxiliaryHeader32 *auxiliaryHeader32() const; + const XCOFFAuxiliaryHeader64 *auxiliaryHeader64() const; + const void *getPointerToSymbolTable() const { return SymbolTblPtr; } Expected getSymbolSectionName(XCOFFSymbolRef Ref) const; diff --git a/llvm/lib/Object/XCOFFObjectFile.cpp b/llvm/lib/Object/XCOFFObjectFile.cpp index 1a3a394ce9cb7..9b0a5efacba7a 100644 --- a/llvm/lib/Object/XCOFFObjectFile.cpp +++ b/llvm/lib/Object/XCOFFObjectFile.cpp @@ -149,6 +149,16 @@ const XCOFFFileHeader64 *XCOFFObjectFile::fileHeader64() const { return static_cast(FileHeader); } +const XCOFFAuxiliaryHeader32 *XCOFFObjectFile::auxiliaryHeader32() const { + assert(!is64Bit() && "32-bit interface called on 64-bit object file."); + return static_cast(AuxiliaryHeader); +} + +const XCOFFAuxiliaryHeader64 *XCOFFObjectFile::auxiliaryHeader64() const { + assert(is64Bit() && "64-bit interface called on a 32-bit object file."); + return static_cast(AuxiliaryHeader); +} + template const T *XCOFFObjectFile::sectionHeaderTable() const { return static_cast(SectionHeaderTable); } @@ -1027,8 +1037,15 @@ XCOFFObjectFile::create(unsigned Type, MemoryBufferRef MBR) { Obj->FileHeader = FileHeaderOrErr.get(); CurOffset += Obj->getFileHeaderSize(); - // TODO FIXME we don't have support for an optional header yet, so just skip - // past it. + + if (Obj->getOptionalHeaderSize()) { + auto AuxiliaryHeaderOrErr = + getObject(Data, Base + CurOffset, Obj->getOptionalHeaderSize()); + if (Error E = AuxiliaryHeaderOrErr.takeError()) + return std::move(E); + Obj->AuxiliaryHeader = AuxiliaryHeaderOrErr.get(); + } + CurOffset += Obj->getOptionalHeaderSize(); // Parse the section header table if it is present. diff --git a/llvm/test/tools/llvm-readobj/XCOFF/Inputs/xcoff-32-xlc-exec b/llvm/test/tools/llvm-readobj/XCOFF/Inputs/xcoff-32-xlc-exec new file mode 100755 index 0000000000000000000000000000000000000000..f06f5993efba9f2308d32b61e1e834537d6a91ce GIT binary patch literal 4813 zcmb_gO>7&-6@E)nGUX5!m8gMJ8}Q0j3q=-oNlKPwHLXdh5aizoiP9)Q+SQ7rBsLUD za91wVGR0DM0Ur#6Y;|x8A7oS&a!3I8QuNS+lDeo50eWqV0)^caDB4S|EdsIMo1LXd zRzES)k$2xWZ@!s%^WK};p_RW<;5*T+E~2BqA)+^EI_y)PA%!S#7xho^1XSvr3zIUS zQpYxMmV9XU;V(dbIzs;FRj~Fbnw>7$&~smY+%Z{p%?kSS;;m{a(>4L!@jJEwF)z!b z5n!TY;vLr(EQ=9rc)$-}K(w^J94(tSQ|V%p*0)J6zeyKv!iPiWBcjR#4SZegRE9c< z%DEGz^1EkBc`-B`L~=`(LP9Y z-3jzL;9S78&J!AY=aV0le%NudR69a6O}<~wyLxp9b&L^o7N~!k{D0y;qID}5u)<~Tu8oBPky`u2=eist;(lNuZmy2mLWf_@VrZE-# z5?t@AZc)P;pKx zpJSZkhjA(unjY(;_&c}#TfA=AC&#Tnyi%{fC;gCccKz@d>TUHyJTVnBqMnwLYrW614uPkIIiAKkEw*{t@<~ehc+`vObOa9n?2v zea5L!Y0RW}$2v%pVMZ_RNnIi#{0`#&|L zqQhu(0x}kfoHvGt6A^VxkLi)~YIJx!a$!6sc7yx9=*))6$9828G-{tl{vLQuVd{|k zQTQLH3x5@q(~v&MImki4@288!T;A(M@eV+RtLf72nFY@s_4M3^f-$)4>J1}Vv?DiM zb<;Rf(e29J@x2omYn>xsACE7JT!V57a{xbt(!=;Fkk8el4~oQZ?sD9?N`0zHzYg3f z_57XgkoaB`X9M_%)Nca&B^G{^_jX(}Il^+@2Lj*)#}GtPGs#*mYRIW)3}Ypql3%|QsF>MoK5494>7tQJFJ^M- zl#w%6(tO`RF49o9A4mfV2{Z+COrXm^;g_F7>vf=hp?d}Bs{--V&kD2#)GJUGXy&J1 zMvtEX4G7&9(4asZ(bu`v$9epXcQLPTqJj97iVNM3fhGj{70@>Y`ZLfJBR}?&tMg9- zji2fcQ-G~{o?AQEmgC)ina};Fu&YHjza$Xnvc^bc@=1X>kBT$e=di1j8H^sB zzsNx#&fe1kZ2$!Y;>^X)Kr65E6@fTwv2$AYI#ddCW#OHV(z@^4IE`H@r~&cDt7RO? zX+00xIC3u8U!Dznb7o(j6f~@d@6q&Dlg&M{r#BZk>kW>yuE+0LDP#bgyN7TF!MS$` zryHD&{WzYV!P(r8<5>mHd;4*`Sb+2XejHVv*BI|aedpi)C2!ynfJl8O1dS#STkM7b zKHY^6f8i2)B)^>_VtUeTgxf`FJ+o!Jf^J(+Yi_`Y9or3?ha^YFyJ`B0a*0?KSaO?)BEv9Y{ zT^_J&HSxezXE z6nqmLZ-06E)_5tumK--;S6j!>9JbnYiB}FGReKyV@6IIxS^0xwkZn z>Rj9tKprLN)v%BT++IC=H$>6eIAZqK+%})&5Gj9X`l=uBP3PO7A^x9&5ibk|?SBO@ zj7bAmCOfl|HVWdm`D%eQP5r=s3tDW4XNKs7p)BVQC#%3h!*8Dv*qV|TV4K)HH?D2EN(bPF~4f#N<+qi<=%OA zH6=S^*x5`QFK1=jG)5|!Hj??3f@!z5yq->}m(83SyMV=v508uw4`U^<$nHw?$+Kto PSdF-PY9plW{bTgMs5kWP literal 0 HcmV?d00001 diff --git a/llvm/test/tools/llvm-readobj/XCOFF/Inputs/xcoff-32-xlc-obj-malform.o b/llvm/test/tools/llvm-readobj/XCOFF/Inputs/xcoff-32-xlc-obj-malform.o new file mode 100644 index 0000000000000000000000000000000000000000..678b83fae26c5e06ce6529a7ed0b8feb557ae0c5 GIT binary patch literal 1691 zcmds1OHUI~6#izW#sM2GrW#+tsgI4Av8`wdF`<=c#Ag>oyCBj^i!@>(vBruz|o zcLf1Ai(o8-^j!f<9c#y_xPa;1Ca{P@nQV4+dMaNi6-P&}UrI_e96{OCS6^<_HeC%S zXNk{!hglr}$TLanqfOD8v}syD?F4OrcA7RwE4jXkEh83lFzJw+LvDiH1i6WM1S)6A zcMtjgBHvHs`;2oqNQz|)i#4Rg21XnWX(xoNlfcBS+SWT&(}DQwGe`qM!+O~?R%0Pl z=Qvx-nIyO;&*V3JPc!*~I;nqDI=?&p2p1=pqP`Ugstr6KfOwosS^x>I_!1THh3nu8 zqn>&ABwgJ{bxa|XD5#M9w*3kPhyn_+C-y6J!i(AC`Nt<8 literal 0 HcmV?d00001 diff --git a/llvm/test/tools/llvm-readobj/XCOFF/Inputs/xcoff-32-xlc-obj.o b/llvm/test/tools/llvm-readobj/XCOFF/Inputs/xcoff-32-xlc-obj.o new file mode 100644 index 0000000000000000000000000000000000000000..109177cac74c8ecd5476c0aa73a58e6bbf4ac8cf GIT binary patch literal 1690 zcmds1OHUI~6#izW#z7k`rW!Q_r#?1f#KEN+tBOoRategfaKKR_9Fx`*v zyK4xzSp;Jtr0)n=>R7u@#sy68Hi2av&SbOWvorZZsW?7zW!pfw&iLt zIZJ%uJIv}3K%PljA8m@(q)pTMX{Trdw6nB9TFLcgY!$JXgK3A{9C8!nCdf@JB2YO) zzI({`7x{i7->00zK~k(@RJ=z@Y+}sOkaj}IItfhOtZlzlH64h*K7%wMG;EYjV?7o^ zb%C?BoJoRv@=Sii_au`qsFV6frSrSfk8*KxDe7C1pxVGg0*J@Cqy>=Rimy-sU$_oE zH|m*3PSDkTRL2!EiGm8rZ`-d>fGD64d*XmXJzmV7%unYCrPQ{&j7LT(S1d&%_JkK} z(Xt1n@%JF?RRKu$ZEplq3@*l7l9|)`K5$d!@U`(?1+Ns^-UiO7a_V~>4Qo91da3P! z_N1%I)nMte*FJAk@|9vYud_;~9dkzS4tvRR8vbOjhIAinpoZ1Wot*k7&-6@E)n5^XCso!F^t2kk0t6U9+?Nm`aA^~aQC81iq7L`aqXtyUy0F`-D7 zOBoER7%R62p_j;M4=&Jy(x!%iqCifqd#aM=;6o4T%`JMcg&wH-;+{&^f!OcO&JIag z65TX?((c>uy>DmUn>VvNTJ`d;kU{Uqdxm#G{H;PSiLF48<3YpsfFEkf-HPj?JZ z0QLa>LKLJ93dYV#wosul4{5HnhM{qPM?~T+l~GEUOP*KtEBl94waf89c0KE9aqg1W zI%^|kmu%0_5VwdQRzEHucNRUWIQuas7#UNJBdlKhE4b!7ShH|mt;A)5kM-?Go+28)LY-?@Xr}rnqWK-c>y=k1eDyF<^`F#rdGsgc^KPiS0U=nG zoyTe|1+0-<3CVFfL1BMvDpS-oKY8d)BF1vGiK9zSX&X+@W3&@(#aUY* zcc2?}S`1$2yb+&lxAxJQTJ46HyguyK$Kh|ZuX!92!zbfb%pa!zUSsUOU$tqax3bBeqBh8PN!57Avk8|vG#Pc7_S>nHRmf*@CC9Q(9=*U<xUJCkd!5!SRT z)_5n{I7?xkkC?BzV0AA0r$^ke=2GBtFhtkM9&vr z=#TA)8L@s{cZx}KD({$cPSH#z9W$Gm;v;D`&rKuQtFsyFHr1=+hW^+HbUYe8W*s>) z9MuQRxEVdB$Bqm|2Z!Q*p%H=qzQcPCKt2cfxzG6jCH{M=Rr`piy{Cc1BZem`;RT_6 z89IRDJ2)WP9ib@L=4tZdmv&(VKf!)(r%`soj^h#g=eDqaev5X#vW5NF20M>0zvRX# z(9Qk&BE|(viu2+a8INti7bF%O_^(MU^5S+S<~F&XuIBqY^bP)=4SrW*9%sIPaf5$J z;&$ox`^Q^A@Ry}OEb$GA`31x6y)QAKz&9msGp8NfEM=!y6^i-S)5(%!md$cDIa`>@ zrp)48&b(wN3k5UQZ^VqKX=lo2%FblpG%?R(@jkIgunLC$_m=X7l6h+696F!19mgCL z{qfpEpZ&4Vw1cFdj)*#{+ zR7eLJQiz|Cb)O3qR=!1`=M-83YFCK+3n;VAA`fQp}Cz$`+EK{IOaASeo_svFIKhpV--1!ox?vjvAM8*0JfdQY_A@GRKB4F_)e0-tK@ z5435%VClp0T5Y{EAS@VJu>(o+DiY)T8^NNzo)Y8S$Px2L_nf@UAbu?(xK43Ag2M=M zpgzZV^(A1c*J6elM0@M=hijUEDXZEMGn?osuRXu70yrhbk##@R%qfF2uQ;2xGY`&> zT5xzC{#bD~?`s8|_xQ()$ld4E^MafByT$Ko>lB#w<|ok~*ev7|srhLSK{2F7>+&oZ zR<^()Zl3V#rMaG;e+ffmy_lnY6&zi}!x=yt>xFg_;GAKOsQV@y)awQ~Hs2^XY0(TF zsOQD?(!u$f8Xp;NbKN_}zULEsA)^& zZ-}y4IWjat~lmNK(x zs~~n&1 | \ +# RUN: FileCheck --check-prefixes=XLC64EXEC,WARN64 %s + +# RUN: llvm-readobj --auxiliary-header %p/Inputs/xcoff-32-xlc-exec | \ +# RUN: FileCheck --check-prefix=XLC32EXEC %s + +# RUN: llvm-readobj --auxiliary-header %p/Inputs/xcoff-32-xlc-obj.o | \ +# RUN: FileCheck --check-prefix=XLC32OBJ %s + +# RUN: llvm-readobj --headers %p/Inputs/xcoff-32-xlc-obj.o | \ +# RUN: FileCheck --check-prefix=XLC32OBJ %s + +# RUN: llvm-readobj --auxiliary-header %p/Inputs/xcoff-32-xlc-obj-malform.o 2>&1 | \ +# RUN: FileCheck --check-prefixes=XLC32OBJ-PART,WARN-PART %s + +# XLC32EXEC: File: {{.*}}xcoff-32-xlc-exec +# XLC32EXEC-NEXT: Format: aixcoff-rs6000 +# XLC32EXEC-NEXT: Arch: powerpc +# XLC32EXEC-NEXT: AddressSize: 32bit +# XLC32EXEC-NEXT: AuxiliaryHeader { +# XLC32EXEC-NEXT: Magic: 0x10B +# XLC32EXEC-NEXT: Version: 0x1 +# XLC32EXEC-NEXT: Size of .text section: 0x498 +# XLC32EXEC-NEXT: Size of .data section: 0xF0 +# XLC32EXEC-NEXT: Size of .bss section: 0x4 +# XLC32EXEC-NEXT: Entry point address: 0x20000658 +# XLC32EXEC-NEXT: .text section start address: 0x10000128 +# XLC32EXEC-NEXT: .data section start address: 0x200005C0 +# XLC32EXEC-NEXT: TOC anchor address: 0x2000066C +# XLC32EXEC-NEXT: Section number of entryPoint: 2 +# XLC32EXEC-NEXT: Section number of .text: 1 +# XLC32EXEC-NEXT: Section number of .data: 2 +# XLC32EXEC-NEXT: Section number of TOC: 2 +# XLC32EXEC-NEXT: Section number of loader data: 4 +# XLC32EXEC-NEXT: Section number of .bss: 3 +# XLC32EXEC-NEXT: Maxium alignment of .text: 0x7 +# XLC32EXEC-NEXT: Maxium alignment of .data: 0x3 +# XLC32EXEC-NEXT: Module type: 0x314C +# XLC32EXEC-NEXT: CPU type of objects: 0x0 +# XLC32EXEC-NEXT: (Reserved): 0x0 +# XLC32EXEC-NEXT: Maximum stack size: 0x0 +# XLC32EXEC-NEXT: Maximum data size: 0x0 +# XLC32EXEC-NEXT: Reserved for debugger: 0x0 +# XLC32EXEC-NEXT: Text page size: 0x0 +# XLC32EXEC-NEXT: Data page size: 0x0 +# XLC32EXEC-NEXT: Stack page size: 0x0 +# XLC32EXEC-NEXT: Flag: 0x0 +# XLC32EXEC-NEXT: Alignment of thread-local storage: 0x0 +# XLC32EXEC-NEXT: Section number for .tdata: 0 +# XLC32EXEC-NEXT: Section number for .tbss: 0 +# XLC32EXEC-NEXT: } + + +# XLC64EXEC: File: {{.*}}xcoff-64-xlc-exec +# XLC64EXEC-NEXT: Format: aix5coff64-rs6000 +# XLC64EXEC-NEXT: Arch: powerpc64 +# XLC64EXEC-NEXT: AddressSize: 64bit +# XLC64EXEC-NEXT: AuxiliaryHeader { +# XLC64EXEC-NEXT: Magic: 0x10B +# XLC64EXEC-NEXT: Version: 0x1 +# XLC64EXEC-NEXT: Reserved for debugger: 0x0 +# XLC64EXEC-NEXT: .text section start address: 0x1000001F8 +# XLC64EXEC-NEXT: .data section start address: 0x110000640 +# XLC64EXEC-NEXT: TOC anchor address: 0x110000738 +# XLC64EXEC-NEXT: Section number of entryPoint: 2 +# XLC64EXEC-NEXT: Section number of .text: 1 +# XLC64EXEC-NEXT: Section number of .data: 2 +# XLC64EXEC-NEXT: Section number of TOC: 2 +# XLC64EXEC-NEXT: Section number of loader data: 4 +# XLC64EXEC-NEXT: Section number of .bss: 3 +# XLC64EXEC-NEXT: Maxium alignment of .text: 0x7 +# XLC64EXEC-NEXT: Maxium alignment of .data: 0x3 +# XLC64EXEC-NEXT: Module type: 0x314C +# XLC64EXEC-NEXT: CPU type of objects: 0x0 +# XLC64EXEC-NEXT: (Reserved): 0x0 +# XLC64EXEC-NEXT: Text page size: 0x0 +# XLC64EXEC-NEXT: Data page size: 0x0 +# XLC64EXEC-NEXT: Stack page size: 0x0 +# XLC64EXEC-NEXT: Flag: 0x0 +# XLC64EXEC-NEXT: Alignment of thread-local storage: 0x0 +# XLC64EXEC-NEXT: Size of .text section: 0x448 +# XLC64EXEC-NEXT: Size of .data section: 0x180 +# XLC64EXEC-NEXT: Size of .bss section: 0x8 +# XLC64EXEC-NEXT: Entry point address: 0x110000710 +# XLC64EXEC-NEXT: Maximum stack size: 0x0 +# XLC64EXEC-NEXT: Maximum data size: 0x0 +# XLC64EXEC-NEXT: Section number for .tdata: 0 +# XLC64EXEC-NEXT: Section number for .tbss: 0 +# XLC64EXEC-NEXT: Additional flags 64-bit XCOFF: 0x0 +# WARN64: {{.*}}llvm-readobj: warning: '': There are extra data beyond auxiliary header +# XLC64EXEC-NEXT: Extra raw data: (00 00 00 00 00 00 00 00 00 00) +# XLC64EXEC-NEXT: } + +# XLC32OBJ: File: {{.*}}xcoff-32-xlc-obj.o +# XLC32OBJ-NEXT: Format: aixcoff-rs6000 +# XLC32OBJ-NEXT: Arch: powerpc +# XLC32OBJ-NEXT: AddressSize: 32bit +# XLC32OBJ: AuxiliaryHeader { +# XLC32OBJ-NEXT: Magic: 0x10B +# XLC32OBJ-NEXT: Version: 0x0 +# XLC32OBJ-NEXT: Size of .text section: 0x200 +# XLC32OBJ-NEXT: Size of .data section: 0x3C +# XLC32OBJ-NEXT: Size of .bss section: 0x0 +# XLC32OBJ-NEXT: Entry point address: 0x0 +# XLC32OBJ-NEXT: .text section start address: 0x0 +# XLC32OBJ-NEXT: .data section start address: 0x200 +# XLC32OBJ-NEXT: } + +# XLC32OBJ-PART: File: {{.*}}xcoff-32-xlc-obj-malform.o +# XLC32OBJ-PART-NEXT: Format: aixcoff-rs6000 +# XLC32OBJ-PART-NEXT: Arch: powerpc +# XLC32OBJ-PART-NEXT: AddressSize: 32bit +# XLC32OBJ-PART-NEXT: AuxiliaryHeader { +# XLC32OBJ-PART-NEXT: Magic: 0x10B +# XLC32OBJ-PART-NEXT: Version: 0x0 +# XLC32OBJ-PART-NEXT: Size of .text section: 0x200 +# XLC32OBJ-PART-NEXT: Size of .data section: 0x3C +# XLC32OBJ-PART-NEXT: Size of .bss section: 0x0 +# XLC32OBJ-PART-NEXT: Entry point address: 0x0 +# XLC32OBJ-PART-NEXT: .text section start address: 0x0 +# WARN-PART: {{.*}}llvm-readobj: warning: '': Only partial field for .data section start address at offset (24). +# XLC32OBJ-PART-NEXT: Raw data: (00 00 02) +# XLC32OBJ-PART-NEXT: } + diff --git a/llvm/tools/llvm-readobj/ObjDumper.h b/llvm/tools/llvm-readobj/ObjDumper.h index e6178f78ef9ea..b395a95f3cb47 100644 --- a/llvm/tools/llvm-readobj/ObjDumper.h +++ b/llvm/tools/llvm-readobj/ObjDumper.h @@ -97,6 +97,9 @@ class ObjDumper { llvm::codeview::GlobalTypeTableBuilder &GlobalCVTypes, bool GHash) {} + // Only implement for XCOFF + virtual void printAuxiliaryHeader() {} + // Only implemented for MachO. virtual void printMachODataInCode() { } virtual void printMachOVersionMin() { } diff --git a/llvm/tools/llvm-readobj/Opts.td b/llvm/tools/llvm-readobj/Opts.td index fac7e3b8d866b..7723691e8225e 100644 --- a/llvm/tools/llvm-readobj/Opts.td +++ b/llvm/tools/llvm-readobj/Opts.td @@ -83,6 +83,10 @@ def coff_load_config : FF<"coff-load-config", "Display load config">, Group, Group; def coff_tls_directory : FF<"coff-tls-directory", "Display TLS directory">, Group; +// XCOFF specific options. +def grp_xcoff : OptionGroup<"kind">, HelpText<"OPTIONS (XCOFF specific)">; +def auxiliary_header : FF<"auxiliary-header" , "display the auxiliary header">, Group; + def help : FF<"help", "Display this help">; def version : FF<"version", "Display the version">; diff --git a/llvm/tools/llvm-readobj/XCOFFDumper.cpp b/llvm/tools/llvm-readobj/XCOFFDumper.cpp index 9967915fd3dcb..c67edd6a98bce 100644 --- a/llvm/tools/llvm-readobj/XCOFFDumper.cpp +++ b/llvm/tools/llvm-readobj/XCOFFDumper.cpp @@ -16,6 +16,8 @@ #include "llvm/Support/FormattedStream.h" #include "llvm/Support/ScopedPrinter.h" +#include + using namespace llvm; using namespace object; @@ -28,6 +30,7 @@ class XCOFFDumper : public ObjDumper { : ObjDumper(Writer, Obj.getFileName()), Obj(Obj) {} void printFileHeaders() override; + void printAuxiliaryHeader() override; void printSectionHeaders() override; void printRelocations() override; void printSymbols() override; @@ -47,6 +50,8 @@ class XCOFFDumper : public ObjDumper { void printSymbol(const SymbolRef &); template void printRelocations(ArrayRef Sections); + void printAuxiliaryHeader(const XCOFFAuxiliaryHeader32 *AuxHeader); + void printAuxiliaryHeader(const XCOFFAuxiliaryHeader64 *AuxHeader); const XCOFFObjectFile &Obj; }; } // anonymous namespace @@ -98,6 +103,13 @@ void XCOFFDumper::printFileHeaders() { // XCOFFObjectFile has the necessary support. } +void XCOFFDumper::printAuxiliaryHeader() { + if (Obj.is64Bit()) + printAuxiliaryHeader(Obj.auxiliaryHeader64()); + else + printAuxiliaryHeader(Obj.auxiliaryHeader32()); +} + void XCOFFDumper::printSectionHeaders() { if (Obj.is64Bit()) printSectionHeaders(Obj.sections64()); @@ -578,6 +590,176 @@ void XCOFFDumper::printGenericSectionHeader(T &Sec) const { W.printNumber("NumberOfLineNumbers", Sec.NumberOfLineNumbers); } +void XCOFFDumper::printAuxiliaryHeader( + const XCOFFAuxiliaryHeader32 *AuxHeader) { + if (AuxHeader == nullptr) + return; + uint16_t AuxSize = Obj.getOptionalHeaderSize(); + uint16_t PartialFieldOffset = AuxSize; + const char *PartialFieldName = nullptr; + + DictScope DS(W, "AuxiliaryHeader"); + +#define PrintAuxMember32(H, S, T) \ + if (offsetof(XCOFFAuxiliaryHeader32, T) + \ + sizeof(XCOFFAuxiliaryHeader32::T) <= \ + AuxSize) \ + W.print##H(S, AuxHeader->T); \ + else if (offsetof(XCOFFAuxiliaryHeader32, T) < AuxSize) { \ + PartialFieldOffset = offsetof(XCOFFAuxiliaryHeader32, T); \ + PartialFieldName = S; \ + } + + PrintAuxMember32(Hex, "Magic", AuxMagic); + PrintAuxMember32(Hex, "Version", Version); + PrintAuxMember32(Hex, "Size of .text section", TextSize); + PrintAuxMember32(Hex, "Size of .data section", InitDataSize); + PrintAuxMember32(Hex, "Size of .bss section", BssDataSize); + PrintAuxMember32(Hex, "Entry point address", EntryPointAddr); + PrintAuxMember32(Hex, ".text section start address", TextStartAddr); + PrintAuxMember32(Hex, ".data section start address", DataStartAddr); + PrintAuxMember32(Hex, "TOC anchor address", TOCAnchorAddr); + PrintAuxMember32(Number, "Section number of entryPoint", SecNumOfEntryPoint); + PrintAuxMember32(Number, "Section number of .text", SecNumOfText); + PrintAuxMember32(Number, "Section number of .data", SecNumOfData); + PrintAuxMember32(Number, "Section number of TOC", SecNumOfTOC); + PrintAuxMember32(Number, "Section number of loader data", SecNumOfLoader); + PrintAuxMember32(Number, "Section number of .bss", SecNumOfBSS); + PrintAuxMember32(Hex, "Maxium alignment of .text", MaxAlignOfText); + PrintAuxMember32(Hex, "Maxium alignment of .data", MaxAlignOfData); + PrintAuxMember32(Hex, "Module type", ModuleType); + PrintAuxMember32(Hex, "CPU type of objects", CpuFlag); + PrintAuxMember32(Hex, "(Reserved)", CpuType); + PrintAuxMember32(Hex, "Maximum stack size", MaxStackSize); + PrintAuxMember32(Hex, "Maximum data size", MaxDataSize); + PrintAuxMember32(Hex, "Reserved for debugger", ReservedForDebugger); + PrintAuxMember32(Hex, "Text page size", TextPageSize); + PrintAuxMember32(Hex, "Data page size", DataPageSize); + PrintAuxMember32(Hex, "Stack page size", StackPageSize); + if (offsetof(XCOFFAuxiliaryHeader32, FlagAndTDataAlignment) + + sizeof(XCOFFAuxiliaryHeader32::FlagAndTDataAlignment) <= + AuxSize) { + W.printHex("Flag", AuxHeader->getFlag()); + W.printHex("Alignment of thread-local storage", + AuxHeader->getTDataAlignment()); + } + + PrintAuxMember32(Number, "Section number for .tdata", SecNumOfTData); + PrintAuxMember32(Number, "Section number for .tbss", SecNumOfTBSS); + + // Deal with error. + if (PartialFieldOffset < AuxSize) { + std::string ErrInfo; + llvm::raw_string_ostream StringOS(ErrInfo); + StringOS << "Only partial field for " << PartialFieldName << " at offset (" + << PartialFieldOffset << ")."; + StringOS.flush(); + reportWarning( + make_error(ErrInfo, object_error::parse_failed), + "-"); + W.printBinary( + "Raw data", "", + ArrayRef((const uint8_t *)(AuxHeader) + PartialFieldOffset, + AuxSize - PartialFieldOffset)); + } else if (sizeof(XCOFFAuxiliaryHeader32) < AuxSize) { + reportWarning(make_error( + "There are extra data beyond auxiliary header", + object_error::parse_failed), + "-"); + W.printBinary("Extra raw data", "", + ArrayRef((const uint8_t *)(AuxHeader) + + sizeof(XCOFFAuxiliaryHeader32), + AuxSize - sizeof(XCOFFAuxiliaryHeader32))); + } + +#undef PrintAuxMember32 +} + +void XCOFFDumper::printAuxiliaryHeader( + const XCOFFAuxiliaryHeader64 *AuxHeader) { + if (AuxHeader == nullptr) + return; + uint16_t AuxSize = Obj.getOptionalHeaderSize(); + uint16_t PartialFieldOffset = AuxSize; + const char *PartialFieldName = nullptr; + + DictScope DS(W, "AuxiliaryHeader"); + +#define PrintAuxMember64(H, S, T) \ + if (offsetof(XCOFFAuxiliaryHeader64, T) + \ + sizeof(XCOFFAuxiliaryHeader64::T) <= \ + AuxSize) \ + W.print##H(S, AuxHeader->T); \ + else if (offsetof(XCOFFAuxiliaryHeader64, T) < AuxSize) { \ + PartialFieldOffset = offsetof(XCOFFAuxiliaryHeader64, T); \ + PartialFieldName = S; \ + } + + PrintAuxMember64(Hex, "Magic", AuxMagic); + PrintAuxMember64(Hex, "Version", Version); + PrintAuxMember64(Hex, "Reserved for debugger", ReservedForDebugger); + PrintAuxMember64(Hex, ".text section start address", TextStartAddr); + PrintAuxMember64(Hex, ".data section start address", DataStartAddr); + PrintAuxMember64(Hex, "TOC anchor address", TOCAnchorAddr); + PrintAuxMember64(Number, "Section number of entryPoint", SecNumOfEntryPoint); + PrintAuxMember64(Number, "Section number of .text", SecNumOfText); + PrintAuxMember64(Number, "Section number of .data", SecNumOfData); + PrintAuxMember64(Number, "Section number of TOC", SecNumOfTOC); + PrintAuxMember64(Number, "Section number of loader data", SecNumOfLoader); + PrintAuxMember64(Number, "Section number of .bss", SecNumOfBSS); + PrintAuxMember64(Hex, "Maxium alignment of .text", MaxAlignOfText); + PrintAuxMember64(Hex, "Maxium alignment of .data", MaxAlignOfData); + PrintAuxMember64(Hex, "Module type", ModuleType); + PrintAuxMember64(Hex, "CPU type of objects", CpuFlag); + PrintAuxMember64(Hex, "(Reserved)", CpuType); + PrintAuxMember64(Hex, "Text page size", TextPageSize); + PrintAuxMember64(Hex, "Data page size", DataPageSize); + PrintAuxMember64(Hex, "Stack page size", StackPageSize); + if (offsetof(XCOFFAuxiliaryHeader64, FlagAndTDataAlignment) + + sizeof(XCOFFAuxiliaryHeader64::FlagAndTDataAlignment) <= + AuxSize) { + W.printHex("Flag", AuxHeader->getFlag()); + W.printHex("Alignment of thread-local storage", + AuxHeader->getTDataAlignment()); + } + PrintAuxMember64(Hex, "Size of .text section", TextSize); + PrintAuxMember64(Hex, "Size of .data section", InitDataSize); + PrintAuxMember64(Hex, "Size of .bss section", BssDataSize); + PrintAuxMember64(Hex, "Entry point address", EntryPointAddr); + PrintAuxMember64(Hex, "Maximum stack size", MaxStackSize); + PrintAuxMember64(Hex, "Maximum data size", MaxDataSize); + PrintAuxMember64(Number, "Section number for .tdata", SecNumOfTData); + PrintAuxMember64(Number, "Section number for .tbss", SecNumOfTBSS); + PrintAuxMember64(Hex, "Additional flags 64-bit XCOFF", XCOFF64Flag); + + if (PartialFieldOffset < AuxSize) { + std::string ErrInfo; + llvm::raw_string_ostream StringOS(ErrInfo); + StringOS << "Only partial field for " << PartialFieldName << " at offset (" + << PartialFieldOffset << ")."; + StringOS.flush(); + reportWarning( + make_error(ErrInfo, object_error::parse_failed), + "-"); + ; + W.printBinary( + "Raw data", "", + ArrayRef((const uint8_t *)(AuxHeader) + PartialFieldOffset, + AuxSize - PartialFieldOffset)); + } else if (sizeof(XCOFFAuxiliaryHeader64) < AuxSize) { + reportWarning(make_error( + "There are extra data beyond auxiliary header", + object_error::parse_failed), + "-"); + W.printBinary("Extra raw data", "", + ArrayRef((const uint8_t *)(AuxHeader) + + sizeof(XCOFFAuxiliaryHeader64), + AuxSize - sizeof(XCOFFAuxiliaryHeader64))); + } + +#undef PrintAuxMember64 +} + template void XCOFFDumper::printSectionHeaders(ArrayRef Sections) { ListScope Group(W, "Sections"); diff --git a/llvm/tools/llvm-readobj/llvm-readobj.cpp b/llvm/tools/llvm-readobj/llvm-readobj.cpp index 001dace9b86b1..a598e2c28832d 100644 --- a/llvm/tools/llvm-readobj/llvm-readobj.cpp +++ b/llvm/tools/llvm-readobj/llvm-readobj.cpp @@ -149,6 +149,9 @@ static bool COFFLoadConfig; static bool COFFResources; static bool COFFTLSDirectory; +// XCOFF specific options. +static bool XCOFFAuxiliaryHeader; + OutputStyleTy Output = OutputStyleTy::LLVM; static std::vector InputFilenames; } // namespace opts @@ -268,6 +271,9 @@ static void parseOptions(const opt::InputArgList &Args) { opts::COFFResources = Args.hasArg(OPT_coff_resources); opts::COFFTLSDirectory = Args.hasArg(OPT_coff_tls_directory); + // XCOFF specific options. + opts::XCOFFAuxiliaryHeader = Args.hasArg(OPT_auxiliary_header); + opts::InputFilenames = Args.getAllArgValues(OPT_INPUT); } @@ -343,6 +349,9 @@ static void dumpObject(ObjectFile &Obj, ScopedPrinter &Writer, if (opts::FileHeaders) Dumper->printFileHeaders(); + if (Obj.isXCOFF() && opts::XCOFFAuxiliaryHeader) + Dumper->printAuxiliaryHeader(); + // This is only used for ELF currently. In some cases, when an object is // corrupt (e.g. truncated), we can't dump anything except the file header. if (!ContentErrString.empty()) @@ -577,6 +586,7 @@ int main(int argc, char *argv[]) { if (opts::All) { opts::FileHeaders = true; + opts::XCOFFAuxiliaryHeader = true; opts::ProgramHeaders = true; opts::SectionHeaders = true; opts::Symbols = true; @@ -595,6 +605,7 @@ int main(int argc, char *argv[]) { if (opts::Headers) { opts::FileHeaders = true; + opts::XCOFFAuxiliaryHeader = true; opts::ProgramHeaders = true; opts::SectionHeaders = true; }