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.
10//
11//===----------------------------------------------------------------------===//
12
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"
18
19#include <ctime>
20
21using namespace llvm;
22using namespace object;
23
24namespace {
25
26class XCOFFDumper : public ObjDumper {
27
28public:
29  XCOFFDumper(const XCOFFObjectFile &Obj, ScopedPrinter &Writer)
30      : ObjDumper(Writer, Obj.getFileName()), Obj(Obj) {}
31
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;
45
46  ScopedPrinter &getScopedPrinter() const { return W; }
47
48private:
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);
82
83  const XCOFFObjectFile &Obj;
84  const static int32_t FirstSymIdxOfLoaderSec = 3;
85};
86} // anonymous namespace
87
88void XCOFFDumper::printFileHeaders() {
89  DictScope DS(W, "FileHeader");
90  W.printHex("Magic", Obj.getMagic());
91  W.printNumber("NumberOfSections", Obj.getNumberOfSections());
92
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;
100
101    char FormattedTime[80] = {};
102
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);
112  }
113
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);
127  }
128
129  W.printHex("OptionalHeaderSize", Obj.getOptionalHeaderSize());
130  W.printHex("Flags", Obj.getFlags());
131
132  // TODO FIXME Add support for the auxiliary header (if any) once
133  // XCOFFObjectFile has the necessary support.
134}
135
136void XCOFFDumper::printAuxiliaryHeader() {
137  DictScope DS(W, "AuxiliaryHeader");
138
139  if (Obj.is64Bit())
140    printAuxiliaryHeader(Obj.auxiliaryHeader64());
141  else
142    printAuxiliaryHeader(Obj.auxiliaryHeader32());
143}
144
145void XCOFFDumper::printSectionHeaders() {
146  if (Obj.is64Bit())
147    printSectionHeaders(Obj.sections64());
148  else
149    printSectionHeaders(Obj.sections32());
150}
151
152void 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;
160  }
161  uintptr_t LoaderSectionAddr = LoaderSectionAddrOrError.get();
162
163  if (LoaderSectionAddr == 0)
164    return;
165
166  W.indent();
167  if (PrintHeader)
168    printLoaderSectionHeader(LoaderSectionAddr);
169
170  if (PrintSymbols)
171    printLoaderSectionSymbols(LoaderSectionAddr);
172
173  if (PrintRelocations)
174    printLoaderSectionRelocationEntries(LoaderSectionAddr);
175
176  W.unindent();
177}
178
179void XCOFFDumper::printLoaderSectionHeader(uintptr_t LoaderSectionAddr) {
180  DictScope DS(W, "Loader Section Header");
181
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);
192  };
193
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);
204  }
205}
206
207const 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
224};
225
226template <typename LoaderSectionSymbolEntry, typename LoaderSectionHeader>
227void 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()));
233
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;
243    }
244
245    Expected<StringRef> SymbolNameOrErr =
246        LoadSecSymEntPtr->getSymbolName(LoadSecHeader);
247    if (!SymbolNameOrErr) {
248      reportUniqueWarning(SymbolNameOrErr.takeError());
249      return;
250    }
251
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);
262  }
263}
264
265void 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);
273}
274
275const 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
285};
286
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.
291static 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";
305  }
306}
307
308template <typename LoadSectionRelocTy>
309void 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;
316    };
317    auto IsFixupIndicated = [](uint8_t Info) {
318      return Info & XCOFF::XR_FIXUP_INDICATOR_MASK;
319    };
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;
325    };
326
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";
345  }
346}
347
348template <typename LoaderSectionHeader, typename LoaderSectionSymbolEntry,
349          typename LoaderSectionRelocationEntry>
350void 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()));
357
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";
362
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);
377
378      Expected<StringRef> SymbolNameOrErr =
379          LoaderSecRelSymEntPtr->getSymbolName(LoaderSec);
380      if (!SymbolNameOrErr) {
381        reportUniqueWarning(SymbolNameOrErr.takeError());
382        return;
383      }
384      SymbolName = SymbolNameOrErr.get();
385    } else
386      SymbolName =
387          getImplicitLoaderSectionSymName(LoaderSecRelEntPtr->SymbolIndex);
388
389    printLoaderSectionRelocationEntry(LoaderSecRelEntPtr, SymbolName);
390  }
391}
392
393void XCOFFDumper::printLoaderSectionRelocationEntries(
394    uintptr_t LoaderSectionAddr) {
395  DictScope DS(W, "Loader Section Relocations");
396
397  if (Obj.is64Bit())
398    printLoaderSectionRelocationEntriesHelper<LoaderSectionHeader64,
399                                              LoaderSectionSymbolEntry64,
400                                              LoaderSectionRelocationEntry64>(
401        LoaderSectionAddr);
402  else
403    printLoaderSectionRelocationEntriesHelper<LoaderSectionHeader32,
404                                              LoaderSectionSymbolEntry32,
405                                              LoaderSectionRelocationEntry32>(
406        LoaderSectionAddr);
407}
408
409template <typename T>
410void 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;
419    }
420    StringRef SymName = *ErrOrSymbolName;
421
422    W.printNumber("Symbol", SymName, SymIdx);
423  }
424  W.printNumber("LangID", ExceptionSectEnt.getLangID());
425  W.printNumber("Reason", ExceptionSectEnt.getReason());
426}
427
428template <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;
433  }
434  ArrayRef<T> ExceptSectEnts = *ExceptSectEntsOrErr;
435
436  DictScope DS(W, "Exception section");
437  if (ExceptSectEnts.empty())
438    return;
439  for (auto &Ent : ExceptSectEnts)
440    printExceptionSectionEntry(Ent);
441}
442
443void XCOFFDumper::printExceptionSection() {
444  if (Obj.is64Bit())
445    printExceptionSectionEntries<ExceptionSectionEntry64>();
446  else
447    printExceptionSectionEntries<ExceptionSectionEntry32>();
448}
449
450void XCOFFDumper::printRelocations() {
451  if (Obj.is64Bit())
452    printRelocations<XCOFFSectionHeader64, XCOFFRelocation64>(Obj.sections64());
453  else
454    printRelocations<XCOFFSectionHeader32, XCOFFRelocation32>(Obj.sections32());
455}
456
457template <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;
463  }
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";
478  }
479}
480
481template <typename Shdr, typename RelTy>
482void 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;
495    }
496
497    const ArrayRef<RelTy> Relocations = *ErrOrRelocations;
498    if (Relocations.empty())
499      continue;
500
501    W.startLine() << "Section (index: " << Index << ") " << Sec.getName()
502                  << " {\n";
503    W.indent();
504
505    for (const RelTy Reloc : Relocations)
506      printRelocation(Reloc);
507
508    W.unindent();
509    W.startLine() << "}\n";
510  }
511}
512
513const 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
518};
519
520const 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
526};
527
528void 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));
542  }
543}
544
545static const EnumEntry<XCOFF::StorageMappingClass> CsectStorageMappingClass[] =
546    {
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
556};
557
558const 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
563};
564
565void XCOFFDumper::printCsectAuxEnt(XCOFFCsectAuxRef AuxEntRef) {
566  assert((!Obj.is64Bit() || AuxEntRef.getAuxType64() == XCOFF::AUX_CSECT) &&
567         "Mismatched auxiliary type!");
568
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));
583
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());
590  }
591}
592
593void XCOFFDumper::printSectAuxEntForStat(
594    const XCOFFSectAuxEntForStat *AuxEntPtr) {
595  assert(!Obj.is64Bit() && "32-bit interface called on 64-bit object file.");
596
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);
601
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);
606}
607
608void XCOFFDumper::printExceptionAuxEnt(const XCOFFExceptionAuxEnt *AuxEntPtr) {
609  assert(Obj.is64Bit() && "64-bit interface called on 32-bit object file.");
610
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));
619}
620
621void XCOFFDumper::printFunctionAuxEnt(const XCOFFFunctionAuxEnt32 *AuxEntPtr) {
622  assert(!Obj.is64Bit() && "32-bit interface called on 64-bit object file.");
623
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);
631}
632
633void XCOFFDumper::printFunctionAuxEnt(const XCOFFFunctionAuxEnt64 *AuxEntPtr) {
634  assert(Obj.is64Bit() && "64-bit interface called on 32-bit object file.");
635
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));
644}
645
646void XCOFFDumper::printBlockAuxEnt(const XCOFFBlockAuxEnt32 *AuxEntPtr) {
647  assert(!Obj.is64Bit() && "32-bit interface called on 64-bit object file.");
648
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);
654}
655
656void XCOFFDumper::printBlockAuxEnt(const XCOFFBlockAuxEnt64 *AuxEntPtr) {
657  assert(Obj.is64Bit() && "64-bit interface called on 32-bit object file.");
658
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));
665}
666
667template <typename T>
668void 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));
677}
678
679static 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";
707  }
708}
709
710const 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
715};
716
717const 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
722};
723
724template <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;
728}
729
730static 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";
738}
739
740void XCOFFDumper::printSymbol(const SymbolRef &S) {
741  DataRefImpl SymbolDRI = S.getRawDataRefImpl();
742  XCOFFSymbolRef SymbolEntRef = Obj.toSymbolRef(SymbolDRI);
743
744  uint8_t NumberOfAuxEntries = SymbolEntRef.getNumberOfAuxEntries();
745
746  DictScope SymDs(W, "Symbol");
747
748  StringRef SymbolName =
749      unwrapOrError(Obj.getFileName(), SymbolEntRef.getName());
750
751  uint32_t SymbolIdx = Obj.getSymbolIndex(SymbolEntRef.getEntryAddress());
752  XCOFF::StorageClass SymbolClass = SymbolEntRef.getStorageClass();
753
754  W.printNumber("Index", SymbolIdx);
755  W.printString("Name", SymbolName);
756  W.printHex(GetSymbolValueName(SymbolClass), SymbolEntRef.getValue());
757
758  StringRef SectionName =
759      unwrapOrError(Obj.getFileName(), Obj.getSymbolSectionName(SymbolEntRef));
760
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());
769
770  W.printEnum("StorageClass", static_cast<uint8_t>(SymbolClass),
771              ArrayRef(SymStorageClass));
772  W.printNumber("NumberOfAuxEntries", NumberOfAuxEntries);
773
774  if (NumberOfAuxEntries == 0)
775    return;
776
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");
785  };
786
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);
793
794      if (Obj.is64Bit() &&
795          *Obj.getSymbolAuxType(AuxAddress) != XCOFF::SymbolAuxType::AUX_FILE) {
796        printUnexpectedRawAuxEnt(W, AuxAddress);
797        continue;
798      }
799
800      const XCOFFFileAuxEnt *FileAuxEntPtr =
801          getAuxEntPtr<XCOFFFileAuxEnt>(AuxAddress);
802      printFileAuxEnt(FileAuxEntPtr);
803    }
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;
816
817      uintptr_t AuxAddress = XCOFFObjectFile::getAdvancedSymbolEntryAddress(
818          SymbolEntRef.getEntryAddress(), I);
819
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);
834        }
835      } else {
836        const XCOFFFunctionAuxEnt32 *AuxEntPtr =
837            getAuxEntPtr<XCOFFFunctionAuxEnt32>(AuxAddress);
838        printFunctionAuxEnt(AuxEntPtr);
839      }
840    }
841
842    // Print the CSECT auxiliary entry.
843    auto ErrOrCsectAuxRef = SymbolEntRef.getXCOFFCsectAuxRef();
844    if (!ErrOrCsectAuxRef)
845      reportUniqueWarning(ErrOrCsectAuxRef.takeError());
846    else
847      printCsectAuxEnt(*ErrOrCsectAuxRef);
848
849    break;
850  }
851  case XCOFF::C_STAT: {
852    checkNumOfAux();
853
854    const XCOFFSectAuxEntForStat *StatAuxEntPtr =
855        getAuxEntPtr<XCOFFSectAuxEntForStat>(
856            XCOFFObjectFile::getAdvancedSymbolEntryAddress(
857                SymbolEntRef.getEntryAddress(), 1));
858    printSectAuxEntForStat(StatAuxEntPtr);
859    break;
860  }
861  case XCOFF::C_DWARF: {
862    checkNumOfAux();
863
864    uintptr_t AuxAddress = XCOFFObjectFile::getAdvancedSymbolEntryAddress(
865        SymbolEntRef.getEntryAddress(), 1);
866
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);
875    }
876    break;
877  }
878  case XCOFF::C_BLOCK:
879  case XCOFF::C_FCN: {
880    checkNumOfAux();
881
882    uintptr_t AuxAddress = XCOFFObjectFile::getAdvancedSymbolEntryAddress(
883        SymbolEntRef.getEntryAddress(), 1);
884
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);
893    }
894    break;
895  }
896  default:
897    for (int i = 1; i <= NumberOfAuxEntries; i++) {
898      printUnexpectedRawAuxEnt(W,
899                               XCOFFObjectFile::getAdvancedSymbolEntryAddress(
900                                   SymbolEntRef.getEntryAddress(), i));
901    }
902    break;
903  }
904}
905
906void XCOFFDumper::printSymbols(bool /*ExtraSymInfo*/) {
907  ListScope Group(W, "Symbols");
908  for (const SymbolRef &S : Obj.symbols())
909    printSymbol(S);
910}
911
912void 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);
921}
922
923void XCOFFDumper::printDynamicSymbols() {
924  llvm_unreachable("Unimplemented functionality for XCOFFDumper");
925}
926
927void XCOFFDumper::printUnwindInfo() {
928  llvm_unreachable("Unimplemented functionality for XCOFFDumper");
929}
930
931void XCOFFDumper::printStackMap() const {
932  llvm_unreachable("Unimplemented functionality for XCOFFDumper");
933}
934
935void XCOFFDumper::printNeededLibraries() {
936  ListScope D(W, "NeededLibraries");
937  auto ImportFilesOrError = Obj.getImportFileTable();
938  if (!ImportFilesOrError) {
939    reportUniqueWarning(ImportFilesOrError.takeError());
940    return;
941  }
942
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;
948
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);
955  }
956
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";
971    }
972  }
973}
974
975const 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
984};
985
986template <typename T>
987void 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());
993  }
994
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);
1004}
1005
1006template <typename T>
1007void 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);
1017}
1018
1019enum PrintStyle { Hex, Number };
1020template <typename T, typename V>
1021static 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;
1034  }
1035}
1036
1037template <class T>
1038void 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)));
1057}
1058
1059void 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;
1066
1067  auto PrintAuxMember = [&](PrintStyle Style, const char *MemberName,
1068                            auto &Member) {
1069    printAuxMemberHelper(Style, MemberName, Member, AuxHeader, AuxSize,
1070                         PartialFieldOffset, PartialFieldName, W);
1071  };
1072
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());
1107  }
1108
1109  PrintAuxMember(Number, "Section number for .tdata", AuxHeader->SecNumOfTData);
1110  PrintAuxMember(Number, "Section number for .tbss", AuxHeader->SecNumOfTBSS);
1111
1112  checkAndPrintAuxHeaderParseError(PartialFieldName, PartialFieldOffset,
1113                                   AuxSize, *AuxHeader, this);
1114}
1115
1116void 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;
1123
1124  auto PrintAuxMember = [&](PrintStyle Style, const char *MemberName,
1125                            auto &Member) {
1126    printAuxMemberHelper(Style, MemberName, Member, AuxHeader, AuxSize,
1127                         PartialFieldOffset, PartialFieldName, W);
1128  };
1129
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());
1158  }
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);
1168
1169  checkAndPrintAuxHeaderParseError(PartialFieldName, PartialFieldOffset,
1170                                   AuxSize, *AuxHeader, this);
1171}
1172
1173template <typename T>
1174void XCOFFDumper::printSectionHeaders(ArrayRef<T> Sections) {
1175  ListScope Group(W, "Sections");
1176
1177  uint16_t Index = 1;
1178  for (const T &Sec : Sections) {
1179    DictScope SecDS(W, "Section");
1180
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;
1197    }
1198    if (Sec.isReservedSectionType())
1199      W.printHex("Flags", "Reserved", SectionType);
1200    else
1201      W.printEnum("Type", SectionType, ArrayRef(SectionTypeFlagsNames));
1202  }
1203
1204  if (opts::SectionRelocations)
1205    report_fatal_error("Dumping section relocations is unimplemented");
1206
1207  if (opts::SectionSymbols)
1208    report_fatal_error("Dumping symbols is unimplemented");
1209
1210  if (opts::SectionData)
1211    report_fatal_error("Dumping section data is unimplemented");
1212}
1213
1214namespace llvm {
1215std::unique_ptr<ObjDumper>
1216createXCOFFDumper(const object::XCOFFObjectFile &XObj, ScopedPrinter &Writer) {
1217  return std::make_unique<XCOFFDumper>(XObj, Writer);
1218}
1219} // namespace llvm
1220