From fd75ee9154d25a7ac4b806a193ef7ad846703c0c Mon Sep 17 00:00:00 2001 From: Sean Fertile Date: Fri, 3 May 2019 12:57:07 +0000 Subject: [PATCH] [Object][XCOFF] Add an XCOFF dumper for llvm-readobj. Patch adds support for dumping of file headers with llvm-readobj. XCOFF object files are added to test dumping a well formed file, and dumping both negative timestamps and negative symbol counts, both of which are allowed in the XCOFF definition. Differential Revision: https://reviews.llvm.org/D60878 llvm-svn: 359878 --- llvm/include/llvm/Object/XCOFFObjectFile.h | 13 ++- llvm/lib/Object/XCOFFObjectFile.cpp | 41 +++++-- .../Inputs/xcoff-basic-neg-sym-count.o | Bin 0 -> 876 bytes .../llvm-readobj/Inputs/xcoff-basic-neg-time.o | Bin 0 -> 3567 bytes llvm/test/tools/llvm-readobj/Inputs/xcoff-basic.o | Bin 0 -> 3567 bytes llvm/test/tools/llvm-readobj/xcoff-basic.test | 66 +++++++++++ llvm/tools/llvm-readobj/CMakeLists.txt | 1 + llvm/tools/llvm-readobj/ObjDumper.h | 4 + llvm/tools/llvm-readobj/XCOFFDumper.cpp | 121 +++++++++++++++++++++ llvm/tools/llvm-readobj/llvm-readobj.cpp | 2 + 10 files changed, 240 insertions(+), 8 deletions(-) create mode 100644 llvm/test/tools/llvm-readobj/Inputs/xcoff-basic-neg-sym-count.o create mode 100644 llvm/test/tools/llvm-readobj/Inputs/xcoff-basic-neg-time.o create mode 100644 llvm/test/tools/llvm-readobj/Inputs/xcoff-basic.o create mode 100644 llvm/test/tools/llvm-readobj/xcoff-basic.test create mode 100644 llvm/tools/llvm-readobj/XCOFFDumper.cpp diff --git a/llvm/include/llvm/Object/XCOFFObjectFile.h b/llvm/include/llvm/Object/XCOFFObjectFile.h index caa792d..36429b9 100644 --- a/llvm/include/llvm/Object/XCOFFObjectFile.h +++ b/llvm/include/llvm/Object/XCOFFObjectFile.h @@ -71,7 +71,6 @@ private: const XCOFFSectionHeader *toSection(DataRefImpl Ref) const; - uint16_t getNumberOfSections() const; public: void moveSymbolNext(DataRefImpl &Symb) const override; @@ -122,6 +121,18 @@ public: XCOFFObjectFile(MemoryBufferRef Object, std::error_code &EC); const XCOFFFileHeader *getFileHeader() const { return FileHdrPtr; } + + uint16_t getMagic() const; + uint16_t getNumberOfSections() const; + int32_t getTimeStamp() const; + uint32_t getSymbolTableOffset() const; + + // Note that this value is signed and might return a negative value. Negative + // values are reserved for future use. + int32_t getNumberOfSymbolTableEntries() const; + + uint16_t getOptionalHeaderSize() const; + uint16_t getFlags() const; }; // XCOFFObjectFile } // namespace object diff --git a/llvm/lib/Object/XCOFFObjectFile.cpp b/llvm/lib/Object/XCOFFObjectFile.cpp index bc98259..2a45653 100644 --- a/llvm/lib/Object/XCOFFObjectFile.cpp +++ b/llvm/lib/Object/XCOFFObjectFile.cpp @@ -69,10 +69,6 @@ size_t XCOFFObjectFile::getSectionHeaderSize() const { return sizeof(XCOFFSectionHeader); } -uint16_t XCOFFObjectFile::getNumberOfSections() const { - return FileHdrPtr->NumberOfSections; -} - void XCOFFObjectFile::moveSymbolNext(DataRefImpl &Symb) const { llvm_unreachable("Not yet implemented!"); return; @@ -247,9 +243,9 @@ section_iterator XCOFFObjectFile::section_end() const { } uint8_t XCOFFObjectFile::getBytesInAddress() const { - uint8_t Result = 0; - llvm_unreachable("Not yet implemented!"); - return Result; + // Only support 32-bit object files for now ... + assert(getFileHeaderSize() == XCOFF32FileHeaderSize); + return 4; } StringRef XCOFFObjectFile::getFileFormatName() const { @@ -300,6 +296,37 @@ XCOFFObjectFile::XCOFFObjectFile(MemoryBufferRef Object, std::error_code &EC) } } +uint16_t XCOFFObjectFile::getMagic() const { + return FileHdrPtr->Magic; +} + +uint16_t XCOFFObjectFile::getNumberOfSections() const { + return FileHdrPtr->NumberOfSections; +} + +int32_t XCOFFObjectFile::getTimeStamp() const { + return FileHdrPtr->TimeStamp; +} + +uint32_t XCOFFObjectFile::getSymbolTableOffset() const { + return FileHdrPtr->SymbolTableOffset; +} + +int32_t XCOFFObjectFile::getNumberOfSymbolTableEntries() const { + // As far as symbol table size is concerned, if this field is negative it is + // to be treated as a 0. However since this field is also used for printing we + // don't want to truncate any negative values. + return FileHdrPtr->NumberOfSymTableEntries; +} + +uint16_t XCOFFObjectFile::getOptionalHeaderSize() const { + return FileHdrPtr->AuxHeaderSize; +} + +uint16_t XCOFFObjectFile::getFlags() const { + return FileHdrPtr->Flags; +} + Expected> ObjectFile::createXCOFFObjectFile(MemoryBufferRef Object) { StringRef Data = Object.getBuffer(); diff --git a/llvm/test/tools/llvm-readobj/Inputs/xcoff-basic-neg-sym-count.o b/llvm/test/tools/llvm-readobj/Inputs/xcoff-basic-neg-sym-count.o new file mode 100644 index 0000000000000000000000000000000000000000..e7f63664acd332798fa375feceecfd97bc4b3676 GIT binary patch literal 876 zcmd^7F;0a*5PbufY$A3R78V<&G_+U(u`m?I15gNRVh@Fh6dM~`Pr)fXfVc1}&amue zRjhvbCz;*1Z{ECJ!q68E+P9Ava2Q!maYTm#NR}tgM1T!KK0ZE=?zrrti+(VC(D_3* zcE0Ys;@`S5?}x#X#CJ)C_j$R=M{npzepf8|AQFC`HZlRp5I1f4#<}qS?ISm~|)b1a-|nMf8U8q~ba7tybR*)T|J$Uvq!v`ajRN z`p<&?E8o96pbMV6mh;li9|h)g%lo-WK?nyp=4z{Y1%lo6uVYQqy9jZmP$ly?AT7yM2+NZ zPz1fO5I+(^G`-}G3)H9J0eA#1khtqJa0Ptl%+Jn-t`wZ}2A# z|MA_gUlI+4M089SiGtT5QNWKK^a2aI1r)~J7rw9xo*Kr^A;-&=ztmx)HAsCV>uD~hTQfIRz~zLfW$@|C-U{+UQOAZ?4p zN3bgrbNu|LNj$$r?~CqxNU=yK)+$`@OyM=)9l0kG->pwX;#>czNTZN8MVf%rnNpa+ z-aAv%kWgP}Ppr_>fmor3#MT)|x5SE5p-GWSkXA*)3DLAj*PN~isU$k2p20DrYoc4X zI^qbpF^!@WEMApQku@`-;gtx7#hOjg@H#|ai{@v_g}vSVuBeFq`J3|F`QxpFUT?15 zI^5j~k@iU|Xpvo+_MRSd7*bUfkUTnmyqm72Dkvr~2K89iO@m5RPn@)1%*xhLs&c|+ z{8+P$sj4|-FsW!9oWp1C^aEAna&4}xEml+EyhYk3nEBdVC5>6A?HQGxrLFXiKkF(y z&x;|2`5?iVS$e?U?CCv}_a$Qt>mDi~m6Pb9Q@GYIFzOt*pi$OXuimhcqv}p@H*#wLGXCV%`m*=i@@SCc{PE^oq^Y^$BXNRYav%9-Bwb(aPx;a zPJJIw@mfoGt$4i7TUR`KyySixUT>r^?kv*hbq}b*8F+O(UZW|`yfeBD{=@ zR`o+u0fG(Qp8qL0{ExKAcq#y8Xl5gU7187?#6Q USf((F;{C&DyBkNXPNz@*0-io0HUIzs literal 0 HcmV?d00001 diff --git a/llvm/test/tools/llvm-readobj/Inputs/xcoff-basic.o b/llvm/test/tools/llvm-readobj/Inputs/xcoff-basic.o new file mode 100644 index 0000000000000000000000000000000000000000..c84056bdb00bd986a512d8c827e5a11cdb50e812 GIT binary patch literal 3567 zcmds3UvC>l5TCQ1V3nvOBvb(^vMPRvP;#=JG;N$(ie0OuQCpx2r4kVrJGPTFQ6o7Q z6hR*>#2*PEnm+Qz1L~*X1Mm@e)ycH42=*{!cU zG=*7FPs(#O>>M45L;=>~?ysjUcn-tZIkZZ|l?T4?g;ns>Fm?_(ZtlgzZlxlH-CpN- z$G*#W0DtIyQ~t~UQXY1wFx)1(HzY$=ts0_Z6f_9-v21&jo)mM>hhNbYaMPy&71ywd zj2}XNQp`X1{5Fi=5(Vo=RZy3`7QcDbl*dYMLM-s;d*ZduL1AKeUbQXeIgRy`cFj~hqNWq6r}Eq!VLD_ zohd;=eW87^LQjWcg&q=HXCd7YD^7)`MJhvD6A33oC6R78T?PN1d_`NVrpkGXv`sJz_4#TVvsm9ZDm_bE=`DZOb$DJ7 zLkja=f-$r7fW6t*dnoVA#uzp{R6r^x(L<+jtzTf&IdDm%tg%tMWoZf1AK@8oRHO7W z?DUgY*n1lDN}|Lmcg$ZKa++B@wZUzA!Q=WNebQ}JQ7gt2CT|{Si zwV0Q_1VfM4>w+~8kC#*_!)r2)$>6mG)aW^Q{o?WBn(o@h2RDt3M8);tJ80WPYHwMK z>TWTpL)<1%v(hb)x+{K6#=mKNHXIQD*zl8My~&;llfxb+iRa8(?ZnTf^J6inecal$ z_e})|HhF)Bt_J${Q z1`7{!Im=Ji`2h#)tFSOx_x2mw*ku;_4oU@hM#-!|WqA%AC@5uN%;GL(W%VQ?D}A(a z+*5bk168T2O1V~EtSv66YPqtk=yvn2dU!|ORQ &Result); +std::error_code createXCOFFDumper(const object::ObjectFile *Obj, + ScopedPrinter &Writer, + std::unique_ptr &Result); + void dumpCOFFImportFile(const object::COFFImportFile *File, ScopedPrinter &Writer); diff --git a/llvm/tools/llvm-readobj/XCOFFDumper.cpp b/llvm/tools/llvm-readobj/XCOFFDumper.cpp new file mode 100644 index 0000000..009b99c --- /dev/null +++ b/llvm/tools/llvm-readobj/XCOFFDumper.cpp @@ -0,0 +1,121 @@ +//===-- XCOFFDumper.cpp - XCOFF dumping utility -----------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements an XCOFF specific dumper for llvm-readobj. +// +//===----------------------------------------------------------------------===// + +#include "Error.h" +#include "ObjDumper.h" +#include "llvm-readobj.h" +#include "llvm/Object/XCOFFObjectFile.h" +#include "llvm/Support/ScopedPrinter.h" + +using namespace llvm; +using namespace object; + +namespace { + +class XCOFFDumper : public ObjDumper { +public: + XCOFFDumper(const XCOFFObjectFile &Obj, ScopedPrinter &Writer) + : ObjDumper(Writer), Obj(Obj) {} + + void printFileHeaders() override; + void printSectionHeaders() override; + void printRelocations() override; + void printSymbols() override; + void printDynamicSymbols() override; + void printUnwindInfo() override; + void printStackMap() const override; + void printNeededLibraries() override; + +private: + const XCOFFObjectFile &Obj; +}; +} // anonymous namespace + +void XCOFFDumper::printFileHeaders() { + DictScope DS(W, "FileHeader"); + W.printHex("Magic", Obj.getMagic()); + W.printNumber("NumberOfSections", Obj.getNumberOfSections()); + + // Negative timestamp values are reserved for future use. + int32_t TimeStamp = Obj.getTimeStamp(); + if (TimeStamp > 0) { + // This handling of the time stamp assumes that the host system's time_t is + // compatible with AIX time_t. If a platform is not compatible, the lit + // tests will let us know. + time_t TimeDate = TimeStamp; + + char FormattedTime[21] = {}; + size_t BytesWritten = + strftime(FormattedTime, 21, "%Y-%m-%dT%H:%M:%SZ", gmtime(&TimeDate)); + if (BytesWritten) + W.printHex("TimeStamp", FormattedTime, TimeStamp); + else + W.printHex("Timestamp", TimeStamp); + } else { + W.printHex("TimeStamp", TimeStamp == 0 ? "None" : "Reserved Value", + TimeStamp); + } + + W.printHex("SymbolTableOffset", Obj.getSymbolTableOffset()); + int32_t SymTabEntries = Obj.getNumberOfSymbolTableEntries(); + if (SymTabEntries >= 0) + W.printNumber("SymbolTableEntries", SymTabEntries); + else + W.printHex("SymbolTableEntries", "Reserved Value", SymTabEntries); + + W.printHex("OptionalHeaderSize", Obj.getOptionalHeaderSize()); + W.printHex("Flags", Obj.getFlags()); + + // TODO FIXME Add support for the auxiliary header (if any) once + // XCOFFObjectFile has the necessary support. +} + +void XCOFFDumper::printSectionHeaders() { + llvm_unreachable("Unimplemented functionality for XCOFFDumper"); +} + +void XCOFFDumper::printRelocations() { + llvm_unreachable("Unimplemented functionality for XCOFFDumper"); +} + +void XCOFFDumper::printSymbols() { + llvm_unreachable("Unimplemented functionality for XCOFFDumper"); +} + +void XCOFFDumper::printDynamicSymbols() { + llvm_unreachable("Unimplemented functionality for XCOFFDumper"); +} + +void XCOFFDumper::printUnwindInfo() { + llvm_unreachable("Unimplemented functionality for XCOFFDumper"); +} + +void XCOFFDumper::printStackMap() const { + llvm_unreachable("Unimplemented functionality for XCOFFDumper"); +} + +void XCOFFDumper::printNeededLibraries() { + llvm_unreachable("Unimplemented functionality for XCOFFDumper"); +} + +namespace llvm { +std::error_code createXCOFFDumper(const object::ObjectFile *Obj, + ScopedPrinter &Writer, + std::unique_ptr &Result) { + const XCOFFObjectFile *XObj = dyn_cast(Obj); + if (!XObj) + return readobj_error::unsupported_obj_file_format; + + Result.reset(new XCOFFDumper(*XObj, Writer)); + return readobj_error::success; +} +} // namespace llvm diff --git a/llvm/tools/llvm-readobj/llvm-readobj.cpp b/llvm/tools/llvm-readobj/llvm-readobj.cpp index 89fddc7..e8cea5a 100644 --- a/llvm/tools/llvm-readobj/llvm-readobj.cpp +++ b/llvm/tools/llvm-readobj/llvm-readobj.cpp @@ -440,6 +440,8 @@ static std::error_code createDumper(const ObjectFile *Obj, return createMachODumper(Obj, Writer, Result); if (Obj->isWasm()) return createWasmDumper(Obj, Writer, Result); + if (Obj->isXCOFF()) + return createXCOFFDumper(Obj, Writer, Result); return readobj_error::unsupported_obj_file_format; } -- 2.7.4