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