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 //===----------------------------------------------------------------------===//
14 #include "ObjDumper.h"
15 #include "llvm-readobj.h"
16 #include "llvm/Object/XCOFFObjectFile.h"
17 #include "llvm/Support/ScopedPrinter.h"
20 using namespace object
;
24 class XCOFFDumper
: public ObjDumper
{
26 SymbolTypeMask
= 0x07,
27 SymbolAlignmentMask
= 0xF8,
28 SymbolAlignmentBitOffset
= 3
32 XCOFFDumper(const XCOFFObjectFile
&Obj
, ScopedPrinter
&Writer
)
33 : ObjDumper(Writer
), Obj(Obj
) {}
35 void printFileHeaders() override
;
36 void printSectionHeaders() override
;
37 void printRelocations() override
;
38 void printSymbols() override
;
39 void printDynamicSymbols() override
;
40 void printUnwindInfo() override
;
41 void printStackMap() const override
;
42 void printNeededLibraries() override
;
45 template <typename T
> void printSectionHeaders(ArrayRef
<T
> Sections
);
46 template <typename T
> void printGenericSectionHeader(T
&Sec
) const;
47 template <typename T
> void printOverflowSectionHeader(T
&Sec
) const;
48 void printFileAuxEnt(const XCOFFFileAuxEnt
*AuxEntPtr
);
49 void printCsectAuxEnt32(const XCOFFCsectAuxEnt32
*AuxEntPtr
);
50 void printSectAuxEntForStat(const XCOFFSectAuxEntForStat
*AuxEntPtr
);
51 void printSymbol(const SymbolRef
&);
53 // Least significant 3 bits are reserved.
54 static constexpr unsigned SectionFlagsReservedMask
= 0x7;
56 // The low order 16 bits of section flags denotes the section type.
57 static constexpr unsigned SectionFlagsTypeMask
= 0xffffu
;
59 void printRelocations(ArrayRef
<XCOFFSectionHeader32
> Sections
);
60 const XCOFFObjectFile
&Obj
;
62 } // anonymous namespace
64 void XCOFFDumper::printFileHeaders() {
65 DictScope
DS(W
, "FileHeader");
66 W
.printHex("Magic", Obj
.getMagic());
67 W
.printNumber("NumberOfSections", Obj
.getNumberOfSections());
69 // Negative timestamp values are reserved for future use.
70 int32_t TimeStamp
= Obj
.getTimeStamp();
72 // This handling of the time stamp assumes that the host system's time_t is
73 // compatible with AIX time_t. If a platform is not compatible, the lit
74 // tests will let us know.
75 time_t TimeDate
= TimeStamp
;
77 char FormattedTime
[21] = {};
79 strftime(FormattedTime
, 21, "%Y-%m-%dT%H:%M:%SZ", gmtime(&TimeDate
));
81 W
.printHex("TimeStamp", FormattedTime
, TimeStamp
);
83 W
.printHex("Timestamp", TimeStamp
);
85 W
.printHex("TimeStamp", TimeStamp
== 0 ? "None" : "Reserved Value",
89 // The number of symbol table entries is an unsigned value in 64-bit objects
90 // and a signed value (with negative values being 'reserved') in 32-bit
93 W
.printHex("SymbolTableOffset", Obj
.getSymbolTableOffset64());
94 W
.printNumber("SymbolTableEntries", Obj
.getNumberOfSymbolTableEntries64());
96 W
.printHex("SymbolTableOffset", Obj
.getSymbolTableOffset32());
97 int32_t SymTabEntries
= Obj
.getRawNumberOfSymbolTableEntries32();
98 if (SymTabEntries
>= 0)
99 W
.printNumber("SymbolTableEntries", SymTabEntries
);
101 W
.printHex("SymbolTableEntries", "Reserved Value", SymTabEntries
);
104 W
.printHex("OptionalHeaderSize", Obj
.getOptionalHeaderSize());
105 W
.printHex("Flags", Obj
.getFlags());
107 // TODO FIXME Add support for the auxiliary header (if any) once
108 // XCOFFObjectFile has the necessary support.
111 void XCOFFDumper::printSectionHeaders() {
113 printSectionHeaders(Obj
.sections64());
115 printSectionHeaders(Obj
.sections32());
118 void XCOFFDumper::printRelocations() {
120 llvm_unreachable("64-bit relocation output not implemented!");
122 printRelocations(Obj
.sections32());
125 static const EnumEntry
<XCOFF::RelocationType
> RelocationTypeNameclass
[] = {
128 ECase(R_POS
), ECase(R_RL
), ECase(R_RLA
), ECase(R_NEG
),
129 ECase(R_REL
), ECase(R_TOC
), ECase(R_TRL
), ECase(R_TRLA
),
130 ECase(R_GL
), ECase(R_TCL
), ECase(R_REF
), ECase(R_BA
),
131 ECase(R_BR
), ECase(R_RBA
), ECase(R_RBR
), ECase(R_TLS
),
132 ECase(R_TLS_IE
), ECase(R_TLS_LD
), ECase(R_TLS_LE
), ECase(R_TLSM
),
133 ECase(R_TLSML
), ECase(R_TOCU
), ECase(R_TOCL
)
137 void XCOFFDumper::printRelocations(ArrayRef
<XCOFFSectionHeader32
> Sections
) {
138 if (!opts::ExpandRelocs
)
139 report_fatal_error("Unexpanded relocation output not implemented.");
141 ListScope
LS(W
, "Relocations");
143 for (const auto &Sec
: Sections
) {
145 // Only the .text, .data, .tdata, and STYP_DWARF sections have relocation.
146 if (Sec
.Flags
!= XCOFF::STYP_TEXT
&& Sec
.Flags
!= XCOFF::STYP_DATA
&&
147 Sec
.Flags
!= XCOFF::STYP_TDATA
&& Sec
.Flags
!= XCOFF::STYP_DWARF
)
149 auto Relocations
= unwrapOrError(Obj
.getFileName(), Obj
.relocations(Sec
));
150 if (Relocations
.empty())
153 W
.startLine() << "Section (index: " << Index
<< ") " << Sec
.getName()
155 for (auto Reloc
: Relocations
) {
156 StringRef SymbolName
= unwrapOrError(
157 Obj
.getFileName(), Obj
.getSymbolNameByIndex(Reloc
.SymbolIndex
));
159 DictScope
RelocScope(W
, "Relocation");
160 W
.printHex("Virtual Address", Reloc
.VirtualAddress
);
161 W
.printNumber("Symbol", SymbolName
, Reloc
.SymbolIndex
);
162 W
.printString("IsSigned", Reloc
.isRelocationSigned() ? "Yes" : "No");
163 W
.printNumber("FixupBitValue", Reloc
.isFixupIndicated() ? 1 : 0);
164 W
.printNumber("Length", Reloc
.getRelocatedLength());
165 W
.printEnum("Type", (uint8_t)Reloc
.Type
,
166 makeArrayRef(RelocationTypeNameclass
));
169 W
.startLine() << "}\n";
173 static const EnumEntry
<XCOFF::CFileStringType
> FileStringType
[] = {
176 ECase(XFT_FN
), ECase(XFT_CT
), ECase(XFT_CV
), ECase(XFT_CD
)
180 void XCOFFDumper::printFileAuxEnt(const XCOFFFileAuxEnt
*AuxEntPtr
) {
183 "Printing for File Auxiliary Entry in 64-bit is unimplemented.");
185 unwrapOrError(Obj
.getFileName(), Obj
.getCFileName(AuxEntPtr
));
186 DictScope
SymDs(W
, "File Auxiliary Entry");
187 W
.printNumber("Index",
188 Obj
.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr
)));
189 W
.printString("Name", FileName
);
190 W
.printEnum("Type", static_cast<uint8_t>(AuxEntPtr
->Type
),
191 makeArrayRef(FileStringType
));
194 static const EnumEntry
<XCOFF::StorageMappingClass
> CsectStorageMappingClass
[] =
198 ECase(XMC_PR
), ECase(XMC_RO
), ECase(XMC_DB
),
199 ECase(XMC_GL
), ECase(XMC_XO
), ECase(XMC_SV
),
200 ECase(XMC_SV64
), ECase(XMC_SV3264
), ECase(XMC_TI
),
201 ECase(XMC_TB
), ECase(XMC_RW
), ECase(XMC_TC0
),
202 ECase(XMC_TC
), ECase(XMC_TD
), ECase(XMC_DS
),
203 ECase(XMC_UA
), ECase(XMC_BS
), ECase(XMC_UC
),
204 ECase(XMC_TL
), ECase(XMC_TE
)
208 static const EnumEntry
<XCOFF::SymbolType
> CsectSymbolTypeClass
[] = {
211 ECase(XTY_ER
), ECase(XTY_SD
), ECase(XTY_LD
), ECase(XTY_CM
)
215 void XCOFFDumper::printCsectAuxEnt32(const XCOFFCsectAuxEnt32
*AuxEntPtr
) {
216 assert(!Obj
.is64Bit() && "32-bit interface called on 64-bit object file.");
218 DictScope
SymDs(W
, "CSECT Auxiliary Entry");
219 W
.printNumber("Index",
220 Obj
.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr
)));
221 if ((AuxEntPtr
->SymbolAlignmentAndType
& SymbolTypeMask
) == XCOFF::XTY_LD
)
222 W
.printNumber("ContainingCsectSymbolIndex", AuxEntPtr
->SectionOrLength
);
224 W
.printNumber("SectionLen", AuxEntPtr
->SectionOrLength
);
225 W
.printHex("ParameterHashIndex", AuxEntPtr
->ParameterHashIndex
);
226 W
.printHex("TypeChkSectNum", AuxEntPtr
->TypeChkSectNum
);
227 // Print out symbol alignment and type.
228 W
.printNumber("SymbolAlignmentLog2",
229 (AuxEntPtr
->SymbolAlignmentAndType
& SymbolAlignmentMask
) >>
230 SymbolAlignmentBitOffset
);
231 W
.printEnum("SymbolType", AuxEntPtr
->SymbolAlignmentAndType
& SymbolTypeMask
,
232 makeArrayRef(CsectSymbolTypeClass
));
233 W
.printEnum("StorageMappingClass",
234 static_cast<uint8_t>(AuxEntPtr
->StorageMappingClass
),
235 makeArrayRef(CsectStorageMappingClass
));
236 W
.printHex("StabInfoIndex", AuxEntPtr
->StabInfoIndex
);
237 W
.printHex("StabSectNum", AuxEntPtr
->StabSectNum
);
240 void XCOFFDumper::printSectAuxEntForStat(
241 const XCOFFSectAuxEntForStat
*AuxEntPtr
) {
242 assert(!Obj
.is64Bit() && "32-bit interface called on 64-bit object file.");
244 DictScope
SymDs(W
, "Sect Auxiliary Entry For Stat");
245 W
.printNumber("Index",
246 Obj
.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr
)));
247 W
.printNumber("SectionLength", AuxEntPtr
->SectionLength
);
249 // Unlike the corresponding fields in the section header, NumberOfRelocEnt
250 // and NumberOfLineNum do not handle values greater than 65535.
251 W
.printNumber("NumberOfRelocEnt", AuxEntPtr
->NumberOfRelocEnt
);
252 W
.printNumber("NumberOfLineNum", AuxEntPtr
->NumberOfLineNum
);
255 static const EnumEntry
<XCOFF::StorageClass
> SymStorageClass
[] = {
258 ECase(C_NULL
), ECase(C_AUTO
), ECase(C_EXT
), ECase(C_STAT
),
259 ECase(C_REG
), ECase(C_EXTDEF
), ECase(C_LABEL
), ECase(C_ULABEL
),
260 ECase(C_MOS
), ECase(C_ARG
), ECase(C_STRTAG
), ECase(C_MOU
),
261 ECase(C_UNTAG
), ECase(C_TPDEF
), ECase(C_USTATIC
), ECase(C_ENTAG
),
262 ECase(C_MOE
), ECase(C_REGPARM
), ECase(C_FIELD
), ECase(C_BLOCK
),
263 ECase(C_FCN
), ECase(C_EOS
), ECase(C_FILE
), ECase(C_LINE
),
264 ECase(C_ALIAS
), ECase(C_HIDDEN
), ECase(C_HIDEXT
), ECase(C_BINCL
),
265 ECase(C_EINCL
), ECase(C_INFO
), ECase(C_WEAKEXT
), ECase(C_DWARF
),
266 ECase(C_GSYM
), ECase(C_LSYM
), ECase(C_PSYM
), ECase(C_RSYM
),
267 ECase(C_RPSYM
), ECase(C_STSYM
), ECase(C_TCSYM
), ECase(C_BCOMM
),
268 ECase(C_ECOML
), ECase(C_ECOMM
), ECase(C_DECL
), ECase(C_ENTRY
),
269 ECase(C_FUN
), ECase(C_BSTAT
), ECase(C_ESTAT
), ECase(C_GTLS
),
270 ECase(C_STTLS
), ECase(C_EFCN
)
274 static StringRef
GetSymbolValueName(XCOFF::StorageClass SC
) {
277 case XCOFF::C_WEAKEXT
:
278 case XCOFF::C_HIDEXT
:
280 return "Value (RelocatableAddress)";
282 return "Value (SymbolTableIndex)";
297 assert(false && "This StorageClass for the symbol is not yet implemented.");
304 static const EnumEntry
<XCOFF::CFileLangId
> CFileLangIdClass
[] = {
307 ECase(TB_C
), ECase(TB_CPLUSPLUS
)
311 static const EnumEntry
<XCOFF::CFileCpuId
> CFileCpuIdClass
[] = {
314 ECase(TCPU_PPC64
), ECase(TCPU_COM
), ECase(TCPU_970
)
318 void XCOFFDumper::printSymbol(const SymbolRef
&S
) {
320 report_fatal_error("64-bit support is unimplemented.");
322 DataRefImpl SymbolDRI
= S
.getRawDataRefImpl();
323 const XCOFFSymbolEntry
*SymbolEntPtr
= Obj
.toSymbolEntry(SymbolDRI
);
325 XCOFFSymbolRef
XCOFFSymRef(SymbolDRI
, &Obj
);
326 uint8_t NumberOfAuxEntries
= XCOFFSymRef
.getNumberOfAuxEntries();
328 DictScope
SymDs(W
, "Symbol");
330 StringRef SymbolName
=
331 unwrapOrError(Obj
.getFileName(), Obj
.getSymbolName(SymbolDRI
));
333 W
.printNumber("Index",
334 Obj
.getSymbolIndex(reinterpret_cast<uintptr_t>(SymbolEntPtr
)));
335 W
.printString("Name", SymbolName
);
336 W
.printHex(GetSymbolValueName(SymbolEntPtr
->StorageClass
),
337 SymbolEntPtr
->Value
);
339 StringRef SectionName
=
340 unwrapOrError(Obj
.getFileName(), Obj
.getSymbolSectionName(SymbolEntPtr
));
342 W
.printString("Section", SectionName
);
343 if (XCOFFSymRef
.getStorageClass() == XCOFF::C_FILE
) {
344 W
.printEnum("Source Language ID",
345 SymbolEntPtr
->CFileLanguageIdAndTypeId
.LanguageId
,
346 makeArrayRef(CFileLangIdClass
));
347 W
.printEnum("CPU Version ID",
348 SymbolEntPtr
->CFileLanguageIdAndTypeId
.CpuTypeId
,
349 makeArrayRef(CFileCpuIdClass
));
351 W
.printHex("Type", SymbolEntPtr
->SymbolType
);
353 W
.printEnum("StorageClass", static_cast<uint8_t>(SymbolEntPtr
->StorageClass
),
354 makeArrayRef(SymStorageClass
));
355 W
.printNumber("NumberOfAuxEntries", SymbolEntPtr
->NumberOfAuxEntries
);
357 if (NumberOfAuxEntries
== 0)
360 switch (XCOFFSymRef
.getStorageClass()) {
362 // If the symbol is C_FILE and has auxiliary entries...
363 for (int i
= 1; i
<= NumberOfAuxEntries
; i
++) {
364 const XCOFFFileAuxEnt
*FileAuxEntPtr
=
365 reinterpret_cast<const XCOFFFileAuxEnt
*>(SymbolEntPtr
+ i
);
367 Obj
.checkSymbolEntryPointer(reinterpret_cast<uintptr_t>(FileAuxEntPtr
));
369 printFileAuxEnt(FileAuxEntPtr
);
373 case XCOFF::C_WEAKEXT
:
374 case XCOFF::C_HIDEXT
:
375 // If the symbol is for a function, and it has more than 1 auxiliary entry,
376 // then one of them must be function auxiliary entry which we do not
378 if (XCOFFSymRef
.isFunction() && NumberOfAuxEntries
>= 2)
379 report_fatal_error("Function auxiliary entry printing is unimplemented.");
381 // If there is more than 1 auxiliary entry, instead of printing out
382 // error information, print out the raw Auxiliary entry from 1st till
383 // the last - 1. The last one must be a CSECT Auxiliary Entry.
384 for (int i
= 1; i
< NumberOfAuxEntries
; i
++) {
385 W
.startLine() << "!Unexpected raw auxiliary entry data:\n";
386 W
.startLine() << format_bytes(
387 ArrayRef
<uint8_t>(reinterpret_cast<const uint8_t *>(SymbolEntPtr
+ i
),
388 XCOFF::SymbolTableEntrySize
));
391 // The symbol's last auxiliary entry is a CSECT Auxiliary Entry.
392 printCsectAuxEnt32(XCOFFSymRef
.getXCOFFCsectAuxEnt32());
395 if (NumberOfAuxEntries
> 1)
397 "C_STAT symbol should not have more than 1 auxiliary entry.");
399 const XCOFFSectAuxEntForStat
*StatAuxEntPtr
;
401 reinterpret_cast<const XCOFFSectAuxEntForStat
*>(SymbolEntPtr
+ 1);
403 Obj
.checkSymbolEntryPointer(reinterpret_cast<uintptr_t>(StatAuxEntPtr
));
405 printSectAuxEntForStat(StatAuxEntPtr
);
410 report_fatal_error("Symbol table entry printing for this storage class "
411 "type is unimplemented.");
414 for (int i
= 1; i
<= NumberOfAuxEntries
; i
++) {
415 W
.startLine() << "!Unexpected raw auxiliary entry data:\n";
416 W
.startLine() << format_bytes(
417 ArrayRef
<uint8_t>(reinterpret_cast<const uint8_t *>(SymbolEntPtr
+ i
),
418 XCOFF::SymbolTableEntrySize
));
424 void XCOFFDumper::printSymbols() {
425 ListScope
Group(W
, "Symbols");
426 for (const SymbolRef
&S
: Obj
.symbols())
430 void XCOFFDumper::printDynamicSymbols() {
431 llvm_unreachable("Unimplemented functionality for XCOFFDumper");
434 void XCOFFDumper::printUnwindInfo() {
435 llvm_unreachable("Unimplemented functionality for XCOFFDumper");
438 void XCOFFDumper::printStackMap() const {
439 llvm_unreachable("Unimplemented functionality for XCOFFDumper");
442 void XCOFFDumper::printNeededLibraries() {
443 llvm_unreachable("Unimplemented functionality for XCOFFDumper");
446 static const EnumEntry
<XCOFF::SectionTypeFlags
> SectionTypeFlagsNames
[] = {
449 ECase(STYP_PAD
), ECase(STYP_DWARF
), ECase(STYP_TEXT
),
450 ECase(STYP_DATA
), ECase(STYP_BSS
), ECase(STYP_EXCEPT
),
451 ECase(STYP_INFO
), ECase(STYP_TDATA
), ECase(STYP_TBSS
),
452 ECase(STYP_LOADER
), ECase(STYP_DEBUG
), ECase(STYP_TYPCHK
),
457 template <typename T
>
458 void XCOFFDumper::printOverflowSectionHeader(T
&Sec
) const {
460 reportWarning(make_error
<StringError
>("An 64-bit XCOFF object file may not "
461 "contain an overflow section header.",
462 object_error::parse_failed
),
466 W
.printString("Name", Sec
.getName());
467 W
.printNumber("NumberOfRelocations", Sec
.PhysicalAddress
);
468 W
.printNumber("NumberOfLineNumbers", Sec
.VirtualAddress
);
469 W
.printHex("Size", Sec
.SectionSize
);
470 W
.printHex("RawDataOffset", Sec
.FileOffsetToRawData
);
471 W
.printHex("RelocationPointer", Sec
.FileOffsetToRelocationInfo
);
472 W
.printHex("LineNumberPointer", Sec
.FileOffsetToLineNumberInfo
);
473 W
.printNumber("IndexOfSectionOverflowed", Sec
.NumberOfRelocations
);
474 W
.printNumber("IndexOfSectionOverflowed", Sec
.NumberOfLineNumbers
);
477 template <typename T
>
478 void XCOFFDumper::printGenericSectionHeader(T
&Sec
) const {
479 W
.printString("Name", Sec
.getName());
480 W
.printHex("PhysicalAddress", Sec
.PhysicalAddress
);
481 W
.printHex("VirtualAddress", Sec
.VirtualAddress
);
482 W
.printHex("Size", Sec
.SectionSize
);
483 W
.printHex("RawDataOffset", Sec
.FileOffsetToRawData
);
484 W
.printHex("RelocationPointer", Sec
.FileOffsetToRelocationInfo
);
485 W
.printHex("LineNumberPointer", Sec
.FileOffsetToLineNumberInfo
);
486 W
.printNumber("NumberOfRelocations", Sec
.NumberOfRelocations
);
487 W
.printNumber("NumberOfLineNumbers", Sec
.NumberOfLineNumbers
);
490 template <typename T
>
491 void XCOFFDumper::printSectionHeaders(ArrayRef
<T
> Sections
) {
492 ListScope
Group(W
, "Sections");
495 for (const T
&Sec
: Sections
) {
496 DictScope
SecDS(W
, "Section");
498 W
.printNumber("Index", Index
++);
500 uint16_t SectionType
= Sec
.Flags
& SectionFlagsTypeMask
;
501 switch (SectionType
) {
502 case XCOFF::STYP_OVRFLO
:
503 printOverflowSectionHeader(Sec
);
505 case XCOFF::STYP_LOADER
:
506 case XCOFF::STYP_EXCEPT
:
507 case XCOFF::STYP_TYPCHK
:
508 // TODO The interpretation of loader, exception and type check section
509 // headers are different from that of generic section headers. We will
510 // implement them later. We interpret them as generic section headers for
513 printGenericSectionHeader(Sec
);
516 // For now we just dump the section type portion of the flags.
517 if (SectionType
& SectionFlagsReservedMask
)
518 W
.printHex("Flags", "Reserved", SectionType
);
520 W
.printEnum("Type", SectionType
, makeArrayRef(SectionTypeFlagsNames
));
523 if (opts::SectionRelocations
)
524 report_fatal_error("Dumping section relocations is unimplemented");
526 if (opts::SectionSymbols
)
527 report_fatal_error("Dumping symbols is unimplemented");
529 if (opts::SectionData
)
530 report_fatal_error("Dumping section data is unimplemented");
534 std::error_code
createXCOFFDumper(const object::ObjectFile
*Obj
,
535 ScopedPrinter
&Writer
,
536 std::unique_ptr
<ObjDumper
> &Result
) {
537 const XCOFFObjectFile
*XObj
= dyn_cast
<XCOFFObjectFile
>(Obj
);
539 return readobj_error::unsupported_obj_file_format
;
541 Result
.reset(new XCOFFDumper(*XObj
, Writer
));
542 return readobj_error::success
;