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