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