Skip to content

Commit e373ba4

Browse files
authored
[llvm-objdump] Implement decoding auxiliary header for xcoff with llvm-objdump --private-headers (#105682)
Implement decoding auxiliary header of XCOFF object file with llvm-objdump --private-headers
1 parent 76a52db commit e373ba4

File tree

2 files changed

+303
-4
lines changed

2 files changed

+303
-4
lines changed
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
## Test that `llvm-objdump --private-headers` prints out the auxiliary header of an XCOFF object file.
2+
# RUN: yaml2obj %s -o %t1
3+
# RUN: llvm-objdump --private-headers %t1 | \
4+
# RUN: FileCheck %s --check-prefixes=CHECK32,COMMON --match-full-lines --strict-whitespace
5+
# RUN: yaml2obj %s -DMAGIC=0x1F7 -DFLAG64=0x2 -o %t2
6+
# RUN: llvm-objdump --private-headers %t2 | \
7+
# RUN: FileCheck %s --check-prefixes=CHECK64,COMMON --match-full-lines --strict-whitespace
8+
9+
--- !XCOFF
10+
FileHeader:
11+
MagicNumber: [[MAGIC=0x1DF]]
12+
AuxiliaryHeader:
13+
Magic: 0x10B
14+
Version: 0x1
15+
TextSectionSize: 0x8
16+
DataSectionSize: 0x9
17+
BssSectionSize: 0x10
18+
EntryPointAddr: 0x1111
19+
TextStartAddr: 0x2222
20+
DataStartAddr: 0x3333
21+
TOCAnchorAddr: 0x4444
22+
SecNumOfEntryPoint: 1
23+
SecNumOfText: 2
24+
SecNumOfData: 3
25+
SecNumOfTOC: 4
26+
SecNumOfLoader: 5
27+
SecNumOfBSS: 6
28+
MaxAlignOfText: 0x7
29+
MaxAlignOfData: 0x3
30+
ModuleType: 0x1
31+
TextPageSize: 0x1
32+
DataPageSize: 0x1
33+
StackPageSize: 0x1
34+
SecNumOfTData: 7
35+
SecNumOfTBSS: 8
36+
FlagAndTDataAlignment: 0x1
37+
Flag: [[FLAG64=<none>]]
38+
Sections:
39+
- Flags: [ STYP_TEXT ]
40+
SectionData: "1232"
41+
- Flags: [ STYP_DATA ]
42+
SectionData: "5678"
43+
- Flags: [ STYP_BSS ]
44+
SectionData: "9101"
45+
- Flags: [ STYP_TDATA ]
46+
SectionData: "1112"
47+
- Flags: [ STYP_TBSS ]
48+
SectionData: "1314"
49+
50+
# COMMON:---Auxiliary Header:
51+
# COMMON-NEXT:Magic: 0x10b
52+
# COMMON-NEXT:Version: 0x1
53+
# CHECK32-NEXT:Size of .text section: 0x8
54+
# CHECK32-NEXT:Size of .data section: 0x9
55+
# CHECK32-NEXT:Size of .bss section: 0x10
56+
# CHECK32-NEXT:Entry point address: 0x1111
57+
# CHECK64-NEXT:Reserved for debugger: 0x0
58+
# COMMON-NEXT:.text section start address: 0x2222
59+
# COMMON-NEXT:.data section start address: 0x3333
60+
# COMMON-NEXT:TOC anchor address: 0x4444
61+
# COMMON-NEXT:Section number of entryPoint: 1
62+
# COMMON-NEXT:Section number of .text: 2
63+
# COMMON-NEXT:Section number of .data: 3
64+
# COMMON-NEXT:Section number of TOC: 4
65+
# COMMON-NEXT:Section number of loader data: 5
66+
# COMMON-NEXT:Section number of .bss: 6
67+
# COMMON-NEXT:Maxium alignment of .text: 0x7
68+
# COMMON-NEXT:Maxium alignment of .data: 0x3
69+
# COMMON-NEXT:Module type: 0x0
70+
# COMMON-NEXT:CPU type of objects: 0x1
71+
# CHECK32-NEXT:Maximum stack size: 0x0
72+
# CHECK32-NEXT:Maximum data size: 0x0
73+
# CHECK32-NEXT:Reserved for debugger: 0x0
74+
# COMMON-NEXT:Text page size: 0x1
75+
# COMMON-NEXT:Data page size: 0x1
76+
# COMMON-NEXT:Stack page size: 0x1
77+
# COMMON-NEXT:Flag: 0x0
78+
# COMMON-NEXT:Alignment of thread-local storage: 0x1
79+
# CHECK64-NEXT:Size of .text section: 0x8
80+
# CHECK64-NEXT:Size of .data section: 0x9
81+
# CHECK64-NEXT:Size of .bss section: 0x10
82+
# CHECK64-NEXT:Entry point address: 0x1111
83+
# CHECK64-NEXT:Maximum stack size: 0x0
84+
# CHECK64-NEXT:Maximum data size: 0x0
85+
# COMMON-NEXT:Section number for .tdata: 7
86+
# COMMON-NEXT:Section number for .tbss: 8
87+
# CHECK64-NEXT:Additional flags 64-bit XCOFF: 0x2
88+
89+
## Test how llvm-objdump behaves when the auxiliary header of the XCOFF object file contains a partial field.
90+
# RUN: cp %t1 %t1_err1
91+
# 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')"
92+
# RUN: llvm-objdump --private-headers %t1_err1 2>&1 | FileCheck %s --check-prefix=WARN1 --match-full-lines --strict-whitespace
93+
94+
# WARN1:{{.*}}: only partial field for Section number for .tdata: at offset (68)
95+
# WARN1-NEXT:Raw data (00)
96+
97+
## Test how llvm-objdump behaves when the auxiliary header of the XCOFF object file contains extra data.
98+
# RUN: cp %t1 %t1_extra
99+
# 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')"
100+
# RUN: llvm-objdump --private-headers %t1_extra 2>&1 | FileCheck %s --check-prefix=EXTRA --match-full-lines --strict-whitespace
101+
102+
# EXTRA:Extra raw data (00000000 000000)
103+
# EXTRA-NOT:{{.}}

llvm/tools/llvm-objdump/XCOFFDump.cpp

Lines changed: 200 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ using namespace llvm::support;
3232

3333
namespace {
3434
class XCOFFDumper : public objdump::Dumper {
35+
enum PrintStyle { Hex, Number };
3536
const XCOFFObjectFile &Obj;
3637
unsigned Width;
3738

@@ -41,14 +42,32 @@ class XCOFFDumper : public objdump::Dumper {
4142
private:
4243
void printPrivateHeaders() override;
4344
void printFileHeader();
44-
FormattedString formatName(StringRef Name);
45+
void printAuxiliaryHeader();
46+
void printAuxiliaryHeader(const XCOFFAuxiliaryHeader32 *AuxHeader);
47+
void printAuxiliaryHeader(const XCOFFAuxiliaryHeader64 *AuxHeader);
48+
template <typename AuxHeaderMemberType, typename XCOFFAuxiliaryHeader>
49+
void printAuxMemberHelper(PrintStyle Style, const char *MemberName,
50+
const AuxHeaderMemberType &Member,
51+
const XCOFFAuxiliaryHeader *AuxHeader,
52+
uint16_t AuxSize, uint16_t &PartialFieldOffset,
53+
const char *&PartialFieldName);
54+
template <typename XCOFFAuxiliaryHeader>
55+
void checkAndPrintAuxHeaderParseError(const char *PartialFieldName,
56+
uint16_t PartialFieldOffset,
57+
uint16_t AuxSize,
58+
XCOFFAuxiliaryHeader &AuxHeader);
59+
60+
void printBinary(StringRef Name, ArrayRef<uint8_t> Data);
4561
void printHex(StringRef Name, uint64_t Value);
4662
void printNumber(StringRef Name, uint64_t Value);
63+
FormattedString formatName(StringRef Name);
4764
void printStrHex(StringRef Name, StringRef Str, uint64_t Value);
48-
void setWidth(unsigned W) { Width = W; };
4965
};
5066

51-
void XCOFFDumper::printPrivateHeaders() { printFileHeader(); }
67+
void XCOFFDumper::printPrivateHeaders() {
68+
printFileHeader();
69+
printAuxiliaryHeader();
70+
}
5271

5372
FormattedString XCOFFDumper::formatName(StringRef Name) {
5473
return FormattedString(Name, Width, FormattedString::JustifyLeft);
@@ -67,8 +86,185 @@ void XCOFFDumper::printStrHex(StringRef Name, StringRef Str, uint64_t Value) {
6786
<< ")\n";
6887
}
6988

89+
void XCOFFDumper::printBinary(StringRef Name, ArrayRef<uint8_t> Data) {
90+
unsigned OrgWidth = Width;
91+
Width = 0;
92+
outs() << formatName(Name) << " (" << format_bytes(Data) << ")\n";
93+
Width = OrgWidth;
94+
}
95+
96+
void XCOFFDumper::printAuxiliaryHeader() {
97+
Width = 36;
98+
if (Obj.is64Bit())
99+
printAuxiliaryHeader(Obj.auxiliaryHeader64());
100+
else
101+
printAuxiliaryHeader(Obj.auxiliaryHeader32());
102+
}
103+
104+
template <typename AuxHeaderMemberType, typename XCOFFAuxiliaryHeader>
105+
void XCOFFDumper::printAuxMemberHelper(PrintStyle Style, const char *MemberName,
106+
const AuxHeaderMemberType &Member,
107+
const XCOFFAuxiliaryHeader *AuxHeader,
108+
uint16_t AuxSize,
109+
uint16_t &PartialFieldOffset,
110+
const char *&PartialFieldName) {
111+
ptrdiff_t Offset = reinterpret_cast<const char *>(&Member) -
112+
reinterpret_cast<const char *>(AuxHeader);
113+
if (Offset + sizeof(Member) <= AuxSize) {
114+
if (Style == Hex)
115+
printHex(MemberName, Member);
116+
else
117+
printNumber(MemberName, Member);
118+
} else if (Offset < AuxSize) {
119+
PartialFieldOffset = Offset;
120+
PartialFieldName = MemberName;
121+
}
122+
}
123+
124+
template <typename XCOFFAuxiliaryHeader>
125+
void XCOFFDumper::checkAndPrintAuxHeaderParseError(
126+
const char *PartialFieldName, uint16_t PartialFieldOffset, uint16_t AuxSize,
127+
XCOFFAuxiliaryHeader &AuxHeader) {
128+
if (PartialFieldOffset < AuxSize) {
129+
std::string Buf;
130+
raw_string_ostream OS(Buf);
131+
OS.flush();
132+
OS << FormattedString("Raw data", 0, FormattedString::JustifyLeft) << " ("
133+
<< format_bytes(
134+
ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(&AuxHeader) +
135+
PartialFieldOffset,
136+
AuxSize - PartialFieldOffset))
137+
<< ")\n";
138+
reportUniqueWarning(Twine("only partial field for ") + PartialFieldName +
139+
" at offset (" + Twine(PartialFieldOffset) + ")\n" +
140+
OS.str());
141+
} else if (sizeof(AuxHeader) < AuxSize) {
142+
printBinary(
143+
"Extra raw data",
144+
ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(&AuxHeader) +
145+
sizeof(AuxHeader),
146+
AuxSize - sizeof(AuxHeader)));
147+
}
148+
}
149+
150+
void XCOFFDumper::printAuxiliaryHeader(
151+
const XCOFFAuxiliaryHeader32 *AuxHeader) {
152+
if (AuxHeader == nullptr)
153+
return;
154+
outs() << "\n---Auxiliary Header:\n";
155+
uint16_t AuxSize = Obj.getOptionalHeaderSize();
156+
uint16_t PartialFieldOffset = AuxSize;
157+
const char *PartialFieldName = nullptr;
158+
159+
auto PrintAuxMember = [&](PrintStyle Style, const char *MemberName,
160+
auto &Member) {
161+
printAuxMemberHelper(Style, MemberName, Member, AuxHeader, AuxSize,
162+
PartialFieldOffset, PartialFieldName);
163+
};
164+
165+
PrintAuxMember(Hex, "Magic:", AuxHeader->AuxMagic);
166+
PrintAuxMember(Hex, "Version:", AuxHeader->Version);
167+
PrintAuxMember(Hex, "Size of .text section:", AuxHeader->TextSize);
168+
PrintAuxMember(Hex, "Size of .data section:", AuxHeader->InitDataSize);
169+
PrintAuxMember(Hex, "Size of .bss section:", AuxHeader->BssDataSize);
170+
PrintAuxMember(Hex, "Entry point address:", AuxHeader->EntryPointAddr);
171+
PrintAuxMember(Hex, ".text section start address:", AuxHeader->TextStartAddr);
172+
PrintAuxMember(Hex, ".data section start address:", AuxHeader->DataStartAddr);
173+
PrintAuxMember(Hex, "TOC anchor address:", AuxHeader->TOCAnchorAddr);
174+
PrintAuxMember(
175+
Number, "Section number of entryPoint:", AuxHeader->SecNumOfEntryPoint);
176+
PrintAuxMember(Number, "Section number of .text:", AuxHeader->SecNumOfText);
177+
PrintAuxMember(Number, "Section number of .data:", AuxHeader->SecNumOfData);
178+
PrintAuxMember(Number, "Section number of TOC:", AuxHeader->SecNumOfTOC);
179+
PrintAuxMember(Number,
180+
"Section number of loader data:", AuxHeader->SecNumOfLoader);
181+
PrintAuxMember(Number, "Section number of .bss:", AuxHeader->SecNumOfBSS);
182+
PrintAuxMember(Hex, "Maxium alignment of .text:", AuxHeader->MaxAlignOfText);
183+
PrintAuxMember(Hex, "Maxium alignment of .data:", AuxHeader->MaxAlignOfData);
184+
PrintAuxMember(Hex, "Module type:", AuxHeader->ModuleType);
185+
PrintAuxMember(Hex, "CPU type of objects:", AuxHeader->CpuFlag);
186+
PrintAuxMember(Hex, "Maximum stack size:", AuxHeader->MaxStackSize);
187+
PrintAuxMember(Hex, "Maximum data size:", AuxHeader->MaxDataSize);
188+
PrintAuxMember(Hex, "Reserved for debugger:", AuxHeader->ReservedForDebugger);
189+
PrintAuxMember(Hex, "Text page size:", AuxHeader->TextPageSize);
190+
PrintAuxMember(Hex, "Data page size:", AuxHeader->DataPageSize);
191+
PrintAuxMember(Hex, "Stack page size:", AuxHeader->StackPageSize);
192+
if (offsetof(XCOFFAuxiliaryHeader32, FlagAndTDataAlignment) +
193+
sizeof(XCOFFAuxiliaryHeader32::FlagAndTDataAlignment) <=
194+
AuxSize) {
195+
printHex("Flag:", AuxHeader->getFlag());
196+
printHex("Alignment of thread-local storage:",
197+
AuxHeader->getTDataAlignment());
198+
}
199+
200+
PrintAuxMember(Number,
201+
"Section number for .tdata:", AuxHeader->SecNumOfTData);
202+
PrintAuxMember(Number, "Section number for .tbss:", AuxHeader->SecNumOfTBSS);
203+
204+
checkAndPrintAuxHeaderParseError(PartialFieldName, PartialFieldOffset,
205+
AuxSize, *AuxHeader);
206+
}
207+
208+
void XCOFFDumper::printAuxiliaryHeader(
209+
const XCOFFAuxiliaryHeader64 *AuxHeader) {
210+
if (AuxHeader == nullptr)
211+
return;
212+
uint16_t AuxSize = Obj.getOptionalHeaderSize();
213+
outs() << "\n---Auxiliary Header:\n";
214+
uint16_t PartialFieldOffset = AuxSize;
215+
const char *PartialFieldName = nullptr;
216+
217+
auto PrintAuxMember = [&](PrintStyle Style, const char *MemberName,
218+
auto &Member) {
219+
printAuxMemberHelper(Style, MemberName, Member, AuxHeader, AuxSize,
220+
PartialFieldOffset, PartialFieldName);
221+
};
222+
223+
PrintAuxMember(Hex, "Magic:", AuxHeader->AuxMagic);
224+
PrintAuxMember(Hex, "Version:", AuxHeader->Version);
225+
PrintAuxMember(Hex, "Reserved for debugger:", AuxHeader->ReservedForDebugger);
226+
PrintAuxMember(Hex, ".text section start address:", AuxHeader->TextStartAddr);
227+
PrintAuxMember(Hex, ".data section start address:", AuxHeader->DataStartAddr);
228+
PrintAuxMember(Hex, "TOC anchor address:", AuxHeader->TOCAnchorAddr);
229+
PrintAuxMember(
230+
Number, "Section number of entryPoint:", AuxHeader->SecNumOfEntryPoint);
231+
PrintAuxMember(Number, "Section number of .text:", AuxHeader->SecNumOfText);
232+
PrintAuxMember(Number, "Section number of .data:", AuxHeader->SecNumOfData);
233+
PrintAuxMember(Number, "Section number of TOC:", AuxHeader->SecNumOfTOC);
234+
PrintAuxMember(Number,
235+
"Section number of loader data:", AuxHeader->SecNumOfLoader);
236+
PrintAuxMember(Number, "Section number of .bss:", AuxHeader->SecNumOfBSS);
237+
PrintAuxMember(Hex, "Maxium alignment of .text:", AuxHeader->MaxAlignOfText);
238+
PrintAuxMember(Hex, "Maxium alignment of .data:", AuxHeader->MaxAlignOfData);
239+
PrintAuxMember(Hex, "Module type:", AuxHeader->ModuleType);
240+
PrintAuxMember(Hex, "CPU type of objects:", AuxHeader->CpuFlag);
241+
PrintAuxMember(Hex, "Text page size:", AuxHeader->TextPageSize);
242+
PrintAuxMember(Hex, "Data page size:", AuxHeader->DataPageSize);
243+
PrintAuxMember(Hex, "Stack page size:", AuxHeader->StackPageSize);
244+
if (offsetof(XCOFFAuxiliaryHeader64, FlagAndTDataAlignment) +
245+
sizeof(XCOFFAuxiliaryHeader64::FlagAndTDataAlignment) <=
246+
AuxSize) {
247+
printHex("Flag:", AuxHeader->getFlag());
248+
printHex("Alignment of thread-local storage:",
249+
AuxHeader->getTDataAlignment());
250+
}
251+
PrintAuxMember(Hex, "Size of .text section:", AuxHeader->TextSize);
252+
PrintAuxMember(Hex, "Size of .data section:", AuxHeader->InitDataSize);
253+
PrintAuxMember(Hex, "Size of .bss section:", AuxHeader->BssDataSize);
254+
PrintAuxMember(Hex, "Entry point address:", AuxHeader->EntryPointAddr);
255+
PrintAuxMember(Hex, "Maximum stack size:", AuxHeader->MaxStackSize);
256+
PrintAuxMember(Hex, "Maximum data size:", AuxHeader->MaxDataSize);
257+
PrintAuxMember(Number,
258+
"Section number for .tdata:", AuxHeader->SecNumOfTData);
259+
PrintAuxMember(Number, "Section number for .tbss:", AuxHeader->SecNumOfTBSS);
260+
PrintAuxMember(Hex, "Additional flags 64-bit XCOFF:", AuxHeader->XCOFF64Flag);
261+
262+
checkAndPrintAuxHeaderParseError(PartialFieldName, PartialFieldOffset,
263+
AuxSize, *AuxHeader);
264+
}
265+
70266
void XCOFFDumper::printFileHeader() {
71-
setWidth(20);
267+
Width = 20;
72268
outs() << "\n---File Header:\n";
73269
printHex("Magic:", Obj.getMagic());
74270
printNumber("NumberOfSections:", Obj.getNumberOfSections());

0 commit comments

Comments
 (0)