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 void printFileAuxEnt(const XCOFFFileAuxEnt
*AuxEntPtr
);
47 void printCsectAuxEnt32(const XCOFFCsectAuxEnt32
*AuxEntPtr
);
48 void printSectAuxEntForStat(const XCOFFSectAuxEntForStat
*AuxEntPtr
);
49 void printSymbol(const SymbolRef
&);
51 // Least significant 3 bits are reserved.
52 static constexpr unsigned SectionFlagsReservedMask
= 0x7;
53 const XCOFFObjectFile
&Obj
;
55 } // anonymous namespace
57 void XCOFFDumper::printFileHeaders() {
58 DictScope
DS(W
, "FileHeader");
59 W
.printHex("Magic", Obj
.getMagic());
60 W
.printNumber("NumberOfSections", Obj
.getNumberOfSections());
62 // Negative timestamp values are reserved for future use.
63 int32_t TimeStamp
= Obj
.getTimeStamp();
65 // This handling of the time stamp assumes that the host system's time_t is
66 // compatible with AIX time_t. If a platform is not compatible, the lit
67 // tests will let us know.
68 time_t TimeDate
= TimeStamp
;
70 char FormattedTime
[21] = {};
72 strftime(FormattedTime
, 21, "%Y-%m-%dT%H:%M:%SZ", gmtime(&TimeDate
));
74 W
.printHex("TimeStamp", FormattedTime
, TimeStamp
);
76 W
.printHex("Timestamp", TimeStamp
);
78 W
.printHex("TimeStamp", TimeStamp
== 0 ? "None" : "Reserved Value",
82 // The number of symbol table entries is an unsigned value in 64-bit objects
83 // and a signed value (with negative values being 'reserved') in 32-bit
86 W
.printHex("SymbolTableOffset", Obj
.getSymbolTableOffset64());
87 W
.printNumber("SymbolTableEntries", Obj
.getNumberOfSymbolTableEntries64());
89 W
.printHex("SymbolTableOffset", Obj
.getSymbolTableOffset32());
90 int32_t SymTabEntries
= Obj
.getRawNumberOfSymbolTableEntries32();
91 if (SymTabEntries
>= 0)
92 W
.printNumber("SymbolTableEntries", SymTabEntries
);
94 W
.printHex("SymbolTableEntries", "Reserved Value", SymTabEntries
);
97 W
.printHex("OptionalHeaderSize", Obj
.getOptionalHeaderSize());
98 W
.printHex("Flags", Obj
.getFlags());
100 // TODO FIXME Add support for the auxiliary header (if any) once
101 // XCOFFObjectFile has the necessary support.
104 void XCOFFDumper::printSectionHeaders() {
106 printSectionHeaders(Obj
.sections64());
108 printSectionHeaders(Obj
.sections32());
111 void XCOFFDumper::printRelocations() {
112 llvm_unreachable("Unimplemented functionality for XCOFFDumper");
115 static const EnumEntry
<XCOFF::CFileStringType
> FileStringType
[] = {
118 ECase(XFT_FN
), ECase(XFT_CT
), ECase(XFT_CV
), ECase(XFT_CD
)
122 void XCOFFDumper::printFileAuxEnt(const XCOFFFileAuxEnt
*AuxEntPtr
) {
125 "Printing for File Auxiliary Entry in 64-bit is unimplemented.");
127 unwrapOrError(Obj
.getFileName(), Obj
.getCFileName(AuxEntPtr
));
128 DictScope
SymDs(W
, "File Auxiliary Entry");
129 W
.printNumber("Index",
130 Obj
.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr
)));
131 W
.printString("Name", FileName
);
132 W
.printEnum("Type", static_cast<uint8_t>(AuxEntPtr
->Type
),
133 makeArrayRef(FileStringType
));
136 static const EnumEntry
<XCOFF::StorageMappingClass
> CsectStorageMappingClass
[] =
140 ECase(XMC_PR
), ECase(XMC_RO
), ECase(XMC_DB
),
141 ECase(XMC_GL
), ECase(XMC_XO
), ECase(XMC_SV
),
142 ECase(XMC_SV64
), ECase(XMC_SV3264
), ECase(XMC_TI
),
143 ECase(XMC_TB
), ECase(XMC_RW
), ECase(XMC_TC0
),
144 ECase(XMC_TC
), ECase(XMC_TD
), ECase(XMC_DS
),
145 ECase(XMC_UA
), ECase(XMC_BS
), ECase(XMC_UC
),
146 ECase(XMC_TL
), ECase(XMC_TE
)
150 static const EnumEntry
<XCOFF::SymbolType
> CsectSymbolTypeClass
[] = {
153 ECase(XTY_ER
), ECase(XTY_SD
), ECase(XTY_LD
), ECase(XTY_CM
)
157 void XCOFFDumper::printCsectAuxEnt32(const XCOFFCsectAuxEnt32
*AuxEntPtr
) {
158 assert(!Obj
.is64Bit() && "32-bit interface called on 64-bit object file.");
160 DictScope
SymDs(W
, "CSECT Auxiliary Entry");
161 W
.printNumber("Index",
162 Obj
.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr
)));
163 if ((AuxEntPtr
->SymbolAlignmentAndType
& SymbolTypeMask
) == XCOFF::XTY_LD
)
164 W
.printNumber("ContainingCsectSymbolIndex", AuxEntPtr
->SectionOrLength
);
166 W
.printNumber("SectionLen", AuxEntPtr
->SectionOrLength
);
167 W
.printHex("ParameterHashIndex", AuxEntPtr
->ParameterHashIndex
);
168 W
.printHex("TypeChkSectNum", AuxEntPtr
->TypeChkSectNum
);
169 // Print out symbol alignment and type.
170 W
.printNumber("SymbolAlignmentLog2",
171 (AuxEntPtr
->SymbolAlignmentAndType
& SymbolAlignmentMask
) >>
172 SymbolAlignmentBitOffset
);
173 W
.printEnum("SymbolType", AuxEntPtr
->SymbolAlignmentAndType
& SymbolTypeMask
,
174 makeArrayRef(CsectSymbolTypeClass
));
175 W
.printEnum("StorageMappingClass",
176 static_cast<uint8_t>(AuxEntPtr
->StorageMappingClass
),
177 makeArrayRef(CsectStorageMappingClass
));
178 W
.printHex("StabInfoIndex", AuxEntPtr
->StabInfoIndex
);
179 W
.printHex("StabSectNum", AuxEntPtr
->StabSectNum
);
182 void XCOFFDumper::printSectAuxEntForStat(
183 const XCOFFSectAuxEntForStat
*AuxEntPtr
) {
184 assert(!Obj
.is64Bit() && "32-bit interface called on 64-bit object file.");
186 DictScope
SymDs(W
, "Sect Auxiliary Entry For Stat");
187 W
.printNumber("Index",
188 Obj
.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr
)));
189 W
.printNumber("SectionLength", AuxEntPtr
->SectionLength
);
191 // Unlike the corresponding fields in the section header, NumberOfRelocEnt
192 // and NumberOfLineNum do not handle values greater than 65535.
193 W
.printNumber("NumberOfRelocEnt", AuxEntPtr
->NumberOfRelocEnt
);
194 W
.printNumber("NumberOfLineNum", AuxEntPtr
->NumberOfLineNum
);
197 static const EnumEntry
<XCOFF::StorageClass
> SymStorageClass
[] = {
200 ECase(C_NULL
), ECase(C_AUTO
), ECase(C_EXT
), ECase(C_STAT
),
201 ECase(C_REG
), ECase(C_EXTDEF
), ECase(C_LABEL
), ECase(C_ULABEL
),
202 ECase(C_MOS
), ECase(C_ARG
), ECase(C_STRTAG
), ECase(C_MOU
),
203 ECase(C_UNTAG
), ECase(C_TPDEF
), ECase(C_USTATIC
), ECase(C_ENTAG
),
204 ECase(C_MOE
), ECase(C_REGPARM
), ECase(C_FIELD
), ECase(C_BLOCK
),
205 ECase(C_FCN
), ECase(C_EOS
), ECase(C_FILE
), ECase(C_LINE
),
206 ECase(C_ALIAS
), ECase(C_HIDDEN
), ECase(C_HIDEXT
), ECase(C_BINCL
),
207 ECase(C_EINCL
), ECase(C_INFO
), ECase(C_WEAKEXT
), ECase(C_DWARF
),
208 ECase(C_GSYM
), ECase(C_LSYM
), ECase(C_PSYM
), ECase(C_RSYM
),
209 ECase(C_RPSYM
), ECase(C_STSYM
), ECase(C_TCSYM
), ECase(C_BCOMM
),
210 ECase(C_ECOML
), ECase(C_ECOMM
), ECase(C_DECL
), ECase(C_ENTRY
),
211 ECase(C_FUN
), ECase(C_BSTAT
), ECase(C_ESTAT
), ECase(C_GTLS
),
212 ECase(C_STTLS
), ECase(C_EFCN
)
216 static StringRef
GetSymbolValueName(XCOFF::StorageClass SC
) {
219 case XCOFF::C_WEAKEXT
:
220 case XCOFF::C_HIDEXT
:
222 return "Value (RelocatableAddress)";
224 return "Value (SymbolTableIndex)";
239 assert(false && "This StorageClass for the symbol is not yet implemented.");
246 static const EnumEntry
<XCOFF::CFileLangId
> CFileLangIdClass
[] = {
249 ECase(TB_C
), ECase(TB_CPLUSPLUS
)
253 static const EnumEntry
<XCOFF::CFileCpuId
> CFileCpuIdClass
[] = {
256 ECase(TCPU_PPC64
), ECase(TCPU_COM
), ECase(TCPU_970
)
260 void XCOFFDumper::printSymbol(const SymbolRef
&S
) {
262 report_fatal_error("64-bit support is unimplemented.");
264 DataRefImpl SymbolDRI
= S
.getRawDataRefImpl();
265 const XCOFFSymbolEntry
*SymbolEntPtr
= Obj
.toSymbolEntry(SymbolDRI
);
267 XCOFFSymbolRef
XCOFFSymRef(SymbolDRI
, &Obj
);
268 uint8_t NumberOfAuxEntries
= XCOFFSymRef
.getNumberOfAuxEntries();
270 DictScope
SymDs(W
, "Symbol");
272 StringRef SymbolName
=
273 unwrapOrError(Obj
.getFileName(), Obj
.getSymbolName(SymbolDRI
));
275 W
.printNumber("Index",
276 Obj
.getSymbolIndex(reinterpret_cast<uintptr_t>(SymbolEntPtr
)));
277 W
.printString("Name", SymbolName
);
278 W
.printHex(GetSymbolValueName(SymbolEntPtr
->StorageClass
),
279 SymbolEntPtr
->Value
);
281 StringRef SectionName
=
282 unwrapOrError(Obj
.getFileName(), Obj
.getSymbolSectionName(SymbolEntPtr
));
284 W
.printString("Section", SectionName
);
285 if (XCOFFSymRef
.getStorageClass() == XCOFF::C_FILE
) {
286 W
.printEnum("Source Language ID",
287 SymbolEntPtr
->CFileLanguageIdAndTypeId
.LanguageId
,
288 makeArrayRef(CFileLangIdClass
));
289 W
.printEnum("CPU Version ID",
290 SymbolEntPtr
->CFileLanguageIdAndTypeId
.CpuTypeId
,
291 makeArrayRef(CFileCpuIdClass
));
293 W
.printHex("Type", SymbolEntPtr
->SymbolType
);
295 W
.printEnum("StorageClass", static_cast<uint8_t>(SymbolEntPtr
->StorageClass
),
296 makeArrayRef(SymStorageClass
));
297 W
.printNumber("NumberOfAuxEntries", SymbolEntPtr
->NumberOfAuxEntries
);
299 if (NumberOfAuxEntries
== 0)
302 switch (XCOFFSymRef
.getStorageClass()) {
304 // If the symbol is C_FILE and has auxiliary entries...
305 for (int i
= 1; i
<= NumberOfAuxEntries
; i
++) {
306 const XCOFFFileAuxEnt
*FileAuxEntPtr
=
307 reinterpret_cast<const XCOFFFileAuxEnt
*>(SymbolEntPtr
+ i
);
309 Obj
.checkSymbolEntryPointer(reinterpret_cast<uintptr_t>(FileAuxEntPtr
));
311 printFileAuxEnt(FileAuxEntPtr
);
315 case XCOFF::C_WEAKEXT
:
316 case XCOFF::C_HIDEXT
:
317 // If the symbol is for a function, and it has more than 1 auxiliary entry,
318 // then one of them must be function auxiliary entry which we do not
320 if (XCOFFSymRef
.isFunction() && NumberOfAuxEntries
>= 2)
321 report_fatal_error("Function auxiliary entry printing is unimplemented.");
323 // If there is more than 1 auxiliary entry, instead of printing out
324 // error information, print out the raw Auxiliary entry from 1st till
325 // the last - 1. The last one must be a CSECT Auxiliary Entry.
326 for (int i
= 1; i
< NumberOfAuxEntries
; i
++) {
327 W
.startLine() << "!Unexpected raw auxiliary entry data:\n";
328 W
.startLine() << format_bytes(
329 ArrayRef
<uint8_t>(reinterpret_cast<const uint8_t *>(SymbolEntPtr
+ i
),
330 XCOFF::SymbolTableEntrySize
));
333 // The symbol's last auxiliary entry is a CSECT Auxiliary Entry.
334 printCsectAuxEnt32(XCOFFSymRef
.getXCOFFCsectAuxEnt32());
337 if (NumberOfAuxEntries
> 1)
339 "C_STAT symbol should not have more than 1 auxiliary entry.");
341 const XCOFFSectAuxEntForStat
*StatAuxEntPtr
;
343 reinterpret_cast<const XCOFFSectAuxEntForStat
*>(SymbolEntPtr
+ 1);
345 Obj
.checkSymbolEntryPointer(reinterpret_cast<uintptr_t>(StatAuxEntPtr
));
347 printSectAuxEntForStat(StatAuxEntPtr
);
352 report_fatal_error("Symbol table entry printing for this storage class "
353 "type is unimplemented.");
356 for (int i
= 1; i
<= NumberOfAuxEntries
; i
++) {
357 W
.startLine() << "!Unexpected raw auxiliary entry data:\n";
358 W
.startLine() << format_bytes(
359 ArrayRef
<uint8_t>(reinterpret_cast<const uint8_t *>(SymbolEntPtr
+ i
),
360 XCOFF::SymbolTableEntrySize
));
366 void XCOFFDumper::printSymbols() {
367 ListScope
Group(W
, "Symbols");
368 for (const SymbolRef
&S
: Obj
.symbols())
372 void XCOFFDumper::printDynamicSymbols() {
373 llvm_unreachable("Unimplemented functionality for XCOFFDumper");
376 void XCOFFDumper::printUnwindInfo() {
377 llvm_unreachable("Unimplemented functionality for XCOFFDumper");
380 void XCOFFDumper::printStackMap() const {
381 llvm_unreachable("Unimplemented functionality for XCOFFDumper");
384 void XCOFFDumper::printNeededLibraries() {
385 llvm_unreachable("Unimplemented functionality for XCOFFDumper");
388 static const EnumEntry
<XCOFF::SectionTypeFlags
> SectionTypeFlagsNames
[] = {
391 ECase(STYP_PAD
), ECase(STYP_DWARF
), ECase(STYP_TEXT
),
392 ECase(STYP_DATA
), ECase(STYP_BSS
), ECase(STYP_EXCEPT
),
393 ECase(STYP_INFO
), ECase(STYP_TDATA
), ECase(STYP_TBSS
),
394 ECase(STYP_LOADER
), ECase(STYP_DEBUG
), ECase(STYP_TYPCHK
),
399 template <typename T
>
400 void XCOFFDumper::printSectionHeaders(ArrayRef
<T
> Sections
) {
401 ListScope
Group(W
, "Sections");
404 for (const T
&Sec
: Sections
) {
405 DictScope
SecDS(W
, "Section");
407 W
.printNumber("Index", Index
++);
408 W
.printString("Name", Sec
.getName());
410 W
.printHex("PhysicalAddress", Sec
.PhysicalAddress
);
411 W
.printHex("VirtualAddress", Sec
.VirtualAddress
);
412 W
.printHex("Size", Sec
.SectionSize
);
413 W
.printHex("RawDataOffset", Sec
.FileOffsetToRawData
);
414 W
.printHex("RelocationPointer", Sec
.FileOffsetToRelocationInfo
);
415 W
.printHex("LineNumberPointer", Sec
.FileOffsetToLineNumberInfo
);
417 // TODO Need to add overflow handling when NumberOfX == _OVERFLOW_MARKER
418 // in 32-bit object files.
419 W
.printNumber("NumberOfRelocations", Sec
.NumberOfRelocations
);
420 W
.printNumber("NumberOfLineNumbers", Sec
.NumberOfLineNumbers
);
422 // The most significant 16-bits represent the DWARF section subtype. For
423 // now we just dump the section type flags.
424 uint16_t Flags
= Sec
.Flags
& 0xffffu
;
425 if (Flags
& SectionFlagsReservedMask
)
426 W
.printHex("Flags", "Reserved", Flags
);
428 W
.printEnum("Type", Flags
, makeArrayRef(SectionTypeFlagsNames
));
431 if (opts::SectionRelocations
)
432 report_fatal_error("Dumping section relocations is unimplemented");
434 if (opts::SectionSymbols
)
435 report_fatal_error("Dumping symbols is unimplemented");
437 if (opts::SectionData
)
438 report_fatal_error("Dumping section data is unimplemented");
442 std::error_code
createXCOFFDumper(const object::ObjectFile
*Obj
,
443 ScopedPrinter
&Writer
,
444 std::unique_ptr
<ObjDumper
> &Result
) {
445 const XCOFFObjectFile
*XObj
= dyn_cast
<XCOFFObjectFile
>(Obj
);
447 return readobj_error::unsupported_obj_file_format
;
449 Result
.reset(new XCOFFDumper(*XObj
, Writer
));
450 return readobj_error::success
;