diff --git a/llvm/test/tools/llvm-objdump/XCOFF/private-header-auxiliary.test b/llvm/test/tools/llvm-objdump/XCOFF/private-header-auxiliary.test new file mode 100644 index 0000000000000..a2aca3710157f --- /dev/null +++ b/llvm/test/tools/llvm-objdump/XCOFF/private-header-auxiliary.test @@ -0,0 +1,103 @@ +## Test that `llvm-objdump --private-headers` prints out the auxiliary header of an XCOFF object file. +# RUN: yaml2obj %s -o %t1 +# RUN: llvm-objdump --private-headers %t1 | \ +# RUN: FileCheck %s --check-prefixes=CHECK32,COMMON --match-full-lines --strict-whitespace +# RUN: yaml2obj %s -DMAGIC=0x1F7 -DFLAG64=0x2 -o %t2 +# RUN: llvm-objdump --private-headers %t2 | \ +# RUN: FileCheck %s --check-prefixes=CHECK64,COMMON --match-full-lines --strict-whitespace + +--- !XCOFF +FileHeader: + MagicNumber: [[MAGIC=0x1DF]] +AuxiliaryHeader: + Magic: 0x10B + Version: 0x1 + TextSectionSize: 0x8 + DataSectionSize: 0x9 + BssSectionSize: 0x10 + EntryPointAddr: 0x1111 + TextStartAddr: 0x2222 + DataStartAddr: 0x3333 + TOCAnchorAddr: 0x4444 + SecNumOfEntryPoint: 1 + SecNumOfText: 2 + SecNumOfData: 3 + SecNumOfTOC: 4 + SecNumOfLoader: 5 + SecNumOfBSS: 6 + MaxAlignOfText: 0x7 + MaxAlignOfData: 0x3 + ModuleType: 0x1 + TextPageSize: 0x1 + DataPageSize: 0x1 + StackPageSize: 0x1 + SecNumOfTData: 7 + SecNumOfTBSS: 8 + FlagAndTDataAlignment: 0x1 + Flag: [[FLAG64=]] +Sections: + - Flags: [ STYP_TEXT ] + SectionData: "1232" + - Flags: [ STYP_DATA ] + SectionData: "5678" + - Flags: [ STYP_BSS ] + SectionData: "9101" + - Flags: [ STYP_TDATA ] + SectionData: "1112" + - Flags: [ STYP_TBSS ] + SectionData: "1314" + +# COMMON:---Auxiliary Header: +# COMMON-NEXT:Magic: 0x10b +# COMMON-NEXT:Version: 0x1 +# CHECK32-NEXT:Size of .text section: 0x8 +# CHECK32-NEXT:Size of .data section: 0x9 +# CHECK32-NEXT:Size of .bss section: 0x10 +# CHECK32-NEXT:Entry point address: 0x1111 +# CHECK64-NEXT:Reserved for debugger: 0x0 +# COMMON-NEXT:.text section start address: 0x2222 +# COMMON-NEXT:.data section start address: 0x3333 +# COMMON-NEXT:TOC anchor address: 0x4444 +# COMMON-NEXT:Section number of entryPoint: 1 +# COMMON-NEXT:Section number of .text: 2 +# COMMON-NEXT:Section number of .data: 3 +# COMMON-NEXT:Section number of TOC: 4 +# COMMON-NEXT:Section number of loader data: 5 +# COMMON-NEXT:Section number of .bss: 6 +# COMMON-NEXT:Maxium alignment of .text: 0x7 +# COMMON-NEXT:Maxium alignment of .data: 0x3 +# COMMON-NEXT:Module type: 0x0 +# COMMON-NEXT:CPU type of objects: 0x1 +# CHECK32-NEXT:Maximum stack size: 0x0 +# CHECK32-NEXT:Maximum data size: 0x0 +# CHECK32-NEXT:Reserved for debugger: 0x0 +# COMMON-NEXT:Text page size: 0x1 +# COMMON-NEXT:Data page size: 0x1 +# COMMON-NEXT:Stack page size: 0x1 +# COMMON-NEXT:Flag: 0x0 +# COMMON-NEXT:Alignment of thread-local storage: 0x1 +# CHECK64-NEXT:Size of .text section: 0x8 +# CHECK64-NEXT:Size of .data section: 0x9 +# CHECK64-NEXT:Size of .bss section: 0x10 +# CHECK64-NEXT:Entry point address: 0x1111 +# CHECK64-NEXT:Maximum stack size: 0x0 +# CHECK64-NEXT:Maximum data size: 0x0 +# COMMON-NEXT:Section number for .tdata: 7 +# COMMON-NEXT:Section number for .tbss: 8 +# CHECK64-NEXT:Additional flags 64-bit XCOFF: 0x2 + +## Test how llvm-objdump behaves when the auxiliary header of the XCOFF object file contains a partial field. +# RUN: cp %t1 %t1_err1 +# RUN: %python -c "with open(r'%t1_err1', 'r+b') as input: input.seek(17); input.write(b'\x45'); input.seek(4); input.write(b'\x00')" +# RUN: llvm-objdump --private-headers %t1_err1 2>&1 | FileCheck %s --check-prefix=WARN1 --match-full-lines --strict-whitespace + +# WARN1:{{.*}}: only partial field for Section number for .tdata: at offset (68) +# WARN1-NEXT:Raw data (00) + +## Test how llvm-objdump behaves when the auxiliary header of the XCOFF object file contains extra data. +# RUN: cp %t1 %t1_extra +# RUN: %python -c "with open(r'%t1_extra', 'r+b') as input: input.seek(17); input.write(b'\x4f'); input.seek(4); input.write(b'\x00')" +# RUN: llvm-objdump --private-headers %t1_extra 2>&1 | FileCheck %s --check-prefix=EXTRA --match-full-lines --strict-whitespace + +# EXTRA:Extra raw data (00000000 000000) +# EXTRA-NOT:{{.}} diff --git a/llvm/tools/llvm-objdump/XCOFFDump.cpp b/llvm/tools/llvm-objdump/XCOFFDump.cpp index 524bf07c372a9..2e8a8c82b8907 100644 --- a/llvm/tools/llvm-objdump/XCOFFDump.cpp +++ b/llvm/tools/llvm-objdump/XCOFFDump.cpp @@ -32,6 +32,7 @@ using namespace llvm::support; namespace { class XCOFFDumper : public objdump::Dumper { + enum PrintStyle { Hex, Number }; const XCOFFObjectFile &Obj; unsigned Width; @@ -41,14 +42,32 @@ class XCOFFDumper : public objdump::Dumper { private: void printPrivateHeaders() override; void printFileHeader(); - FormattedString formatName(StringRef Name); + void printAuxiliaryHeader(); + void printAuxiliaryHeader(const XCOFFAuxiliaryHeader32 *AuxHeader); + void printAuxiliaryHeader(const XCOFFAuxiliaryHeader64 *AuxHeader); + template + void printAuxMemberHelper(PrintStyle Style, const char *MemberName, + const AuxHeaderMemberType &Member, + const XCOFFAuxiliaryHeader *AuxHeader, + uint16_t AuxSize, uint16_t &PartialFieldOffset, + const char *&PartialFieldName); + template + void checkAndPrintAuxHeaderParseError(const char *PartialFieldName, + uint16_t PartialFieldOffset, + uint16_t AuxSize, + XCOFFAuxiliaryHeader &AuxHeader); + + void printBinary(StringRef Name, ArrayRef Data); void printHex(StringRef Name, uint64_t Value); void printNumber(StringRef Name, uint64_t Value); + FormattedString formatName(StringRef Name); void printStrHex(StringRef Name, StringRef Str, uint64_t Value); - void setWidth(unsigned W) { Width = W; }; }; -void XCOFFDumper::printPrivateHeaders() { printFileHeader(); } +void XCOFFDumper::printPrivateHeaders() { + printFileHeader(); + printAuxiliaryHeader(); +} FormattedString XCOFFDumper::formatName(StringRef Name) { return FormattedString(Name, Width, FormattedString::JustifyLeft); @@ -67,8 +86,185 @@ void XCOFFDumper::printStrHex(StringRef Name, StringRef Str, uint64_t Value) { << ")\n"; } +void XCOFFDumper::printBinary(StringRef Name, ArrayRef Data) { + unsigned OrgWidth = Width; + Width = 0; + outs() << formatName(Name) << " (" << format_bytes(Data) << ")\n"; + Width = OrgWidth; +} + +void XCOFFDumper::printAuxiliaryHeader() { + Width = 36; + if (Obj.is64Bit()) + printAuxiliaryHeader(Obj.auxiliaryHeader64()); + else + printAuxiliaryHeader(Obj.auxiliaryHeader32()); +} + +template +void XCOFFDumper::printAuxMemberHelper(PrintStyle Style, const char *MemberName, + const AuxHeaderMemberType &Member, + const XCOFFAuxiliaryHeader *AuxHeader, + uint16_t AuxSize, + uint16_t &PartialFieldOffset, + const char *&PartialFieldName) { + ptrdiff_t Offset = reinterpret_cast(&Member) - + reinterpret_cast(AuxHeader); + if (Offset + sizeof(Member) <= AuxSize) { + if (Style == Hex) + printHex(MemberName, Member); + else + printNumber(MemberName, Member); + } else if (Offset < AuxSize) { + PartialFieldOffset = Offset; + PartialFieldName = MemberName; + } +} + +template +void XCOFFDumper::checkAndPrintAuxHeaderParseError( + const char *PartialFieldName, uint16_t PartialFieldOffset, uint16_t AuxSize, + XCOFFAuxiliaryHeader &AuxHeader) { + if (PartialFieldOffset < AuxSize) { + std::string Buf; + raw_string_ostream OS(Buf); + OS.flush(); + OS << FormattedString("Raw data", 0, FormattedString::JustifyLeft) << " (" + << format_bytes( + ArrayRef(reinterpret_cast(&AuxHeader) + + PartialFieldOffset, + AuxSize - PartialFieldOffset)) + << ")\n"; + reportUniqueWarning(Twine("only partial field for ") + PartialFieldName + + " at offset (" + Twine(PartialFieldOffset) + ")\n" + + OS.str()); + } else if (sizeof(AuxHeader) < AuxSize) { + printBinary( + "Extra raw data", + ArrayRef(reinterpret_cast(&AuxHeader) + + sizeof(AuxHeader), + AuxSize - sizeof(AuxHeader))); + } +} + +void XCOFFDumper::printAuxiliaryHeader( + const XCOFFAuxiliaryHeader32 *AuxHeader) { + if (AuxHeader == nullptr) + return; + outs() << "\n---Auxiliary Header:\n"; + uint16_t AuxSize = Obj.getOptionalHeaderSize(); + uint16_t PartialFieldOffset = AuxSize; + const char *PartialFieldName = nullptr; + + auto PrintAuxMember = [&](PrintStyle Style, const char *MemberName, + auto &Member) { + printAuxMemberHelper(Style, MemberName, Member, AuxHeader, AuxSize, + PartialFieldOffset, PartialFieldName); + }; + + PrintAuxMember(Hex, "Magic:", AuxHeader->AuxMagic); + PrintAuxMember(Hex, "Version:", AuxHeader->Version); + PrintAuxMember(Hex, "Size of .text section:", AuxHeader->TextSize); + PrintAuxMember(Hex, "Size of .data section:", AuxHeader->InitDataSize); + PrintAuxMember(Hex, "Size of .bss section:", AuxHeader->BssDataSize); + PrintAuxMember(Hex, "Entry point address:", AuxHeader->EntryPointAddr); + PrintAuxMember(Hex, ".text section start address:", AuxHeader->TextStartAddr); + PrintAuxMember(Hex, ".data section start address:", AuxHeader->DataStartAddr); + PrintAuxMember(Hex, "TOC anchor address:", AuxHeader->TOCAnchorAddr); + PrintAuxMember( + Number, "Section number of entryPoint:", AuxHeader->SecNumOfEntryPoint); + PrintAuxMember(Number, "Section number of .text:", AuxHeader->SecNumOfText); + PrintAuxMember(Number, "Section number of .data:", AuxHeader->SecNumOfData); + PrintAuxMember(Number, "Section number of TOC:", AuxHeader->SecNumOfTOC); + PrintAuxMember(Number, + "Section number of loader data:", AuxHeader->SecNumOfLoader); + PrintAuxMember(Number, "Section number of .bss:", AuxHeader->SecNumOfBSS); + PrintAuxMember(Hex, "Maxium alignment of .text:", AuxHeader->MaxAlignOfText); + PrintAuxMember(Hex, "Maxium alignment of .data:", AuxHeader->MaxAlignOfData); + PrintAuxMember(Hex, "Module type:", AuxHeader->ModuleType); + PrintAuxMember(Hex, "CPU type of objects:", AuxHeader->CpuFlag); + PrintAuxMember(Hex, "Maximum stack size:", AuxHeader->MaxStackSize); + PrintAuxMember(Hex, "Maximum data size:", AuxHeader->MaxDataSize); + PrintAuxMember(Hex, "Reserved for debugger:", AuxHeader->ReservedForDebugger); + PrintAuxMember(Hex, "Text page size:", AuxHeader->TextPageSize); + PrintAuxMember(Hex, "Data page size:", AuxHeader->DataPageSize); + PrintAuxMember(Hex, "Stack page size:", AuxHeader->StackPageSize); + if (offsetof(XCOFFAuxiliaryHeader32, FlagAndTDataAlignment) + + sizeof(XCOFFAuxiliaryHeader32::FlagAndTDataAlignment) <= + AuxSize) { + printHex("Flag:", AuxHeader->getFlag()); + printHex("Alignment of thread-local storage:", + AuxHeader->getTDataAlignment()); + } + + PrintAuxMember(Number, + "Section number for .tdata:", AuxHeader->SecNumOfTData); + PrintAuxMember(Number, "Section number for .tbss:", AuxHeader->SecNumOfTBSS); + + checkAndPrintAuxHeaderParseError(PartialFieldName, PartialFieldOffset, + AuxSize, *AuxHeader); +} + +void XCOFFDumper::printAuxiliaryHeader( + const XCOFFAuxiliaryHeader64 *AuxHeader) { + if (AuxHeader == nullptr) + return; + uint16_t AuxSize = Obj.getOptionalHeaderSize(); + outs() << "\n---Auxiliary Header:\n"; + uint16_t PartialFieldOffset = AuxSize; + const char *PartialFieldName = nullptr; + + auto PrintAuxMember = [&](PrintStyle Style, const char *MemberName, + auto &Member) { + printAuxMemberHelper(Style, MemberName, Member, AuxHeader, AuxSize, + PartialFieldOffset, PartialFieldName); + }; + + PrintAuxMember(Hex, "Magic:", AuxHeader->AuxMagic); + PrintAuxMember(Hex, "Version:", AuxHeader->Version); + PrintAuxMember(Hex, "Reserved for debugger:", AuxHeader->ReservedForDebugger); + PrintAuxMember(Hex, ".text section start address:", AuxHeader->TextStartAddr); + PrintAuxMember(Hex, ".data section start address:", AuxHeader->DataStartAddr); + PrintAuxMember(Hex, "TOC anchor address:", AuxHeader->TOCAnchorAddr); + PrintAuxMember( + Number, "Section number of entryPoint:", AuxHeader->SecNumOfEntryPoint); + PrintAuxMember(Number, "Section number of .text:", AuxHeader->SecNumOfText); + PrintAuxMember(Number, "Section number of .data:", AuxHeader->SecNumOfData); + PrintAuxMember(Number, "Section number of TOC:", AuxHeader->SecNumOfTOC); + PrintAuxMember(Number, + "Section number of loader data:", AuxHeader->SecNumOfLoader); + PrintAuxMember(Number, "Section number of .bss:", AuxHeader->SecNumOfBSS); + PrintAuxMember(Hex, "Maxium alignment of .text:", AuxHeader->MaxAlignOfText); + PrintAuxMember(Hex, "Maxium alignment of .data:", AuxHeader->MaxAlignOfData); + PrintAuxMember(Hex, "Module type:", AuxHeader->ModuleType); + PrintAuxMember(Hex, "CPU type of objects:", AuxHeader->CpuFlag); + PrintAuxMember(Hex, "Text page size:", AuxHeader->TextPageSize); + PrintAuxMember(Hex, "Data page size:", AuxHeader->DataPageSize); + PrintAuxMember(Hex, "Stack page size:", AuxHeader->StackPageSize); + if (offsetof(XCOFFAuxiliaryHeader64, FlagAndTDataAlignment) + + sizeof(XCOFFAuxiliaryHeader64::FlagAndTDataAlignment) <= + AuxSize) { + printHex("Flag:", AuxHeader->getFlag()); + printHex("Alignment of thread-local storage:", + AuxHeader->getTDataAlignment()); + } + PrintAuxMember(Hex, "Size of .text section:", AuxHeader->TextSize); + PrintAuxMember(Hex, "Size of .data section:", AuxHeader->InitDataSize); + PrintAuxMember(Hex, "Size of .bss section:", AuxHeader->BssDataSize); + PrintAuxMember(Hex, "Entry point address:", AuxHeader->EntryPointAddr); + PrintAuxMember(Hex, "Maximum stack size:", AuxHeader->MaxStackSize); + PrintAuxMember(Hex, "Maximum data size:", AuxHeader->MaxDataSize); + PrintAuxMember(Number, + "Section number for .tdata:", AuxHeader->SecNumOfTData); + PrintAuxMember(Number, "Section number for .tbss:", AuxHeader->SecNumOfTBSS); + PrintAuxMember(Hex, "Additional flags 64-bit XCOFF:", AuxHeader->XCOFF64Flag); + + checkAndPrintAuxHeaderParseError(PartialFieldName, PartialFieldOffset, + AuxSize, *AuxHeader); +} + void XCOFFDumper::printFileHeader() { - setWidth(20); + Width = 20; outs() << "\n---File Header:\n"; printHex("Magic:", Obj.getMagic()); printNumber("NumberOfSections:", Obj.getNumberOfSections());