-
Notifications
You must be signed in to change notification settings - Fork 15.2k
[llvm-objdump] Implement decoding auxiliary header for xcoff with llvm-objdump --private-headers #105682
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[llvm-objdump] Implement decoding auxiliary header for xcoff with llvm-objdump --private-headers #105682
Changes from 3 commits
3a52dd2
935775c
e38e11f
8bfbee4
4535a2f
de6dce5
081f917
00ce595
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,128 @@ | ||||||
| ## Test that `the llvm-objdump --private-headers` print out the auxiliary header of XCOFF object file. | ||||||
|
||||||
| ## Test that `the llvm-objdump --private-headers` print out the auxiliary header of XCOFF object file. | |
| ## Test that `the llvm-objdump --private-headers` prints out the auxiliary header of an XCOFF object file. |
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a reason these two lines can't be folded together into one python statement? You may also wish to look at using split-file, to allow you to have a proper python script, rather than these inline snippets.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks, combine to one line. This a one line python script, I do not think it need a split-file.
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's a lot of duplication between the 32-bit and 64-bit checks here. Could you use a pattern of something like CHECK for common parts, and CHECK32/CHECK64 for parts that are not common, to reduce the duplication?
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does a Reserved field really need printing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thank, I deleted it.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -37,18 +37,26 @@ class XCOFFDumper : public objdump::Dumper { | |
|
|
||
| public: | ||
| XCOFFDumper(const object::XCOFFObjectFile &O) : Dumper(O), Obj(O) {} | ||
| void printBinary(StringRef Name, ArrayRef<uint8_t> B); | ||
| void printHex(StringRef Name, uint64_t Value); | ||
| void printNumber(StringRef Name, uint64_t Value); | ||
|
|
||
| private: | ||
| void printPrivateHeaders() override; | ||
| void printFileHeader(); | ||
| void printAuxiliaryHeader(); | ||
| void printAuxiliaryHeader(const XCOFFAuxiliaryHeader32 *AuxHeader); | ||
| void printAuxiliaryHeader(const XCOFFAuxiliaryHeader64 *AuxHeader); | ||
| FormattedString formatName(StringRef Name); | ||
| void printHex(StringRef Name, uint64_t Value); | ||
| void printNumber(StringRef Name, uint64_t Value); | ||
| void printStrHex(StringRef Name, StringRef Str, uint64_t Value); | ||
| void setWidth(unsigned W) { Width = W; }; | ||
| unsigned getWidth() { return Width; } | ||
jh7370 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| }; | ||
|
|
||
| void XCOFFDumper::printPrivateHeaders() { printFileHeader(); } | ||
| void XCOFFDumper::printPrivateHeaders() { | ||
| printFileHeader(); | ||
| printAuxiliaryHeader(); | ||
| } | ||
|
|
||
| FormattedString XCOFFDumper::formatName(StringRef Name) { | ||
| return FormattedString(Name, Width, FormattedString::JustifyLeft); | ||
|
|
@@ -67,6 +75,179 @@ void XCOFFDumper::printStrHex(StringRef Name, StringRef Str, uint64_t Value) { | |
| << ")\n"; | ||
| } | ||
|
|
||
| void XCOFFDumper::printBinary(StringRef Name, ArrayRef<uint8_t> B) { | ||
| unsigned OrgWidth = getWidth(); | ||
| setWidth(0); | ||
| outs() << formatName(Name) << " (" << format_bytes(B) << ")\n"; | ||
| setWidth(OrgWidth); | ||
jh7370 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| void XCOFFDumper::printAuxiliaryHeader() { | ||
| setWidth(36); | ||
| if (Obj.is64Bit()) | ||
| printAuxiliaryHeader(Obj.auxiliaryHeader64()); | ||
| else | ||
| printAuxiliaryHeader(Obj.auxiliaryHeader32()); | ||
| } | ||
|
|
||
| enum PrintStyle { Hex, Number }; | ||
| template <typename T, typename V> | ||
|
||
| static void printAuxMemberHelper(PrintStyle Style, const char *MemberName, | ||
| const T &Member, const V *AuxHeader, | ||
| uint16_t AuxSize, uint16_t &PartialFieldOffset, | ||
| const char *&PartialFieldName, | ||
| XCOFFDumper *Dumper) { | ||
| ptrdiff_t Offset = reinterpret_cast<const char *>(&Member) - | ||
| reinterpret_cast<const char *>(AuxHeader); | ||
| if (Offset + sizeof(Member) <= AuxSize) | ||
jh7370 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| Style == Hex ? Dumper->printHex(MemberName, Member) | ||
| : Dumper->printNumber(MemberName, Member); | ||
| else if (Offset < AuxSize) { | ||
| PartialFieldOffset = Offset; | ||
| PartialFieldName = MemberName; | ||
| } | ||
| } | ||
|
|
||
| template <class T> | ||
|
||
| void checkAndPrintAuxHeaderParseError(const char *PartialFieldName, | ||
| uint16_t PartialFieldOffset, | ||
| uint16_t AuxSize, T &AuxHeader, | ||
| XCOFFDumper *Dumper) { | ||
| if (PartialFieldOffset < AuxSize) { | ||
| Dumper->reportUniqueWarning(Twine("only partial field for ") + | ||
| PartialFieldName + " at offset (" + | ||
| Twine(PartialFieldOffset) + ")"); | ||
| Dumper->printBinary( | ||
|
||
| "Raw data", | ||
| ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(&AuxHeader) + | ||
| PartialFieldOffset, | ||
| AuxSize - PartialFieldOffset)); | ||
| } else if (sizeof(AuxHeader) < AuxSize) | ||
|
||
| Dumper->printBinary( | ||
| "Extra raw data", | ||
| ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(&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, this); | ||
| }; | ||
|
|
||
| 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, "(Reserved):", AuxHeader->CpuType); | ||
| 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, this); | ||
| } | ||
|
|
||
| void XCOFFDumper::printAuxiliaryHeader( | ||
| const XCOFFAuxiliaryHeader64 *AuxHeader) { | ||
jh7370 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| 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, this); | ||
| }; | ||
|
|
||
| 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, "(Reserved):", AuxHeader->CpuType); | ||
| 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, this); | ||
| } | ||
|
|
||
| void XCOFFDumper::printFileHeader() { | ||
| setWidth(20); | ||
| outs() << "\n---File Header:\n"; | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please review what I've said in your past reviews about providing comments for individual cases within the test, ordering of RUN/YAML/CHECK lines and whitespace (especially blank lines), and act on them in this test file too.
Have you run this test locally at all?
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, I run this test locally
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
According to the pre-merge checks, this test is failing on Linux. Please review and fix.
I've also previously said that I'd prefer CHECK lines to be immediately after the corresponding test case, which you haven't addressed here.