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/ScopedPrinter.h"
17 
18 using namespace llvm;
19 using namespace object;
20 
21 namespace {
22 
23 class XCOFFDumper : public ObjDumper {
24 
25 public:
26   XCOFFDumper(const XCOFFObjectFile &Obj, ScopedPrinter &Writer)
27       : ObjDumper(Writer, Obj.getFileName()), Obj(Obj) {}
28 
29   void printFileHeaders() override;
30   void printSectionHeaders() override;
31   void printRelocations() override;
32   void printSymbols() override;
33   void printDynamicSymbols() override;
34   void printUnwindInfo() override;
35   void printStackMap() const override;
36   void printNeededLibraries() override;
37 
38 private:
39   template <typename T> void printSectionHeaders(ArrayRef<T> Sections);
40   template <typename T> void printGenericSectionHeader(T &Sec) const;
41   template <typename T> void printOverflowSectionHeader(T &Sec) const;
42   void printFileAuxEnt(const XCOFFFileAuxEnt *AuxEntPtr);
43   void printCsectAuxEnt(XCOFFCsectAuxRef AuxEntRef);
44   void printSectAuxEntForStat(const XCOFFSectAuxEntForStat *AuxEntPtr);
45   void printSymbol(const SymbolRef &);
46   void printRelocations(ArrayRef<XCOFFSectionHeader32> Sections);
47   const XCOFFObjectFile &Obj;
48 };
49 } // anonymous namespace
50 
51 void XCOFFDumper::printFileHeaders() {
52   DictScope DS(W, "FileHeader");
53   W.printHex("Magic", Obj.getMagic());
54   W.printNumber("NumberOfSections", Obj.getNumberOfSections());
55 
56   // Negative timestamp values are reserved for future use.
57   int32_t TimeStamp = Obj.getTimeStamp();
58   if (TimeStamp > 0) {
59     // This handling of the time stamp assumes that the host system's time_t is
60     // compatible with AIX time_t. If a platform is not compatible, the lit
61     // tests will let us know.
62     time_t TimeDate = TimeStamp;
63 
64     char FormattedTime[21] = {};
65     size_t BytesWritten =
66         strftime(FormattedTime, 21, "%Y-%m-%dT%H:%M:%SZ", gmtime(&TimeDate));
67     if (BytesWritten)
68       W.printHex("TimeStamp", FormattedTime, TimeStamp);
69     else
70       W.printHex("Timestamp", TimeStamp);
71   } else {
72     W.printHex("TimeStamp", TimeStamp == 0 ? "None" : "Reserved Value",
73                TimeStamp);
74   }
75 
76   // The number of symbol table entries is an unsigned value in 64-bit objects
77   // and a signed value (with negative values being 'reserved') in 32-bit
78   // objects.
79   if (Obj.is64Bit()) {
80     W.printHex("SymbolTableOffset", Obj.getSymbolTableOffset64());
81     W.printNumber("SymbolTableEntries", Obj.getNumberOfSymbolTableEntries64());
82   } else {
83     W.printHex("SymbolTableOffset", Obj.getSymbolTableOffset32());
84     int32_t SymTabEntries = Obj.getRawNumberOfSymbolTableEntries32();
85     if (SymTabEntries >= 0)
86       W.printNumber("SymbolTableEntries", SymTabEntries);
87     else
88       W.printHex("SymbolTableEntries", "Reserved Value", SymTabEntries);
89   }
90 
91   W.printHex("OptionalHeaderSize", Obj.getOptionalHeaderSize());
92   W.printHex("Flags", Obj.getFlags());
93 
94   // TODO FIXME Add support for the auxiliary header (if any) once
95   // XCOFFObjectFile has the necessary support.
96 }
97 
98 void XCOFFDumper::printSectionHeaders() {
99   if (Obj.is64Bit())
100     printSectionHeaders(Obj.sections64());
101   else
102     printSectionHeaders(Obj.sections32());
103 }
104 
105 void XCOFFDumper::printRelocations() {
106   if (Obj.is64Bit())
107     llvm_unreachable("64-bit relocation output not implemented!");
108   else
109     printRelocations(Obj.sections32());
110 }
111 
112 static const EnumEntry<XCOFF::RelocationType> RelocationTypeNameclass[] = {
113 #define ECase(X)                                                               \
114   { #X, XCOFF::X }
115     ECase(R_POS),    ECase(R_RL),     ECase(R_RLA),    ECase(R_NEG),
116     ECase(R_REL),    ECase(R_TOC),    ECase(R_TRL),    ECase(R_TRLA),
117     ECase(R_GL),     ECase(R_TCL),    ECase(R_REF),    ECase(R_BA),
118     ECase(R_BR),     ECase(R_RBA),    ECase(R_RBR),    ECase(R_TLS),
119     ECase(R_TLS_IE), ECase(R_TLS_LD), ECase(R_TLS_LE), ECase(R_TLSM),
120     ECase(R_TLSML),  ECase(R_TOCU),   ECase(R_TOCL)
121 #undef ECase
122 };
123 
124 void XCOFFDumper::printRelocations(ArrayRef<XCOFFSectionHeader32> Sections) {
125   if (!opts::ExpandRelocs)
126     report_fatal_error("Unexpanded relocation output not implemented.");
127 
128   ListScope LS(W, "Relocations");
129   uint16_t Index = 0;
130   for (const auto &Sec : Sections) {
131     ++Index;
132     // Only the .text, .data, .tdata, and STYP_DWARF sections have relocation.
133     if (Sec.Flags != XCOFF::STYP_TEXT && Sec.Flags != XCOFF::STYP_DATA &&
134         Sec.Flags != XCOFF::STYP_TDATA && Sec.Flags != XCOFF::STYP_DWARF)
135       continue;
136     auto Relocations = unwrapOrError(Obj.getFileName(), Obj.relocations(Sec));
137     if (Relocations.empty())
138       continue;
139 
140     W.startLine() << "Section (index: " << Index << ") " << Sec.getName()
141                   << " {\n";
142     for (auto Reloc : Relocations) {
143       StringRef SymbolName = unwrapOrError(
144           Obj.getFileName(), Obj.getSymbolNameByIndex(Reloc.SymbolIndex));
145 
146       DictScope RelocScope(W, "Relocation");
147       W.printHex("Virtual Address", Reloc.VirtualAddress);
148       W.printNumber("Symbol", SymbolName, Reloc.SymbolIndex);
149       W.printString("IsSigned", Reloc.isRelocationSigned() ? "Yes" : "No");
150       W.printNumber("FixupBitValue", Reloc.isFixupIndicated() ? 1 : 0);
151       W.printNumber("Length", Reloc.getRelocatedLength());
152       W.printEnum("Type", (uint8_t)Reloc.Type,
153                   makeArrayRef(RelocationTypeNameclass));
154     }
155     W.unindent();
156     W.startLine() << "}\n";
157   }
158 }
159 
160 static const EnumEntry<XCOFF::CFileStringType> FileStringType[] = {
161 #define ECase(X)                                                               \
162   { #X, XCOFF::X }
163     ECase(XFT_FN), ECase(XFT_CT), ECase(XFT_CV), ECase(XFT_CD)
164 #undef ECase
165 };
166 
167 static const EnumEntry<XCOFF::SymbolAuxType> SymAuxType[] = {
168 #define ECase(X)                                                               \
169   { #X, XCOFF::X }
170     ECase(AUX_EXCEPT), ECase(AUX_FCN), ECase(AUX_SYM), ECase(AUX_FILE),
171     ECase(AUX_CSECT),  ECase(AUX_SECT)
172 #undef ECase
173 };
174 
175 void XCOFFDumper::printFileAuxEnt(const XCOFFFileAuxEnt *AuxEntPtr) {
176   assert((!Obj.is64Bit() || AuxEntPtr->AuxType == XCOFF::AUX_FILE) &&
177          "Mismatched auxiliary type!");
178   StringRef FileName =
179       unwrapOrError(Obj.getFileName(), Obj.getCFileName(AuxEntPtr));
180   DictScope SymDs(W, "File Auxiliary Entry");
181   W.printNumber("Index",
182                 Obj.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr)));
183   W.printString("Name", FileName);
184   W.printEnum("Type", static_cast<uint8_t>(AuxEntPtr->Type),
185               makeArrayRef(FileStringType));
186   if (Obj.is64Bit()) {
187     W.printEnum("Auxiliary Type", static_cast<uint8_t>(AuxEntPtr->AuxType),
188                 makeArrayRef(SymAuxType));
189   }
190 }
191 
192 static const EnumEntry<XCOFF::StorageMappingClass> CsectStorageMappingClass[] =
193     {
194 #define ECase(X)                                                               \
195   { #X, XCOFF::X }
196         ECase(XMC_PR), ECase(XMC_RO), ECase(XMC_DB),   ECase(XMC_GL),
197         ECase(XMC_XO), ECase(XMC_SV), ECase(XMC_SV64), ECase(XMC_SV3264),
198         ECase(XMC_TI), ECase(XMC_TB), ECase(XMC_RW),   ECase(XMC_TC0),
199         ECase(XMC_TC), ECase(XMC_TD), ECase(XMC_DS),   ECase(XMC_UA),
200         ECase(XMC_BS), ECase(XMC_UC), ECase(XMC_TL),   ECase(XMC_UL),
201         ECase(XMC_TE)
202 #undef ECase
203 };
204 
205 static const EnumEntry<XCOFF::SymbolType> CsectSymbolTypeClass[] = {
206 #define ECase(X)                                                               \
207   { #X, XCOFF::X }
208     ECase(XTY_ER), ECase(XTY_SD), ECase(XTY_LD), ECase(XTY_CM)
209 #undef ECase
210 };
211 
212 void XCOFFDumper::printCsectAuxEnt(XCOFFCsectAuxRef AuxEntRef) {
213   assert((!Obj.is64Bit() || AuxEntRef.getAuxType64() == XCOFF::AUX_CSECT) &&
214          "Mismatched auxiliary type!");
215 
216   DictScope SymDs(W, "CSECT Auxiliary Entry");
217   W.printNumber("Index", Obj.getSymbolIndex(AuxEntRef.getEntryAddress()));
218   W.printNumber(AuxEntRef.isLabel() ? "ContainingCsectSymbolIndex"
219                                     : "SectionLen",
220                 AuxEntRef.getSectionOrLength());
221   W.printHex("ParameterHashIndex", AuxEntRef.getParameterHashIndex());
222   W.printHex("TypeChkSectNum", AuxEntRef.getTypeChkSectNum());
223   // Print out symbol alignment and type.
224   W.printNumber("SymbolAlignmentLog2", AuxEntRef.getAlignmentLog2());
225   W.printEnum("SymbolType", AuxEntRef.getSymbolType(),
226               makeArrayRef(CsectSymbolTypeClass));
227   W.printEnum("StorageMappingClass",
228               static_cast<uint8_t>(AuxEntRef.getStorageMappingClass()),
229               makeArrayRef(CsectStorageMappingClass));
230 
231   if (Obj.is64Bit()) {
232     W.printEnum("Auxiliary Type", static_cast<uint8_t>(XCOFF::AUX_CSECT),
233                 makeArrayRef(SymAuxType));
234   } else {
235     W.printHex("StabInfoIndex", AuxEntRef.getStabInfoIndex32());
236     W.printHex("StabSectNum", AuxEntRef.getStabSectNum32());
237   }
238 }
239 
240 void XCOFFDumper::printSectAuxEntForStat(
241     const XCOFFSectAuxEntForStat *AuxEntPtr) {
242   assert(!Obj.is64Bit() && "32-bit interface called on 64-bit object file.");
243 
244   DictScope SymDs(W, "Sect Auxiliary Entry For Stat");
245   W.printNumber("Index",
246                 Obj.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr)));
247   W.printNumber("SectionLength", AuxEntPtr->SectionLength);
248 
249   // Unlike the corresponding fields in the section header, NumberOfRelocEnt
250   // and NumberOfLineNum do not handle values greater than 65535.
251   W.printNumber("NumberOfRelocEnt", AuxEntPtr->NumberOfRelocEnt);
252   W.printNumber("NumberOfLineNum", AuxEntPtr->NumberOfLineNum);
253 }
254 
255 static const EnumEntry<XCOFF::StorageClass> SymStorageClass[] = {
256 #define ECase(X)                                                               \
257   { #X, XCOFF::X }
258     ECase(C_NULL),  ECase(C_AUTO),    ECase(C_EXT),     ECase(C_STAT),
259     ECase(C_REG),   ECase(C_EXTDEF),  ECase(C_LABEL),   ECase(C_ULABEL),
260     ECase(C_MOS),   ECase(C_ARG),     ECase(C_STRTAG),  ECase(C_MOU),
261     ECase(C_UNTAG), ECase(C_TPDEF),   ECase(C_USTATIC), ECase(C_ENTAG),
262     ECase(C_MOE),   ECase(C_REGPARM), ECase(C_FIELD),   ECase(C_BLOCK),
263     ECase(C_FCN),   ECase(C_EOS),     ECase(C_FILE),    ECase(C_LINE),
264     ECase(C_ALIAS), ECase(C_HIDDEN),  ECase(C_HIDEXT),  ECase(C_BINCL),
265     ECase(C_EINCL), ECase(C_INFO),    ECase(C_WEAKEXT), ECase(C_DWARF),
266     ECase(C_GSYM),  ECase(C_LSYM),    ECase(C_PSYM),    ECase(C_RSYM),
267     ECase(C_RPSYM), ECase(C_STSYM),   ECase(C_TCSYM),   ECase(C_BCOMM),
268     ECase(C_ECOML), ECase(C_ECOMM),   ECase(C_DECL),    ECase(C_ENTRY),
269     ECase(C_FUN),   ECase(C_BSTAT),   ECase(C_ESTAT),   ECase(C_GTLS),
270     ECase(C_STTLS), ECase(C_EFCN)
271 #undef ECase
272 };
273 
274 static StringRef GetSymbolValueName(XCOFF::StorageClass SC) {
275   switch (SC) {
276   case XCOFF::C_EXT:
277   case XCOFF::C_WEAKEXT:
278   case XCOFF::C_HIDEXT:
279   case XCOFF::C_STAT:
280     return "Value (RelocatableAddress)";
281   case XCOFF::C_FILE:
282     return "Value (SymbolTableIndex)";
283   case XCOFF::C_FCN:
284   case XCOFF::C_BLOCK:
285   case XCOFF::C_FUN:
286   case XCOFF::C_STSYM:
287   case XCOFF::C_BINCL:
288   case XCOFF::C_EINCL:
289   case XCOFF::C_INFO:
290   case XCOFF::C_BSTAT:
291   case XCOFF::C_LSYM:
292   case XCOFF::C_PSYM:
293   case XCOFF::C_RPSYM:
294   case XCOFF::C_RSYM:
295   case XCOFF::C_ECOML:
296   case XCOFF::C_DWARF:
297     assert(false && "This StorageClass for the symbol is not yet implemented.");
298     return "";
299   default:
300     return "Value";
301   }
302 }
303 
304 static const EnumEntry<XCOFF::CFileLangId> CFileLangIdClass[] = {
305 #define ECase(X)                                                               \
306   { #X, XCOFF::X }
307     ECase(TB_C), ECase(TB_CPLUSPLUS)
308 #undef ECase
309 };
310 
311 static const EnumEntry<XCOFF::CFileCpuId> CFileCpuIdClass[] = {
312 #define ECase(X)                                                               \
313   { #X, XCOFF::X }
314     ECase(TCPU_PPC64), ECase(TCPU_COM), ECase(TCPU_970)
315 #undef ECase
316 };
317 
318 void XCOFFDumper::printSymbol(const SymbolRef &S) {
319   DataRefImpl SymbolDRI = S.getRawDataRefImpl();
320   XCOFFSymbolRef SymbolEntRef = Obj.toSymbolRef(SymbolDRI);
321 
322   uint8_t NumberOfAuxEntries = SymbolEntRef.getNumberOfAuxEntries();
323 
324   DictScope SymDs(W, "Symbol");
325 
326   StringRef SymbolName =
327       unwrapOrError(Obj.getFileName(), SymbolEntRef.getName());
328 
329   W.printNumber("Index", Obj.getSymbolIndex(SymbolEntRef.getEntryAddress()));
330   W.printString("Name", SymbolName);
331   W.printHex(GetSymbolValueName(SymbolEntRef.getStorageClass()),
332              SymbolEntRef.getValue());
333 
334   StringRef SectionName =
335       unwrapOrError(Obj.getFileName(), Obj.getSymbolSectionName(SymbolEntRef));
336 
337   W.printString("Section", SectionName);
338   if (SymbolEntRef.getStorageClass() == XCOFF::C_FILE) {
339     W.printEnum("Source Language ID", SymbolEntRef.getLanguageIdForCFile(),
340                 makeArrayRef(CFileLangIdClass));
341     W.printEnum("CPU Version ID", SymbolEntRef.getCPUTypeIddForCFile(),
342                 makeArrayRef(CFileCpuIdClass));
343   } else
344     W.printHex("Type", SymbolEntRef.getSymbolType());
345 
346   W.printEnum("StorageClass",
347               static_cast<uint8_t>(SymbolEntRef.getStorageClass()),
348               makeArrayRef(SymStorageClass));
349   W.printNumber("NumberOfAuxEntries", NumberOfAuxEntries);
350 
351   if (NumberOfAuxEntries == 0)
352     return;
353 
354   switch (SymbolEntRef.getStorageClass()) {
355   case XCOFF::C_FILE:
356     // If the symbol is C_FILE and has auxiliary entries...
357     for (int I = 1; I <= NumberOfAuxEntries; I++) {
358       uintptr_t AuxAddress = XCOFFObjectFile::getAdvancedSymbolEntryAddress(
359           SymbolEntRef.getEntryAddress(), I);
360 
361       if (Obj.is64Bit() &&
362           *Obj.getSymbolAuxType(AuxAddress) != XCOFF::SymbolAuxType::AUX_FILE) {
363         W.startLine() << "!Unexpected raw auxiliary entry data:\n";
364         W.startLine() << format_bytes(
365                              ArrayRef<uint8_t>(
366                                  reinterpret_cast<const uint8_t *>(AuxAddress),
367                                  XCOFF::SymbolTableEntrySize),
368                              0, XCOFF::SymbolTableEntrySize)
369                       << "\n";
370         continue;
371       }
372 
373       const XCOFFFileAuxEnt *FileAuxEntPtr =
374           reinterpret_cast<const XCOFFFileAuxEnt *>(AuxAddress);
375 #ifndef NDEBUG
376       Obj.checkSymbolEntryPointer(reinterpret_cast<uintptr_t>(FileAuxEntPtr));
377 #endif
378       printFileAuxEnt(FileAuxEntPtr);
379     }
380     break;
381   case XCOFF::C_EXT:
382   case XCOFF::C_WEAKEXT:
383   case XCOFF::C_HIDEXT: {
384     // If the symbol is for a function, and it has more than 1 auxiliary entry,
385     // then one of them must be function auxiliary entry which we do not
386     // support yet.
387     if (SymbolEntRef.isFunction() && NumberOfAuxEntries >= 2)
388       report_fatal_error("Function auxiliary entry printing is unimplemented.");
389 
390     // If there is more than 1 auxiliary entry, instead of printing out
391     // error information, print out the raw Auxiliary entry.
392     // For 32-bit object, print from first to the last - 1. The last one must be
393     // a CSECT Auxiliary Entry.
394     // For 64-bit object, print from first to last and skips if SymbolAuxType is
395     // AUX_CSECT.
396     for (int I = 1; I <= NumberOfAuxEntries; I++) {
397       if (I == NumberOfAuxEntries && !Obj.is64Bit())
398         break;
399 
400       uintptr_t AuxAddress = XCOFFObjectFile::getAdvancedSymbolEntryAddress(
401           SymbolEntRef.getEntryAddress(), I);
402       if (Obj.is64Bit() &&
403           *Obj.getSymbolAuxType(AuxAddress) == XCOFF::SymbolAuxType::AUX_CSECT)
404         continue;
405 
406       W.startLine() << "!Unexpected raw auxiliary entry data:\n";
407       W.startLine() << format_bytes(
408           ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(AuxAddress),
409                             XCOFF::SymbolTableEntrySize));
410     }
411 
412     auto ErrOrCsectAuxRef = SymbolEntRef.getXCOFFCsectAuxRef();
413     if (!ErrOrCsectAuxRef)
414       reportUniqueWarning(ErrOrCsectAuxRef.takeError());
415     else
416       printCsectAuxEnt(*ErrOrCsectAuxRef);
417 
418     break;
419   }
420   case XCOFF::C_STAT:
421     if (NumberOfAuxEntries > 1)
422       report_fatal_error(
423           "C_STAT symbol should not have more than 1 auxiliary entry.");
424 
425     const XCOFFSectAuxEntForStat *StatAuxEntPtr;
426     StatAuxEntPtr = reinterpret_cast<const XCOFFSectAuxEntForStat *>(
427         XCOFFObjectFile::getAdvancedSymbolEntryAddress(
428             SymbolEntRef.getEntryAddress(), 1));
429 #ifndef NDEBUG
430     Obj.checkSymbolEntryPointer(reinterpret_cast<uintptr_t>(StatAuxEntPtr));
431 #endif
432     printSectAuxEntForStat(StatAuxEntPtr);
433     break;
434   case XCOFF::C_DWARF:
435   case XCOFF::C_BLOCK:
436   case XCOFF::C_FCN:
437     report_fatal_error("Symbol table entry printing for this storage class "
438                        "type is unimplemented.");
439     break;
440   default:
441     for (int i = 1; i <= NumberOfAuxEntries; i++) {
442       W.startLine() << "!Unexpected raw auxiliary entry data:\n";
443       W.startLine() << format_bytes(
444           ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(
445                                 XCOFFObjectFile::getAdvancedSymbolEntryAddress(
446                                     SymbolEntRef.getEntryAddress(), i)),
447                             XCOFF::SymbolTableEntrySize));
448     }
449     break;
450   }
451 }
452 
453 void XCOFFDumper::printSymbols() {
454   ListScope Group(W, "Symbols");
455   for (const SymbolRef &S : Obj.symbols())
456     printSymbol(S);
457 }
458 
459 void XCOFFDumper::printDynamicSymbols() {
460   llvm_unreachable("Unimplemented functionality for XCOFFDumper");
461 }
462 
463 void XCOFFDumper::printUnwindInfo() {
464   llvm_unreachable("Unimplemented functionality for XCOFFDumper");
465 }
466 
467 void XCOFFDumper::printStackMap() const {
468   llvm_unreachable("Unimplemented functionality for XCOFFDumper");
469 }
470 
471 void XCOFFDumper::printNeededLibraries() {
472   llvm_unreachable("Unimplemented functionality for XCOFFDumper");
473 }
474 
475 static const EnumEntry<XCOFF::SectionTypeFlags> SectionTypeFlagsNames[] = {
476 #define ECase(X)                                                               \
477   { #X, XCOFF::X }
478     ECase(STYP_PAD),    ECase(STYP_DWARF), ECase(STYP_TEXT),
479     ECase(STYP_DATA),   ECase(STYP_BSS),   ECase(STYP_EXCEPT),
480     ECase(STYP_INFO),   ECase(STYP_TDATA), ECase(STYP_TBSS),
481     ECase(STYP_LOADER), ECase(STYP_DEBUG), ECase(STYP_TYPCHK),
482     ECase(STYP_OVRFLO)
483 #undef ECase
484 };
485 
486 template <typename T>
487 void XCOFFDumper::printOverflowSectionHeader(T &Sec) const {
488   if (Obj.is64Bit()) {
489     reportWarning(make_error<StringError>("An 64-bit XCOFF object file may not "
490                                           "contain an overflow section header.",
491                                           object_error::parse_failed),
492                   Obj.getFileName());
493   }
494 
495   W.printString("Name", Sec.getName());
496   W.printNumber("NumberOfRelocations", Sec.PhysicalAddress);
497   W.printNumber("NumberOfLineNumbers", Sec.VirtualAddress);
498   W.printHex("Size", Sec.SectionSize);
499   W.printHex("RawDataOffset", Sec.FileOffsetToRawData);
500   W.printHex("RelocationPointer", Sec.FileOffsetToRelocationInfo);
501   W.printHex("LineNumberPointer", Sec.FileOffsetToLineNumberInfo);
502   W.printNumber("IndexOfSectionOverflowed", Sec.NumberOfRelocations);
503   W.printNumber("IndexOfSectionOverflowed", Sec.NumberOfLineNumbers);
504 }
505 
506 template <typename T>
507 void XCOFFDumper::printGenericSectionHeader(T &Sec) const {
508   W.printString("Name", Sec.getName());
509   W.printHex("PhysicalAddress", Sec.PhysicalAddress);
510   W.printHex("VirtualAddress", Sec.VirtualAddress);
511   W.printHex("Size", Sec.SectionSize);
512   W.printHex("RawDataOffset", Sec.FileOffsetToRawData);
513   W.printHex("RelocationPointer", Sec.FileOffsetToRelocationInfo);
514   W.printHex("LineNumberPointer", Sec.FileOffsetToLineNumberInfo);
515   W.printNumber("NumberOfRelocations", Sec.NumberOfRelocations);
516   W.printNumber("NumberOfLineNumbers", Sec.NumberOfLineNumbers);
517 }
518 
519 template <typename T>
520 void XCOFFDumper::printSectionHeaders(ArrayRef<T> Sections) {
521   ListScope Group(W, "Sections");
522 
523   uint16_t Index = 1;
524   for (const T &Sec : Sections) {
525     DictScope SecDS(W, "Section");
526 
527     W.printNumber("Index", Index++);
528     uint16_t SectionType = Sec.getSectionType();
529     switch (SectionType) {
530     case XCOFF::STYP_OVRFLO:
531       printOverflowSectionHeader(Sec);
532       break;
533     case XCOFF::STYP_LOADER:
534     case XCOFF::STYP_EXCEPT:
535     case XCOFF::STYP_TYPCHK:
536       // TODO The interpretation of loader, exception and type check section
537       // headers are different from that of generic section headers. We will
538       // implement them later. We interpret them as generic section headers for
539       // now.
540     default:
541       printGenericSectionHeader(Sec);
542       break;
543     }
544     if (Sec.isReservedSectionType())
545       W.printHex("Flags", "Reserved", SectionType);
546     else
547       W.printEnum("Type", SectionType, makeArrayRef(SectionTypeFlagsNames));
548   }
549 
550   if (opts::SectionRelocations)
551     report_fatal_error("Dumping section relocations is unimplemented");
552 
553   if (opts::SectionSymbols)
554     report_fatal_error("Dumping symbols is unimplemented");
555 
556   if (opts::SectionData)
557     report_fatal_error("Dumping section data is unimplemented");
558 }
559 
560 namespace llvm {
561 std::unique_ptr<ObjDumper>
562 createXCOFFDumper(const object::XCOFFObjectFile &XObj, ScopedPrinter &Writer) {
563   return std::make_unique<XCOFFDumper>(XObj, Writer);
564 }
565 } // namespace llvm
566