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