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