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