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:
XCOFFDumper(const XCOFFObjectFile & Obj,ScopedPrinter & Writer)26   XCOFFDumper(const XCOFFObjectFile &Obj, ScopedPrinter &Writer)
27       : ObjDumper(Writer), 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 printCsectAuxEnt32(const XCOFFCsectAuxEnt32 *AuxEntPtr);
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 
printFileHeaders()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 
printSectionHeaders()98 void XCOFFDumper::printSectionHeaders() {
99   if (Obj.is64Bit())
100     printSectionHeaders(Obj.sections64());
101   else
102     printSectionHeaders(Obj.sections32());
103 }
104 
printRelocations()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 
printRelocations(ArrayRef<XCOFFSectionHeader32> Sections)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 
printFileAuxEnt(const XCOFFFileAuxEnt * AuxEntPtr)167 void XCOFFDumper::printFileAuxEnt(const XCOFFFileAuxEnt *AuxEntPtr) {
168   if (Obj.is64Bit())
169     report_fatal_error(
170         "Printing for File Auxiliary Entry in 64-bit is unimplemented.");
171   StringRef FileName =
172       unwrapOrError(Obj.getFileName(), Obj.getCFileName(AuxEntPtr));
173   DictScope SymDs(W, "File Auxiliary Entry");
174   W.printNumber("Index",
175                 Obj.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr)));
176   W.printString("Name", FileName);
177   W.printEnum("Type", static_cast<uint8_t>(AuxEntPtr->Type),
178               makeArrayRef(FileStringType));
179 }
180 
181 static const EnumEntry<XCOFF::StorageMappingClass> CsectStorageMappingClass[] =
182     {
183 #define ECase(X)                                                               \
184   { #X, XCOFF::X }
185         ECase(XMC_PR),   ECase(XMC_RO),     ECase(XMC_DB),
186         ECase(XMC_GL),   ECase(XMC_XO),     ECase(XMC_SV),
187         ECase(XMC_SV64), ECase(XMC_SV3264), ECase(XMC_TI),
188         ECase(XMC_TB),   ECase(XMC_RW),     ECase(XMC_TC0),
189         ECase(XMC_TC),   ECase(XMC_TD),     ECase(XMC_DS),
190         ECase(XMC_UA),   ECase(XMC_BS),     ECase(XMC_UC),
191         ECase(XMC_TL),   ECase(XMC_TE)
192 #undef ECase
193 };
194 
195 static const EnumEntry<XCOFF::SymbolType> CsectSymbolTypeClass[] = {
196 #define ECase(X)                                                               \
197   { #X, XCOFF::X }
198     ECase(XTY_ER), ECase(XTY_SD), ECase(XTY_LD), ECase(XTY_CM)
199 #undef ECase
200 };
201 
printCsectAuxEnt32(const XCOFFCsectAuxEnt32 * AuxEntPtr)202 void XCOFFDumper::printCsectAuxEnt32(const XCOFFCsectAuxEnt32 *AuxEntPtr) {
203   assert(!Obj.is64Bit() && "32-bit interface called on 64-bit object file.");
204 
205   DictScope SymDs(W, "CSECT Auxiliary Entry");
206   W.printNumber("Index",
207                 Obj.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr)));
208   if (AuxEntPtr->isLabel())
209     W.printNumber("ContainingCsectSymbolIndex", AuxEntPtr->SectionOrLength);
210   else
211     W.printNumber("SectionLen", AuxEntPtr->SectionOrLength);
212   W.printHex("ParameterHashIndex", AuxEntPtr->ParameterHashIndex);
213   W.printHex("TypeChkSectNum", AuxEntPtr->TypeChkSectNum);
214   // Print out symbol alignment and type.
215   W.printNumber("SymbolAlignmentLog2", AuxEntPtr->getAlignmentLog2());
216   W.printEnum("SymbolType", AuxEntPtr->getSymbolType(),
217               makeArrayRef(CsectSymbolTypeClass));
218   W.printEnum("StorageMappingClass",
219               static_cast<uint8_t>(AuxEntPtr->StorageMappingClass),
220               makeArrayRef(CsectStorageMappingClass));
221   W.printHex("StabInfoIndex", AuxEntPtr->StabInfoIndex);
222   W.printHex("StabSectNum", AuxEntPtr->StabSectNum);
223 }
224 
printSectAuxEntForStat(const XCOFFSectAuxEntForStat * AuxEntPtr)225 void XCOFFDumper::printSectAuxEntForStat(
226     const XCOFFSectAuxEntForStat *AuxEntPtr) {
227   assert(!Obj.is64Bit() && "32-bit interface called on 64-bit object file.");
228 
229   DictScope SymDs(W, "Sect Auxiliary Entry For Stat");
230   W.printNumber("Index",
231                 Obj.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr)));
232   W.printNumber("SectionLength", AuxEntPtr->SectionLength);
233 
234   // Unlike the corresponding fields in the section header, NumberOfRelocEnt
235   // and NumberOfLineNum do not handle values greater than 65535.
236   W.printNumber("NumberOfRelocEnt", AuxEntPtr->NumberOfRelocEnt);
237   W.printNumber("NumberOfLineNum", AuxEntPtr->NumberOfLineNum);
238 }
239 
240 static const EnumEntry<XCOFF::StorageClass> SymStorageClass[] = {
241 #define ECase(X)                                                               \
242   { #X, XCOFF::X }
243     ECase(C_NULL),  ECase(C_AUTO),    ECase(C_EXT),     ECase(C_STAT),
244     ECase(C_REG),   ECase(C_EXTDEF),  ECase(C_LABEL),   ECase(C_ULABEL),
245     ECase(C_MOS),   ECase(C_ARG),     ECase(C_STRTAG),  ECase(C_MOU),
246     ECase(C_UNTAG), ECase(C_TPDEF),   ECase(C_USTATIC), ECase(C_ENTAG),
247     ECase(C_MOE),   ECase(C_REGPARM), ECase(C_FIELD),   ECase(C_BLOCK),
248     ECase(C_FCN),   ECase(C_EOS),     ECase(C_FILE),    ECase(C_LINE),
249     ECase(C_ALIAS), ECase(C_HIDDEN),  ECase(C_HIDEXT),  ECase(C_BINCL),
250     ECase(C_EINCL), ECase(C_INFO),    ECase(C_WEAKEXT), ECase(C_DWARF),
251     ECase(C_GSYM),  ECase(C_LSYM),    ECase(C_PSYM),    ECase(C_RSYM),
252     ECase(C_RPSYM), ECase(C_STSYM),   ECase(C_TCSYM),   ECase(C_BCOMM),
253     ECase(C_ECOML), ECase(C_ECOMM),   ECase(C_DECL),    ECase(C_ENTRY),
254     ECase(C_FUN),   ECase(C_BSTAT),   ECase(C_ESTAT),   ECase(C_GTLS),
255     ECase(C_STTLS), ECase(C_EFCN)
256 #undef ECase
257 };
258 
GetSymbolValueName(XCOFF::StorageClass SC)259 static StringRef GetSymbolValueName(XCOFF::StorageClass SC) {
260   switch (SC) {
261   case XCOFF::C_EXT:
262   case XCOFF::C_WEAKEXT:
263   case XCOFF::C_HIDEXT:
264   case XCOFF::C_STAT:
265     return "Value (RelocatableAddress)";
266   case XCOFF::C_FILE:
267     return "Value (SymbolTableIndex)";
268   case XCOFF::C_FCN:
269   case XCOFF::C_BLOCK:
270   case XCOFF::C_FUN:
271   case XCOFF::C_STSYM:
272   case XCOFF::C_BINCL:
273   case XCOFF::C_EINCL:
274   case XCOFF::C_INFO:
275   case XCOFF::C_BSTAT:
276   case XCOFF::C_LSYM:
277   case XCOFF::C_PSYM:
278   case XCOFF::C_RPSYM:
279   case XCOFF::C_RSYM:
280   case XCOFF::C_ECOML:
281   case XCOFF::C_DWARF:
282     assert(false && "This StorageClass for the symbol is not yet implemented.");
283     return "";
284   default:
285     return "Value";
286   }
287 }
288 
289 static const EnumEntry<XCOFF::CFileLangId> CFileLangIdClass[] = {
290 #define ECase(X)                                                               \
291   { #X, XCOFF::X }
292     ECase(TB_C), ECase(TB_CPLUSPLUS)
293 #undef ECase
294 };
295 
296 static const EnumEntry<XCOFF::CFileCpuId> CFileCpuIdClass[] = {
297 #define ECase(X)                                                               \
298   { #X, XCOFF::X }
299     ECase(TCPU_PPC64), ECase(TCPU_COM), ECase(TCPU_970)
300 #undef ECase
301 };
302 
printSymbol(const SymbolRef & S)303 void XCOFFDumper::printSymbol(const SymbolRef &S) {
304   if (Obj.is64Bit())
305     report_fatal_error("64-bit support is unimplemented.");
306 
307   DataRefImpl SymbolDRI = S.getRawDataRefImpl();
308   const XCOFFSymbolEntry *SymbolEntPtr = Obj.toSymbolEntry(SymbolDRI);
309 
310   XCOFFSymbolRef XCOFFSymRef(SymbolDRI, &Obj);
311   uint8_t NumberOfAuxEntries = XCOFFSymRef.getNumberOfAuxEntries();
312 
313   DictScope SymDs(W, "Symbol");
314 
315   StringRef SymbolName =
316       unwrapOrError(Obj.getFileName(), Obj.getSymbolName(SymbolDRI));
317 
318   W.printNumber("Index",
319                 Obj.getSymbolIndex(reinterpret_cast<uintptr_t>(SymbolEntPtr)));
320   W.printString("Name", SymbolName);
321   W.printHex(GetSymbolValueName(SymbolEntPtr->StorageClass),
322              SymbolEntPtr->Value);
323 
324   StringRef SectionName =
325       unwrapOrError(Obj.getFileName(), Obj.getSymbolSectionName(SymbolEntPtr));
326 
327   W.printString("Section", SectionName);
328   if (XCOFFSymRef.getStorageClass() == XCOFF::C_FILE) {
329     W.printEnum("Source Language ID",
330                 SymbolEntPtr->CFileLanguageIdAndTypeId.LanguageId,
331                 makeArrayRef(CFileLangIdClass));
332     W.printEnum("CPU Version ID",
333                 SymbolEntPtr->CFileLanguageIdAndTypeId.CpuTypeId,
334                 makeArrayRef(CFileCpuIdClass));
335   } else
336     W.printHex("Type", SymbolEntPtr->SymbolType);
337 
338   W.printEnum("StorageClass", static_cast<uint8_t>(SymbolEntPtr->StorageClass),
339               makeArrayRef(SymStorageClass));
340   W.printNumber("NumberOfAuxEntries", SymbolEntPtr->NumberOfAuxEntries);
341 
342   if (NumberOfAuxEntries == 0)
343     return;
344 
345   switch (XCOFFSymRef.getStorageClass()) {
346   case XCOFF::C_FILE:
347     // If the symbol is C_FILE and has auxiliary entries...
348     for (int i = 1; i <= NumberOfAuxEntries; i++) {
349       const XCOFFFileAuxEnt *FileAuxEntPtr =
350           reinterpret_cast<const XCOFFFileAuxEnt *>(SymbolEntPtr + i);
351 #ifndef NDEBUG
352       Obj.checkSymbolEntryPointer(reinterpret_cast<uintptr_t>(FileAuxEntPtr));
353 #endif
354       printFileAuxEnt(FileAuxEntPtr);
355     }
356     break;
357   case XCOFF::C_EXT:
358   case XCOFF::C_WEAKEXT:
359   case XCOFF::C_HIDEXT:
360     // If the symbol is for a function, and it has more than 1 auxiliary entry,
361     // then one of them must be function auxiliary entry which we do not
362     // support yet.
363     if (XCOFFSymRef.isFunction() && NumberOfAuxEntries >= 2)
364       report_fatal_error("Function auxiliary entry printing is unimplemented.");
365 
366     // If there is more than 1 auxiliary entry, instead of printing out
367     // error information, print out the raw Auxiliary entry from 1st till
368     // the last - 1. The last one must be a CSECT Auxiliary Entry.
369     for (int i = 1; i < NumberOfAuxEntries; i++) {
370       W.startLine() << "!Unexpected raw auxiliary entry data:\n";
371       W.startLine() << format_bytes(
372           ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(SymbolEntPtr + i),
373                             XCOFF::SymbolTableEntrySize));
374     }
375 
376     // The symbol's last auxiliary entry is a CSECT Auxiliary Entry.
377     printCsectAuxEnt32(XCOFFSymRef.getXCOFFCsectAuxEnt32());
378     break;
379   case XCOFF::C_STAT:
380     if (NumberOfAuxEntries > 1)
381       report_fatal_error(
382           "C_STAT symbol should not have more than 1 auxiliary entry.");
383 
384     const XCOFFSectAuxEntForStat *StatAuxEntPtr;
385     StatAuxEntPtr =
386         reinterpret_cast<const XCOFFSectAuxEntForStat *>(SymbolEntPtr + 1);
387 #ifndef NDEBUG
388     Obj.checkSymbolEntryPointer(reinterpret_cast<uintptr_t>(StatAuxEntPtr));
389 #endif
390     printSectAuxEntForStat(StatAuxEntPtr);
391     break;
392   case XCOFF::C_DWARF:
393   case XCOFF::C_BLOCK:
394   case XCOFF::C_FCN:
395     report_fatal_error("Symbol table entry printing for this storage class "
396                        "type is unimplemented.");
397     break;
398   default:
399     for (int i = 1; i <= NumberOfAuxEntries; i++) {
400       W.startLine() << "!Unexpected raw auxiliary entry data:\n";
401       W.startLine() << format_bytes(
402           ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(SymbolEntPtr + i),
403                             XCOFF::SymbolTableEntrySize));
404     }
405     break;
406   }
407 }
408 
printSymbols()409 void XCOFFDumper::printSymbols() {
410   ListScope Group(W, "Symbols");
411   for (const SymbolRef &S : Obj.symbols())
412     printSymbol(S);
413 }
414 
printDynamicSymbols()415 void XCOFFDumper::printDynamicSymbols() {
416   llvm_unreachable("Unimplemented functionality for XCOFFDumper");
417 }
418 
printUnwindInfo()419 void XCOFFDumper::printUnwindInfo() {
420   llvm_unreachable("Unimplemented functionality for XCOFFDumper");
421 }
422 
printStackMap() const423 void XCOFFDumper::printStackMap() const {
424   llvm_unreachable("Unimplemented functionality for XCOFFDumper");
425 }
426 
printNeededLibraries()427 void XCOFFDumper::printNeededLibraries() {
428   llvm_unreachable("Unimplemented functionality for XCOFFDumper");
429 }
430 
431 static const EnumEntry<XCOFF::SectionTypeFlags> SectionTypeFlagsNames[] = {
432 #define ECase(X)                                                               \
433   { #X, XCOFF::X }
434     ECase(STYP_PAD),    ECase(STYP_DWARF), ECase(STYP_TEXT),
435     ECase(STYP_DATA),   ECase(STYP_BSS),   ECase(STYP_EXCEPT),
436     ECase(STYP_INFO),   ECase(STYP_TDATA), ECase(STYP_TBSS),
437     ECase(STYP_LOADER), ECase(STYP_DEBUG), ECase(STYP_TYPCHK),
438     ECase(STYP_OVRFLO)
439 #undef ECase
440 };
441 
442 template <typename T>
printOverflowSectionHeader(T & Sec) const443 void XCOFFDumper::printOverflowSectionHeader(T &Sec) const {
444   if (Obj.is64Bit()) {
445     reportWarning(make_error<StringError>("An 64-bit XCOFF object file may not "
446                                           "contain an overflow section header.",
447                                           object_error::parse_failed),
448                   Obj.getFileName());
449   }
450 
451   W.printString("Name", Sec.getName());
452   W.printNumber("NumberOfRelocations", Sec.PhysicalAddress);
453   W.printNumber("NumberOfLineNumbers", Sec.VirtualAddress);
454   W.printHex("Size", Sec.SectionSize);
455   W.printHex("RawDataOffset", Sec.FileOffsetToRawData);
456   W.printHex("RelocationPointer", Sec.FileOffsetToRelocationInfo);
457   W.printHex("LineNumberPointer", Sec.FileOffsetToLineNumberInfo);
458   W.printNumber("IndexOfSectionOverflowed", Sec.NumberOfRelocations);
459   W.printNumber("IndexOfSectionOverflowed", Sec.NumberOfLineNumbers);
460 }
461 
462 template <typename T>
printGenericSectionHeader(T & Sec) const463 void XCOFFDumper::printGenericSectionHeader(T &Sec) const {
464   W.printString("Name", Sec.getName());
465   W.printHex("PhysicalAddress", Sec.PhysicalAddress);
466   W.printHex("VirtualAddress", Sec.VirtualAddress);
467   W.printHex("Size", Sec.SectionSize);
468   W.printHex("RawDataOffset", Sec.FileOffsetToRawData);
469   W.printHex("RelocationPointer", Sec.FileOffsetToRelocationInfo);
470   W.printHex("LineNumberPointer", Sec.FileOffsetToLineNumberInfo);
471   W.printNumber("NumberOfRelocations", Sec.NumberOfRelocations);
472   W.printNumber("NumberOfLineNumbers", Sec.NumberOfLineNumbers);
473 }
474 
475 template <typename T>
printSectionHeaders(ArrayRef<T> Sections)476 void XCOFFDumper::printSectionHeaders(ArrayRef<T> Sections) {
477   ListScope Group(W, "Sections");
478 
479   uint16_t Index = 1;
480   for (const T &Sec : Sections) {
481     DictScope SecDS(W, "Section");
482 
483     W.printNumber("Index", Index++);
484     uint16_t SectionType = Sec.getSectionType();
485     switch (SectionType) {
486     case XCOFF::STYP_OVRFLO:
487       printOverflowSectionHeader(Sec);
488       break;
489     case XCOFF::STYP_LOADER:
490     case XCOFF::STYP_EXCEPT:
491     case XCOFF::STYP_TYPCHK:
492       // TODO The interpretation of loader, exception and type check section
493       // headers are different from that of generic section headers. We will
494       // implement them later. We interpret them as generic section headers for
495       // now.
496     default:
497       printGenericSectionHeader(Sec);
498       break;
499     }
500     if (Sec.isReservedSectionType())
501       W.printHex("Flags", "Reserved", SectionType);
502     else
503       W.printEnum("Type", SectionType, makeArrayRef(SectionTypeFlagsNames));
504   }
505 
506   if (opts::SectionRelocations)
507     report_fatal_error("Dumping section relocations is unimplemented");
508 
509   if (opts::SectionSymbols)
510     report_fatal_error("Dumping symbols is unimplemented");
511 
512   if (opts::SectionData)
513     report_fatal_error("Dumping section data is unimplemented");
514 }
515 
516 namespace llvm {
517 std::unique_ptr<ObjDumper>
createXCOFFDumper(const object::XCOFFObjectFile & XObj,ScopedPrinter & Writer)518 createXCOFFDumper(const object::XCOFFObjectFile &XObj, ScopedPrinter &Writer) {
519   return std::make_unique<XCOFFDumper>(XObj, Writer);
520 }
521 } // namespace llvm
522