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 @@ -306,6 +306,15 @@ Display the .rsrc section. +XCOFF ONLY OPTIONS AND COMMANDS +--------------------------------- + +The following options are implemented only for the XCOFF file format. + +.. option:: --auxiliary-headers + + 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 @@ -62,6 +62,97 @@ bool isReservedSectionType() const; }; +static constexpr uint8_t AuxiHeaderFlagMask = 0xF0; +static constexpr uint8_t AuxiHeaderTDataAlignmentMask = 0x0F; + +struct XCOFFAuxiliaryHeader32 { + 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; + uint8_t getFlag() const { return FlagAndTDataAlignment & AuxiHeaderFlagMask; } + uint8_t getTDataAlignment() const { + return FlagAndTDataAlignment & AuxiHeaderTDataAlignmentMask; + } +}; + +struct XCOFFAuxiliaryHeader64 { + 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; + uint8_t getFlag() const { return FlagAndTDataAlignment & AuxiHeaderFlagMask; } + uint8_t getTDataAlignment() const { + return FlagAndTDataAlignment & AuxiHeaderTDataAlignmentMask; + } +}; + // Explicit extern template declarations. struct XCOFFSectionHeader32; struct XCOFFSectionHeader64; @@ -216,6 +307,7 @@ class XCOFFObjectFile : public ObjectFile { private: const void *FileHeader = nullptr; + const void *AuxiliaryHeader = nullptr; const void *SectionHeaderTable = nullptr; const XCOFFSymbolEntry *SymbolTblPtr = nullptr; @@ -320,6 +412,9 @@ // Below here is the non-inherited interface. bool is64Bit() const; + const XCOFFAuxiliaryHeader32 *auxiliaryHeader32() const; + const XCOFFAuxiliaryHeader64 *auxiliaryHeader64() const; + const XCOFFSymbolEntry *getPointerToSymbolTable() const { assert(!is64Bit() && "Symbol table handling not supported yet."); return SymbolTblPtr; 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 @@ -130,6 +130,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); +} + const XCOFFSectionHeader32 * XCOFFObjectFile::sectionHeaderTable32() const { assert(!is64Bit() && "32-bit interface called on 64-bit object file."); @@ -711,8 +721,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$@ + using namespace llvm; using namespace object; @@ -28,6 +30,7 @@ : ObjDumper(Writer), Obj(Obj) {} void printFileHeaders() override; + void printAuxiliaryHeaders() override; void printSectionHeaders() override; void printRelocations() override; void printSymbols() override; @@ -45,6 +48,8 @@ void printSectAuxEntForStat(const XCOFFSectAuxEntForStat *AuxEntPtr); void printSymbol(const SymbolRef &); void printRelocations(ArrayRef Sections); + void printAuxiliaryHeaders(const XCOFFAuxiliaryHeader32 *AuxHeader); + void printAuxiliaryHeaders(const XCOFFAuxiliaryHeader64 *AuxHeader); const XCOFFObjectFile &Obj; }; } // anonymous namespace @@ -96,6 +101,13 @@ // XCOFFObjectFile has the necessary support. } +void XCOFFDumper::printAuxiliaryHeaders() { + if (Obj.is64Bit()) + printAuxiliaryHeaders(Obj.auxiliaryHeader64()); + else + printAuxiliaryHeaders(Obj.auxiliaryHeader32()); +} + void XCOFFDumper::printSectionHeaders() { if (Obj.is64Bit()) printSectionHeaders(Obj.sections64()); @@ -473,6 +485,169 @@ W.printNumber("NumberOfLineNumbers", Sec.NumberOfLineNumbers); } +void XCOFFDumper::printAuxiliaryHeaders(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::printAuxiliaryHeaders( + 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 @@ -174,6 +174,11 @@ cl::opt NeededLibraries("needed-libs", cl::desc("Display the needed libraries")); + // --auxiliary-headers + cl::opt + XCOFFAuxiliaryHeaders("auxiliary-headers", + cl::desc("Display XCOFF Auxiliary headers")); + // --program-headers, --segments, -l cl::opt ProgramHeaders("program-headers", cl::desc("Display ELF program headers")); @@ -548,6 +553,11 @@ if (opts::MachODysymtab) Dumper->printMachODysymtab(); } + + if (Obj->isXCOFF() && opts::XCOFFAuxiliaryHeaders) { + Dumper->printAuxiliaryHeaders(); + } + if (opts::PrintStackMap) Dumper->printStackMap(); if (opts::PrintStackSizes) @@ -688,6 +698,7 @@ if (opts::All) { opts::FileHeaders = true; opts::ProgramHeaders = true; + opts::XCOFFAuxiliaryHeaders = true; opts::SectionHeaders = true; opts::Symbols = true; opts::Relocations = true; @@ -705,6 +716,7 @@ if (opts::Headers) { opts::FileHeaders = true; + opts::XCOFFAuxiliaryHeaders = true; opts::ProgramHeaders = true; opts::SectionHeaders = true; }