[sanitizer] Improve FreeBSD ASLR detection
[llvm-project.git] / llvm / tools / llvm-readobj / XCOFFDumper.cpp
blobe34b105cfbf0ab1f3bdbd2dc001fcb6ae815f790
1 //===-- XCOFFDumper.cpp - XCOFF dumping utility -----------------*- C++ -*-===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8 //
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"
19 #include <stddef.h>
21 using namespace llvm;
22 using namespace object;
24 namespace {
26 class XCOFFDumper : public ObjDumper {
28 public:
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;
43 private:
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();
74 if (TimeStamp > 0) {
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] = {};
81 size_t BytesWritten =
82 strftime(FormattedTime, 21, "%Y-%m-%dT%H:%M:%SZ", gmtime(&TimeDate));
83 if (BytesWritten)
84 W.printHex("TimeStamp", FormattedTime, TimeStamp);
85 else
86 W.printHex("Timestamp", TimeStamp);
87 } else {
88 W.printHex("TimeStamp", TimeStamp == 0 ? "None" : "Reserved Value",
89 TimeStamp);
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
94 // objects.
95 if (Obj.is64Bit()) {
96 W.printHex("SymbolTableOffset", Obj.getSymbolTableOffset64());
97 W.printNumber("SymbolTableEntries", Obj.getNumberOfSymbolTableEntries64());
98 } else {
99 W.printHex("SymbolTableOffset", Obj.getSymbolTableOffset32());
100 int32_t SymTabEntries = Obj.getRawNumberOfSymbolTableEntries32();
101 if (SymTabEntries >= 0)
102 W.printNumber("SymbolTableEntries", SymTabEntries);
103 else
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() {
115 if (Obj.is64Bit())
116 printAuxiliaryHeader(Obj.auxiliaryHeader64());
117 else
118 printAuxiliaryHeader(Obj.auxiliaryHeader32());
121 void XCOFFDumper::printSectionHeaders() {
122 if (Obj.is64Bit())
123 printSectionHeaders(Obj.sections64());
124 else
125 printSectionHeaders(Obj.sections32());
128 void XCOFFDumper::printRelocations() {
129 if (Obj.is64Bit())
130 printRelocations<XCOFFSectionHeader64, XCOFFRelocation64>(Obj.sections64());
131 else
132 printRelocations<XCOFFSectionHeader32, XCOFFRelocation32>(Obj.sections32());
135 const EnumEntry<XCOFF::RelocationType> RelocationTypeNameclass[] = {
136 #define ECase(X) \
137 { #X, XCOFF::X }
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)
144 #undef ECase
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));
152 return;
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));
165 } else {
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");
175 uint16_t Index = 0;
176 for (const Shdr &Sec : Sections) {
177 ++Index;
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)
181 continue;
182 Expected<ArrayRef<RelTy>> ErrOrRelocations = Obj.relocations<Shdr, RelTy>(Sec);
183 if (Error E = ErrOrRelocations.takeError()) {
184 reportUniqueWarning(std::move(E));
185 continue;
188 const ArrayRef<RelTy> Relocations = *ErrOrRelocations;
189 if (Relocations.empty())
190 continue;
192 W.startLine() << "Section (index: " << Index << ") " << Sec.getName()
193 << " {\n";
194 W.indent();
196 for (const RelTy Reloc : Relocations)
197 printRelocation(Reloc);
199 W.unindent();
200 W.startLine() << "}\n";
204 const EnumEntry<XCOFF::CFileStringType> FileStringType[] = {
205 #define ECase(X) \
206 { #X, XCOFF::X }
207 ECase(XFT_FN), ECase(XFT_CT), ECase(XFT_CV), ECase(XFT_CD)
208 #undef ECase
211 const EnumEntry<XCOFF::SymbolAuxType> SymAuxType[] = {
212 #define ECase(X) \
213 { #X, XCOFF::X }
214 ECase(AUX_EXCEPT), ECase(AUX_FCN), ECase(AUX_SYM), ECase(AUX_FILE),
215 ECase(AUX_CSECT), ECase(AUX_SECT)
216 #undef ECase
219 void XCOFFDumper::printFileAuxEnt(const XCOFFFileAuxEnt *AuxEntPtr) {
220 assert((!Obj.is64Bit() || AuxEntPtr->AuxType == XCOFF::AUX_FILE) &&
221 "Mismatched auxiliary type!");
222 StringRef FileName =
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));
230 if (Obj.is64Bit()) {
231 W.printEnum("Auxiliary Type", static_cast<uint8_t>(AuxEntPtr->AuxType),
232 makeArrayRef(SymAuxType));
236 static const EnumEntry<XCOFF::StorageMappingClass> CsectStorageMappingClass[] =
238 #define ECase(X) \
239 { #X, XCOFF::X }
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),
245 ECase(XMC_TE)
246 #undef ECase
249 const EnumEntry<XCOFF::SymbolType> CsectSymbolTypeClass[] = {
250 #define ECase(X) \
251 { #X, XCOFF::X }
252 ECase(XTY_ER), ECase(XTY_SD), ECase(XTY_LD), ECase(XTY_CM)
253 #undef ECase
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"
263 : "SectionLen",
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));
275 if (Obj.is64Bit()) {
276 W.printEnum("Auxiliary Type", static_cast<uint8_t>(XCOFF::AUX_CSECT),
277 makeArrayRef(SymAuxType));
278 } else {
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);
365 if (Obj.is64Bit())
366 W.printEnum("Auxiliary Type", static_cast<uint8_t>(XCOFF::AUX_SECT),
367 makeArrayRef(SymAuxType));
370 const EnumEntry<XCOFF::StorageClass> SymStorageClass[] = {
371 #define ECase(X) \
372 { #X, XCOFF::X }
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)
386 #undef ECase
389 static StringRef GetSymbolValueName(XCOFF::StorageClass SC) {
390 switch (SC) {
391 case XCOFF::C_EXT:
392 case XCOFF::C_WEAKEXT:
393 case XCOFF::C_HIDEXT:
394 case XCOFF::C_STAT:
395 case XCOFF::C_FCN:
396 case XCOFF::C_BLOCK:
397 return "Value (RelocatableAddress)";
398 case XCOFF::C_FILE:
399 return "Value (SymbolTableIndex)";
400 case XCOFF::C_DWARF:
401 return "Value (OffsetInDWARF)";
402 case XCOFF::C_FUN:
403 case XCOFF::C_STSYM:
404 case XCOFF::C_BINCL:
405 case XCOFF::C_EINCL:
406 case XCOFF::C_INFO:
407 case XCOFF::C_BSTAT:
408 case XCOFF::C_LSYM:
409 case XCOFF::C_PSYM:
410 case XCOFF::C_RPSYM:
411 case XCOFF::C_RSYM:
412 case XCOFF::C_ECOML:
413 assert(false && "This StorageClass for the symbol is not yet implemented.");
414 return "";
415 default:
416 return "Value";
420 const EnumEntry<XCOFF::CFileLangId> CFileLangIdClass[] = {
421 #define ECase(X) \
422 { #X, XCOFF::X }
423 ECase(TB_C), ECase(TB_CPLUSPLUS)
424 #undef ECase
427 const EnumEntry<XCOFF::CFileCpuId> CFileCpuIdClass[] = {
428 #define ECase(X) \
429 { #X, XCOFF::X }
430 ECase(TCPU_PPC64), ECase(TCPU_COM), ECase(TCPU_970)
431 #undef ECase
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));
437 return AuxEntPtr;
440 static void printUnexpectedRawAuxEnt(ScopedPrinter &W, uintptr_t AuxAddress) {
441 W.startLine() << "!Unexpected raw auxiliary entry data:\n";
442 W.startLine() << format_bytes(
443 ArrayRef<uint8_t>(
444 reinterpret_cast<const uint8_t *>(AuxAddress),
445 XCOFF::SymbolTableEntrySize),
446 None, XCOFF::SymbolTableEntrySize)
447 << "\n";
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));
477 } else
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)
485 return;
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 "
494 "auxiliary entry");
497 switch (SymbolClass) {
498 case XCOFF::C_FILE:
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);
504 if (Obj.is64Bit() &&
505 *Obj.getSymbolAuxType(AuxAddress) != XCOFF::SymbolAuxType::AUX_FILE) {
506 printUnexpectedRawAuxEnt(W, AuxAddress);
507 continue;
510 const XCOFFFileAuxEnt *FileAuxEntPtr =
511 getAuxEntPtr<XCOFFFileAuxEnt>(AuxAddress);
512 printFileAuxEnt(FileAuxEntPtr);
514 break;
515 case XCOFF::C_EXT:
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 "
524 "auxiliary entry");
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())
534 break;
536 uintptr_t AuxAddress = XCOFFObjectFile::getAdvancedSymbolEntryAddress(
537 SymbolEntRef.getEntryAddress(), I);
539 if (Obj.is64Bit()) {
540 XCOFF::SymbolAuxType Type = *Obj.getSymbolAuxType(AuxAddress);
541 if (Type == XCOFF::SymbolAuxType::AUX_CSECT)
542 continue;
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);
551 } else {
552 printUnexpectedRawAuxEnt(W, AuxAddress);
554 } else {
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());
565 else
566 printCsectAuxEnt(*ErrOrCsectAuxRef);
568 break;
570 case XCOFF::C_STAT: {
571 checkNumOfAux();
573 const XCOFFSectAuxEntForStat *StatAuxEntPtr =
574 getAuxEntPtr<XCOFFSectAuxEntForStat>(
575 XCOFFObjectFile::getAdvancedSymbolEntryAddress(
576 SymbolEntRef.getEntryAddress(), 1));
577 printSectAuxEntForStat(StatAuxEntPtr);
578 break;
580 case XCOFF::C_DWARF: {
581 checkNumOfAux();
583 uintptr_t AuxAddress = XCOFFObjectFile::getAdvancedSymbolEntryAddress(
584 SymbolEntRef.getEntryAddress(), 1);
586 if (Obj.is64Bit()) {
587 const XCOFFSectAuxEntForDWARF64 *AuxEntPtr =
588 getAuxEntPtr<XCOFFSectAuxEntForDWARF64>(AuxAddress);
589 printSectAuxEntForDWARF<XCOFFSectAuxEntForDWARF64>(AuxEntPtr);
590 } else {
591 const XCOFFSectAuxEntForDWARF32 *AuxEntPtr =
592 getAuxEntPtr<XCOFFSectAuxEntForDWARF32>(AuxAddress);
593 printSectAuxEntForDWARF<XCOFFSectAuxEntForDWARF32>(AuxEntPtr);
595 break;
597 case XCOFF::C_BLOCK:
598 case XCOFF::C_FCN: {
599 checkNumOfAux();
601 uintptr_t AuxAddress = XCOFFObjectFile::getAdvancedSymbolEntryAddress(
602 SymbolEntRef.getEntryAddress(), 1);
604 if (Obj.is64Bit()) {
605 const XCOFFBlockAuxEnt64 *AuxEntPtr =
606 getAuxEntPtr<XCOFFBlockAuxEnt64>(AuxAddress);
607 printBlockAuxEnt(AuxEntPtr);
608 } else {
609 const XCOFFBlockAuxEnt32 *AuxEntPtr =
610 getAuxEntPtr<XCOFFBlockAuxEnt32>(AuxAddress);
611 printBlockAuxEnt(AuxEntPtr);
613 break;
615 default:
616 for (int i = 1; i <= NumberOfAuxEntries; i++) {
617 printUnexpectedRawAuxEnt(W,
618 XCOFFObjectFile::getAdvancedSymbolEntryAddress(
619 SymbolEntRef.getEntryAddress(), i));
621 break;
625 void XCOFFDumper::printSymbols() {
626 ListScope Group(W, "Symbols");
627 for (const SymbolRef &S : Obj.symbols())
628 printSymbol(S);
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).
638 if (StrTabSize > 4)
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());
659 return;
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) << " ";
688 else
689 OS << CurrentStr << "\n";
694 const EnumEntry<XCOFF::SectionTypeFlags> SectionTypeFlagsNames[] = {
695 #define ECase(X) \
696 { #X, XCOFF::X }
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),
701 ECase(STYP_OVRFLO)
702 #undef ECase
705 template <typename T>
706 void XCOFFDumper::printOverflowSectionHeader(T &Sec) const {
707 if (Obj.is64Bit()) {
708 reportWarning(make_error<StringError>("An 64-bit XCOFF object file may not "
709 "contain an overflow section header.",
710 object_error::parse_failed),
711 Obj.getFileName());
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)
741 return;
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) <= \
751 AuxSize) \
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) <=
786 AuxSize) {
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);
795 // Deal with error.
796 if (PartialFieldOffset < AuxSize) {
797 std::string ErrInfo;
798 llvm::raw_string_ostream StringOS(ErrInfo);
799 StringOS << "Only partial field for " << PartialFieldName << " at offset ("
800 << PartialFieldOffset << ").";
801 StringOS.flush();
802 reportWarning(
803 make_error<GenericBinaryError>(ErrInfo, object_error::parse_failed),
804 "-");
805 W.printBinary(
806 "Raw data", "",
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),
813 "-");
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)
826 return;
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) <= \
836 AuxSize) \
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) <=
865 AuxSize) {
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) {
881 std::string ErrInfo;
882 llvm::raw_string_ostream StringOS(ErrInfo);
883 StringOS << "Only partial field for " << PartialFieldName << " at offset ("
884 << PartialFieldOffset << ").";
885 StringOS.flush();
886 reportWarning(
887 make_error<GenericBinaryError>(ErrInfo, object_error::parse_failed),
888 "-");
890 W.printBinary(
891 "Raw data", "",
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),
898 "-");
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");
912 uint16_t Index = 1;
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);
921 break;
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
928 // now.
929 default:
930 printGenericSectionHeader(Sec);
931 break;
933 if (Sec.isReservedSectionType())
934 W.printHex("Flags", "Reserved", SectionType);
935 else
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");
949 namespace llvm {
950 std::unique_ptr<ObjDumper>
951 createXCOFFDumper(const object::XCOFFObjectFile &XObj, ScopedPrinter &Writer) {
952 return std::make_unique<XCOFFDumper>(XObj, Writer);
954 } // namespace llvm