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