diff --git a/llvm/docs/CommandGuide/llvm-readobj.rst b/llvm/docs/CommandGuide/llvm-readobj.rst --- a/llvm/docs/CommandGuide/llvm-readobj.rst +++ b/llvm/docs/CommandGuide/llvm-readobj.rst @@ -311,6 +311,15 @@ 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 --- a/llvm/include/llvm/Object/XCOFFObjectFile.h +++ b/llvm/include/llvm/Object/XCOFFObjectFile.h @@ -51,6 +51,101 @@ 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 XCOFFObjectFile : public ObjectFile { private: const void *FileHeader = nullptr; + const void *AuxiliaryHeader = nullptr; const void *SectionHeaderTable = nullptr; const void *SymbolTblPtr = nullptr; @@ -401,6 +497,9 @@ // 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 --- a/llvm/lib/Object/XCOFFObjectFile.cpp +++ b/llvm/lib/Object/XCOFFObjectFile.cpp @@ -149,6 +149,16 @@ 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); } @@ -888,8 +898,15 @@ 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..0000000000000000000000000000000000000000 GIT binary patch literal 0 Hc$@; def expand_relocs : FF<"expand-relocs", "Expand each shown relocation to multiple lines">; def file_header : FF<"file-header", "Display file header">; +def auxiliary_header : FF<"auxiliary-header" , "auxiliary-headers">; def headers : FF<"headers", "Equivalent to setting: --file-header, --program-headers, --section-headers">; defm hex_dump : Eq<"hex-dump", "Display the specified section(s) as hexadecimal bytes">, MetaVarName<"">; def relocs : FF<"relocs", "Display the relocation entries in the file">; diff --git a/llvm/tools/llvm-readobj/XCOFFDumper.cpp b/llvm/tools/llvm-readobj/XCOFFDumper.cpp --- 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 @@ : 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 @@ 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 @@ // 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,170 @@ W.printNumber("NumberOfLineNumbers", Sec.NumberOfLineNumbers); } +void XCOFFDumper::printAuxiliaryHeader( + const XCOFFAuxiliaryHeader32 *AuxHeader) { + if (AuxHeader == nullptr) { + W.printString("The XCOFF object file do not have a auxiliary header."); + return; + } + uint16_t AuxiSize = Obj.getOptionalHeaderSize(); + uint16_t PartialFieldOffset = AuxiSize; + const char *PartialFieldName; + + DictScope DS(W, "AuxiliaryHeader"); + +#define PrintAuxMember32(H, S, T) \ + if (offsetof(XCOFFAuxiliaryHeader32, T) + \ + sizeof(XCOFFAuxiliaryHeader32::T) <= \ + AuxiSize) \ + W.print##H(S, AuxHeader->T); \ + else if (offsetof(XCOFFAuxiliaryHeader32, T) < AuxiSize) { \ + 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) <= + AuxiSize) { + 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 < AuxiSize) { + std::string ErrInfo; + llvm::raw_string_ostream StringOS(ErrInfo); + StringOS << "Only partial field for " << PartialFieldName << " at offset (" + << PartialFieldOffset << ") Raw data:"; + StringOS.flush(); + W.printBinary( + "!!!Warning", ErrInfo, + ArrayRef((const uint8_t *)(AuxHeader) + PartialFieldOffset, + AuxiSize - PartialFieldOffset)); + } else if (sizeof(XCOFFAuxiliaryHeader32) < AuxiSize) { + W.printBinary( + "!!!Warning", + "There are extra data beyond XCOFFAuxiliaryHeader32. Extra raw data", + ArrayRef((const uint8_t *)(AuxHeader) + + sizeof(XCOFFAuxiliaryHeader32), + AuxiSize - sizeof(XCOFFAuxiliaryHeader32))); + } + +#undef PrintAuxMember32 +} + +void XCOFFDumper::printAuxiliaryHeader( + const XCOFFAuxiliaryHeader64 *AuxHeader) { + if (AuxHeader == nullptr) { + W.printString("The XCOFF object file do not have a auxiliary header."); + return; + } + uint16_t AuxiSize = Obj.getOptionalHeaderSize(); + uint16_t PartialFieldOffset = AuxiSize; + const char *PartialFieldName; + + DictScope DS(W, "AuxiliaryHeader"); + +#define PrintAuxMember64(H, S, T) \ + if (offsetof(XCOFFAuxiliaryHeader64, T) + \ + sizeof(XCOFFAuxiliaryHeader64::T) <= \ + AuxiSize) \ + W.print##H(S, AuxHeader->T); \ + else if (offsetof(XCOFFAuxiliaryHeader64, T) < AuxiSize) { \ + 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) <= + AuxiSize) { + 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 < AuxiSize) { + std::string ErrInfo; + llvm::raw_string_ostream StringOS(ErrInfo); + StringOS << "Only partial field for " << PartialFieldName << " at offset (" + << PartialFieldOffset << ") Raw data:"; + StringOS.flush(); + W.printBinary( + "!!!Warning", ErrInfo, + ArrayRef((const uint8_t *)(AuxHeader) + PartialFieldOffset, + AuxiSize - PartialFieldOffset)); + } else if (sizeof(XCOFFAuxiliaryHeader64) < AuxiSize) { + W.printBinary( + "!!!Warning", + "There are extra data beyond XCOFFAuxiliaryHeader64. Extra raw data", + ArrayRef((const uint8_t *)(AuxHeader) + + sizeof(XCOFFAuxiliaryHeader64), + AuxiSize - 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 --- a/llvm/tools/llvm-readobj/llvm-readobj.cpp +++ b/llvm/tools/llvm-readobj/llvm-readobj.cpp @@ -97,6 +97,7 @@ static bool DynRelocs; static bool DynamicSymbols; static bool FileHeaders; +static bool XCOFFAuxiliaryHeader; static bool Headers; static std::vector HexDump; static bool PrintStackMap; @@ -268,6 +269,9 @@ 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 +347,10 @@ 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 +585,7 @@ if (opts::All) { opts::FileHeaders = true; + opts::XCOFFAuxiliaryHeader = true; opts::ProgramHeaders = true; opts::SectionHeaders = true; opts::Symbols = true;