Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / llvm / tools / llvm-readobj / XCOFFDumper.cpp
blob8ebd670d5d56afd6d9b70ff636a64d68aaa99b2f
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 <ctime>
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(bool ExtraSymInfo) override;
37 void printDynamicSymbols() override;
38 void printUnwindInfo() override;
39 void printStackMap() const override;
40 void printNeededLibraries() override;
41 void printStringTable() override;
42 void printExceptionSection() override;
43 void printLoaderSection(bool PrintHeader, bool PrintSymbols,
44 bool PrintRelocations) override;
46 ScopedPrinter &getScopedPrinter() const { return W; }
48 private:
49 template <typename T> void printSectionHeaders(ArrayRef<T> Sections);
50 template <typename T> void printGenericSectionHeader(T &Sec) const;
51 template <typename T> void printOverflowSectionHeader(T &Sec) const;
52 template <typename T>
53 void printExceptionSectionEntry(const T &ExceptionSectEnt) const;
54 template <typename T> void printExceptionSectionEntries() const;
55 template <typename T> const T *getAuxEntPtr(uintptr_t AuxAddress);
56 void printFileAuxEnt(const XCOFFFileAuxEnt *AuxEntPtr);
57 void printCsectAuxEnt(XCOFFCsectAuxRef AuxEntRef);
58 void printSectAuxEntForStat(const XCOFFSectAuxEntForStat *AuxEntPtr);
59 void printExceptionAuxEnt(const XCOFFExceptionAuxEnt *AuxEntPtr);
60 void printFunctionAuxEnt(const XCOFFFunctionAuxEnt32 *AuxEntPtr);
61 void printFunctionAuxEnt(const XCOFFFunctionAuxEnt64 *AuxEntPtr);
62 void printBlockAuxEnt(const XCOFFBlockAuxEnt32 *AuxEntPtr);
63 void printBlockAuxEnt(const XCOFFBlockAuxEnt64 *AuxEntPtr);
64 template <typename T> void printSectAuxEntForDWARF(const T *AuxEntPtr);
65 void printSymbol(const SymbolRef &);
66 template <typename RelTy> void printRelocation(RelTy Reloc);
67 template <typename Shdr, typename RelTy>
68 void printRelocations(ArrayRef<Shdr> Sections);
69 void printAuxiliaryHeader(const XCOFFAuxiliaryHeader32 *AuxHeader);
70 void printAuxiliaryHeader(const XCOFFAuxiliaryHeader64 *AuxHeader);
71 void printLoaderSectionHeader(uintptr_t LoaderSectAddr);
72 void printLoaderSectionSymbols(uintptr_t LoaderSectAddr);
73 template <typename LoaderSectionSymbolEntry, typename LoaderSectionHeader>
74 void printLoaderSectionSymbolsHelper(uintptr_t LoaderSectAddr);
75 template <typename LoadSectionRelocTy>
76 void printLoaderSectionRelocationEntry(LoadSectionRelocTy *LoaderSecRelEntPtr,
77 StringRef SymbolName);
78 void printLoaderSectionRelocationEntries(uintptr_t LoaderSectAddr);
79 template <typename LoaderSectionHeader, typename LoaderSectionSymbolEntry,
80 typename LoaderSectionRelocationEntry>
81 void printLoaderSectionRelocationEntriesHelper(uintptr_t LoaderSectAddr);
83 const XCOFFObjectFile &Obj;
84 const static int32_t FirstSymIdxOfLoaderSec = 3;
86 } // anonymous namespace
88 void XCOFFDumper::printFileHeaders() {
89 DictScope DS(W, "FileHeader");
90 W.printHex("Magic", Obj.getMagic());
91 W.printNumber("NumberOfSections", Obj.getNumberOfSections());
93 // Negative timestamp values are reserved for future use.
94 int32_t TimeStamp = Obj.getTimeStamp();
95 if (TimeStamp > 0) {
96 // This handling of the time stamp assumes that the host system's time_t is
97 // compatible with AIX time_t. If a platform is not compatible, the lit
98 // tests will let us know.
99 time_t TimeDate = TimeStamp;
101 char FormattedTime[80] = {};
103 size_t BytesFormatted =
104 strftime(FormattedTime, sizeof(FormattedTime), "%F %T", gmtime(&TimeDate));
105 if (BytesFormatted)
106 W.printHex("TimeStamp", FormattedTime, TimeStamp);
107 else
108 W.printHex("Timestamp", TimeStamp);
109 } else {
110 W.printHex("TimeStamp", TimeStamp == 0 ? "None" : "Reserved Value",
111 TimeStamp);
114 // The number of symbol table entries is an unsigned value in 64-bit objects
115 // and a signed value (with negative values being 'reserved') in 32-bit
116 // objects.
117 if (Obj.is64Bit()) {
118 W.printHex("SymbolTableOffset", Obj.getSymbolTableOffset64());
119 W.printNumber("SymbolTableEntries", Obj.getNumberOfSymbolTableEntries64());
120 } else {
121 W.printHex("SymbolTableOffset", Obj.getSymbolTableOffset32());
122 int32_t SymTabEntries = Obj.getRawNumberOfSymbolTableEntries32();
123 if (SymTabEntries >= 0)
124 W.printNumber("SymbolTableEntries", SymTabEntries);
125 else
126 W.printHex("SymbolTableEntries", "Reserved Value", SymTabEntries);
129 W.printHex("OptionalHeaderSize", Obj.getOptionalHeaderSize());
130 W.printHex("Flags", Obj.getFlags());
132 // TODO FIXME Add support for the auxiliary header (if any) once
133 // XCOFFObjectFile has the necessary support.
136 void XCOFFDumper::printAuxiliaryHeader() {
137 DictScope DS(W, "AuxiliaryHeader");
139 if (Obj.is64Bit())
140 printAuxiliaryHeader(Obj.auxiliaryHeader64());
141 else
142 printAuxiliaryHeader(Obj.auxiliaryHeader32());
145 void XCOFFDumper::printSectionHeaders() {
146 if (Obj.is64Bit())
147 printSectionHeaders(Obj.sections64());
148 else
149 printSectionHeaders(Obj.sections32());
152 void XCOFFDumper::printLoaderSection(bool PrintHeader, bool PrintSymbols,
153 bool PrintRelocations) {
154 DictScope DS(W, "Loader Section");
155 Expected<uintptr_t> LoaderSectionAddrOrError =
156 Obj.getSectionFileOffsetToRawData(XCOFF::STYP_LOADER);
157 if (!LoaderSectionAddrOrError) {
158 reportUniqueWarning(LoaderSectionAddrOrError.takeError());
159 return;
161 uintptr_t LoaderSectionAddr = LoaderSectionAddrOrError.get();
163 if (LoaderSectionAddr == 0)
164 return;
166 W.indent();
167 if (PrintHeader)
168 printLoaderSectionHeader(LoaderSectionAddr);
170 if (PrintSymbols)
171 printLoaderSectionSymbols(LoaderSectionAddr);
173 if (PrintRelocations)
174 printLoaderSectionRelocationEntries(LoaderSectionAddr);
176 W.unindent();
179 void XCOFFDumper::printLoaderSectionHeader(uintptr_t LoaderSectionAddr) {
180 DictScope DS(W, "Loader Section Header");
182 auto PrintLoadSecHeaderCommon = [&](const auto *LDHeader) {
183 W.printNumber("Version", LDHeader->Version);
184 W.printNumber("NumberOfSymbolEntries", LDHeader->NumberOfSymTabEnt);
185 W.printNumber("NumberOfRelocationEntries", LDHeader->NumberOfRelTabEnt);
186 W.printNumber("LengthOfImportFileIDStringTable",
187 LDHeader->LengthOfImpidStrTbl);
188 W.printNumber("NumberOfImportFileIDs", LDHeader->NumberOfImpid);
189 W.printHex("OffsetToImportFileIDs", LDHeader->OffsetToImpid);
190 W.printNumber("LengthOfStringTable", LDHeader->LengthOfStrTbl);
191 W.printHex("OffsetToStringTable", LDHeader->OffsetToStrTbl);
194 if (Obj.is64Bit()) {
195 const LoaderSectionHeader64 *LoaderSec64 =
196 reinterpret_cast<const LoaderSectionHeader64 *>(LoaderSectionAddr);
197 PrintLoadSecHeaderCommon(LoaderSec64);
198 W.printHex("OffsetToSymbolTable", LoaderSec64->OffsetToSymTbl);
199 W.printHex("OffsetToRelocationEntries", LoaderSec64->OffsetToRelEnt);
200 } else {
201 const LoaderSectionHeader32 *LoaderSec32 =
202 reinterpret_cast<const LoaderSectionHeader32 *>(LoaderSectionAddr);
203 PrintLoadSecHeaderCommon(LoaderSec32);
207 const EnumEntry<XCOFF::StorageClass> SymStorageClass[] = {
208 #define ECase(X) \
209 { #X, XCOFF::X }
210 ECase(C_NULL), ECase(C_AUTO), ECase(C_EXT), ECase(C_STAT),
211 ECase(C_REG), ECase(C_EXTDEF), ECase(C_LABEL), ECase(C_ULABEL),
212 ECase(C_MOS), ECase(C_ARG), ECase(C_STRTAG), ECase(C_MOU),
213 ECase(C_UNTAG), ECase(C_TPDEF), ECase(C_USTATIC), ECase(C_ENTAG),
214 ECase(C_MOE), ECase(C_REGPARM), ECase(C_FIELD), ECase(C_BLOCK),
215 ECase(C_FCN), ECase(C_EOS), ECase(C_FILE), ECase(C_LINE),
216 ECase(C_ALIAS), ECase(C_HIDDEN), ECase(C_HIDEXT), ECase(C_BINCL),
217 ECase(C_EINCL), ECase(C_INFO), ECase(C_WEAKEXT), ECase(C_DWARF),
218 ECase(C_GSYM), ECase(C_LSYM), ECase(C_PSYM), ECase(C_RSYM),
219 ECase(C_RPSYM), ECase(C_STSYM), ECase(C_TCSYM), ECase(C_BCOMM),
220 ECase(C_ECOML), ECase(C_ECOMM), ECase(C_DECL), ECase(C_ENTRY),
221 ECase(C_FUN), ECase(C_BSTAT), ECase(C_ESTAT), ECase(C_GTLS),
222 ECase(C_STTLS), ECase(C_EFCN)
223 #undef ECase
226 template <typename LoaderSectionSymbolEntry, typename LoaderSectionHeader>
227 void XCOFFDumper::printLoaderSectionSymbolsHelper(uintptr_t LoaderSectionAddr) {
228 const LoaderSectionHeader *LoadSecHeader =
229 reinterpret_cast<const LoaderSectionHeader *>(LoaderSectionAddr);
230 const LoaderSectionSymbolEntry *LoadSecSymEntPtr =
231 reinterpret_cast<LoaderSectionSymbolEntry *>(
232 LoaderSectionAddr + uintptr_t(LoadSecHeader->getOffsetToSymTbl()));
234 for (uint32_t i = 0; i < LoadSecHeader->NumberOfSymTabEnt;
235 ++i, ++LoadSecSymEntPtr) {
236 if (Error E = Binary::checkOffset(
237 Obj.getMemoryBufferRef(),
238 LoaderSectionAddr + uintptr_t(LoadSecHeader->getOffsetToSymTbl()) +
239 (i * sizeof(LoaderSectionSymbolEntry)),
240 sizeof(LoaderSectionSymbolEntry))) {
241 reportUniqueWarning(std::move(E));
242 return;
245 Expected<StringRef> SymbolNameOrErr =
246 LoadSecSymEntPtr->getSymbolName(LoadSecHeader);
247 if (!SymbolNameOrErr) {
248 reportUniqueWarning(SymbolNameOrErr.takeError());
249 return;
252 DictScope DS(W, "Symbol");
253 W.printString("Name", SymbolNameOrErr.get());
254 W.printHex("Virtual Address", LoadSecSymEntPtr->Value);
255 W.printNumber("SectionNum", LoadSecSymEntPtr->SectionNumber);
256 W.printHex("SymbolType", LoadSecSymEntPtr->SymbolType);
257 W.printEnum("StorageClass",
258 static_cast<uint8_t>(LoadSecSymEntPtr->StorageClass),
259 ArrayRef(SymStorageClass));
260 W.printHex("ImportFileID", LoadSecSymEntPtr->ImportFileID);
261 W.printNumber("ParameterTypeCheck", LoadSecSymEntPtr->ParameterTypeCheck);
265 void XCOFFDumper::printLoaderSectionSymbols(uintptr_t LoaderSectionAddr) {
266 DictScope DS(W, "Loader Section Symbols");
267 if (Obj.is64Bit())
268 printLoaderSectionSymbolsHelper<LoaderSectionSymbolEntry64,
269 LoaderSectionHeader64>(LoaderSectionAddr);
270 else
271 printLoaderSectionSymbolsHelper<LoaderSectionSymbolEntry32,
272 LoaderSectionHeader32>(LoaderSectionAddr);
275 const EnumEntry<XCOFF::RelocationType> RelocationTypeNameclass[] = {
276 #define ECase(X) \
277 { #X, XCOFF::X }
278 ECase(R_POS), ECase(R_RL), ECase(R_RLA), ECase(R_NEG),
279 ECase(R_REL), ECase(R_TOC), ECase(R_TRL), ECase(R_TRLA),
280 ECase(R_GL), ECase(R_TCL), ECase(R_REF), ECase(R_BA),
281 ECase(R_BR), ECase(R_RBA), ECase(R_RBR), ECase(R_TLS),
282 ECase(R_TLS_IE), ECase(R_TLS_LD), ECase(R_TLS_LE), ECase(R_TLSM),
283 ECase(R_TLSML), ECase(R_TOCU), ECase(R_TOCL)
284 #undef ECase
287 // From the XCOFF specification: there are five implicit external symbols, one
288 // each for the .text, .data, .bss, .tdata, and .tbss sections. These symbols
289 // are referenced from the relocation table entries using symbol table index
290 // values 0, 1, 2, -1, and -2, respectively.
291 static const char *getImplicitLoaderSectionSymName(int SymIndx) {
292 switch (SymIndx) {
293 default:
294 return "Unkown Symbol Name";
295 case -2:
296 return ".tbss";
297 case -1:
298 return ".tdata";
299 case 0:
300 return ".text";
301 case 1:
302 return ".data";
303 case 2:
304 return ".bss";
308 template <typename LoadSectionRelocTy>
309 void XCOFFDumper::printLoaderSectionRelocationEntry(
310 LoadSectionRelocTy *LoaderSecRelEntPtr, StringRef SymbolName) {
311 uint16_t Type = LoaderSecRelEntPtr->Type;
312 if (opts::ExpandRelocs) {
313 DictScope DS(W, "Relocation");
314 auto IsRelocationSigned = [](uint8_t Info) {
315 return Info & XCOFF::XR_SIGN_INDICATOR_MASK;
317 auto IsFixupIndicated = [](uint8_t Info) {
318 return Info & XCOFF::XR_FIXUP_INDICATOR_MASK;
320 auto GetRelocatedLength = [](uint8_t Info) {
321 // The relocation encodes the bit length being relocated minus 1. Add
322 // back
323 // the 1 to get the actual length being relocated.
324 return (Info & XCOFF::XR_BIASED_LENGTH_MASK) + 1;
327 uint8_t Info = Type >> 8;
328 W.printHex("Virtual Address", LoaderSecRelEntPtr->VirtualAddr);
329 W.printNumber("Symbol", SymbolName, LoaderSecRelEntPtr->SymbolIndex);
330 W.printString("IsSigned", IsRelocationSigned(Info) ? "Yes" : "No");
331 W.printNumber("FixupBitValue", IsFixupIndicated(Info) ? 1 : 0);
332 W.printNumber("Length", GetRelocatedLength(Info));
333 W.printEnum("Type", static_cast<uint8_t>(Type),
334 ArrayRef(RelocationTypeNameclass));
335 W.printNumber("SectionNumber", LoaderSecRelEntPtr->SectionNum);
336 } else {
337 W.startLine() << format_hex(LoaderSecRelEntPtr->VirtualAddr,
338 Obj.is64Bit() ? 18 : 10)
339 << " " << format_hex(Type, 6) << " ("
340 << XCOFF::getRelocationTypeString(
341 static_cast<XCOFF::RelocationType>(Type))
342 << ")" << format_decimal(LoaderSecRelEntPtr->SectionNum, 8)
343 << " " << SymbolName << " ("
344 << LoaderSecRelEntPtr->SymbolIndex << ")\n";
348 template <typename LoaderSectionHeader, typename LoaderSectionSymbolEntry,
349 typename LoaderSectionRelocationEntry>
350 void XCOFFDumper::printLoaderSectionRelocationEntriesHelper(
351 uintptr_t LoaderSectionAddr) {
352 const LoaderSectionHeader *LoaderSec =
353 reinterpret_cast<const LoaderSectionHeader *>(LoaderSectionAddr);
354 const LoaderSectionRelocationEntry *LoaderSecRelEntPtr =
355 reinterpret_cast<const LoaderSectionRelocationEntry *>(
356 LoaderSectionAddr + uintptr_t(LoaderSec->getOffsetToRelEnt()));
358 if (!opts::ExpandRelocs)
359 W.startLine() << center_justify("Vaddr", Obj.is64Bit() ? 18 : 10)
360 << center_justify("Type", 15) << right_justify("SecNum", 8)
361 << center_justify("SymbolName (Index) ", 24) << "\n";
363 for (uint32_t i = 0; i < LoaderSec->NumberOfRelTabEnt;
364 ++i, ++LoaderSecRelEntPtr) {
365 StringRef SymbolName;
366 if (LoaderSecRelEntPtr->SymbolIndex >= FirstSymIdxOfLoaderSec) {
367 // Because there are implicit symbol index values (-2, -1, 0, 1, 2),
368 // LoaderSecRelEnt.SymbolIndex - FirstSymIdxOfLoaderSec will get the
369 // real symbol from the symbol table.
370 const uint64_t SymOffset =
371 (LoaderSecRelEntPtr->SymbolIndex - FirstSymIdxOfLoaderSec) *
372 sizeof(LoaderSectionSymbolEntry);
373 const LoaderSectionSymbolEntry *LoaderSecRelSymEntPtr =
374 reinterpret_cast<LoaderSectionSymbolEntry *>(
375 LoaderSectionAddr + uintptr_t(LoaderSec->getOffsetToSymTbl()) +
376 SymOffset);
378 Expected<StringRef> SymbolNameOrErr =
379 LoaderSecRelSymEntPtr->getSymbolName(LoaderSec);
380 if (!SymbolNameOrErr) {
381 reportUniqueWarning(SymbolNameOrErr.takeError());
382 return;
384 SymbolName = SymbolNameOrErr.get();
385 } else
386 SymbolName =
387 getImplicitLoaderSectionSymName(LoaderSecRelEntPtr->SymbolIndex);
389 printLoaderSectionRelocationEntry(LoaderSecRelEntPtr, SymbolName);
393 void XCOFFDumper::printLoaderSectionRelocationEntries(
394 uintptr_t LoaderSectionAddr) {
395 DictScope DS(W, "Loader Section Relocations");
397 if (Obj.is64Bit())
398 printLoaderSectionRelocationEntriesHelper<LoaderSectionHeader64,
399 LoaderSectionSymbolEntry64,
400 LoaderSectionRelocationEntry64>(
401 LoaderSectionAddr);
402 else
403 printLoaderSectionRelocationEntriesHelper<LoaderSectionHeader32,
404 LoaderSectionSymbolEntry32,
405 LoaderSectionRelocationEntry32>(
406 LoaderSectionAddr);
409 template <typename T>
410 void XCOFFDumper::printExceptionSectionEntry(const T &ExceptionSectEnt) const {
411 if (ExceptionSectEnt.getReason())
412 W.printHex("Trap Instr Addr", ExceptionSectEnt.getTrapInstAddr());
413 else {
414 uint32_t SymIdx = ExceptionSectEnt.getSymbolIndex();
415 Expected<StringRef> ErrOrSymbolName = Obj.getSymbolNameByIndex(SymIdx);
416 if (Error E = ErrOrSymbolName.takeError()) {
417 reportUniqueWarning(std::move(E));
418 return;
420 StringRef SymName = *ErrOrSymbolName;
422 W.printNumber("Symbol", SymName, SymIdx);
424 W.printNumber("LangID", ExceptionSectEnt.getLangID());
425 W.printNumber("Reason", ExceptionSectEnt.getReason());
428 template <typename T> void XCOFFDumper::printExceptionSectionEntries() const {
429 Expected<ArrayRef<T>> ExceptSectEntsOrErr = Obj.getExceptionEntries<T>();
430 if (Error E = ExceptSectEntsOrErr.takeError()) {
431 reportUniqueWarning(std::move(E));
432 return;
434 ArrayRef<T> ExceptSectEnts = *ExceptSectEntsOrErr;
436 DictScope DS(W, "Exception section");
437 if (ExceptSectEnts.empty())
438 return;
439 for (auto &Ent : ExceptSectEnts)
440 printExceptionSectionEntry(Ent);
443 void XCOFFDumper::printExceptionSection() {
444 if (Obj.is64Bit())
445 printExceptionSectionEntries<ExceptionSectionEntry64>();
446 else
447 printExceptionSectionEntries<ExceptionSectionEntry32>();
450 void XCOFFDumper::printRelocations() {
451 if (Obj.is64Bit())
452 printRelocations<XCOFFSectionHeader64, XCOFFRelocation64>(Obj.sections64());
453 else
454 printRelocations<XCOFFSectionHeader32, XCOFFRelocation32>(Obj.sections32());
457 template <typename RelTy> void XCOFFDumper::printRelocation(RelTy Reloc) {
458 Expected<StringRef> ErrOrSymbolName =
459 Obj.getSymbolNameByIndex(Reloc.SymbolIndex);
460 if (Error E = ErrOrSymbolName.takeError()) {
461 reportUniqueWarning(std::move(E));
462 return;
464 StringRef SymbolName = *ErrOrSymbolName;
465 StringRef RelocName = XCOFF::getRelocationTypeString(Reloc.Type);
466 if (opts::ExpandRelocs) {
467 DictScope Group(W, "Relocation");
468 W.printHex("Virtual Address", Reloc.VirtualAddress);
469 W.printNumber("Symbol", SymbolName, Reloc.SymbolIndex);
470 W.printString("IsSigned", Reloc.isRelocationSigned() ? "Yes" : "No");
471 W.printNumber("FixupBitValue", Reloc.isFixupIndicated() ? 1 : 0);
472 W.printNumber("Length", Reloc.getRelocatedLength());
473 W.printEnum("Type", (uint8_t)Reloc.Type, ArrayRef(RelocationTypeNameclass));
474 } else {
475 raw_ostream &OS = W.startLine();
476 OS << W.hex(Reloc.VirtualAddress) << " " << RelocName << " " << SymbolName
477 << "(" << Reloc.SymbolIndex << ") " << W.hex(Reloc.Info) << "\n";
481 template <typename Shdr, typename RelTy>
482 void XCOFFDumper::printRelocations(ArrayRef<Shdr> Sections) {
483 ListScope LS(W, "Relocations");
484 uint16_t Index = 0;
485 for (const Shdr &Sec : Sections) {
486 ++Index;
487 // Only the .text, .data, .tdata, and STYP_DWARF sections have relocation.
488 if (Sec.Flags != XCOFF::STYP_TEXT && Sec.Flags != XCOFF::STYP_DATA &&
489 Sec.Flags != XCOFF::STYP_TDATA && Sec.Flags != XCOFF::STYP_DWARF)
490 continue;
491 Expected<ArrayRef<RelTy>> ErrOrRelocations = Obj.relocations<Shdr, RelTy>(Sec);
492 if (Error E = ErrOrRelocations.takeError()) {
493 reportUniqueWarning(std::move(E));
494 continue;
497 const ArrayRef<RelTy> Relocations = *ErrOrRelocations;
498 if (Relocations.empty())
499 continue;
501 W.startLine() << "Section (index: " << Index << ") " << Sec.getName()
502 << " {\n";
503 W.indent();
505 for (const RelTy Reloc : Relocations)
506 printRelocation(Reloc);
508 W.unindent();
509 W.startLine() << "}\n";
513 const EnumEntry<XCOFF::CFileStringType> FileStringType[] = {
514 #define ECase(X) \
515 { #X, XCOFF::X }
516 ECase(XFT_FN), ECase(XFT_CT), ECase(XFT_CV), ECase(XFT_CD)
517 #undef ECase
520 const EnumEntry<XCOFF::SymbolAuxType> SymAuxType[] = {
521 #define ECase(X) \
522 { #X, XCOFF::X }
523 ECase(AUX_EXCEPT), ECase(AUX_FCN), ECase(AUX_SYM), ECase(AUX_FILE),
524 ECase(AUX_CSECT), ECase(AUX_SECT)
525 #undef ECase
528 void XCOFFDumper::printFileAuxEnt(const XCOFFFileAuxEnt *AuxEntPtr) {
529 assert((!Obj.is64Bit() || AuxEntPtr->AuxType == XCOFF::AUX_FILE) &&
530 "Mismatched auxiliary type!");
531 StringRef FileName =
532 unwrapOrError(Obj.getFileName(), Obj.getCFileName(AuxEntPtr));
533 DictScope SymDs(W, "File Auxiliary Entry");
534 W.printNumber("Index",
535 Obj.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr)));
536 W.printString("Name", FileName);
537 W.printEnum("Type", static_cast<uint8_t>(AuxEntPtr->Type),
538 ArrayRef(FileStringType));
539 if (Obj.is64Bit()) {
540 W.printEnum("Auxiliary Type", static_cast<uint8_t>(AuxEntPtr->AuxType),
541 ArrayRef(SymAuxType));
545 static const EnumEntry<XCOFF::StorageMappingClass> CsectStorageMappingClass[] =
547 #define ECase(X) \
548 { #X, XCOFF::X }
549 ECase(XMC_PR), ECase(XMC_RO), ECase(XMC_DB), ECase(XMC_GL),
550 ECase(XMC_XO), ECase(XMC_SV), ECase(XMC_SV64), ECase(XMC_SV3264),
551 ECase(XMC_TI), ECase(XMC_TB), ECase(XMC_RW), ECase(XMC_TC0),
552 ECase(XMC_TC), ECase(XMC_TD), ECase(XMC_DS), ECase(XMC_UA),
553 ECase(XMC_BS), ECase(XMC_UC), ECase(XMC_TL), ECase(XMC_UL),
554 ECase(XMC_TE)
555 #undef ECase
558 const EnumEntry<XCOFF::SymbolType> CsectSymbolTypeClass[] = {
559 #define ECase(X) \
560 { #X, XCOFF::X }
561 ECase(XTY_ER), ECase(XTY_SD), ECase(XTY_LD), ECase(XTY_CM)
562 #undef ECase
565 void XCOFFDumper::printCsectAuxEnt(XCOFFCsectAuxRef AuxEntRef) {
566 assert((!Obj.is64Bit() || AuxEntRef.getAuxType64() == XCOFF::AUX_CSECT) &&
567 "Mismatched auxiliary type!");
569 DictScope SymDs(W, "CSECT Auxiliary Entry");
570 W.printNumber("Index", Obj.getSymbolIndex(AuxEntRef.getEntryAddress()));
571 W.printNumber(AuxEntRef.isLabel() ? "ContainingCsectSymbolIndex"
572 : "SectionLen",
573 AuxEntRef.getSectionOrLength());
574 W.printHex("ParameterHashIndex", AuxEntRef.getParameterHashIndex());
575 W.printHex("TypeChkSectNum", AuxEntRef.getTypeChkSectNum());
576 // Print out symbol alignment and type.
577 W.printNumber("SymbolAlignmentLog2", AuxEntRef.getAlignmentLog2());
578 W.printEnum("SymbolType", AuxEntRef.getSymbolType(),
579 ArrayRef(CsectSymbolTypeClass));
580 W.printEnum("StorageMappingClass",
581 static_cast<uint8_t>(AuxEntRef.getStorageMappingClass()),
582 ArrayRef(CsectStorageMappingClass));
584 if (Obj.is64Bit()) {
585 W.printEnum("Auxiliary Type", static_cast<uint8_t>(XCOFF::AUX_CSECT),
586 ArrayRef(SymAuxType));
587 } else {
588 W.printHex("StabInfoIndex", AuxEntRef.getStabInfoIndex32());
589 W.printHex("StabSectNum", AuxEntRef.getStabSectNum32());
593 void XCOFFDumper::printSectAuxEntForStat(
594 const XCOFFSectAuxEntForStat *AuxEntPtr) {
595 assert(!Obj.is64Bit() && "32-bit interface called on 64-bit object file.");
597 DictScope SymDs(W, "Sect Auxiliary Entry For Stat");
598 W.printNumber("Index",
599 Obj.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr)));
600 W.printNumber("SectionLength", AuxEntPtr->SectionLength);
602 // Unlike the corresponding fields in the section header, NumberOfRelocEnt
603 // and NumberOfLineNum do not handle values greater than 65535.
604 W.printNumber("NumberOfRelocEnt", AuxEntPtr->NumberOfRelocEnt);
605 W.printNumber("NumberOfLineNum", AuxEntPtr->NumberOfLineNum);
608 void XCOFFDumper::printExceptionAuxEnt(const XCOFFExceptionAuxEnt *AuxEntPtr) {
609 assert(Obj.is64Bit() && "64-bit interface called on 32-bit object file.");
611 DictScope SymDs(W, "Exception Auxiliary Entry");
612 W.printNumber("Index",
613 Obj.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr)));
614 W.printHex("OffsetToExceptionTable", AuxEntPtr->OffsetToExceptionTbl);
615 W.printHex("SizeOfFunction", AuxEntPtr->SizeOfFunction);
616 W.printNumber("SymbolIndexOfNextBeyond", AuxEntPtr->SymIdxOfNextBeyond);
617 W.printEnum("Auxiliary Type", static_cast<uint8_t>(AuxEntPtr->AuxType),
618 ArrayRef(SymAuxType));
621 void XCOFFDumper::printFunctionAuxEnt(const XCOFFFunctionAuxEnt32 *AuxEntPtr) {
622 assert(!Obj.is64Bit() && "32-bit interface called on 64-bit object file.");
624 DictScope SymDs(W, "Function Auxiliary Entry");
625 W.printNumber("Index",
626 Obj.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr)));
627 W.printHex("OffsetToExceptionTable", AuxEntPtr->OffsetToExceptionTbl);
628 W.printHex("SizeOfFunction", AuxEntPtr->SizeOfFunction);
629 W.printHex("PointerToLineNum", AuxEntPtr->PtrToLineNum);
630 W.printNumber("SymbolIndexOfNextBeyond", AuxEntPtr->SymIdxOfNextBeyond);
633 void XCOFFDumper::printFunctionAuxEnt(const XCOFFFunctionAuxEnt64 *AuxEntPtr) {
634 assert(Obj.is64Bit() && "64-bit interface called on 32-bit object file.");
636 DictScope SymDs(W, "Function Auxiliary Entry");
637 W.printNumber("Index",
638 Obj.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr)));
639 W.printHex("SizeOfFunction", AuxEntPtr->SizeOfFunction);
640 W.printHex("PointerToLineNum", AuxEntPtr->PtrToLineNum);
641 W.printNumber("SymbolIndexOfNextBeyond", AuxEntPtr->SymIdxOfNextBeyond);
642 W.printEnum("Auxiliary Type", static_cast<uint8_t>(AuxEntPtr->AuxType),
643 ArrayRef(SymAuxType));
646 void XCOFFDumper::printBlockAuxEnt(const XCOFFBlockAuxEnt32 *AuxEntPtr) {
647 assert(!Obj.is64Bit() && "32-bit interface called on 64-bit object file.");
649 DictScope SymDs(W, "Block Auxiliary Entry");
650 W.printNumber("Index",
651 Obj.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr)));
652 W.printHex("LineNumber (High 2 Bytes)", AuxEntPtr->LineNumHi);
653 W.printHex("LineNumber (Low 2 Bytes)", AuxEntPtr->LineNumLo);
656 void XCOFFDumper::printBlockAuxEnt(const XCOFFBlockAuxEnt64 *AuxEntPtr) {
657 assert(Obj.is64Bit() && "64-bit interface called on 32-bit object file.");
659 DictScope SymDs(W, "Block Auxiliary Entry");
660 W.printNumber("Index",
661 Obj.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr)));
662 W.printHex("LineNumber", AuxEntPtr->LineNum);
663 W.printEnum("Auxiliary Type", static_cast<uint8_t>(AuxEntPtr->AuxType),
664 ArrayRef(SymAuxType));
667 template <typename T>
668 void XCOFFDumper::printSectAuxEntForDWARF(const T *AuxEntPtr) {
669 DictScope SymDs(W, "Sect Auxiliary Entry For DWARF");
670 W.printNumber("Index",
671 Obj.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr)));
672 W.printHex("LengthOfSectionPortion", AuxEntPtr->LengthOfSectionPortion);
673 W.printNumber("NumberOfRelocEntries", AuxEntPtr->NumberOfRelocEnt);
674 if (Obj.is64Bit())
675 W.printEnum("Auxiliary Type", static_cast<uint8_t>(XCOFF::AUX_SECT),
676 ArrayRef(SymAuxType));
679 static StringRef GetSymbolValueName(XCOFF::StorageClass SC) {
680 switch (SC) {
681 case XCOFF::C_EXT:
682 case XCOFF::C_WEAKEXT:
683 case XCOFF::C_HIDEXT:
684 case XCOFF::C_STAT:
685 case XCOFF::C_FCN:
686 case XCOFF::C_BLOCK:
687 return "Value (RelocatableAddress)";
688 case XCOFF::C_FILE:
689 return "Value (SymbolTableIndex)";
690 case XCOFF::C_DWARF:
691 return "Value (OffsetInDWARF)";
692 case XCOFF::C_FUN:
693 case XCOFF::C_STSYM:
694 case XCOFF::C_BINCL:
695 case XCOFF::C_EINCL:
696 case XCOFF::C_INFO:
697 case XCOFF::C_BSTAT:
698 case XCOFF::C_LSYM:
699 case XCOFF::C_PSYM:
700 case XCOFF::C_RPSYM:
701 case XCOFF::C_RSYM:
702 case XCOFF::C_ECOML:
703 assert(false && "This StorageClass for the symbol is not yet implemented.");
704 return "";
705 default:
706 return "Value";
710 const EnumEntry<XCOFF::CFileLangId> CFileLangIdClass[] = {
711 #define ECase(X) \
712 { #X, XCOFF::X }
713 ECase(TB_C), ECase(TB_Fortran), ECase(TB_CPLUSPLUS)
714 #undef ECase
717 const EnumEntry<XCOFF::CFileCpuId> CFileCpuIdClass[] = {
718 #define ECase(X) \
719 { #X, XCOFF::X }
720 ECase(TCPU_PPC64), ECase(TCPU_COM), ECase(TCPU_970)
721 #undef ECase
724 template <typename T> const T *XCOFFDumper::getAuxEntPtr(uintptr_t AuxAddress) {
725 const T *AuxEntPtr = reinterpret_cast<const T *>(AuxAddress);
726 Obj.checkSymbolEntryPointer(reinterpret_cast<uintptr_t>(AuxEntPtr));
727 return AuxEntPtr;
730 static void printUnexpectedRawAuxEnt(ScopedPrinter &W, uintptr_t AuxAddress) {
731 W.startLine() << "!Unexpected raw auxiliary entry data:\n";
732 W.startLine() << format_bytes(
733 ArrayRef<uint8_t>(
734 reinterpret_cast<const uint8_t *>(AuxAddress),
735 XCOFF::SymbolTableEntrySize),
736 std::nullopt, XCOFF::SymbolTableEntrySize)
737 << "\n";
740 void XCOFFDumper::printSymbol(const SymbolRef &S) {
741 DataRefImpl SymbolDRI = S.getRawDataRefImpl();
742 XCOFFSymbolRef SymbolEntRef = Obj.toSymbolRef(SymbolDRI);
744 uint8_t NumberOfAuxEntries = SymbolEntRef.getNumberOfAuxEntries();
746 DictScope SymDs(W, "Symbol");
748 StringRef SymbolName =
749 unwrapOrError(Obj.getFileName(), SymbolEntRef.getName());
751 uint32_t SymbolIdx = Obj.getSymbolIndex(SymbolEntRef.getEntryAddress());
752 XCOFF::StorageClass SymbolClass = SymbolEntRef.getStorageClass();
754 W.printNumber("Index", SymbolIdx);
755 W.printString("Name", SymbolName);
756 W.printHex(GetSymbolValueName(SymbolClass), SymbolEntRef.getValue());
758 StringRef SectionName =
759 unwrapOrError(Obj.getFileName(), Obj.getSymbolSectionName(SymbolEntRef));
761 W.printString("Section", SectionName);
762 if (SymbolClass == XCOFF::C_FILE) {
763 W.printEnum("Source Language ID", SymbolEntRef.getLanguageIdForCFile(),
764 ArrayRef(CFileLangIdClass));
765 W.printEnum("CPU Version ID", SymbolEntRef.getCPUTypeIddForCFile(),
766 ArrayRef(CFileCpuIdClass));
767 } else
768 W.printHex("Type", SymbolEntRef.getSymbolType());
770 W.printEnum("StorageClass", static_cast<uint8_t>(SymbolClass),
771 ArrayRef(SymStorageClass));
772 W.printNumber("NumberOfAuxEntries", NumberOfAuxEntries);
774 if (NumberOfAuxEntries == 0)
775 return;
777 auto checkNumOfAux = [=] {
778 if (NumberOfAuxEntries > 1)
779 reportUniqueWarning("the " +
780 enumToString(static_cast<uint8_t>(SymbolClass),
781 ArrayRef(SymStorageClass)) +
782 " symbol at index " + Twine(SymbolIdx) +
783 " should not have more than 1 "
784 "auxiliary entry");
787 switch (SymbolClass) {
788 case XCOFF::C_FILE:
789 // If the symbol is C_FILE and has auxiliary entries...
790 for (int I = 1; I <= NumberOfAuxEntries; I++) {
791 uintptr_t AuxAddress = XCOFFObjectFile::getAdvancedSymbolEntryAddress(
792 SymbolEntRef.getEntryAddress(), I);
794 if (Obj.is64Bit() &&
795 *Obj.getSymbolAuxType(AuxAddress) != XCOFF::SymbolAuxType::AUX_FILE) {
796 printUnexpectedRawAuxEnt(W, AuxAddress);
797 continue;
800 const XCOFFFileAuxEnt *FileAuxEntPtr =
801 getAuxEntPtr<XCOFFFileAuxEnt>(AuxAddress);
802 printFileAuxEnt(FileAuxEntPtr);
804 break;
805 case XCOFF::C_EXT:
806 case XCOFF::C_WEAKEXT:
807 case XCOFF::C_HIDEXT: {
808 // For 32-bit objects, print the function auxiliary symbol table entry. The
809 // last one must be a CSECT auxiliary entry.
810 // For 64-bit objects, both a function auxiliary entry and an exception
811 // auxiliary entry may appear, print them in the loop and skip printing the
812 // CSECT auxiliary entry, which will be printed outside the loop.
813 for (int I = 1; I <= NumberOfAuxEntries; I++) {
814 if (I == NumberOfAuxEntries && !Obj.is64Bit())
815 break;
817 uintptr_t AuxAddress = XCOFFObjectFile::getAdvancedSymbolEntryAddress(
818 SymbolEntRef.getEntryAddress(), I);
820 if (Obj.is64Bit()) {
821 XCOFF::SymbolAuxType Type = *Obj.getSymbolAuxType(AuxAddress);
822 if (Type == XCOFF::SymbolAuxType::AUX_CSECT)
823 continue;
824 if (Type == XCOFF::SymbolAuxType::AUX_FCN) {
825 const XCOFFFunctionAuxEnt64 *AuxEntPtr =
826 getAuxEntPtr<XCOFFFunctionAuxEnt64>(AuxAddress);
827 printFunctionAuxEnt(AuxEntPtr);
828 } else if (Type == XCOFF::SymbolAuxType::AUX_EXCEPT) {
829 const XCOFFExceptionAuxEnt *AuxEntPtr =
830 getAuxEntPtr<XCOFFExceptionAuxEnt>(AuxAddress);
831 printExceptionAuxEnt(AuxEntPtr);
832 } else {
833 printUnexpectedRawAuxEnt(W, AuxAddress);
835 } else {
836 const XCOFFFunctionAuxEnt32 *AuxEntPtr =
837 getAuxEntPtr<XCOFFFunctionAuxEnt32>(AuxAddress);
838 printFunctionAuxEnt(AuxEntPtr);
842 // Print the CSECT auxiliary entry.
843 auto ErrOrCsectAuxRef = SymbolEntRef.getXCOFFCsectAuxRef();
844 if (!ErrOrCsectAuxRef)
845 reportUniqueWarning(ErrOrCsectAuxRef.takeError());
846 else
847 printCsectAuxEnt(*ErrOrCsectAuxRef);
849 break;
851 case XCOFF::C_STAT: {
852 checkNumOfAux();
854 const XCOFFSectAuxEntForStat *StatAuxEntPtr =
855 getAuxEntPtr<XCOFFSectAuxEntForStat>(
856 XCOFFObjectFile::getAdvancedSymbolEntryAddress(
857 SymbolEntRef.getEntryAddress(), 1));
858 printSectAuxEntForStat(StatAuxEntPtr);
859 break;
861 case XCOFF::C_DWARF: {
862 checkNumOfAux();
864 uintptr_t AuxAddress = XCOFFObjectFile::getAdvancedSymbolEntryAddress(
865 SymbolEntRef.getEntryAddress(), 1);
867 if (Obj.is64Bit()) {
868 const XCOFFSectAuxEntForDWARF64 *AuxEntPtr =
869 getAuxEntPtr<XCOFFSectAuxEntForDWARF64>(AuxAddress);
870 printSectAuxEntForDWARF<XCOFFSectAuxEntForDWARF64>(AuxEntPtr);
871 } else {
872 const XCOFFSectAuxEntForDWARF32 *AuxEntPtr =
873 getAuxEntPtr<XCOFFSectAuxEntForDWARF32>(AuxAddress);
874 printSectAuxEntForDWARF<XCOFFSectAuxEntForDWARF32>(AuxEntPtr);
876 break;
878 case XCOFF::C_BLOCK:
879 case XCOFF::C_FCN: {
880 checkNumOfAux();
882 uintptr_t AuxAddress = XCOFFObjectFile::getAdvancedSymbolEntryAddress(
883 SymbolEntRef.getEntryAddress(), 1);
885 if (Obj.is64Bit()) {
886 const XCOFFBlockAuxEnt64 *AuxEntPtr =
887 getAuxEntPtr<XCOFFBlockAuxEnt64>(AuxAddress);
888 printBlockAuxEnt(AuxEntPtr);
889 } else {
890 const XCOFFBlockAuxEnt32 *AuxEntPtr =
891 getAuxEntPtr<XCOFFBlockAuxEnt32>(AuxAddress);
892 printBlockAuxEnt(AuxEntPtr);
894 break;
896 default:
897 for (int i = 1; i <= NumberOfAuxEntries; i++) {
898 printUnexpectedRawAuxEnt(W,
899 XCOFFObjectFile::getAdvancedSymbolEntryAddress(
900 SymbolEntRef.getEntryAddress(), i));
902 break;
906 void XCOFFDumper::printSymbols(bool /*ExtraSymInfo*/) {
907 ListScope Group(W, "Symbols");
908 for (const SymbolRef &S : Obj.symbols())
909 printSymbol(S);
912 void XCOFFDumper::printStringTable() {
913 DictScope DS(W, "StringTable");
914 StringRef StrTable = Obj.getStringTable();
915 uint32_t StrTabSize = StrTable.size();
916 W.printNumber("Length", StrTabSize);
917 // Print strings from the fifth byte, since the first four bytes contain the
918 // length (in bytes) of the string table (including the length field).
919 if (StrTabSize > 4)
920 printAsStringList(StrTable, 4);
923 void XCOFFDumper::printDynamicSymbols() {
924 llvm_unreachable("Unimplemented functionality for XCOFFDumper");
927 void XCOFFDumper::printUnwindInfo() {
928 llvm_unreachable("Unimplemented functionality for XCOFFDumper");
931 void XCOFFDumper::printStackMap() const {
932 llvm_unreachable("Unimplemented functionality for XCOFFDumper");
935 void XCOFFDumper::printNeededLibraries() {
936 ListScope D(W, "NeededLibraries");
937 auto ImportFilesOrError = Obj.getImportFileTable();
938 if (!ImportFilesOrError) {
939 reportUniqueWarning(ImportFilesOrError.takeError());
940 return;
943 StringRef ImportFileTable = ImportFilesOrError.get();
944 const char *CurrentStr = ImportFileTable.data();
945 const char *TableEnd = ImportFileTable.end();
946 // Default column width for names is 13 even if no names are that long.
947 size_t BaseWidth = 13;
949 // Get the max width of BASE columns.
950 for (size_t StrIndex = 0; CurrentStr < TableEnd; ++StrIndex) {
951 size_t CurrentLen = strlen(CurrentStr);
952 CurrentStr += strlen(CurrentStr) + 1;
953 if (StrIndex % 3 == 1)
954 BaseWidth = std::max(BaseWidth, CurrentLen);
957 auto &OS = static_cast<formatted_raw_ostream &>(W.startLine());
958 // Each entry consists of 3 strings: the path_name, base_name and
959 // archive_member_name. The first entry is a default LIBPATH value and other
960 // entries have no path_name. We just dump the base_name and
961 // archive_member_name here.
962 OS << left_justify("BASE", BaseWidth) << " MEMBER\n";
963 CurrentStr = ImportFileTable.data();
964 for (size_t StrIndex = 0; CurrentStr < TableEnd;
965 ++StrIndex, CurrentStr += strlen(CurrentStr) + 1) {
966 if (StrIndex >= 3 && StrIndex % 3 != 0) {
967 if (StrIndex % 3 == 1)
968 OS << " " << left_justify(CurrentStr, BaseWidth) << " ";
969 else
970 OS << CurrentStr << "\n";
975 const EnumEntry<XCOFF::SectionTypeFlags> SectionTypeFlagsNames[] = {
976 #define ECase(X) \
977 { #X, XCOFF::X }
978 ECase(STYP_PAD), ECase(STYP_DWARF), ECase(STYP_TEXT),
979 ECase(STYP_DATA), ECase(STYP_BSS), ECase(STYP_EXCEPT),
980 ECase(STYP_INFO), ECase(STYP_TDATA), ECase(STYP_TBSS),
981 ECase(STYP_LOADER), ECase(STYP_DEBUG), ECase(STYP_TYPCHK),
982 ECase(STYP_OVRFLO)
983 #undef ECase
986 template <typename T>
987 void XCOFFDumper::printOverflowSectionHeader(T &Sec) const {
988 if (Obj.is64Bit()) {
989 reportWarning(make_error<StringError>("An 64-bit XCOFF object file may not "
990 "contain an overflow section header.",
991 object_error::parse_failed),
992 Obj.getFileName());
995 W.printString("Name", Sec.getName());
996 W.printNumber("NumberOfRelocations", Sec.PhysicalAddress);
997 W.printNumber("NumberOfLineNumbers", Sec.VirtualAddress);
998 W.printHex("Size", Sec.SectionSize);
999 W.printHex("RawDataOffset", Sec.FileOffsetToRawData);
1000 W.printHex("RelocationPointer", Sec.FileOffsetToRelocationInfo);
1001 W.printHex("LineNumberPointer", Sec.FileOffsetToLineNumberInfo);
1002 W.printNumber("IndexOfSectionOverflowed", Sec.NumberOfRelocations);
1003 W.printNumber("IndexOfSectionOverflowed", Sec.NumberOfLineNumbers);
1006 template <typename T>
1007 void XCOFFDumper::printGenericSectionHeader(T &Sec) const {
1008 W.printString("Name", Sec.getName());
1009 W.printHex("PhysicalAddress", Sec.PhysicalAddress);
1010 W.printHex("VirtualAddress", Sec.VirtualAddress);
1011 W.printHex("Size", Sec.SectionSize);
1012 W.printHex("RawDataOffset", Sec.FileOffsetToRawData);
1013 W.printHex("RelocationPointer", Sec.FileOffsetToRelocationInfo);
1014 W.printHex("LineNumberPointer", Sec.FileOffsetToLineNumberInfo);
1015 W.printNumber("NumberOfRelocations", Sec.NumberOfRelocations);
1016 W.printNumber("NumberOfLineNumbers", Sec.NumberOfLineNumbers);
1019 enum PrintStyle { Hex, Number };
1020 template <typename T, typename V>
1021 static void printAuxMemberHelper(PrintStyle Style, const char *MemberName,
1022 const T &Member, const V *AuxHeader,
1023 uint16_t AuxSize, uint16_t &PartialFieldOffset,
1024 const char *&PartialFieldName,
1025 ScopedPrinter &W) {
1026 ptrdiff_t Offset = reinterpret_cast<const char *>(&Member) -
1027 reinterpret_cast<const char *>(AuxHeader);
1028 if (Offset + sizeof(Member) <= AuxSize)
1029 Style == Hex ? W.printHex(MemberName, Member)
1030 : W.printNumber(MemberName, Member);
1031 else if (Offset < AuxSize) {
1032 PartialFieldOffset = Offset;
1033 PartialFieldName = MemberName;
1037 template <class T>
1038 void checkAndPrintAuxHeaderParseError(const char *PartialFieldName,
1039 uint16_t PartialFieldOffset,
1040 uint16_t AuxSize, T &AuxHeader,
1041 XCOFFDumper *Dumper) {
1042 if (PartialFieldOffset < AuxSize) {
1043 Dumper->reportUniqueWarning(Twine("only partial field for ") +
1044 PartialFieldName + " at offset (" +
1045 Twine(PartialFieldOffset) + ")");
1046 Dumper->getScopedPrinter().printBinary(
1047 "Raw data", "",
1048 ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(&AuxHeader) +
1049 PartialFieldOffset,
1050 AuxSize - PartialFieldOffset));
1051 } else if (sizeof(AuxHeader) < AuxSize)
1052 Dumper->getScopedPrinter().printBinary(
1053 "Extra raw data", "",
1054 ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(&AuxHeader) +
1055 sizeof(AuxHeader),
1056 AuxSize - sizeof(AuxHeader)));
1059 void XCOFFDumper::printAuxiliaryHeader(
1060 const XCOFFAuxiliaryHeader32 *AuxHeader) {
1061 if (AuxHeader == nullptr)
1062 return;
1063 uint16_t AuxSize = Obj.getOptionalHeaderSize();
1064 uint16_t PartialFieldOffset = AuxSize;
1065 const char *PartialFieldName = nullptr;
1067 auto PrintAuxMember = [&](PrintStyle Style, const char *MemberName,
1068 auto &Member) {
1069 printAuxMemberHelper(Style, MemberName, Member, AuxHeader, AuxSize,
1070 PartialFieldOffset, PartialFieldName, W);
1073 PrintAuxMember(Hex, "Magic", AuxHeader->AuxMagic);
1074 PrintAuxMember(Hex, "Version", AuxHeader->Version);
1075 PrintAuxMember(Hex, "Size of .text section", AuxHeader->TextSize);
1076 PrintAuxMember(Hex, "Size of .data section", AuxHeader->InitDataSize);
1077 PrintAuxMember(Hex, "Size of .bss section", AuxHeader->BssDataSize);
1078 PrintAuxMember(Hex, "Entry point address", AuxHeader->EntryPointAddr);
1079 PrintAuxMember(Hex, ".text section start address", AuxHeader->TextStartAddr);
1080 PrintAuxMember(Hex, ".data section start address", AuxHeader->DataStartAddr);
1081 PrintAuxMember(Hex, "TOC anchor address", AuxHeader->TOCAnchorAddr);
1082 PrintAuxMember(Number, "Section number of entryPoint",
1083 AuxHeader->SecNumOfEntryPoint);
1084 PrintAuxMember(Number, "Section number of .text", AuxHeader->SecNumOfText);
1085 PrintAuxMember(Number, "Section number of .data", AuxHeader->SecNumOfData);
1086 PrintAuxMember(Number, "Section number of TOC", AuxHeader->SecNumOfTOC);
1087 PrintAuxMember(Number, "Section number of loader data",
1088 AuxHeader->SecNumOfLoader);
1089 PrintAuxMember(Number, "Section number of .bss", AuxHeader->SecNumOfBSS);
1090 PrintAuxMember(Hex, "Maxium alignment of .text", AuxHeader->MaxAlignOfText);
1091 PrintAuxMember(Hex, "Maxium alignment of .data", AuxHeader->MaxAlignOfData);
1092 PrintAuxMember(Hex, "Module type", AuxHeader->ModuleType);
1093 PrintAuxMember(Hex, "CPU type of objects", AuxHeader->CpuFlag);
1094 PrintAuxMember(Hex, "(Reserved)", AuxHeader->CpuType);
1095 PrintAuxMember(Hex, "Maximum stack size", AuxHeader->MaxStackSize);
1096 PrintAuxMember(Hex, "Maximum data size", AuxHeader->MaxDataSize);
1097 PrintAuxMember(Hex, "Reserved for debugger", AuxHeader->ReservedForDebugger);
1098 PrintAuxMember(Hex, "Text page size", AuxHeader->TextPageSize);
1099 PrintAuxMember(Hex, "Data page size", AuxHeader->DataPageSize);
1100 PrintAuxMember(Hex, "Stack page size", AuxHeader->StackPageSize);
1101 if (offsetof(XCOFFAuxiliaryHeader32, FlagAndTDataAlignment) +
1102 sizeof(XCOFFAuxiliaryHeader32::FlagAndTDataAlignment) <=
1103 AuxSize) {
1104 W.printHex("Flag", AuxHeader->getFlag());
1105 W.printHex("Alignment of thread-local storage",
1106 AuxHeader->getTDataAlignment());
1109 PrintAuxMember(Number, "Section number for .tdata", AuxHeader->SecNumOfTData);
1110 PrintAuxMember(Number, "Section number for .tbss", AuxHeader->SecNumOfTBSS);
1112 checkAndPrintAuxHeaderParseError(PartialFieldName, PartialFieldOffset,
1113 AuxSize, *AuxHeader, this);
1116 void XCOFFDumper::printAuxiliaryHeader(
1117 const XCOFFAuxiliaryHeader64 *AuxHeader) {
1118 if (AuxHeader == nullptr)
1119 return;
1120 uint16_t AuxSize = Obj.getOptionalHeaderSize();
1121 uint16_t PartialFieldOffset = AuxSize;
1122 const char *PartialFieldName = nullptr;
1124 auto PrintAuxMember = [&](PrintStyle Style, const char *MemberName,
1125 auto &Member) {
1126 printAuxMemberHelper(Style, MemberName, Member, AuxHeader, AuxSize,
1127 PartialFieldOffset, PartialFieldName, W);
1130 PrintAuxMember(Hex, "Magic", AuxHeader->AuxMagic);
1131 PrintAuxMember(Hex, "Version", AuxHeader->Version);
1132 PrintAuxMember(Hex, "Reserved for debugger", AuxHeader->ReservedForDebugger);
1133 PrintAuxMember(Hex, ".text section start address", AuxHeader->TextStartAddr);
1134 PrintAuxMember(Hex, ".data section start address", AuxHeader->DataStartAddr);
1135 PrintAuxMember(Hex, "TOC anchor address", AuxHeader->TOCAnchorAddr);
1136 PrintAuxMember(Number, "Section number of entryPoint",
1137 AuxHeader->SecNumOfEntryPoint);
1138 PrintAuxMember(Number, "Section number of .text", AuxHeader->SecNumOfText);
1139 PrintAuxMember(Number, "Section number of .data", AuxHeader->SecNumOfData);
1140 PrintAuxMember(Number, "Section number of TOC", AuxHeader->SecNumOfTOC);
1141 PrintAuxMember(Number, "Section number of loader data",
1142 AuxHeader->SecNumOfLoader);
1143 PrintAuxMember(Number, "Section number of .bss", AuxHeader->SecNumOfBSS);
1144 PrintAuxMember(Hex, "Maxium alignment of .text", AuxHeader->MaxAlignOfText);
1145 PrintAuxMember(Hex, "Maxium alignment of .data", AuxHeader->MaxAlignOfData);
1146 PrintAuxMember(Hex, "Module type", AuxHeader->ModuleType);
1147 PrintAuxMember(Hex, "CPU type of objects", AuxHeader->CpuFlag);
1148 PrintAuxMember(Hex, "(Reserved)", AuxHeader->CpuType);
1149 PrintAuxMember(Hex, "Text page size", AuxHeader->TextPageSize);
1150 PrintAuxMember(Hex, "Data page size", AuxHeader->DataPageSize);
1151 PrintAuxMember(Hex, "Stack page size", AuxHeader->StackPageSize);
1152 if (offsetof(XCOFFAuxiliaryHeader64, FlagAndTDataAlignment) +
1153 sizeof(XCOFFAuxiliaryHeader64::FlagAndTDataAlignment) <=
1154 AuxSize) {
1155 W.printHex("Flag", AuxHeader->getFlag());
1156 W.printHex("Alignment of thread-local storage",
1157 AuxHeader->getTDataAlignment());
1159 PrintAuxMember(Hex, "Size of .text section", AuxHeader->TextSize);
1160 PrintAuxMember(Hex, "Size of .data section", AuxHeader->InitDataSize);
1161 PrintAuxMember(Hex, "Size of .bss section", AuxHeader->BssDataSize);
1162 PrintAuxMember(Hex, "Entry point address", AuxHeader->EntryPointAddr);
1163 PrintAuxMember(Hex, "Maximum stack size", AuxHeader->MaxStackSize);
1164 PrintAuxMember(Hex, "Maximum data size", AuxHeader->MaxDataSize);
1165 PrintAuxMember(Number, "Section number for .tdata", AuxHeader->SecNumOfTData);
1166 PrintAuxMember(Number, "Section number for .tbss", AuxHeader->SecNumOfTBSS);
1167 PrintAuxMember(Hex, "Additional flags 64-bit XCOFF", AuxHeader->XCOFF64Flag);
1169 checkAndPrintAuxHeaderParseError(PartialFieldName, PartialFieldOffset,
1170 AuxSize, *AuxHeader, this);
1173 template <typename T>
1174 void XCOFFDumper::printSectionHeaders(ArrayRef<T> Sections) {
1175 ListScope Group(W, "Sections");
1177 uint16_t Index = 1;
1178 for (const T &Sec : Sections) {
1179 DictScope SecDS(W, "Section");
1181 W.printNumber("Index", Index++);
1182 uint16_t SectionType = Sec.getSectionType();
1183 switch (SectionType) {
1184 case XCOFF::STYP_OVRFLO:
1185 printOverflowSectionHeader(Sec);
1186 break;
1187 case XCOFF::STYP_LOADER:
1188 case XCOFF::STYP_EXCEPT:
1189 case XCOFF::STYP_TYPCHK:
1190 // TODO The interpretation of loader, exception and type check section
1191 // headers are different from that of generic section headers. We will
1192 // implement them later. We interpret them as generic section headers for
1193 // now.
1194 default:
1195 printGenericSectionHeader(Sec);
1196 break;
1198 if (Sec.isReservedSectionType())
1199 W.printHex("Flags", "Reserved", SectionType);
1200 else
1201 W.printEnum("Type", SectionType, ArrayRef(SectionTypeFlagsNames));
1204 if (opts::SectionRelocations)
1205 report_fatal_error("Dumping section relocations is unimplemented");
1207 if (opts::SectionSymbols)
1208 report_fatal_error("Dumping symbols is unimplemented");
1210 if (opts::SectionData)
1211 report_fatal_error("Dumping section data is unimplemented");
1214 namespace llvm {
1215 std::unique_ptr<ObjDumper>
1216 createXCOFFDumper(const object::XCOFFObjectFile &XObj, ScopedPrinter &Writer) {
1217 return std::make_unique<XCOFFDumper>(XObj, Writer);
1219 } // namespace llvm