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 #include <stddef.h>
21 
22 using namespace llvm;
23 using namespace object;
24 
25 namespace {
26 
27 class XCOFFDumper : public ObjDumper {
28 
29 public:
30   XCOFFDumper(const XCOFFObjectFile &Obj, ScopedPrinter &Writer)
31       : ObjDumper(Writer, Obj.getFileName()), Obj(Obj) {}
32 
33   void printFileHeaders() override;
34   void printAuxiliaryHeader() override;
35   void printSectionHeaders() override;
36   void printRelocations() override;
37   void printSymbols() override;
38   void printDynamicSymbols() override;
39   void printUnwindInfo() override;
40   void printStackMap() const override;
41   void printNeededLibraries() override;
42   void printStringTable() override;
43 
44 private:
45   template <typename T> void printSectionHeaders(ArrayRef<T> Sections);
46   template <typename T> void printGenericSectionHeader(T &Sec) const;
47   template <typename T> void printOverflowSectionHeader(T &Sec) const;
48   template <typename T> const T *getAuxEntPtr(uintptr_t AuxAddress);
49   void printFileAuxEnt(const XCOFFFileAuxEnt *AuxEntPtr);
50   void printCsectAuxEnt(XCOFFCsectAuxRef AuxEntRef);
51   void printSectAuxEntForStat(const XCOFFSectAuxEntForStat *AuxEntPtr);
52   void printExceptionAuxEnt(const XCOFFExceptionAuxEnt *AuxEntPtr);
53   void printFunctionAuxEnt(const XCOFFFunctionAuxEnt32 *AuxEntPtr);
54   void printFunctionAuxEnt(const XCOFFFunctionAuxEnt64 *AuxEntPtr);
55   void printBlockAuxEnt(const XCOFFBlockAuxEnt32 *AuxEntPtr);
56   void printBlockAuxEnt(const XCOFFBlockAuxEnt64 *AuxEntPtr);
57   template <typename T> void printSectAuxEntForDWARF(const T *AuxEntPtr);
58   void printSymbol(const SymbolRef &);
59   template <typename RelTy> void printRelocation(RelTy Reloc);
60   template <typename Shdr, typename RelTy>
61   void printRelocations(ArrayRef<Shdr> Sections);
62   void printAuxiliaryHeader(const XCOFFAuxiliaryHeader32 *AuxHeader);
63   void printAuxiliaryHeader(const XCOFFAuxiliaryHeader64 *AuxHeader);
64   const XCOFFObjectFile &Obj;
65 };
66 } // anonymous namespace
67 
68 void XCOFFDumper::printFileHeaders() {
69   DictScope DS(W, "FileHeader");
70   W.printHex("Magic", Obj.getMagic());
71   W.printNumber("NumberOfSections", Obj.getNumberOfSections());
72 
73   // Negative timestamp values are reserved for future use.
74   int32_t TimeStamp = Obj.getTimeStamp();
75   if (TimeStamp > 0) {
76     // This handling of the time stamp assumes that the host system's time_t is
77     // compatible with AIX time_t. If a platform is not compatible, the lit
78     // tests will let us know.
79     time_t TimeDate = TimeStamp;
80 
81     char FormattedTime[21] = {};
82     size_t BytesWritten =
83         strftime(FormattedTime, 21, "%Y-%m-%dT%H:%M:%SZ", gmtime(&TimeDate));
84     if (BytesWritten)
85       W.printHex("TimeStamp", FormattedTime, TimeStamp);
86     else
87       W.printHex("Timestamp", TimeStamp);
88   } else {
89     W.printHex("TimeStamp", TimeStamp == 0 ? "None" : "Reserved Value",
90                TimeStamp);
91   }
92 
93   // The number of symbol table entries is an unsigned value in 64-bit objects
94   // and a signed value (with negative values being 'reserved') in 32-bit
95   // objects.
96   if (Obj.is64Bit()) {
97     W.printHex("SymbolTableOffset", Obj.getSymbolTableOffset64());
98     W.printNumber("SymbolTableEntries", Obj.getNumberOfSymbolTableEntries64());
99   } else {
100     W.printHex("SymbolTableOffset", Obj.getSymbolTableOffset32());
101     int32_t SymTabEntries = Obj.getRawNumberOfSymbolTableEntries32();
102     if (SymTabEntries >= 0)
103       W.printNumber("SymbolTableEntries", SymTabEntries);
104     else
105       W.printHex("SymbolTableEntries", "Reserved Value", SymTabEntries);
106   }
107 
108   W.printHex("OptionalHeaderSize", Obj.getOptionalHeaderSize());
109   W.printHex("Flags", Obj.getFlags());
110 
111   // TODO FIXME Add support for the auxiliary header (if any) once
112   // XCOFFObjectFile has the necessary support.
113 }
114 
115 void XCOFFDumper::printAuxiliaryHeader() {
116   if (Obj.is64Bit())
117     printAuxiliaryHeader(Obj.auxiliaryHeader64());
118   else
119     printAuxiliaryHeader(Obj.auxiliaryHeader32());
120 }
121 
122 void XCOFFDumper::printSectionHeaders() {
123   if (Obj.is64Bit())
124     printSectionHeaders(Obj.sections64());
125   else
126     printSectionHeaders(Obj.sections32());
127 }
128 
129 void XCOFFDumper::printRelocations() {
130   if (Obj.is64Bit())
131     printRelocations<XCOFFSectionHeader64, XCOFFRelocation64>(Obj.sections64());
132   else
133     printRelocations<XCOFFSectionHeader32, XCOFFRelocation32>(Obj.sections32());
134 }
135 
136 const EnumEntry<XCOFF::RelocationType> RelocationTypeNameclass[] = {
137 #define ECase(X)                                                               \
138   { #X, XCOFF::X }
139     ECase(R_POS),    ECase(R_RL),     ECase(R_RLA),    ECase(R_NEG),
140     ECase(R_REL),    ECase(R_TOC),    ECase(R_TRL),    ECase(R_TRLA),
141     ECase(R_GL),     ECase(R_TCL),    ECase(R_REF),    ECase(R_BA),
142     ECase(R_BR),     ECase(R_RBA),    ECase(R_RBR),    ECase(R_TLS),
143     ECase(R_TLS_IE), ECase(R_TLS_LD), ECase(R_TLS_LE), ECase(R_TLSM),
144     ECase(R_TLSML),  ECase(R_TOCU),   ECase(R_TOCL)
145 #undef ECase
146 };
147 
148 template <typename RelTy> void XCOFFDumper::printRelocation(RelTy Reloc) {
149   Expected<StringRef> ErrOrSymbolName =
150       Obj.getSymbolNameByIndex(Reloc.SymbolIndex);
151   if (Error E = ErrOrSymbolName.takeError()) {
152     reportUniqueWarning(std::move(E));
153     return;
154   }
155   StringRef SymbolName = *ErrOrSymbolName;
156   StringRef RelocName = XCOFF::getRelocationTypeString(Reloc.Type);
157   if (opts::ExpandRelocs) {
158     DictScope Group(W, "Relocation");
159     W.printHex("Virtual Address", Reloc.VirtualAddress);
160     W.printNumber("Symbol", SymbolName, Reloc.SymbolIndex);
161     W.printString("IsSigned", Reloc.isRelocationSigned() ? "Yes" : "No");
162     W.printNumber("FixupBitValue", Reloc.isFixupIndicated() ? 1 : 0);
163     W.printNumber("Length", Reloc.getRelocatedLength());
164     W.printEnum("Type", (uint8_t)Reloc.Type,
165                 makeArrayRef(RelocationTypeNameclass));
166   } else {
167     raw_ostream &OS = W.startLine();
168     OS << W.hex(Reloc.VirtualAddress) << " " << RelocName << " " << SymbolName
169        << "(" << Reloc.SymbolIndex << ") " << W.hex(Reloc.Info) << "\n";
170   }
171 }
172 
173 template <typename Shdr, typename RelTy>
174 void XCOFFDumper::printRelocations(ArrayRef<Shdr> Sections) {
175   ListScope LS(W, "Relocations");
176   uint16_t Index = 0;
177   for (const Shdr &Sec : Sections) {
178     ++Index;
179     // Only the .text, .data, .tdata, and STYP_DWARF sections have relocation.
180     if (Sec.Flags != XCOFF::STYP_TEXT && Sec.Flags != XCOFF::STYP_DATA &&
181         Sec.Flags != XCOFF::STYP_TDATA && Sec.Flags != XCOFF::STYP_DWARF)
182       continue;
183     Expected<ArrayRef<RelTy>> ErrOrRelocations = Obj.relocations<Shdr, RelTy>(Sec);
184     if (Error E = ErrOrRelocations.takeError()) {
185       reportUniqueWarning(std::move(E));
186       continue;
187     }
188 
189     const ArrayRef<RelTy> Relocations = *ErrOrRelocations;
190     if (Relocations.empty())
191       continue;
192 
193     W.startLine() << "Section (index: " << Index << ") " << Sec.getName()
194                   << " {\n";
195     W.indent();
196 
197     for (const RelTy Reloc : Relocations)
198       printRelocation(Reloc);
199 
200     W.unindent();
201     W.startLine() << "}\n";
202   }
203 }
204 
205 const EnumEntry<XCOFF::CFileStringType> FileStringType[] = {
206 #define ECase(X)                                                               \
207   { #X, XCOFF::X }
208     ECase(XFT_FN), ECase(XFT_CT), ECase(XFT_CV), ECase(XFT_CD)
209 #undef ECase
210 };
211 
212 const EnumEntry<XCOFF::SymbolAuxType> SymAuxType[] = {
213 #define ECase(X)                                                               \
214   { #X, XCOFF::X }
215     ECase(AUX_EXCEPT), ECase(AUX_FCN), ECase(AUX_SYM), ECase(AUX_FILE),
216     ECase(AUX_CSECT),  ECase(AUX_SECT)
217 #undef ECase
218 };
219 
220 void XCOFFDumper::printFileAuxEnt(const XCOFFFileAuxEnt *AuxEntPtr) {
221   assert((!Obj.is64Bit() || AuxEntPtr->AuxType == XCOFF::AUX_FILE) &&
222          "Mismatched auxiliary type!");
223   StringRef FileName =
224       unwrapOrError(Obj.getFileName(), Obj.getCFileName(AuxEntPtr));
225   DictScope SymDs(W, "File Auxiliary Entry");
226   W.printNumber("Index",
227                 Obj.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr)));
228   W.printString("Name", FileName);
229   W.printEnum("Type", static_cast<uint8_t>(AuxEntPtr->Type),
230               makeArrayRef(FileStringType));
231   if (Obj.is64Bit()) {
232     W.printEnum("Auxiliary Type", static_cast<uint8_t>(AuxEntPtr->AuxType),
233                 makeArrayRef(SymAuxType));
234   }
235 }
236 
237 static const EnumEntry<XCOFF::StorageMappingClass> CsectStorageMappingClass[] =
238     {
239 #define ECase(X)                                                               \
240   { #X, XCOFF::X }
241         ECase(XMC_PR), ECase(XMC_RO), ECase(XMC_DB),   ECase(XMC_GL),
242         ECase(XMC_XO), ECase(XMC_SV), ECase(XMC_SV64), ECase(XMC_SV3264),
243         ECase(XMC_TI), ECase(XMC_TB), ECase(XMC_RW),   ECase(XMC_TC0),
244         ECase(XMC_TC), ECase(XMC_TD), ECase(XMC_DS),   ECase(XMC_UA),
245         ECase(XMC_BS), ECase(XMC_UC), ECase(XMC_TL),   ECase(XMC_UL),
246         ECase(XMC_TE)
247 #undef ECase
248 };
249 
250 const EnumEntry<XCOFF::SymbolType> CsectSymbolTypeClass[] = {
251 #define ECase(X)                                                               \
252   { #X, XCOFF::X }
253     ECase(XTY_ER), ECase(XTY_SD), ECase(XTY_LD), ECase(XTY_CM)
254 #undef ECase
255 };
256 
257 void XCOFFDumper::printCsectAuxEnt(XCOFFCsectAuxRef AuxEntRef) {
258   assert((!Obj.is64Bit() || AuxEntRef.getAuxType64() == XCOFF::AUX_CSECT) &&
259          "Mismatched auxiliary type!");
260 
261   DictScope SymDs(W, "CSECT Auxiliary Entry");
262   W.printNumber("Index", Obj.getSymbolIndex(AuxEntRef.getEntryAddress()));
263   W.printNumber(AuxEntRef.isLabel() ? "ContainingCsectSymbolIndex"
264                                     : "SectionLen",
265                 AuxEntRef.getSectionOrLength());
266   W.printHex("ParameterHashIndex", AuxEntRef.getParameterHashIndex());
267   W.printHex("TypeChkSectNum", AuxEntRef.getTypeChkSectNum());
268   // Print out symbol alignment and type.
269   W.printNumber("SymbolAlignmentLog2", AuxEntRef.getAlignmentLog2());
270   W.printEnum("SymbolType", AuxEntRef.getSymbolType(),
271               makeArrayRef(CsectSymbolTypeClass));
272   W.printEnum("StorageMappingClass",
273               static_cast<uint8_t>(AuxEntRef.getStorageMappingClass()),
274               makeArrayRef(CsectStorageMappingClass));
275 
276   if (Obj.is64Bit()) {
277     W.printEnum("Auxiliary Type", static_cast<uint8_t>(XCOFF::AUX_CSECT),
278                 makeArrayRef(SymAuxType));
279   } else {
280     W.printHex("StabInfoIndex", AuxEntRef.getStabInfoIndex32());
281     W.printHex("StabSectNum", AuxEntRef.getStabSectNum32());
282   }
283 }
284 
285 void XCOFFDumper::printSectAuxEntForStat(
286     const XCOFFSectAuxEntForStat *AuxEntPtr) {
287   assert(!Obj.is64Bit() && "32-bit interface called on 64-bit object file.");
288 
289   DictScope SymDs(W, "Sect Auxiliary Entry For Stat");
290   W.printNumber("Index",
291                 Obj.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr)));
292   W.printNumber("SectionLength", AuxEntPtr->SectionLength);
293 
294   // Unlike the corresponding fields in the section header, NumberOfRelocEnt
295   // and NumberOfLineNum do not handle values greater than 65535.
296   W.printNumber("NumberOfRelocEnt", AuxEntPtr->NumberOfRelocEnt);
297   W.printNumber("NumberOfLineNum", AuxEntPtr->NumberOfLineNum);
298 }
299 
300 void XCOFFDumper::printExceptionAuxEnt(const XCOFFExceptionAuxEnt *AuxEntPtr) {
301   assert(Obj.is64Bit() && "64-bit interface called on 32-bit object file.");
302 
303   DictScope SymDs(W, "Exception Auxiliary Entry");
304   W.printNumber("Index",
305                 Obj.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr)));
306   W.printHex("OffsetToExceptionTable", AuxEntPtr->OffsetToExceptionTbl);
307   W.printHex("SizeOfFunction", AuxEntPtr->SizeOfFunction);
308   W.printNumber("SymbolIndexOfNextBeyond", AuxEntPtr->SymIdxOfNextBeyond);
309   W.printEnum("Auxiliary Type", static_cast<uint8_t>(AuxEntPtr->AuxType),
310               makeArrayRef(SymAuxType));
311 }
312 
313 void XCOFFDumper::printFunctionAuxEnt(const XCOFFFunctionAuxEnt32 *AuxEntPtr) {
314   assert(!Obj.is64Bit() && "32-bit interface called on 64-bit object file.");
315 
316   DictScope SymDs(W, "Function Auxiliary Entry");
317   W.printNumber("Index",
318                 Obj.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr)));
319   W.printHex("OffsetToExceptionTable", AuxEntPtr->OffsetToExceptionTbl);
320   W.printHex("SizeOfFunction", AuxEntPtr->SizeOfFunction);
321   W.printHex("PointerToLineNum", AuxEntPtr->PtrToLineNum);
322   W.printNumber("SymbolIndexOfNextBeyond", AuxEntPtr->SymIdxOfNextBeyond);
323 }
324 
325 void XCOFFDumper::printFunctionAuxEnt(const XCOFFFunctionAuxEnt64 *AuxEntPtr) {
326   assert(Obj.is64Bit() && "64-bit interface called on 32-bit object file.");
327 
328   DictScope SymDs(W, "Function Auxiliary Entry");
329   W.printNumber("Index",
330                 Obj.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr)));
331   W.printHex("SizeOfFunction", AuxEntPtr->SizeOfFunction);
332   W.printHex("PointerToLineNum", AuxEntPtr->PtrToLineNum);
333   W.printNumber("SymbolIndexOfNextBeyond", AuxEntPtr->SymIdxOfNextBeyond);
334   W.printEnum("Auxiliary Type", static_cast<uint8_t>(AuxEntPtr->AuxType),
335               makeArrayRef(SymAuxType));
336 }
337 
338 void XCOFFDumper::printBlockAuxEnt(const XCOFFBlockAuxEnt32 *AuxEntPtr) {
339   assert(!Obj.is64Bit() && "32-bit interface called on 64-bit object file.");
340 
341   DictScope SymDs(W, "Block Auxiliary Entry");
342   W.printNumber("Index",
343                 Obj.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr)));
344   W.printHex("LineNumber (High 2 Bytes)", AuxEntPtr->LineNumHi);
345   W.printHex("LineNumber (Low 2 Bytes)", AuxEntPtr->LineNumLo);
346 }
347 
348 void XCOFFDumper::printBlockAuxEnt(const XCOFFBlockAuxEnt64 *AuxEntPtr) {
349   assert(Obj.is64Bit() && "64-bit interface called on 32-bit object file.");
350 
351   DictScope SymDs(W, "Block Auxiliary Entry");
352   W.printNumber("Index",
353                 Obj.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr)));
354   W.printHex("LineNumber", AuxEntPtr->LineNum);
355   W.printEnum("Auxiliary Type", static_cast<uint8_t>(AuxEntPtr->AuxType),
356               makeArrayRef(SymAuxType));
357 }
358 
359 template <typename T>
360 void XCOFFDumper::printSectAuxEntForDWARF(const T *AuxEntPtr) {
361   DictScope SymDs(W, "Sect Auxiliary Entry For DWARF");
362   W.printNumber("Index",
363                 Obj.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr)));
364   W.printHex("LengthOfSectionPortion", AuxEntPtr->LengthOfSectionPortion);
365   W.printNumber("NumberOfRelocEntries", AuxEntPtr->NumberOfRelocEnt);
366   if (Obj.is64Bit())
367     W.printEnum("Auxiliary Type", static_cast<uint8_t>(XCOFF::AUX_SECT),
368                 makeArrayRef(SymAuxType));
369 }
370 
371 const EnumEntry<XCOFF::StorageClass> SymStorageClass[] = {
372 #define ECase(X)                                                               \
373   { #X, XCOFF::X }
374     ECase(C_NULL),  ECase(C_AUTO),    ECase(C_EXT),     ECase(C_STAT),
375     ECase(C_REG),   ECase(C_EXTDEF),  ECase(C_LABEL),   ECase(C_ULABEL),
376     ECase(C_MOS),   ECase(C_ARG),     ECase(C_STRTAG),  ECase(C_MOU),
377     ECase(C_UNTAG), ECase(C_TPDEF),   ECase(C_USTATIC), ECase(C_ENTAG),
378     ECase(C_MOE),   ECase(C_REGPARM), ECase(C_FIELD),   ECase(C_BLOCK),
379     ECase(C_FCN),   ECase(C_EOS),     ECase(C_FILE),    ECase(C_LINE),
380     ECase(C_ALIAS), ECase(C_HIDDEN),  ECase(C_HIDEXT),  ECase(C_BINCL),
381     ECase(C_EINCL), ECase(C_INFO),    ECase(C_WEAKEXT), ECase(C_DWARF),
382     ECase(C_GSYM),  ECase(C_LSYM),    ECase(C_PSYM),    ECase(C_RSYM),
383     ECase(C_RPSYM), ECase(C_STSYM),   ECase(C_TCSYM),   ECase(C_BCOMM),
384     ECase(C_ECOML), ECase(C_ECOMM),   ECase(C_DECL),    ECase(C_ENTRY),
385     ECase(C_FUN),   ECase(C_BSTAT),   ECase(C_ESTAT),   ECase(C_GTLS),
386     ECase(C_STTLS), ECase(C_EFCN)
387 #undef ECase
388 };
389 
390 static StringRef GetSymbolValueName(XCOFF::StorageClass SC) {
391   switch (SC) {
392   case XCOFF::C_EXT:
393   case XCOFF::C_WEAKEXT:
394   case XCOFF::C_HIDEXT:
395   case XCOFF::C_STAT:
396   case XCOFF::C_FCN:
397   case XCOFF::C_BLOCK:
398     return "Value (RelocatableAddress)";
399   case XCOFF::C_FILE:
400     return "Value (SymbolTableIndex)";
401   case XCOFF::C_DWARF:
402     return "Value (OffsetInDWARF)";
403   case XCOFF::C_FUN:
404   case XCOFF::C_STSYM:
405   case XCOFF::C_BINCL:
406   case XCOFF::C_EINCL:
407   case XCOFF::C_INFO:
408   case XCOFF::C_BSTAT:
409   case XCOFF::C_LSYM:
410   case XCOFF::C_PSYM:
411   case XCOFF::C_RPSYM:
412   case XCOFF::C_RSYM:
413   case XCOFF::C_ECOML:
414     assert(false && "This StorageClass for the symbol is not yet implemented.");
415     return "";
416   default:
417     return "Value";
418   }
419 }
420 
421 const EnumEntry<XCOFF::CFileLangId> CFileLangIdClass[] = {
422 #define ECase(X)                                                               \
423   { #X, XCOFF::X }
424     ECase(TB_C), ECase(TB_CPLUSPLUS)
425 #undef ECase
426 };
427 
428 const EnumEntry<XCOFF::CFileCpuId> CFileCpuIdClass[] = {
429 #define ECase(X)                                                               \
430   { #X, XCOFF::X }
431     ECase(TCPU_PPC64), ECase(TCPU_COM), ECase(TCPU_970)
432 #undef ECase
433 };
434 
435 template <typename T> const T *XCOFFDumper::getAuxEntPtr(uintptr_t AuxAddress) {
436   const T *AuxEntPtr = reinterpret_cast<const T *>(AuxAddress);
437   Obj.checkSymbolEntryPointer(reinterpret_cast<uintptr_t>(AuxEntPtr));
438   return AuxEntPtr;
439 }
440 
441 static void printUnexpectedRawAuxEnt(ScopedPrinter &W, uintptr_t AuxAddress) {
442   W.startLine() << "!Unexpected raw auxiliary entry data:\n";
443   W.startLine() << format_bytes(
444                        ArrayRef<uint8_t>(
445                            reinterpret_cast<const uint8_t *>(AuxAddress),
446                            XCOFF::SymbolTableEntrySize),
447                        None, XCOFF::SymbolTableEntrySize)
448                 << "\n";
449 }
450 
451 void XCOFFDumper::printSymbol(const SymbolRef &S) {
452   DataRefImpl SymbolDRI = S.getRawDataRefImpl();
453   XCOFFSymbolRef SymbolEntRef = Obj.toSymbolRef(SymbolDRI);
454 
455   uint8_t NumberOfAuxEntries = SymbolEntRef.getNumberOfAuxEntries();
456 
457   DictScope SymDs(W, "Symbol");
458 
459   StringRef SymbolName =
460       unwrapOrError(Obj.getFileName(), SymbolEntRef.getName());
461 
462   uint32_t SymbolIdx = Obj.getSymbolIndex(SymbolEntRef.getEntryAddress());
463   XCOFF::StorageClass SymbolClass = SymbolEntRef.getStorageClass();
464 
465   W.printNumber("Index", SymbolIdx);
466   W.printString("Name", SymbolName);
467   W.printHex(GetSymbolValueName(SymbolClass), SymbolEntRef.getValue());
468 
469   StringRef SectionName =
470       unwrapOrError(Obj.getFileName(), Obj.getSymbolSectionName(SymbolEntRef));
471 
472   W.printString("Section", SectionName);
473   if (SymbolClass == XCOFF::C_FILE) {
474     W.printEnum("Source Language ID", SymbolEntRef.getLanguageIdForCFile(),
475                 makeArrayRef(CFileLangIdClass));
476     W.printEnum("CPU Version ID", SymbolEntRef.getCPUTypeIddForCFile(),
477                 makeArrayRef(CFileCpuIdClass));
478   } else
479     W.printHex("Type", SymbolEntRef.getSymbolType());
480 
481   W.printEnum("StorageClass", static_cast<uint8_t>(SymbolClass),
482               makeArrayRef(SymStorageClass));
483   W.printNumber("NumberOfAuxEntries", NumberOfAuxEntries);
484 
485   if (NumberOfAuxEntries == 0)
486     return;
487 
488   auto checkNumOfAux = [=] {
489     if (NumberOfAuxEntries > 1)
490       reportUniqueWarning("the " +
491                           enumToString(static_cast<uint8_t>(SymbolClass),
492                                        makeArrayRef(SymStorageClass)) +
493                           " symbol at index " + Twine(SymbolIdx) +
494                           " should not have more than 1 "
495                           "auxiliary entry");
496   };
497 
498   switch (SymbolClass) {
499   case XCOFF::C_FILE:
500     // If the symbol is C_FILE and has auxiliary entries...
501     for (int I = 1; I <= NumberOfAuxEntries; I++) {
502       uintptr_t AuxAddress = XCOFFObjectFile::getAdvancedSymbolEntryAddress(
503           SymbolEntRef.getEntryAddress(), I);
504 
505       if (Obj.is64Bit() &&
506           *Obj.getSymbolAuxType(AuxAddress) != XCOFF::SymbolAuxType::AUX_FILE) {
507         printUnexpectedRawAuxEnt(W, AuxAddress);
508         continue;
509       }
510 
511       const XCOFFFileAuxEnt *FileAuxEntPtr =
512           getAuxEntPtr<XCOFFFileAuxEnt>(AuxAddress);
513       printFileAuxEnt(FileAuxEntPtr);
514     }
515     break;
516   case XCOFF::C_EXT:
517   case XCOFF::C_WEAKEXT:
518   case XCOFF::C_HIDEXT: {
519     if (!SymbolEntRef.isFunction() && NumberOfAuxEntries > 1)
520       reportUniqueWarning("the non-function " +
521                           enumToString(static_cast<uint8_t>(SymbolClass),
522                                        makeArrayRef(SymStorageClass)) +
523                           " symbol at index " + Twine(SymbolIdx) +
524                           " should have only 1 auxiliary entry, i.e. the CSECT "
525                           "auxiliary entry");
526 
527     // For 32-bit objects, print the function auxiliary symbol table entry. The
528     // last one must be a CSECT auxiliary entry.
529     // For 64-bit objects, both a function auxiliary entry and an exception
530     // auxiliary entry may appear, print them in the loop and skip printing the
531     // CSECT auxiliary entry, which will be printed outside the loop.
532     for (int I = 1; I <= NumberOfAuxEntries; I++) {
533       if ((I == NumberOfAuxEntries && !Obj.is64Bit()) ||
534           !SymbolEntRef.isFunction())
535         break;
536 
537       uintptr_t AuxAddress = XCOFFObjectFile::getAdvancedSymbolEntryAddress(
538           SymbolEntRef.getEntryAddress(), I);
539 
540       if (Obj.is64Bit()) {
541         XCOFF::SymbolAuxType Type = *Obj.getSymbolAuxType(AuxAddress);
542         if (Type == XCOFF::SymbolAuxType::AUX_CSECT)
543           continue;
544         if (Type == XCOFF::SymbolAuxType::AUX_FCN) {
545           const XCOFFFunctionAuxEnt64 *AuxEntPtr =
546               getAuxEntPtr<XCOFFFunctionAuxEnt64>(AuxAddress);
547           printFunctionAuxEnt(AuxEntPtr);
548         } else if (Type == XCOFF::SymbolAuxType::AUX_EXCEPT) {
549           const XCOFFExceptionAuxEnt *AuxEntPtr =
550               getAuxEntPtr<XCOFFExceptionAuxEnt>(AuxAddress);
551           printExceptionAuxEnt(AuxEntPtr);
552         } else {
553           printUnexpectedRawAuxEnt(W, AuxAddress);
554         }
555       } else {
556         const XCOFFFunctionAuxEnt32 *AuxEntPtr =
557             getAuxEntPtr<XCOFFFunctionAuxEnt32>(AuxAddress);
558         printFunctionAuxEnt(AuxEntPtr);
559       }
560     }
561 
562     // Print the CSECT auxiliary entry.
563     auto ErrOrCsectAuxRef = SymbolEntRef.getXCOFFCsectAuxRef();
564     if (!ErrOrCsectAuxRef)
565       reportUniqueWarning(ErrOrCsectAuxRef.takeError());
566     else
567       printCsectAuxEnt(*ErrOrCsectAuxRef);
568 
569     break;
570   }
571   case XCOFF::C_STAT: {
572     checkNumOfAux();
573 
574     const XCOFFSectAuxEntForStat *StatAuxEntPtr =
575         getAuxEntPtr<XCOFFSectAuxEntForStat>(
576             XCOFFObjectFile::getAdvancedSymbolEntryAddress(
577                 SymbolEntRef.getEntryAddress(), 1));
578     printSectAuxEntForStat(StatAuxEntPtr);
579     break;
580   }
581   case XCOFF::C_DWARF: {
582     checkNumOfAux();
583 
584     uintptr_t AuxAddress = XCOFFObjectFile::getAdvancedSymbolEntryAddress(
585         SymbolEntRef.getEntryAddress(), 1);
586 
587     if (Obj.is64Bit()) {
588       const XCOFFSectAuxEntForDWARF64 *AuxEntPtr =
589           getAuxEntPtr<XCOFFSectAuxEntForDWARF64>(AuxAddress);
590       printSectAuxEntForDWARF<XCOFFSectAuxEntForDWARF64>(AuxEntPtr);
591     } else {
592       const XCOFFSectAuxEntForDWARF32 *AuxEntPtr =
593           getAuxEntPtr<XCOFFSectAuxEntForDWARF32>(AuxAddress);
594       printSectAuxEntForDWARF<XCOFFSectAuxEntForDWARF32>(AuxEntPtr);
595     }
596     break;
597   }
598   case XCOFF::C_BLOCK:
599   case XCOFF::C_FCN: {
600     checkNumOfAux();
601 
602     uintptr_t AuxAddress = XCOFFObjectFile::getAdvancedSymbolEntryAddress(
603         SymbolEntRef.getEntryAddress(), 1);
604 
605     if (Obj.is64Bit()) {
606       const XCOFFBlockAuxEnt64 *AuxEntPtr =
607           getAuxEntPtr<XCOFFBlockAuxEnt64>(AuxAddress);
608       printBlockAuxEnt(AuxEntPtr);
609     } else {
610       const XCOFFBlockAuxEnt32 *AuxEntPtr =
611           getAuxEntPtr<XCOFFBlockAuxEnt32>(AuxAddress);
612       printBlockAuxEnt(AuxEntPtr);
613     }
614     break;
615   }
616   default:
617     for (int i = 1; i <= NumberOfAuxEntries; i++) {
618       printUnexpectedRawAuxEnt(W,
619                                XCOFFObjectFile::getAdvancedSymbolEntryAddress(
620                                    SymbolEntRef.getEntryAddress(), i));
621     }
622     break;
623   }
624 }
625 
626 void XCOFFDumper::printSymbols() {
627   ListScope Group(W, "Symbols");
628   for (const SymbolRef &S : Obj.symbols())
629     printSymbol(S);
630 }
631 
632 void XCOFFDumper::printStringTable() {
633   DictScope DS(W, "StringTable");
634   StringRef StrTable = Obj.getStringTable();
635   uint32_t StrTabSize = StrTable.size();
636   W.printNumber("Length", StrTabSize);
637   // Print strings from the fifth byte, since the first four bytes contain the
638   // length (in bytes) of the string table (including the length field).
639   if (StrTabSize > 4)
640     printAsStringList(StrTable, 4);
641 }
642 
643 void XCOFFDumper::printDynamicSymbols() {
644   llvm_unreachable("Unimplemented functionality for XCOFFDumper");
645 }
646 
647 void XCOFFDumper::printUnwindInfo() {
648   llvm_unreachable("Unimplemented functionality for XCOFFDumper");
649 }
650 
651 void XCOFFDumper::printStackMap() const {
652   llvm_unreachable("Unimplemented functionality for XCOFFDumper");
653 }
654 
655 void XCOFFDumper::printNeededLibraries() {
656   ListScope D(W, "NeededLibraries");
657   auto ImportFilesOrError = Obj.getImportFileTable();
658   if (!ImportFilesOrError) {
659     reportUniqueWarning(ImportFilesOrError.takeError());
660     return;
661   }
662 
663   StringRef ImportFileTable = ImportFilesOrError.get();
664   const char *CurrentStr = ImportFileTable.data();
665   const char *TableEnd = ImportFileTable.end();
666   // Default column width for names is 13 even if no names are that long.
667   size_t BaseWidth = 13;
668 
669   // Get the max width of BASE columns.
670   for (size_t StrIndex = 0; CurrentStr < TableEnd; ++StrIndex) {
671     size_t CurrentLen = strlen(CurrentStr);
672     CurrentStr += strlen(CurrentStr) + 1;
673     if (StrIndex % 3 == 1)
674       BaseWidth = std::max(BaseWidth, CurrentLen);
675   }
676 
677   auto &OS = static_cast<formatted_raw_ostream &>(W.startLine());
678   // Each entry consists of 3 strings: the path_name, base_name and
679   // archive_member_name. The first entry is a default LIBPATH value and other
680   // entries have no path_name. We just dump the base_name and
681   // archive_member_name here.
682   OS << left_justify("BASE", BaseWidth)  << " MEMBER\n";
683   CurrentStr = ImportFileTable.data();
684   for (size_t StrIndex = 0; CurrentStr < TableEnd;
685        ++StrIndex, CurrentStr += strlen(CurrentStr) + 1) {
686     if (StrIndex >= 3 && StrIndex % 3 != 0) {
687       if (StrIndex % 3 == 1)
688         OS << "  " << left_justify(CurrentStr, BaseWidth) << " ";
689       else
690         OS << CurrentStr << "\n";
691     }
692   }
693 }
694 
695 const EnumEntry<XCOFF::SectionTypeFlags> SectionTypeFlagsNames[] = {
696 #define ECase(X)                                                               \
697   { #X, XCOFF::X }
698     ECase(STYP_PAD),    ECase(STYP_DWARF), ECase(STYP_TEXT),
699     ECase(STYP_DATA),   ECase(STYP_BSS),   ECase(STYP_EXCEPT),
700     ECase(STYP_INFO),   ECase(STYP_TDATA), ECase(STYP_TBSS),
701     ECase(STYP_LOADER), ECase(STYP_DEBUG), ECase(STYP_TYPCHK),
702     ECase(STYP_OVRFLO)
703 #undef ECase
704 };
705 
706 template <typename T>
707 void XCOFFDumper::printOverflowSectionHeader(T &Sec) const {
708   if (Obj.is64Bit()) {
709     reportWarning(make_error<StringError>("An 64-bit XCOFF object file may not "
710                                           "contain an overflow section header.",
711                                           object_error::parse_failed),
712                   Obj.getFileName());
713   }
714 
715   W.printString("Name", Sec.getName());
716   W.printNumber("NumberOfRelocations", Sec.PhysicalAddress);
717   W.printNumber("NumberOfLineNumbers", Sec.VirtualAddress);
718   W.printHex("Size", Sec.SectionSize);
719   W.printHex("RawDataOffset", Sec.FileOffsetToRawData);
720   W.printHex("RelocationPointer", Sec.FileOffsetToRelocationInfo);
721   W.printHex("LineNumberPointer", Sec.FileOffsetToLineNumberInfo);
722   W.printNumber("IndexOfSectionOverflowed", Sec.NumberOfRelocations);
723   W.printNumber("IndexOfSectionOverflowed", Sec.NumberOfLineNumbers);
724 }
725 
726 template <typename T>
727 void XCOFFDumper::printGenericSectionHeader(T &Sec) const {
728   W.printString("Name", Sec.getName());
729   W.printHex("PhysicalAddress", Sec.PhysicalAddress);
730   W.printHex("VirtualAddress", Sec.VirtualAddress);
731   W.printHex("Size", Sec.SectionSize);
732   W.printHex("RawDataOffset", Sec.FileOffsetToRawData);
733   W.printHex("RelocationPointer", Sec.FileOffsetToRelocationInfo);
734   W.printHex("LineNumberPointer", Sec.FileOffsetToLineNumberInfo);
735   W.printNumber("NumberOfRelocations", Sec.NumberOfRelocations);
736   W.printNumber("NumberOfLineNumbers", Sec.NumberOfLineNumbers);
737 }
738 
739 void XCOFFDumper::printAuxiliaryHeader(
740     const XCOFFAuxiliaryHeader32 *AuxHeader) {
741   if (AuxHeader == nullptr)
742     return;
743   uint16_t AuxSize = Obj.getOptionalHeaderSize();
744   uint16_t PartialFieldOffset = AuxSize;
745   const char *PartialFieldName = nullptr;
746 
747   DictScope DS(W, "AuxiliaryHeader");
748 
749 #define PrintAuxMember32(H, S, T)                                              \
750   if (offsetof(XCOFFAuxiliaryHeader32, T) +                                    \
751           sizeof(XCOFFAuxiliaryHeader32::T) <=                                 \
752       AuxSize)                                                                 \
753     W.print##H(S, AuxHeader->T);                                               \
754   else if (offsetof(XCOFFAuxiliaryHeader32, T) < AuxSize) {                    \
755     PartialFieldOffset = offsetof(XCOFFAuxiliaryHeader32, T);                  \
756     PartialFieldName = S;                                                      \
757   }
758 
759   PrintAuxMember32(Hex, "Magic", AuxMagic);
760   PrintAuxMember32(Hex, "Version", Version);
761   PrintAuxMember32(Hex, "Size of .text section", TextSize);
762   PrintAuxMember32(Hex, "Size of .data section", InitDataSize);
763   PrintAuxMember32(Hex, "Size of .bss section", BssDataSize);
764   PrintAuxMember32(Hex, "Entry point address", EntryPointAddr);
765   PrintAuxMember32(Hex, ".text section start address", TextStartAddr);
766   PrintAuxMember32(Hex, ".data section start address", DataStartAddr);
767   PrintAuxMember32(Hex, "TOC anchor address", TOCAnchorAddr);
768   PrintAuxMember32(Number, "Section number of entryPoint", SecNumOfEntryPoint);
769   PrintAuxMember32(Number, "Section number of .text", SecNumOfText);
770   PrintAuxMember32(Number, "Section number of .data", SecNumOfData);
771   PrintAuxMember32(Number, "Section number of TOC", SecNumOfTOC);
772   PrintAuxMember32(Number, "Section number of loader data", SecNumOfLoader);
773   PrintAuxMember32(Number, "Section number of .bss", SecNumOfBSS);
774   PrintAuxMember32(Hex, "Maxium alignment of .text", MaxAlignOfText);
775   PrintAuxMember32(Hex, "Maxium alignment of .data", MaxAlignOfData);
776   PrintAuxMember32(Hex, "Module type", ModuleType);
777   PrintAuxMember32(Hex, "CPU type of objects", CpuFlag);
778   PrintAuxMember32(Hex, "(Reserved)", CpuType);
779   PrintAuxMember32(Hex, "Maximum stack size", MaxStackSize);
780   PrintAuxMember32(Hex, "Maximum data size", MaxDataSize);
781   PrintAuxMember32(Hex, "Reserved for debugger", ReservedForDebugger);
782   PrintAuxMember32(Hex, "Text page size", TextPageSize);
783   PrintAuxMember32(Hex, "Data page size", DataPageSize);
784   PrintAuxMember32(Hex, "Stack page size", StackPageSize);
785   if (offsetof(XCOFFAuxiliaryHeader32, FlagAndTDataAlignment) +
786           sizeof(XCOFFAuxiliaryHeader32::FlagAndTDataAlignment) <=
787       AuxSize) {
788     W.printHex("Flag", AuxHeader->getFlag());
789     W.printHex("Alignment of thread-local storage",
790                AuxHeader->getTDataAlignment());
791   }
792 
793   PrintAuxMember32(Number, "Section number for .tdata", SecNumOfTData);
794   PrintAuxMember32(Number, "Section number for .tbss", SecNumOfTBSS);
795 
796   // Deal with error.
797   if (PartialFieldOffset < AuxSize) {
798     std::string ErrInfo;
799     llvm::raw_string_ostream StringOS(ErrInfo);
800     StringOS << "Only partial field for " << PartialFieldName << " at offset ("
801              << PartialFieldOffset << ").";
802     StringOS.flush();
803     reportWarning(
804         make_error<GenericBinaryError>(ErrInfo, object_error::parse_failed),
805         "-");
806     W.printBinary(
807         "Raw data", "",
808         ArrayRef<uint8_t>((const uint8_t *)(AuxHeader) + PartialFieldOffset,
809                           AuxSize - PartialFieldOffset));
810   } else if (sizeof(XCOFFAuxiliaryHeader32) < AuxSize) {
811     reportWarning(make_error<GenericBinaryError>(
812                       "There are extra data beyond auxiliary header",
813                       object_error::parse_failed),
814                   "-");
815     W.printBinary("Extra raw data", "",
816                   ArrayRef<uint8_t>((const uint8_t *)(AuxHeader) +
817                                         sizeof(XCOFFAuxiliaryHeader32),
818                                     AuxSize - sizeof(XCOFFAuxiliaryHeader32)));
819   }
820 
821 #undef PrintAuxMember32
822 }
823 
824 void XCOFFDumper::printAuxiliaryHeader(
825     const XCOFFAuxiliaryHeader64 *AuxHeader) {
826   if (AuxHeader == nullptr)
827     return;
828   uint16_t AuxSize = Obj.getOptionalHeaderSize();
829   uint16_t PartialFieldOffset = AuxSize;
830   const char *PartialFieldName = nullptr;
831 
832   DictScope DS(W, "AuxiliaryHeader");
833 
834 #define PrintAuxMember64(H, S, T)                                              \
835   if (offsetof(XCOFFAuxiliaryHeader64, T) +                                    \
836           sizeof(XCOFFAuxiliaryHeader64::T) <=                                 \
837       AuxSize)                                                                 \
838     W.print##H(S, AuxHeader->T);                                               \
839   else if (offsetof(XCOFFAuxiliaryHeader64, T) < AuxSize) {                    \
840     PartialFieldOffset = offsetof(XCOFFAuxiliaryHeader64, T);                  \
841     PartialFieldName = S;                                                      \
842   }
843 
844   PrintAuxMember64(Hex, "Magic", AuxMagic);
845   PrintAuxMember64(Hex, "Version", Version);
846   PrintAuxMember64(Hex, "Reserved for debugger", ReservedForDebugger);
847   PrintAuxMember64(Hex, ".text section start address", TextStartAddr);
848   PrintAuxMember64(Hex, ".data section start address", DataStartAddr);
849   PrintAuxMember64(Hex, "TOC anchor address", TOCAnchorAddr);
850   PrintAuxMember64(Number, "Section number of entryPoint", SecNumOfEntryPoint);
851   PrintAuxMember64(Number, "Section number of .text", SecNumOfText);
852   PrintAuxMember64(Number, "Section number of .data", SecNumOfData);
853   PrintAuxMember64(Number, "Section number of TOC", SecNumOfTOC);
854   PrintAuxMember64(Number, "Section number of loader data", SecNumOfLoader);
855   PrintAuxMember64(Number, "Section number of .bss", SecNumOfBSS);
856   PrintAuxMember64(Hex, "Maxium alignment of .text", MaxAlignOfText);
857   PrintAuxMember64(Hex, "Maxium alignment of .data", MaxAlignOfData);
858   PrintAuxMember64(Hex, "Module type", ModuleType);
859   PrintAuxMember64(Hex, "CPU type of objects", CpuFlag);
860   PrintAuxMember64(Hex, "(Reserved)", CpuType);
861   PrintAuxMember64(Hex, "Text page size", TextPageSize);
862   PrintAuxMember64(Hex, "Data page size", DataPageSize);
863   PrintAuxMember64(Hex, "Stack page size", StackPageSize);
864   if (offsetof(XCOFFAuxiliaryHeader64, FlagAndTDataAlignment) +
865           sizeof(XCOFFAuxiliaryHeader64::FlagAndTDataAlignment) <=
866       AuxSize) {
867     W.printHex("Flag", AuxHeader->getFlag());
868     W.printHex("Alignment of thread-local storage",
869                AuxHeader->getTDataAlignment());
870   }
871   PrintAuxMember64(Hex, "Size of .text section", TextSize);
872   PrintAuxMember64(Hex, "Size of .data section", InitDataSize);
873   PrintAuxMember64(Hex, "Size of .bss section", BssDataSize);
874   PrintAuxMember64(Hex, "Entry point address", EntryPointAddr);
875   PrintAuxMember64(Hex, "Maximum stack size", MaxStackSize);
876   PrintAuxMember64(Hex, "Maximum data size", MaxDataSize);
877   PrintAuxMember64(Number, "Section number for .tdata", SecNumOfTData);
878   PrintAuxMember64(Number, "Section number for .tbss", SecNumOfTBSS);
879   PrintAuxMember64(Hex, "Additional flags 64-bit XCOFF", XCOFF64Flag);
880 
881   if (PartialFieldOffset < AuxSize) {
882     std::string ErrInfo;
883     llvm::raw_string_ostream StringOS(ErrInfo);
884     StringOS << "Only partial field for " << PartialFieldName << " at offset ("
885              << PartialFieldOffset << ").";
886     StringOS.flush();
887     reportWarning(
888         make_error<GenericBinaryError>(ErrInfo, object_error::parse_failed),
889         "-");
890     ;
891     W.printBinary(
892         "Raw data", "",
893         ArrayRef<uint8_t>((const uint8_t *)(AuxHeader) + PartialFieldOffset,
894                           AuxSize - PartialFieldOffset));
895   } else if (sizeof(XCOFFAuxiliaryHeader64) < AuxSize) {
896     reportWarning(make_error<GenericBinaryError>(
897                       "There are extra data beyond auxiliary header",
898                       object_error::parse_failed),
899                   "-");
900     W.printBinary("Extra raw data", "",
901                   ArrayRef<uint8_t>((const uint8_t *)(AuxHeader) +
902                                         sizeof(XCOFFAuxiliaryHeader64),
903                                     AuxSize - sizeof(XCOFFAuxiliaryHeader64)));
904   }
905 
906 #undef PrintAuxMember64
907 }
908 
909 template <typename T>
910 void XCOFFDumper::printSectionHeaders(ArrayRef<T> Sections) {
911   ListScope Group(W, "Sections");
912 
913   uint16_t Index = 1;
914   for (const T &Sec : Sections) {
915     DictScope SecDS(W, "Section");
916 
917     W.printNumber("Index", Index++);
918     uint16_t SectionType = Sec.getSectionType();
919     switch (SectionType) {
920     case XCOFF::STYP_OVRFLO:
921       printOverflowSectionHeader(Sec);
922       break;
923     case XCOFF::STYP_LOADER:
924     case XCOFF::STYP_EXCEPT:
925     case XCOFF::STYP_TYPCHK:
926       // TODO The interpretation of loader, exception and type check section
927       // headers are different from that of generic section headers. We will
928       // implement them later. We interpret them as generic section headers for
929       // now.
930     default:
931       printGenericSectionHeader(Sec);
932       break;
933     }
934     if (Sec.isReservedSectionType())
935       W.printHex("Flags", "Reserved", SectionType);
936     else
937       W.printEnum("Type", SectionType, makeArrayRef(SectionTypeFlagsNames));
938   }
939 
940   if (opts::SectionRelocations)
941     report_fatal_error("Dumping section relocations is unimplemented");
942 
943   if (opts::SectionSymbols)
944     report_fatal_error("Dumping symbols is unimplemented");
945 
946   if (opts::SectionData)
947     report_fatal_error("Dumping section data is unimplemented");
948 }
949 
950 namespace llvm {
951 std::unique_ptr<ObjDumper>
952 createXCOFFDumper(const object::XCOFFObjectFile &XObj, ScopedPrinter &Writer) {
953   return std::make_unique<XCOFFDumper>(XObj, Writer);
954 }
955 } // namespace llvm
956