1 //===-- XCOFFDumper.cpp - XCOFF dumping utility -----------------*- C++ -*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // This file implements an XCOFF specific dumper for llvm-readobj.
11 //===----------------------------------------------------------------------===//
13 #include "ObjDumper.h"
14 #include "llvm-readobj.h"
15 #include "llvm/Object/XCOFFObjectFile.h"
16 #include "llvm/Support/FormattedStream.h"
17 #include "llvm/Support/ScopedPrinter.h"
22 using namespace object
;
26 class XCOFFDumper
: public ObjDumper
{
29 XCOFFDumper(const XCOFFObjectFile
&Obj
, ScopedPrinter
&Writer
)
30 : ObjDumper(Writer
, Obj
.getFileName()), Obj(Obj
) {}
32 void printFileHeaders() override
;
33 void printAuxiliaryHeader() override
;
34 void printSectionHeaders() override
;
35 void printRelocations() override
;
36 void printSymbols() override
;
37 void printDynamicSymbols() override
;
38 void printUnwindInfo() override
;
39 void printStackMap() const override
;
40 void printNeededLibraries() override
;
41 void printStringTable() override
;
44 template <typename T
> void printSectionHeaders(ArrayRef
<T
> Sections
);
45 template <typename T
> void printGenericSectionHeader(T
&Sec
) const;
46 template <typename T
> void printOverflowSectionHeader(T
&Sec
) const;
47 template <typename T
> const T
*getAuxEntPtr(uintptr_t AuxAddress
);
48 void printFileAuxEnt(const XCOFFFileAuxEnt
*AuxEntPtr
);
49 void printCsectAuxEnt(XCOFFCsectAuxRef AuxEntRef
);
50 void printSectAuxEntForStat(const XCOFFSectAuxEntForStat
*AuxEntPtr
);
51 void printExceptionAuxEnt(const XCOFFExceptionAuxEnt
*AuxEntPtr
);
52 void printFunctionAuxEnt(const XCOFFFunctionAuxEnt32
*AuxEntPtr
);
53 void printFunctionAuxEnt(const XCOFFFunctionAuxEnt64
*AuxEntPtr
);
54 void printBlockAuxEnt(const XCOFFBlockAuxEnt32
*AuxEntPtr
);
55 void printBlockAuxEnt(const XCOFFBlockAuxEnt64
*AuxEntPtr
);
56 template <typename T
> void printSectAuxEntForDWARF(const T
*AuxEntPtr
);
57 void printSymbol(const SymbolRef
&);
58 template <typename RelTy
> void printRelocation(RelTy Reloc
);
59 template <typename Shdr
, typename RelTy
>
60 void printRelocations(ArrayRef
<Shdr
> Sections
);
61 void printAuxiliaryHeader(const XCOFFAuxiliaryHeader32
*AuxHeader
);
62 void printAuxiliaryHeader(const XCOFFAuxiliaryHeader64
*AuxHeader
);
63 const XCOFFObjectFile
&Obj
;
65 } // anonymous namespace
67 void XCOFFDumper::printFileHeaders() {
68 DictScope
DS(W
, "FileHeader");
69 W
.printHex("Magic", Obj
.getMagic());
70 W
.printNumber("NumberOfSections", Obj
.getNumberOfSections());
72 // Negative timestamp values are reserved for future use.
73 int32_t TimeStamp
= Obj
.getTimeStamp();
75 // This handling of the time stamp assumes that the host system's time_t is
76 // compatible with AIX time_t. If a platform is not compatible, the lit
77 // tests will let us know.
78 time_t TimeDate
= TimeStamp
;
80 char FormattedTime
[21] = {};
82 strftime(FormattedTime
, 21, "%Y-%m-%dT%H:%M:%SZ", gmtime(&TimeDate
));
84 W
.printHex("TimeStamp", FormattedTime
, TimeStamp
);
86 W
.printHex("Timestamp", TimeStamp
);
88 W
.printHex("TimeStamp", TimeStamp
== 0 ? "None" : "Reserved Value",
92 // The number of symbol table entries is an unsigned value in 64-bit objects
93 // and a signed value (with negative values being 'reserved') in 32-bit
96 W
.printHex("SymbolTableOffset", Obj
.getSymbolTableOffset64());
97 W
.printNumber("SymbolTableEntries", Obj
.getNumberOfSymbolTableEntries64());
99 W
.printHex("SymbolTableOffset", Obj
.getSymbolTableOffset32());
100 int32_t SymTabEntries
= Obj
.getRawNumberOfSymbolTableEntries32();
101 if (SymTabEntries
>= 0)
102 W
.printNumber("SymbolTableEntries", SymTabEntries
);
104 W
.printHex("SymbolTableEntries", "Reserved Value", SymTabEntries
);
107 W
.printHex("OptionalHeaderSize", Obj
.getOptionalHeaderSize());
108 W
.printHex("Flags", Obj
.getFlags());
110 // TODO FIXME Add support for the auxiliary header (if any) once
111 // XCOFFObjectFile has the necessary support.
114 void XCOFFDumper::printAuxiliaryHeader() {
116 printAuxiliaryHeader(Obj
.auxiliaryHeader64());
118 printAuxiliaryHeader(Obj
.auxiliaryHeader32());
121 void XCOFFDumper::printSectionHeaders() {
123 printSectionHeaders(Obj
.sections64());
125 printSectionHeaders(Obj
.sections32());
128 void XCOFFDumper::printRelocations() {
130 printRelocations
<XCOFFSectionHeader64
, XCOFFRelocation64
>(Obj
.sections64());
132 printRelocations
<XCOFFSectionHeader32
, XCOFFRelocation32
>(Obj
.sections32());
135 const EnumEntry
<XCOFF::RelocationType
> RelocationTypeNameclass
[] = {
138 ECase(R_POS
), ECase(R_RL
), ECase(R_RLA
), ECase(R_NEG
),
139 ECase(R_REL
), ECase(R_TOC
), ECase(R_TRL
), ECase(R_TRLA
),
140 ECase(R_GL
), ECase(R_TCL
), ECase(R_REF
), ECase(R_BA
),
141 ECase(R_BR
), ECase(R_RBA
), ECase(R_RBR
), ECase(R_TLS
),
142 ECase(R_TLS_IE
), ECase(R_TLS_LD
), ECase(R_TLS_LE
), ECase(R_TLSM
),
143 ECase(R_TLSML
), ECase(R_TOCU
), ECase(R_TOCL
)
147 template <typename RelTy
> void XCOFFDumper::printRelocation(RelTy Reloc
) {
148 Expected
<StringRef
> ErrOrSymbolName
=
149 Obj
.getSymbolNameByIndex(Reloc
.SymbolIndex
);
150 if (Error E
= ErrOrSymbolName
.takeError()) {
151 reportUniqueWarning(std::move(E
));
154 StringRef SymbolName
= *ErrOrSymbolName
;
155 StringRef RelocName
= XCOFF::getRelocationTypeString(Reloc
.Type
);
156 if (opts::ExpandRelocs
) {
157 DictScope
Group(W
, "Relocation");
158 W
.printHex("Virtual Address", Reloc
.VirtualAddress
);
159 W
.printNumber("Symbol", SymbolName
, Reloc
.SymbolIndex
);
160 W
.printString("IsSigned", Reloc
.isRelocationSigned() ? "Yes" : "No");
161 W
.printNumber("FixupBitValue", Reloc
.isFixupIndicated() ? 1 : 0);
162 W
.printNumber("Length", Reloc
.getRelocatedLength());
163 W
.printEnum("Type", (uint8_t)Reloc
.Type
,
164 makeArrayRef(RelocationTypeNameclass
));
166 raw_ostream
&OS
= W
.startLine();
167 OS
<< W
.hex(Reloc
.VirtualAddress
) << " " << RelocName
<< " " << SymbolName
168 << "(" << Reloc
.SymbolIndex
<< ") " << W
.hex(Reloc
.Info
) << "\n";
172 template <typename Shdr
, typename RelTy
>
173 void XCOFFDumper::printRelocations(ArrayRef
<Shdr
> Sections
) {
174 ListScope
LS(W
, "Relocations");
176 for (const Shdr
&Sec
: Sections
) {
178 // Only the .text, .data, .tdata, and STYP_DWARF sections have relocation.
179 if (Sec
.Flags
!= XCOFF::STYP_TEXT
&& Sec
.Flags
!= XCOFF::STYP_DATA
&&
180 Sec
.Flags
!= XCOFF::STYP_TDATA
&& Sec
.Flags
!= XCOFF::STYP_DWARF
)
182 Expected
<ArrayRef
<RelTy
>> ErrOrRelocations
= Obj
.relocations
<Shdr
, RelTy
>(Sec
);
183 if (Error E
= ErrOrRelocations
.takeError()) {
184 reportUniqueWarning(std::move(E
));
188 const ArrayRef
<RelTy
> Relocations
= *ErrOrRelocations
;
189 if (Relocations
.empty())
192 W
.startLine() << "Section (index: " << Index
<< ") " << Sec
.getName()
196 for (const RelTy Reloc
: Relocations
)
197 printRelocation(Reloc
);
200 W
.startLine() << "}\n";
204 const EnumEntry
<XCOFF::CFileStringType
> FileStringType
[] = {
207 ECase(XFT_FN
), ECase(XFT_CT
), ECase(XFT_CV
), ECase(XFT_CD
)
211 const EnumEntry
<XCOFF::SymbolAuxType
> SymAuxType
[] = {
214 ECase(AUX_EXCEPT
), ECase(AUX_FCN
), ECase(AUX_SYM
), ECase(AUX_FILE
),
215 ECase(AUX_CSECT
), ECase(AUX_SECT
)
219 void XCOFFDumper::printFileAuxEnt(const XCOFFFileAuxEnt
*AuxEntPtr
) {
220 assert((!Obj
.is64Bit() || AuxEntPtr
->AuxType
== XCOFF::AUX_FILE
) &&
221 "Mismatched auxiliary type!");
223 unwrapOrError(Obj
.getFileName(), Obj
.getCFileName(AuxEntPtr
));
224 DictScope
SymDs(W
, "File Auxiliary Entry");
225 W
.printNumber("Index",
226 Obj
.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr
)));
227 W
.printString("Name", FileName
);
228 W
.printEnum("Type", static_cast<uint8_t>(AuxEntPtr
->Type
),
229 makeArrayRef(FileStringType
));
231 W
.printEnum("Auxiliary Type", static_cast<uint8_t>(AuxEntPtr
->AuxType
),
232 makeArrayRef(SymAuxType
));
236 static const EnumEntry
<XCOFF::StorageMappingClass
> CsectStorageMappingClass
[] =
240 ECase(XMC_PR
), ECase(XMC_RO
), ECase(XMC_DB
), ECase(XMC_GL
),
241 ECase(XMC_XO
), ECase(XMC_SV
), ECase(XMC_SV64
), ECase(XMC_SV3264
),
242 ECase(XMC_TI
), ECase(XMC_TB
), ECase(XMC_RW
), ECase(XMC_TC0
),
243 ECase(XMC_TC
), ECase(XMC_TD
), ECase(XMC_DS
), ECase(XMC_UA
),
244 ECase(XMC_BS
), ECase(XMC_UC
), ECase(XMC_TL
), ECase(XMC_UL
),
249 const EnumEntry
<XCOFF::SymbolType
> CsectSymbolTypeClass
[] = {
252 ECase(XTY_ER
), ECase(XTY_SD
), ECase(XTY_LD
), ECase(XTY_CM
)
256 void XCOFFDumper::printCsectAuxEnt(XCOFFCsectAuxRef AuxEntRef
) {
257 assert((!Obj
.is64Bit() || AuxEntRef
.getAuxType64() == XCOFF::AUX_CSECT
) &&
258 "Mismatched auxiliary type!");
260 DictScope
SymDs(W
, "CSECT Auxiliary Entry");
261 W
.printNumber("Index", Obj
.getSymbolIndex(AuxEntRef
.getEntryAddress()));
262 W
.printNumber(AuxEntRef
.isLabel() ? "ContainingCsectSymbolIndex"
264 AuxEntRef
.getSectionOrLength());
265 W
.printHex("ParameterHashIndex", AuxEntRef
.getParameterHashIndex());
266 W
.printHex("TypeChkSectNum", AuxEntRef
.getTypeChkSectNum());
267 // Print out symbol alignment and type.
268 W
.printNumber("SymbolAlignmentLog2", AuxEntRef
.getAlignmentLog2());
269 W
.printEnum("SymbolType", AuxEntRef
.getSymbolType(),
270 makeArrayRef(CsectSymbolTypeClass
));
271 W
.printEnum("StorageMappingClass",
272 static_cast<uint8_t>(AuxEntRef
.getStorageMappingClass()),
273 makeArrayRef(CsectStorageMappingClass
));
276 W
.printEnum("Auxiliary Type", static_cast<uint8_t>(XCOFF::AUX_CSECT
),
277 makeArrayRef(SymAuxType
));
279 W
.printHex("StabInfoIndex", AuxEntRef
.getStabInfoIndex32());
280 W
.printHex("StabSectNum", AuxEntRef
.getStabSectNum32());
284 void XCOFFDumper::printSectAuxEntForStat(
285 const XCOFFSectAuxEntForStat
*AuxEntPtr
) {
286 assert(!Obj
.is64Bit() && "32-bit interface called on 64-bit object file.");
288 DictScope
SymDs(W
, "Sect Auxiliary Entry For Stat");
289 W
.printNumber("Index",
290 Obj
.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr
)));
291 W
.printNumber("SectionLength", AuxEntPtr
->SectionLength
);
293 // Unlike the corresponding fields in the section header, NumberOfRelocEnt
294 // and NumberOfLineNum do not handle values greater than 65535.
295 W
.printNumber("NumberOfRelocEnt", AuxEntPtr
->NumberOfRelocEnt
);
296 W
.printNumber("NumberOfLineNum", AuxEntPtr
->NumberOfLineNum
);
299 void XCOFFDumper::printExceptionAuxEnt(const XCOFFExceptionAuxEnt
*AuxEntPtr
) {
300 assert(Obj
.is64Bit() && "64-bit interface called on 32-bit object file.");
302 DictScope
SymDs(W
, "Exception Auxiliary Entry");
303 W
.printNumber("Index",
304 Obj
.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr
)));
305 W
.printHex("OffsetToExceptionTable", AuxEntPtr
->OffsetToExceptionTbl
);
306 W
.printHex("SizeOfFunction", AuxEntPtr
->SizeOfFunction
);
307 W
.printNumber("SymbolIndexOfNextBeyond", AuxEntPtr
->SymIdxOfNextBeyond
);
308 W
.printEnum("Auxiliary Type", static_cast<uint8_t>(AuxEntPtr
->AuxType
),
309 makeArrayRef(SymAuxType
));
312 void XCOFFDumper::printFunctionAuxEnt(const XCOFFFunctionAuxEnt32
*AuxEntPtr
) {
313 assert(!Obj
.is64Bit() && "32-bit interface called on 64-bit object file.");
315 DictScope
SymDs(W
, "Function Auxiliary Entry");
316 W
.printNumber("Index",
317 Obj
.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr
)));
318 W
.printHex("OffsetToExceptionTable", AuxEntPtr
->OffsetToExceptionTbl
);
319 W
.printHex("SizeOfFunction", AuxEntPtr
->SizeOfFunction
);
320 W
.printHex("PointerToLineNum", AuxEntPtr
->PtrToLineNum
);
321 W
.printNumber("SymbolIndexOfNextBeyond", AuxEntPtr
->SymIdxOfNextBeyond
);
324 void XCOFFDumper::printFunctionAuxEnt(const XCOFFFunctionAuxEnt64
*AuxEntPtr
) {
325 assert(Obj
.is64Bit() && "64-bit interface called on 32-bit object file.");
327 DictScope
SymDs(W
, "Function Auxiliary Entry");
328 W
.printNumber("Index",
329 Obj
.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr
)));
330 W
.printHex("SizeOfFunction", AuxEntPtr
->SizeOfFunction
);
331 W
.printHex("PointerToLineNum", AuxEntPtr
->PtrToLineNum
);
332 W
.printNumber("SymbolIndexOfNextBeyond", AuxEntPtr
->SymIdxOfNextBeyond
);
333 W
.printEnum("Auxiliary Type", static_cast<uint8_t>(AuxEntPtr
->AuxType
),
334 makeArrayRef(SymAuxType
));
337 void XCOFFDumper::printBlockAuxEnt(const XCOFFBlockAuxEnt32
*AuxEntPtr
) {
338 assert(!Obj
.is64Bit() && "32-bit interface called on 64-bit object file.");
340 DictScope
SymDs(W
, "Block Auxiliary Entry");
341 W
.printNumber("Index",
342 Obj
.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr
)));
343 W
.printHex("LineNumber (High 2 Bytes)", AuxEntPtr
->LineNumHi
);
344 W
.printHex("LineNumber (Low 2 Bytes)", AuxEntPtr
->LineNumLo
);
347 void XCOFFDumper::printBlockAuxEnt(const XCOFFBlockAuxEnt64
*AuxEntPtr
) {
348 assert(Obj
.is64Bit() && "64-bit interface called on 32-bit object file.");
350 DictScope
SymDs(W
, "Block Auxiliary Entry");
351 W
.printNumber("Index",
352 Obj
.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr
)));
353 W
.printHex("LineNumber", AuxEntPtr
->LineNum
);
354 W
.printEnum("Auxiliary Type", static_cast<uint8_t>(AuxEntPtr
->AuxType
),
355 makeArrayRef(SymAuxType
));
358 template <typename T
>
359 void XCOFFDumper::printSectAuxEntForDWARF(const T
*AuxEntPtr
) {
360 DictScope
SymDs(W
, "Sect Auxiliary Entry For DWARF");
361 W
.printNumber("Index",
362 Obj
.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr
)));
363 W
.printHex("LengthOfSectionPortion", AuxEntPtr
->LengthOfSectionPortion
);
364 W
.printNumber("NumberOfRelocEntries", AuxEntPtr
->NumberOfRelocEnt
);
366 W
.printEnum("Auxiliary Type", static_cast<uint8_t>(XCOFF::AUX_SECT
),
367 makeArrayRef(SymAuxType
));
370 const EnumEntry
<XCOFF::StorageClass
> SymStorageClass
[] = {
373 ECase(C_NULL
), ECase(C_AUTO
), ECase(C_EXT
), ECase(C_STAT
),
374 ECase(C_REG
), ECase(C_EXTDEF
), ECase(C_LABEL
), ECase(C_ULABEL
),
375 ECase(C_MOS
), ECase(C_ARG
), ECase(C_STRTAG
), ECase(C_MOU
),
376 ECase(C_UNTAG
), ECase(C_TPDEF
), ECase(C_USTATIC
), ECase(C_ENTAG
),
377 ECase(C_MOE
), ECase(C_REGPARM
), ECase(C_FIELD
), ECase(C_BLOCK
),
378 ECase(C_FCN
), ECase(C_EOS
), ECase(C_FILE
), ECase(C_LINE
),
379 ECase(C_ALIAS
), ECase(C_HIDDEN
), ECase(C_HIDEXT
), ECase(C_BINCL
),
380 ECase(C_EINCL
), ECase(C_INFO
), ECase(C_WEAKEXT
), ECase(C_DWARF
),
381 ECase(C_GSYM
), ECase(C_LSYM
), ECase(C_PSYM
), ECase(C_RSYM
),
382 ECase(C_RPSYM
), ECase(C_STSYM
), ECase(C_TCSYM
), ECase(C_BCOMM
),
383 ECase(C_ECOML
), ECase(C_ECOMM
), ECase(C_DECL
), ECase(C_ENTRY
),
384 ECase(C_FUN
), ECase(C_BSTAT
), ECase(C_ESTAT
), ECase(C_GTLS
),
385 ECase(C_STTLS
), ECase(C_EFCN
)
389 static StringRef
GetSymbolValueName(XCOFF::StorageClass SC
) {
392 case XCOFF::C_WEAKEXT
:
393 case XCOFF::C_HIDEXT
:
397 return "Value (RelocatableAddress)";
399 return "Value (SymbolTableIndex)";
401 return "Value (OffsetInDWARF)";
413 assert(false && "This StorageClass for the symbol is not yet implemented.");
420 const EnumEntry
<XCOFF::CFileLangId
> CFileLangIdClass
[] = {
423 ECase(TB_C
), ECase(TB_CPLUSPLUS
)
427 const EnumEntry
<XCOFF::CFileCpuId
> CFileCpuIdClass
[] = {
430 ECase(TCPU_PPC64
), ECase(TCPU_COM
), ECase(TCPU_970
)
434 template <typename T
> const T
*XCOFFDumper::getAuxEntPtr(uintptr_t AuxAddress
) {
435 const T
*AuxEntPtr
= reinterpret_cast<const T
*>(AuxAddress
);
436 Obj
.checkSymbolEntryPointer(reinterpret_cast<uintptr_t>(AuxEntPtr
));
440 static void printUnexpectedRawAuxEnt(ScopedPrinter
&W
, uintptr_t AuxAddress
) {
441 W
.startLine() << "!Unexpected raw auxiliary entry data:\n";
442 W
.startLine() << format_bytes(
444 reinterpret_cast<const uint8_t *>(AuxAddress
),
445 XCOFF::SymbolTableEntrySize
),
446 None
, XCOFF::SymbolTableEntrySize
)
450 void XCOFFDumper::printSymbol(const SymbolRef
&S
) {
451 DataRefImpl SymbolDRI
= S
.getRawDataRefImpl();
452 XCOFFSymbolRef SymbolEntRef
= Obj
.toSymbolRef(SymbolDRI
);
454 uint8_t NumberOfAuxEntries
= SymbolEntRef
.getNumberOfAuxEntries();
456 DictScope
SymDs(W
, "Symbol");
458 StringRef SymbolName
=
459 unwrapOrError(Obj
.getFileName(), SymbolEntRef
.getName());
461 uint32_t SymbolIdx
= Obj
.getSymbolIndex(SymbolEntRef
.getEntryAddress());
462 XCOFF::StorageClass SymbolClass
= SymbolEntRef
.getStorageClass();
464 W
.printNumber("Index", SymbolIdx
);
465 W
.printString("Name", SymbolName
);
466 W
.printHex(GetSymbolValueName(SymbolClass
), SymbolEntRef
.getValue());
468 StringRef SectionName
=
469 unwrapOrError(Obj
.getFileName(), Obj
.getSymbolSectionName(SymbolEntRef
));
471 W
.printString("Section", SectionName
);
472 if (SymbolClass
== XCOFF::C_FILE
) {
473 W
.printEnum("Source Language ID", SymbolEntRef
.getLanguageIdForCFile(),
474 makeArrayRef(CFileLangIdClass
));
475 W
.printEnum("CPU Version ID", SymbolEntRef
.getCPUTypeIddForCFile(),
476 makeArrayRef(CFileCpuIdClass
));
478 W
.printHex("Type", SymbolEntRef
.getSymbolType());
480 W
.printEnum("StorageClass", static_cast<uint8_t>(SymbolClass
),
481 makeArrayRef(SymStorageClass
));
482 W
.printNumber("NumberOfAuxEntries", NumberOfAuxEntries
);
484 if (NumberOfAuxEntries
== 0)
487 auto checkNumOfAux
= [=] {
488 if (NumberOfAuxEntries
> 1)
489 reportUniqueWarning("the " +
490 enumToString(static_cast<uint8_t>(SymbolClass
),
491 makeArrayRef(SymStorageClass
)) +
492 " symbol at index " + Twine(SymbolIdx
) +
493 " should not have more than 1 "
497 switch (SymbolClass
) {
499 // If the symbol is C_FILE and has auxiliary entries...
500 for (int I
= 1; I
<= NumberOfAuxEntries
; I
++) {
501 uintptr_t AuxAddress
= XCOFFObjectFile::getAdvancedSymbolEntryAddress(
502 SymbolEntRef
.getEntryAddress(), I
);
505 *Obj
.getSymbolAuxType(AuxAddress
) != XCOFF::SymbolAuxType::AUX_FILE
) {
506 printUnexpectedRawAuxEnt(W
, AuxAddress
);
510 const XCOFFFileAuxEnt
*FileAuxEntPtr
=
511 getAuxEntPtr
<XCOFFFileAuxEnt
>(AuxAddress
);
512 printFileAuxEnt(FileAuxEntPtr
);
516 case XCOFF::C_WEAKEXT
:
517 case XCOFF::C_HIDEXT
: {
518 if (!SymbolEntRef
.isFunction() && NumberOfAuxEntries
> 1)
519 reportUniqueWarning("the non-function " +
520 enumToString(static_cast<uint8_t>(SymbolClass
),
521 makeArrayRef(SymStorageClass
)) +
522 " symbol at index " + Twine(SymbolIdx
) +
523 " should have only 1 auxiliary entry, i.e. the CSECT "
526 // For 32-bit objects, print the function auxiliary symbol table entry. The
527 // last one must be a CSECT auxiliary entry.
528 // For 64-bit objects, both a function auxiliary entry and an exception
529 // auxiliary entry may appear, print them in the loop and skip printing the
530 // CSECT auxiliary entry, which will be printed outside the loop.
531 for (int I
= 1; I
<= NumberOfAuxEntries
; I
++) {
532 if ((I
== NumberOfAuxEntries
&& !Obj
.is64Bit()) ||
533 !SymbolEntRef
.isFunction())
536 uintptr_t AuxAddress
= XCOFFObjectFile::getAdvancedSymbolEntryAddress(
537 SymbolEntRef
.getEntryAddress(), I
);
540 XCOFF::SymbolAuxType Type
= *Obj
.getSymbolAuxType(AuxAddress
);
541 if (Type
== XCOFF::SymbolAuxType::AUX_CSECT
)
543 if (Type
== XCOFF::SymbolAuxType::AUX_FCN
) {
544 const XCOFFFunctionAuxEnt64
*AuxEntPtr
=
545 getAuxEntPtr
<XCOFFFunctionAuxEnt64
>(AuxAddress
);
546 printFunctionAuxEnt(AuxEntPtr
);
547 } else if (Type
== XCOFF::SymbolAuxType::AUX_EXCEPT
) {
548 const XCOFFExceptionAuxEnt
*AuxEntPtr
=
549 getAuxEntPtr
<XCOFFExceptionAuxEnt
>(AuxAddress
);
550 printExceptionAuxEnt(AuxEntPtr
);
552 printUnexpectedRawAuxEnt(W
, AuxAddress
);
555 const XCOFFFunctionAuxEnt32
*AuxEntPtr
=
556 getAuxEntPtr
<XCOFFFunctionAuxEnt32
>(AuxAddress
);
557 printFunctionAuxEnt(AuxEntPtr
);
561 // Print the CSECT auxiliary entry.
562 auto ErrOrCsectAuxRef
= SymbolEntRef
.getXCOFFCsectAuxRef();
563 if (!ErrOrCsectAuxRef
)
564 reportUniqueWarning(ErrOrCsectAuxRef
.takeError());
566 printCsectAuxEnt(*ErrOrCsectAuxRef
);
570 case XCOFF::C_STAT
: {
573 const XCOFFSectAuxEntForStat
*StatAuxEntPtr
=
574 getAuxEntPtr
<XCOFFSectAuxEntForStat
>(
575 XCOFFObjectFile::getAdvancedSymbolEntryAddress(
576 SymbolEntRef
.getEntryAddress(), 1));
577 printSectAuxEntForStat(StatAuxEntPtr
);
580 case XCOFF::C_DWARF
: {
583 uintptr_t AuxAddress
= XCOFFObjectFile::getAdvancedSymbolEntryAddress(
584 SymbolEntRef
.getEntryAddress(), 1);
587 const XCOFFSectAuxEntForDWARF64
*AuxEntPtr
=
588 getAuxEntPtr
<XCOFFSectAuxEntForDWARF64
>(AuxAddress
);
589 printSectAuxEntForDWARF
<XCOFFSectAuxEntForDWARF64
>(AuxEntPtr
);
591 const XCOFFSectAuxEntForDWARF32
*AuxEntPtr
=
592 getAuxEntPtr
<XCOFFSectAuxEntForDWARF32
>(AuxAddress
);
593 printSectAuxEntForDWARF
<XCOFFSectAuxEntForDWARF32
>(AuxEntPtr
);
601 uintptr_t AuxAddress
= XCOFFObjectFile::getAdvancedSymbolEntryAddress(
602 SymbolEntRef
.getEntryAddress(), 1);
605 const XCOFFBlockAuxEnt64
*AuxEntPtr
=
606 getAuxEntPtr
<XCOFFBlockAuxEnt64
>(AuxAddress
);
607 printBlockAuxEnt(AuxEntPtr
);
609 const XCOFFBlockAuxEnt32
*AuxEntPtr
=
610 getAuxEntPtr
<XCOFFBlockAuxEnt32
>(AuxAddress
);
611 printBlockAuxEnt(AuxEntPtr
);
616 for (int i
= 1; i
<= NumberOfAuxEntries
; i
++) {
617 printUnexpectedRawAuxEnt(W
,
618 XCOFFObjectFile::getAdvancedSymbolEntryAddress(
619 SymbolEntRef
.getEntryAddress(), i
));
625 void XCOFFDumper::printSymbols() {
626 ListScope
Group(W
, "Symbols");
627 for (const SymbolRef
&S
: Obj
.symbols())
631 void XCOFFDumper::printStringTable() {
632 DictScope
DS(W
, "StringTable");
633 StringRef StrTable
= Obj
.getStringTable();
634 uint32_t StrTabSize
= StrTable
.size();
635 W
.printNumber("Length", StrTabSize
);
636 // Print strings from the fifth byte, since the first four bytes contain the
637 // length (in bytes) of the string table (including the length field).
639 printAsStringList(StrTable
, 4);
642 void XCOFFDumper::printDynamicSymbols() {
643 llvm_unreachable("Unimplemented functionality for XCOFFDumper");
646 void XCOFFDumper::printUnwindInfo() {
647 llvm_unreachable("Unimplemented functionality for XCOFFDumper");
650 void XCOFFDumper::printStackMap() const {
651 llvm_unreachable("Unimplemented functionality for XCOFFDumper");
654 void XCOFFDumper::printNeededLibraries() {
655 ListScope
D(W
, "NeededLibraries");
656 auto ImportFilesOrError
= Obj
.getImportFileTable();
657 if (!ImportFilesOrError
) {
658 reportUniqueWarning(ImportFilesOrError
.takeError());
662 StringRef ImportFileTable
= ImportFilesOrError
.get();
663 const char *CurrentStr
= ImportFileTable
.data();
664 const char *TableEnd
= ImportFileTable
.end();
665 // Default column width for names is 13 even if no names are that long.
666 size_t BaseWidth
= 13;
668 // Get the max width of BASE columns.
669 for (size_t StrIndex
= 0; CurrentStr
< TableEnd
; ++StrIndex
) {
670 size_t CurrentLen
= strlen(CurrentStr
);
671 CurrentStr
+= strlen(CurrentStr
) + 1;
672 if (StrIndex
% 3 == 1)
673 BaseWidth
= std::max(BaseWidth
, CurrentLen
);
676 auto &OS
= static_cast<formatted_raw_ostream
&>(W
.startLine());
677 // Each entry consists of 3 strings: the path_name, base_name and
678 // archive_member_name. The first entry is a default LIBPATH value and other
679 // entries have no path_name. We just dump the base_name and
680 // archive_member_name here.
681 OS
<< left_justify("BASE", BaseWidth
) << " MEMBER\n";
682 CurrentStr
= ImportFileTable
.data();
683 for (size_t StrIndex
= 0; CurrentStr
< TableEnd
;
684 ++StrIndex
, CurrentStr
+= strlen(CurrentStr
) + 1) {
685 if (StrIndex
>= 3 && StrIndex
% 3 != 0) {
686 if (StrIndex
% 3 == 1)
687 OS
<< " " << left_justify(CurrentStr
, BaseWidth
) << " ";
689 OS
<< CurrentStr
<< "\n";
694 const EnumEntry
<XCOFF::SectionTypeFlags
> SectionTypeFlagsNames
[] = {
697 ECase(STYP_PAD
), ECase(STYP_DWARF
), ECase(STYP_TEXT
),
698 ECase(STYP_DATA
), ECase(STYP_BSS
), ECase(STYP_EXCEPT
),
699 ECase(STYP_INFO
), ECase(STYP_TDATA
), ECase(STYP_TBSS
),
700 ECase(STYP_LOADER
), ECase(STYP_DEBUG
), ECase(STYP_TYPCHK
),
705 template <typename T
>
706 void XCOFFDumper::printOverflowSectionHeader(T
&Sec
) const {
708 reportWarning(make_error
<StringError
>("An 64-bit XCOFF object file may not "
709 "contain an overflow section header.",
710 object_error::parse_failed
),
714 W
.printString("Name", Sec
.getName());
715 W
.printNumber("NumberOfRelocations", Sec
.PhysicalAddress
);
716 W
.printNumber("NumberOfLineNumbers", Sec
.VirtualAddress
);
717 W
.printHex("Size", Sec
.SectionSize
);
718 W
.printHex("RawDataOffset", Sec
.FileOffsetToRawData
);
719 W
.printHex("RelocationPointer", Sec
.FileOffsetToRelocationInfo
);
720 W
.printHex("LineNumberPointer", Sec
.FileOffsetToLineNumberInfo
);
721 W
.printNumber("IndexOfSectionOverflowed", Sec
.NumberOfRelocations
);
722 W
.printNumber("IndexOfSectionOverflowed", Sec
.NumberOfLineNumbers
);
725 template <typename T
>
726 void XCOFFDumper::printGenericSectionHeader(T
&Sec
) const {
727 W
.printString("Name", Sec
.getName());
728 W
.printHex("PhysicalAddress", Sec
.PhysicalAddress
);
729 W
.printHex("VirtualAddress", Sec
.VirtualAddress
);
730 W
.printHex("Size", Sec
.SectionSize
);
731 W
.printHex("RawDataOffset", Sec
.FileOffsetToRawData
);
732 W
.printHex("RelocationPointer", Sec
.FileOffsetToRelocationInfo
);
733 W
.printHex("LineNumberPointer", Sec
.FileOffsetToLineNumberInfo
);
734 W
.printNumber("NumberOfRelocations", Sec
.NumberOfRelocations
);
735 W
.printNumber("NumberOfLineNumbers", Sec
.NumberOfLineNumbers
);
738 void XCOFFDumper::printAuxiliaryHeader(
739 const XCOFFAuxiliaryHeader32
*AuxHeader
) {
740 if (AuxHeader
== nullptr)
742 uint16_t AuxSize
= Obj
.getOptionalHeaderSize();
743 uint16_t PartialFieldOffset
= AuxSize
;
744 const char *PartialFieldName
= nullptr;
746 DictScope
DS(W
, "AuxiliaryHeader");
748 #define PrintAuxMember32(H, S, T) \
749 if (offsetof(XCOFFAuxiliaryHeader32, T) + \
750 sizeof(XCOFFAuxiliaryHeader32::T) <= \
752 W.print##H(S, AuxHeader->T); \
753 else if (offsetof(XCOFFAuxiliaryHeader32, T) < AuxSize) { \
754 PartialFieldOffset = offsetof(XCOFFAuxiliaryHeader32, T); \
755 PartialFieldName = S; \
758 PrintAuxMember32(Hex
, "Magic", AuxMagic
);
759 PrintAuxMember32(Hex
, "Version", Version
);
760 PrintAuxMember32(Hex
, "Size of .text section", TextSize
);
761 PrintAuxMember32(Hex
, "Size of .data section", InitDataSize
);
762 PrintAuxMember32(Hex
, "Size of .bss section", BssDataSize
);
763 PrintAuxMember32(Hex
, "Entry point address", EntryPointAddr
);
764 PrintAuxMember32(Hex
, ".text section start address", TextStartAddr
);
765 PrintAuxMember32(Hex
, ".data section start address", DataStartAddr
);
766 PrintAuxMember32(Hex
, "TOC anchor address", TOCAnchorAddr
);
767 PrintAuxMember32(Number
, "Section number of entryPoint", SecNumOfEntryPoint
);
768 PrintAuxMember32(Number
, "Section number of .text", SecNumOfText
);
769 PrintAuxMember32(Number
, "Section number of .data", SecNumOfData
);
770 PrintAuxMember32(Number
, "Section number of TOC", SecNumOfTOC
);
771 PrintAuxMember32(Number
, "Section number of loader data", SecNumOfLoader
);
772 PrintAuxMember32(Number
, "Section number of .bss", SecNumOfBSS
);
773 PrintAuxMember32(Hex
, "Maxium alignment of .text", MaxAlignOfText
);
774 PrintAuxMember32(Hex
, "Maxium alignment of .data", MaxAlignOfData
);
775 PrintAuxMember32(Hex
, "Module type", ModuleType
);
776 PrintAuxMember32(Hex
, "CPU type of objects", CpuFlag
);
777 PrintAuxMember32(Hex
, "(Reserved)", CpuType
);
778 PrintAuxMember32(Hex
, "Maximum stack size", MaxStackSize
);
779 PrintAuxMember32(Hex
, "Maximum data size", MaxDataSize
);
780 PrintAuxMember32(Hex
, "Reserved for debugger", ReservedForDebugger
);
781 PrintAuxMember32(Hex
, "Text page size", TextPageSize
);
782 PrintAuxMember32(Hex
, "Data page size", DataPageSize
);
783 PrintAuxMember32(Hex
, "Stack page size", StackPageSize
);
784 if (offsetof(XCOFFAuxiliaryHeader32
, FlagAndTDataAlignment
) +
785 sizeof(XCOFFAuxiliaryHeader32::FlagAndTDataAlignment
) <=
787 W
.printHex("Flag", AuxHeader
->getFlag());
788 W
.printHex("Alignment of thread-local storage",
789 AuxHeader
->getTDataAlignment());
792 PrintAuxMember32(Number
, "Section number for .tdata", SecNumOfTData
);
793 PrintAuxMember32(Number
, "Section number for .tbss", SecNumOfTBSS
);
796 if (PartialFieldOffset
< AuxSize
) {
798 llvm::raw_string_ostream
StringOS(ErrInfo
);
799 StringOS
<< "Only partial field for " << PartialFieldName
<< " at offset ("
800 << PartialFieldOffset
<< ").";
803 make_error
<GenericBinaryError
>(ErrInfo
, object_error::parse_failed
),
807 ArrayRef
<uint8_t>((const uint8_t *)(AuxHeader
) + PartialFieldOffset
,
808 AuxSize
- PartialFieldOffset
));
809 } else if (sizeof(XCOFFAuxiliaryHeader32
) < AuxSize
) {
810 reportWarning(make_error
<GenericBinaryError
>(
811 "There are extra data beyond auxiliary header",
812 object_error::parse_failed
),
814 W
.printBinary("Extra raw data", "",
815 ArrayRef
<uint8_t>((const uint8_t *)(AuxHeader
) +
816 sizeof(XCOFFAuxiliaryHeader32
),
817 AuxSize
- sizeof(XCOFFAuxiliaryHeader32
)));
820 #undef PrintAuxMember32
823 void XCOFFDumper::printAuxiliaryHeader(
824 const XCOFFAuxiliaryHeader64
*AuxHeader
) {
825 if (AuxHeader
== nullptr)
827 uint16_t AuxSize
= Obj
.getOptionalHeaderSize();
828 uint16_t PartialFieldOffset
= AuxSize
;
829 const char *PartialFieldName
= nullptr;
831 DictScope
DS(W
, "AuxiliaryHeader");
833 #define PrintAuxMember64(H, S, T) \
834 if (offsetof(XCOFFAuxiliaryHeader64, T) + \
835 sizeof(XCOFFAuxiliaryHeader64::T) <= \
837 W.print##H(S, AuxHeader->T); \
838 else if (offsetof(XCOFFAuxiliaryHeader64, T) < AuxSize) { \
839 PartialFieldOffset = offsetof(XCOFFAuxiliaryHeader64, T); \
840 PartialFieldName = S; \
843 PrintAuxMember64(Hex
, "Magic", AuxMagic
);
844 PrintAuxMember64(Hex
, "Version", Version
);
845 PrintAuxMember64(Hex
, "Reserved for debugger", ReservedForDebugger
);
846 PrintAuxMember64(Hex
, ".text section start address", TextStartAddr
);
847 PrintAuxMember64(Hex
, ".data section start address", DataStartAddr
);
848 PrintAuxMember64(Hex
, "TOC anchor address", TOCAnchorAddr
);
849 PrintAuxMember64(Number
, "Section number of entryPoint", SecNumOfEntryPoint
);
850 PrintAuxMember64(Number
, "Section number of .text", SecNumOfText
);
851 PrintAuxMember64(Number
, "Section number of .data", SecNumOfData
);
852 PrintAuxMember64(Number
, "Section number of TOC", SecNumOfTOC
);
853 PrintAuxMember64(Number
, "Section number of loader data", SecNumOfLoader
);
854 PrintAuxMember64(Number
, "Section number of .bss", SecNumOfBSS
);
855 PrintAuxMember64(Hex
, "Maxium alignment of .text", MaxAlignOfText
);
856 PrintAuxMember64(Hex
, "Maxium alignment of .data", MaxAlignOfData
);
857 PrintAuxMember64(Hex
, "Module type", ModuleType
);
858 PrintAuxMember64(Hex
, "CPU type of objects", CpuFlag
);
859 PrintAuxMember64(Hex
, "(Reserved)", CpuType
);
860 PrintAuxMember64(Hex
, "Text page size", TextPageSize
);
861 PrintAuxMember64(Hex
, "Data page size", DataPageSize
);
862 PrintAuxMember64(Hex
, "Stack page size", StackPageSize
);
863 if (offsetof(XCOFFAuxiliaryHeader64
, FlagAndTDataAlignment
) +
864 sizeof(XCOFFAuxiliaryHeader64::FlagAndTDataAlignment
) <=
866 W
.printHex("Flag", AuxHeader
->getFlag());
867 W
.printHex("Alignment of thread-local storage",
868 AuxHeader
->getTDataAlignment());
870 PrintAuxMember64(Hex
, "Size of .text section", TextSize
);
871 PrintAuxMember64(Hex
, "Size of .data section", InitDataSize
);
872 PrintAuxMember64(Hex
, "Size of .bss section", BssDataSize
);
873 PrintAuxMember64(Hex
, "Entry point address", EntryPointAddr
);
874 PrintAuxMember64(Hex
, "Maximum stack size", MaxStackSize
);
875 PrintAuxMember64(Hex
, "Maximum data size", MaxDataSize
);
876 PrintAuxMember64(Number
, "Section number for .tdata", SecNumOfTData
);
877 PrintAuxMember64(Number
, "Section number for .tbss", SecNumOfTBSS
);
878 PrintAuxMember64(Hex
, "Additional flags 64-bit XCOFF", XCOFF64Flag
);
880 if (PartialFieldOffset
< AuxSize
) {
882 llvm::raw_string_ostream
StringOS(ErrInfo
);
883 StringOS
<< "Only partial field for " << PartialFieldName
<< " at offset ("
884 << PartialFieldOffset
<< ").";
887 make_error
<GenericBinaryError
>(ErrInfo
, object_error::parse_failed
),
892 ArrayRef
<uint8_t>((const uint8_t *)(AuxHeader
) + PartialFieldOffset
,
893 AuxSize
- PartialFieldOffset
));
894 } else if (sizeof(XCOFFAuxiliaryHeader64
) < AuxSize
) {
895 reportWarning(make_error
<GenericBinaryError
>(
896 "There are extra data beyond auxiliary header",
897 object_error::parse_failed
),
899 W
.printBinary("Extra raw data", "",
900 ArrayRef
<uint8_t>((const uint8_t *)(AuxHeader
) +
901 sizeof(XCOFFAuxiliaryHeader64
),
902 AuxSize
- sizeof(XCOFFAuxiliaryHeader64
)));
905 #undef PrintAuxMember64
908 template <typename T
>
909 void XCOFFDumper::printSectionHeaders(ArrayRef
<T
> Sections
) {
910 ListScope
Group(W
, "Sections");
913 for (const T
&Sec
: Sections
) {
914 DictScope
SecDS(W
, "Section");
916 W
.printNumber("Index", Index
++);
917 uint16_t SectionType
= Sec
.getSectionType();
918 switch (SectionType
) {
919 case XCOFF::STYP_OVRFLO
:
920 printOverflowSectionHeader(Sec
);
922 case XCOFF::STYP_LOADER
:
923 case XCOFF::STYP_EXCEPT
:
924 case XCOFF::STYP_TYPCHK
:
925 // TODO The interpretation of loader, exception and type check section
926 // headers are different from that of generic section headers. We will
927 // implement them later. We interpret them as generic section headers for
930 printGenericSectionHeader(Sec
);
933 if (Sec
.isReservedSectionType())
934 W
.printHex("Flags", "Reserved", SectionType
);
936 W
.printEnum("Type", SectionType
, makeArrayRef(SectionTypeFlagsNames
));
939 if (opts::SectionRelocations
)
940 report_fatal_error("Dumping section relocations is unimplemented");
942 if (opts::SectionSymbols
)
943 report_fatal_error("Dumping symbols is unimplemented");
945 if (opts::SectionData
)
946 report_fatal_error("Dumping section data is unimplemented");
950 std::unique_ptr
<ObjDumper
>
951 createXCOFFDumper(const object::XCOFFObjectFile
&XObj
, ScopedPrinter
&Writer
) {
952 return std::make_unique
<XCOFFDumper
>(XObj
, Writer
);