xref: /freebsd-src/contrib/llvm-project/llvm/tools/llvm-readobj/XCOFFDumper.cpp (revision 4824e7fd18a1223177218d4aec1b3c6c5c4a444e)
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/FormattedStream.h"
17 #include "llvm/Support/ScopedPrinter.h"
18 
19 #include <stddef.h>
20 
21 using namespace llvm;
22 using namespace object;
23 
24 namespace {
25 
26 class XCOFFDumper : public ObjDumper {
27 
28 public:
29   XCOFFDumper(const XCOFFObjectFile &Obj, ScopedPrinter &Writer)
30       : ObjDumper(Writer, Obj.getFileName()), Obj(Obj) {}
31 
32   void printFileHeaders() override;
33   void printAuxiliaryHeader() override;
34   void printSectionHeaders() override;
35   void printRelocations() override;
36   void printSymbols() override;
37   void printDynamicSymbols() override;
38   void printUnwindInfo() override;
39   void printStackMap() const override;
40   void printNeededLibraries() override;
41   void printStringTable() override;
42 
43 private:
44   template <typename T> void printSectionHeaders(ArrayRef<T> Sections);
45   template <typename T> void printGenericSectionHeader(T &Sec) const;
46   template <typename T> void printOverflowSectionHeader(T &Sec) const;
47   void printFileAuxEnt(const XCOFFFileAuxEnt *AuxEntPtr);
48   void printCsectAuxEnt(XCOFFCsectAuxRef AuxEntRef);
49   void printSectAuxEntForStat(const XCOFFSectAuxEntForStat *AuxEntPtr);
50   void printSymbol(const SymbolRef &);
51   template <typename RelTy> void printRelocation(RelTy Reloc);
52   template <typename Shdr, typename RelTy>
53   void printRelocations(ArrayRef<Shdr> Sections);
54   void printAuxiliaryHeader(const XCOFFAuxiliaryHeader32 *AuxHeader);
55   void printAuxiliaryHeader(const XCOFFAuxiliaryHeader64 *AuxHeader);
56   const XCOFFObjectFile &Obj;
57 };
58 } // anonymous namespace
59 
60 void XCOFFDumper::printFileHeaders() {
61   DictScope DS(W, "FileHeader");
62   W.printHex("Magic", Obj.getMagic());
63   W.printNumber("NumberOfSections", Obj.getNumberOfSections());
64 
65   // Negative timestamp values are reserved for future use.
66   int32_t TimeStamp = Obj.getTimeStamp();
67   if (TimeStamp > 0) {
68     // This handling of the time stamp assumes that the host system's time_t is
69     // compatible with AIX time_t. If a platform is not compatible, the lit
70     // tests will let us know.
71     time_t TimeDate = TimeStamp;
72 
73     char FormattedTime[21] = {};
74     size_t BytesWritten =
75         strftime(FormattedTime, 21, "%Y-%m-%dT%H:%M:%SZ", gmtime(&TimeDate));
76     if (BytesWritten)
77       W.printHex("TimeStamp", FormattedTime, TimeStamp);
78     else
79       W.printHex("Timestamp", TimeStamp);
80   } else {
81     W.printHex("TimeStamp", TimeStamp == 0 ? "None" : "Reserved Value",
82                TimeStamp);
83   }
84 
85   // The number of symbol table entries is an unsigned value in 64-bit objects
86   // and a signed value (with negative values being 'reserved') in 32-bit
87   // objects.
88   if (Obj.is64Bit()) {
89     W.printHex("SymbolTableOffset", Obj.getSymbolTableOffset64());
90     W.printNumber("SymbolTableEntries", Obj.getNumberOfSymbolTableEntries64());
91   } else {
92     W.printHex("SymbolTableOffset", Obj.getSymbolTableOffset32());
93     int32_t SymTabEntries = Obj.getRawNumberOfSymbolTableEntries32();
94     if (SymTabEntries >= 0)
95       W.printNumber("SymbolTableEntries", SymTabEntries);
96     else
97       W.printHex("SymbolTableEntries", "Reserved Value", SymTabEntries);
98   }
99 
100   W.printHex("OptionalHeaderSize", Obj.getOptionalHeaderSize());
101   W.printHex("Flags", Obj.getFlags());
102 
103   // TODO FIXME Add support for the auxiliary header (if any) once
104   // XCOFFObjectFile has the necessary support.
105 }
106 
107 void XCOFFDumper::printAuxiliaryHeader() {
108   if (Obj.is64Bit())
109     printAuxiliaryHeader(Obj.auxiliaryHeader64());
110   else
111     printAuxiliaryHeader(Obj.auxiliaryHeader32());
112 }
113 
114 void XCOFFDumper::printSectionHeaders() {
115   if (Obj.is64Bit())
116     printSectionHeaders(Obj.sections64());
117   else
118     printSectionHeaders(Obj.sections32());
119 }
120 
121 void XCOFFDumper::printRelocations() {
122   if (Obj.is64Bit())
123     printRelocations<XCOFFSectionHeader64, XCOFFRelocation64>(Obj.sections64());
124   else
125     printRelocations<XCOFFSectionHeader32, XCOFFRelocation32>(Obj.sections32());
126 }
127 
128 const EnumEntry<XCOFF::RelocationType> RelocationTypeNameclass[] = {
129 #define ECase(X)                                                               \
130   { #X, XCOFF::X }
131     ECase(R_POS),    ECase(R_RL),     ECase(R_RLA),    ECase(R_NEG),
132     ECase(R_REL),    ECase(R_TOC),    ECase(R_TRL),    ECase(R_TRLA),
133     ECase(R_GL),     ECase(R_TCL),    ECase(R_REF),    ECase(R_BA),
134     ECase(R_BR),     ECase(R_RBA),    ECase(R_RBR),    ECase(R_TLS),
135     ECase(R_TLS_IE), ECase(R_TLS_LD), ECase(R_TLS_LE), ECase(R_TLSM),
136     ECase(R_TLSML),  ECase(R_TOCU),   ECase(R_TOCL)
137 #undef ECase
138 };
139 
140 template <typename RelTy> void XCOFFDumper::printRelocation(RelTy Reloc) {
141   Expected<StringRef> ErrOrSymbolName =
142       Obj.getSymbolNameByIndex(Reloc.SymbolIndex);
143   if (Error E = ErrOrSymbolName.takeError()) {
144     reportUniqueWarning(std::move(E));
145     return;
146   }
147   StringRef SymbolName = *ErrOrSymbolName;
148   StringRef RelocName = XCOFF::getRelocationTypeString(Reloc.Type);
149   if (opts::ExpandRelocs) {
150     DictScope Group(W, "Relocation");
151     W.printHex("Virtual Address", Reloc.VirtualAddress);
152     W.printNumber("Symbol", SymbolName, Reloc.SymbolIndex);
153     W.printString("IsSigned", Reloc.isRelocationSigned() ? "Yes" : "No");
154     W.printNumber("FixupBitValue", Reloc.isFixupIndicated() ? 1 : 0);
155     W.printNumber("Length", Reloc.getRelocatedLength());
156     W.printEnum("Type", (uint8_t)Reloc.Type,
157                 makeArrayRef(RelocationTypeNameclass));
158   } else {
159     raw_ostream &OS = W.startLine();
160     OS << W.hex(Reloc.VirtualAddress) << " " << RelocName << " " << SymbolName
161        << "(" << Reloc.SymbolIndex << ") " << W.hex(Reloc.Info) << "\n";
162   }
163 }
164 
165 template <typename Shdr, typename RelTy>
166 void XCOFFDumper::printRelocations(ArrayRef<Shdr> Sections) {
167   ListScope LS(W, "Relocations");
168   uint16_t Index = 0;
169   for (const Shdr &Sec : Sections) {
170     ++Index;
171     // Only the .text, .data, .tdata, and STYP_DWARF sections have relocation.
172     if (Sec.Flags != XCOFF::STYP_TEXT && Sec.Flags != XCOFF::STYP_DATA &&
173         Sec.Flags != XCOFF::STYP_TDATA && Sec.Flags != XCOFF::STYP_DWARF)
174       continue;
175     Expected<ArrayRef<RelTy>> ErrOrRelocations = Obj.relocations<Shdr, RelTy>(Sec);
176     if (Error E = ErrOrRelocations.takeError()) {
177       reportUniqueWarning(std::move(E));
178       continue;
179     }
180 
181     const ArrayRef<RelTy> Relocations = *ErrOrRelocations;
182     if (Relocations.empty())
183       continue;
184 
185     W.startLine() << "Section (index: " << Index << ") " << Sec.getName()
186                   << " {\n";
187     W.indent();
188 
189     for (const RelTy Reloc : Relocations)
190       printRelocation(Reloc);
191 
192     W.unindent();
193     W.startLine() << "}\n";
194   }
195 }
196 
197 const EnumEntry<XCOFF::CFileStringType> FileStringType[] = {
198 #define ECase(X)                                                               \
199   { #X, XCOFF::X }
200     ECase(XFT_FN), ECase(XFT_CT), ECase(XFT_CV), ECase(XFT_CD)
201 #undef ECase
202 };
203 
204 const EnumEntry<XCOFF::SymbolAuxType> SymAuxType[] = {
205 #define ECase(X)                                                               \
206   { #X, XCOFF::X }
207     ECase(AUX_EXCEPT), ECase(AUX_FCN), ECase(AUX_SYM), ECase(AUX_FILE),
208     ECase(AUX_CSECT),  ECase(AUX_SECT)
209 #undef ECase
210 };
211 
212 void XCOFFDumper::printFileAuxEnt(const XCOFFFileAuxEnt *AuxEntPtr) {
213   assert((!Obj.is64Bit() || AuxEntPtr->AuxType == XCOFF::AUX_FILE) &&
214          "Mismatched auxiliary type!");
215   StringRef FileName =
216       unwrapOrError(Obj.getFileName(), Obj.getCFileName(AuxEntPtr));
217   DictScope SymDs(W, "File Auxiliary Entry");
218   W.printNumber("Index",
219                 Obj.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr)));
220   W.printString("Name", FileName);
221   W.printEnum("Type", static_cast<uint8_t>(AuxEntPtr->Type),
222               makeArrayRef(FileStringType));
223   if (Obj.is64Bit()) {
224     W.printEnum("Auxiliary Type", static_cast<uint8_t>(AuxEntPtr->AuxType),
225                 makeArrayRef(SymAuxType));
226   }
227 }
228 
229 static const EnumEntry<XCOFF::StorageMappingClass> CsectStorageMappingClass[] =
230     {
231 #define ECase(X)                                                               \
232   { #X, XCOFF::X }
233         ECase(XMC_PR), ECase(XMC_RO), ECase(XMC_DB),   ECase(XMC_GL),
234         ECase(XMC_XO), ECase(XMC_SV), ECase(XMC_SV64), ECase(XMC_SV3264),
235         ECase(XMC_TI), ECase(XMC_TB), ECase(XMC_RW),   ECase(XMC_TC0),
236         ECase(XMC_TC), ECase(XMC_TD), ECase(XMC_DS),   ECase(XMC_UA),
237         ECase(XMC_BS), ECase(XMC_UC), ECase(XMC_TL),   ECase(XMC_UL),
238         ECase(XMC_TE)
239 #undef ECase
240 };
241 
242 const EnumEntry<XCOFF::SymbolType> CsectSymbolTypeClass[] = {
243 #define ECase(X)                                                               \
244   { #X, XCOFF::X }
245     ECase(XTY_ER), ECase(XTY_SD), ECase(XTY_LD), ECase(XTY_CM)
246 #undef ECase
247 };
248 
249 void XCOFFDumper::printCsectAuxEnt(XCOFFCsectAuxRef AuxEntRef) {
250   assert((!Obj.is64Bit() || AuxEntRef.getAuxType64() == XCOFF::AUX_CSECT) &&
251          "Mismatched auxiliary type!");
252 
253   DictScope SymDs(W, "CSECT Auxiliary Entry");
254   W.printNumber("Index", Obj.getSymbolIndex(AuxEntRef.getEntryAddress()));
255   W.printNumber(AuxEntRef.isLabel() ? "ContainingCsectSymbolIndex"
256                                     : "SectionLen",
257                 AuxEntRef.getSectionOrLength());
258   W.printHex("ParameterHashIndex", AuxEntRef.getParameterHashIndex());
259   W.printHex("TypeChkSectNum", AuxEntRef.getTypeChkSectNum());
260   // Print out symbol alignment and type.
261   W.printNumber("SymbolAlignmentLog2", AuxEntRef.getAlignmentLog2());
262   W.printEnum("SymbolType", AuxEntRef.getSymbolType(),
263               makeArrayRef(CsectSymbolTypeClass));
264   W.printEnum("StorageMappingClass",
265               static_cast<uint8_t>(AuxEntRef.getStorageMappingClass()),
266               makeArrayRef(CsectStorageMappingClass));
267 
268   if (Obj.is64Bit()) {
269     W.printEnum("Auxiliary Type", static_cast<uint8_t>(XCOFF::AUX_CSECT),
270                 makeArrayRef(SymAuxType));
271   } else {
272     W.printHex("StabInfoIndex", AuxEntRef.getStabInfoIndex32());
273     W.printHex("StabSectNum", AuxEntRef.getStabSectNum32());
274   }
275 }
276 
277 void XCOFFDumper::printSectAuxEntForStat(
278     const XCOFFSectAuxEntForStat *AuxEntPtr) {
279   assert(!Obj.is64Bit() && "32-bit interface called on 64-bit object file.");
280 
281   DictScope SymDs(W, "Sect Auxiliary Entry For Stat");
282   W.printNumber("Index",
283                 Obj.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr)));
284   W.printNumber("SectionLength", AuxEntPtr->SectionLength);
285 
286   // Unlike the corresponding fields in the section header, NumberOfRelocEnt
287   // and NumberOfLineNum do not handle values greater than 65535.
288   W.printNumber("NumberOfRelocEnt", AuxEntPtr->NumberOfRelocEnt);
289   W.printNumber("NumberOfLineNum", AuxEntPtr->NumberOfLineNum);
290 }
291 
292 const EnumEntry<XCOFF::StorageClass> SymStorageClass[] = {
293 #define ECase(X)                                                               \
294   { #X, XCOFF::X }
295     ECase(C_NULL),  ECase(C_AUTO),    ECase(C_EXT),     ECase(C_STAT),
296     ECase(C_REG),   ECase(C_EXTDEF),  ECase(C_LABEL),   ECase(C_ULABEL),
297     ECase(C_MOS),   ECase(C_ARG),     ECase(C_STRTAG),  ECase(C_MOU),
298     ECase(C_UNTAG), ECase(C_TPDEF),   ECase(C_USTATIC), ECase(C_ENTAG),
299     ECase(C_MOE),   ECase(C_REGPARM), ECase(C_FIELD),   ECase(C_BLOCK),
300     ECase(C_FCN),   ECase(C_EOS),     ECase(C_FILE),    ECase(C_LINE),
301     ECase(C_ALIAS), ECase(C_HIDDEN),  ECase(C_HIDEXT),  ECase(C_BINCL),
302     ECase(C_EINCL), ECase(C_INFO),    ECase(C_WEAKEXT), ECase(C_DWARF),
303     ECase(C_GSYM),  ECase(C_LSYM),    ECase(C_PSYM),    ECase(C_RSYM),
304     ECase(C_RPSYM), ECase(C_STSYM),   ECase(C_TCSYM),   ECase(C_BCOMM),
305     ECase(C_ECOML), ECase(C_ECOMM),   ECase(C_DECL),    ECase(C_ENTRY),
306     ECase(C_FUN),   ECase(C_BSTAT),   ECase(C_ESTAT),   ECase(C_GTLS),
307     ECase(C_STTLS), ECase(C_EFCN)
308 #undef ECase
309 };
310 
311 static StringRef GetSymbolValueName(XCOFF::StorageClass SC) {
312   switch (SC) {
313   case XCOFF::C_EXT:
314   case XCOFF::C_WEAKEXT:
315   case XCOFF::C_HIDEXT:
316   case XCOFF::C_STAT:
317     return "Value (RelocatableAddress)";
318   case XCOFF::C_FILE:
319     return "Value (SymbolTableIndex)";
320   case XCOFF::C_FCN:
321   case XCOFF::C_BLOCK:
322   case XCOFF::C_FUN:
323   case XCOFF::C_STSYM:
324   case XCOFF::C_BINCL:
325   case XCOFF::C_EINCL:
326   case XCOFF::C_INFO:
327   case XCOFF::C_BSTAT:
328   case XCOFF::C_LSYM:
329   case XCOFF::C_PSYM:
330   case XCOFF::C_RPSYM:
331   case XCOFF::C_RSYM:
332   case XCOFF::C_ECOML:
333   case XCOFF::C_DWARF:
334     assert(false && "This StorageClass for the symbol is not yet implemented.");
335     return "";
336   default:
337     return "Value";
338   }
339 }
340 
341 const EnumEntry<XCOFF::CFileLangId> CFileLangIdClass[] = {
342 #define ECase(X)                                                               \
343   { #X, XCOFF::X }
344     ECase(TB_C), ECase(TB_CPLUSPLUS)
345 #undef ECase
346 };
347 
348 const EnumEntry<XCOFF::CFileCpuId> CFileCpuIdClass[] = {
349 #define ECase(X)                                                               \
350   { #X, XCOFF::X }
351     ECase(TCPU_PPC64), ECase(TCPU_COM), ECase(TCPU_970)
352 #undef ECase
353 };
354 
355 void XCOFFDumper::printSymbol(const SymbolRef &S) {
356   DataRefImpl SymbolDRI = S.getRawDataRefImpl();
357   XCOFFSymbolRef SymbolEntRef = Obj.toSymbolRef(SymbolDRI);
358 
359   uint8_t NumberOfAuxEntries = SymbolEntRef.getNumberOfAuxEntries();
360 
361   DictScope SymDs(W, "Symbol");
362 
363   StringRef SymbolName =
364       unwrapOrError(Obj.getFileName(), SymbolEntRef.getName());
365 
366   W.printNumber("Index", Obj.getSymbolIndex(SymbolEntRef.getEntryAddress()));
367   W.printString("Name", SymbolName);
368   W.printHex(GetSymbolValueName(SymbolEntRef.getStorageClass()),
369              SymbolEntRef.getValue());
370 
371   StringRef SectionName =
372       unwrapOrError(Obj.getFileName(), Obj.getSymbolSectionName(SymbolEntRef));
373 
374   W.printString("Section", SectionName);
375   if (SymbolEntRef.getStorageClass() == XCOFF::C_FILE) {
376     W.printEnum("Source Language ID", SymbolEntRef.getLanguageIdForCFile(),
377                 makeArrayRef(CFileLangIdClass));
378     W.printEnum("CPU Version ID", SymbolEntRef.getCPUTypeIddForCFile(),
379                 makeArrayRef(CFileCpuIdClass));
380   } else
381     W.printHex("Type", SymbolEntRef.getSymbolType());
382 
383   W.printEnum("StorageClass",
384               static_cast<uint8_t>(SymbolEntRef.getStorageClass()),
385               makeArrayRef(SymStorageClass));
386   W.printNumber("NumberOfAuxEntries", NumberOfAuxEntries);
387 
388   if (NumberOfAuxEntries == 0)
389     return;
390 
391   switch (SymbolEntRef.getStorageClass()) {
392   case XCOFF::C_FILE:
393     // If the symbol is C_FILE and has auxiliary entries...
394     for (int I = 1; I <= NumberOfAuxEntries; I++) {
395       uintptr_t AuxAddress = XCOFFObjectFile::getAdvancedSymbolEntryAddress(
396           SymbolEntRef.getEntryAddress(), I);
397 
398       if (Obj.is64Bit() &&
399           *Obj.getSymbolAuxType(AuxAddress) != XCOFF::SymbolAuxType::AUX_FILE) {
400         W.startLine() << "!Unexpected raw auxiliary entry data:\n";
401         W.startLine() << format_bytes(
402                              ArrayRef<uint8_t>(
403                                  reinterpret_cast<const uint8_t *>(AuxAddress),
404                                  XCOFF::SymbolTableEntrySize),
405                              0, XCOFF::SymbolTableEntrySize)
406                       << "\n";
407         continue;
408       }
409 
410       const XCOFFFileAuxEnt *FileAuxEntPtr =
411           reinterpret_cast<const XCOFFFileAuxEnt *>(AuxAddress);
412 #ifndef NDEBUG
413       Obj.checkSymbolEntryPointer(reinterpret_cast<uintptr_t>(FileAuxEntPtr));
414 #endif
415       printFileAuxEnt(FileAuxEntPtr);
416     }
417     break;
418   case XCOFF::C_EXT:
419   case XCOFF::C_WEAKEXT:
420   case XCOFF::C_HIDEXT: {
421     // If the symbol is for a function, and it has more than 1 auxiliary entry,
422     // then one of them must be function auxiliary entry which we do not
423     // support yet.
424     if (SymbolEntRef.isFunction() && NumberOfAuxEntries >= 2)
425       report_fatal_error("Function auxiliary entry printing is unimplemented.");
426 
427     // If there is more than 1 auxiliary entry, instead of printing out
428     // error information, print out the raw Auxiliary entry.
429     // For 32-bit object, print from first to the last - 1. The last one must be
430     // a CSECT Auxiliary Entry.
431     // For 64-bit object, print from first to last and skips if SymbolAuxType is
432     // AUX_CSECT.
433     for (int I = 1; I <= NumberOfAuxEntries; I++) {
434       if (I == NumberOfAuxEntries && !Obj.is64Bit())
435         break;
436 
437       uintptr_t AuxAddress = XCOFFObjectFile::getAdvancedSymbolEntryAddress(
438           SymbolEntRef.getEntryAddress(), I);
439       if (Obj.is64Bit() &&
440           *Obj.getSymbolAuxType(AuxAddress) == XCOFF::SymbolAuxType::AUX_CSECT)
441         continue;
442 
443       W.startLine() << "!Unexpected raw auxiliary entry data:\n";
444       W.startLine() << format_bytes(
445           ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(AuxAddress),
446                             XCOFF::SymbolTableEntrySize));
447     }
448 
449     auto ErrOrCsectAuxRef = SymbolEntRef.getXCOFFCsectAuxRef();
450     if (!ErrOrCsectAuxRef)
451       reportUniqueWarning(ErrOrCsectAuxRef.takeError());
452     else
453       printCsectAuxEnt(*ErrOrCsectAuxRef);
454 
455     break;
456   }
457   case XCOFF::C_STAT:
458     if (NumberOfAuxEntries > 1)
459       report_fatal_error(
460           "C_STAT symbol should not have more than 1 auxiliary entry.");
461 
462     const XCOFFSectAuxEntForStat *StatAuxEntPtr;
463     StatAuxEntPtr = reinterpret_cast<const XCOFFSectAuxEntForStat *>(
464         XCOFFObjectFile::getAdvancedSymbolEntryAddress(
465             SymbolEntRef.getEntryAddress(), 1));
466 #ifndef NDEBUG
467     Obj.checkSymbolEntryPointer(reinterpret_cast<uintptr_t>(StatAuxEntPtr));
468 #endif
469     printSectAuxEntForStat(StatAuxEntPtr);
470     break;
471   case XCOFF::C_DWARF:
472   case XCOFF::C_BLOCK:
473   case XCOFF::C_FCN:
474     report_fatal_error("Symbol table entry printing for this storage class "
475                        "type is unimplemented.");
476     break;
477   default:
478     for (int i = 1; i <= NumberOfAuxEntries; i++) {
479       W.startLine() << "!Unexpected raw auxiliary entry data:\n";
480       W.startLine() << format_bytes(
481           ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(
482                                 XCOFFObjectFile::getAdvancedSymbolEntryAddress(
483                                     SymbolEntRef.getEntryAddress(), i)),
484                             XCOFF::SymbolTableEntrySize));
485     }
486     break;
487   }
488 }
489 
490 void XCOFFDumper::printSymbols() {
491   ListScope Group(W, "Symbols");
492   for (const SymbolRef &S : Obj.symbols())
493     printSymbol(S);
494 }
495 
496 void XCOFFDumper::printStringTable() {
497   DictScope DS(W, "StringTable");
498   StringRef StrTable = Obj.getStringTable();
499   uint32_t StrTabSize = StrTable.size();
500   W.printNumber("Length", StrTabSize);
501   // Print strings from the fifth byte, since the first four bytes contain the
502   // length (in bytes) of the string table (including the length field).
503   if (StrTabSize > 4)
504     printAsStringList(StrTable, 4);
505 }
506 
507 void XCOFFDumper::printDynamicSymbols() {
508   llvm_unreachable("Unimplemented functionality for XCOFFDumper");
509 }
510 
511 void XCOFFDumper::printUnwindInfo() {
512   llvm_unreachable("Unimplemented functionality for XCOFFDumper");
513 }
514 
515 void XCOFFDumper::printStackMap() const {
516   llvm_unreachable("Unimplemented functionality for XCOFFDumper");
517 }
518 
519 void XCOFFDumper::printNeededLibraries() {
520   ListScope D(W, "NeededLibraries");
521   auto ImportFilesOrError = Obj.getImportFileTable();
522   if (!ImportFilesOrError) {
523     reportUniqueWarning(ImportFilesOrError.takeError());
524     return;
525   }
526 
527   StringRef ImportFileTable = ImportFilesOrError.get();
528   const char *CurrentStr = ImportFileTable.data();
529   const char *TableEnd = ImportFileTable.end();
530   // Default column width for names is 13 even if no names are that long.
531   size_t BaseWidth = 13;
532 
533   // Get the max width of BASE columns.
534   for (size_t StrIndex = 0; CurrentStr < TableEnd; ++StrIndex) {
535     size_t CurrentLen = strlen(CurrentStr);
536     CurrentStr += strlen(CurrentStr) + 1;
537     if (StrIndex % 3 == 1)
538       BaseWidth = std::max(BaseWidth, CurrentLen);
539   }
540 
541   auto &OS = static_cast<formatted_raw_ostream &>(W.startLine());
542   // Each entry consists of 3 strings: the path_name, base_name and
543   // archive_member_name. The first entry is a default LIBPATH value and other
544   // entries have no path_name. We just dump the base_name and
545   // archive_member_name here.
546   OS << left_justify("BASE", BaseWidth)  << " MEMBER\n";
547   CurrentStr = ImportFileTable.data();
548   for (size_t StrIndex = 0; CurrentStr < TableEnd;
549        ++StrIndex, CurrentStr += strlen(CurrentStr) + 1) {
550     if (StrIndex >= 3 && StrIndex % 3 != 0) {
551       if (StrIndex % 3 == 1)
552         OS << "  " << left_justify(CurrentStr, BaseWidth) << " ";
553       else
554         OS << CurrentStr << "\n";
555     }
556   }
557 }
558 
559 const EnumEntry<XCOFF::SectionTypeFlags> SectionTypeFlagsNames[] = {
560 #define ECase(X)                                                               \
561   { #X, XCOFF::X }
562     ECase(STYP_PAD),    ECase(STYP_DWARF), ECase(STYP_TEXT),
563     ECase(STYP_DATA),   ECase(STYP_BSS),   ECase(STYP_EXCEPT),
564     ECase(STYP_INFO),   ECase(STYP_TDATA), ECase(STYP_TBSS),
565     ECase(STYP_LOADER), ECase(STYP_DEBUG), ECase(STYP_TYPCHK),
566     ECase(STYP_OVRFLO)
567 #undef ECase
568 };
569 
570 template <typename T>
571 void XCOFFDumper::printOverflowSectionHeader(T &Sec) const {
572   if (Obj.is64Bit()) {
573     reportWarning(make_error<StringError>("An 64-bit XCOFF object file may not "
574                                           "contain an overflow section header.",
575                                           object_error::parse_failed),
576                   Obj.getFileName());
577   }
578 
579   W.printString("Name", Sec.getName());
580   W.printNumber("NumberOfRelocations", Sec.PhysicalAddress);
581   W.printNumber("NumberOfLineNumbers", Sec.VirtualAddress);
582   W.printHex("Size", Sec.SectionSize);
583   W.printHex("RawDataOffset", Sec.FileOffsetToRawData);
584   W.printHex("RelocationPointer", Sec.FileOffsetToRelocationInfo);
585   W.printHex("LineNumberPointer", Sec.FileOffsetToLineNumberInfo);
586   W.printNumber("IndexOfSectionOverflowed", Sec.NumberOfRelocations);
587   W.printNumber("IndexOfSectionOverflowed", Sec.NumberOfLineNumbers);
588 }
589 
590 template <typename T>
591 void XCOFFDumper::printGenericSectionHeader(T &Sec) const {
592   W.printString("Name", Sec.getName());
593   W.printHex("PhysicalAddress", Sec.PhysicalAddress);
594   W.printHex("VirtualAddress", Sec.VirtualAddress);
595   W.printHex("Size", Sec.SectionSize);
596   W.printHex("RawDataOffset", Sec.FileOffsetToRawData);
597   W.printHex("RelocationPointer", Sec.FileOffsetToRelocationInfo);
598   W.printHex("LineNumberPointer", Sec.FileOffsetToLineNumberInfo);
599   W.printNumber("NumberOfRelocations", Sec.NumberOfRelocations);
600   W.printNumber("NumberOfLineNumbers", Sec.NumberOfLineNumbers);
601 }
602 
603 void XCOFFDumper::printAuxiliaryHeader(
604     const XCOFFAuxiliaryHeader32 *AuxHeader) {
605   if (AuxHeader == nullptr)
606     return;
607   uint16_t AuxSize = Obj.getOptionalHeaderSize();
608   uint16_t PartialFieldOffset = AuxSize;
609   const char *PartialFieldName = nullptr;
610 
611   DictScope DS(W, "AuxiliaryHeader");
612 
613 #define PrintAuxMember32(H, S, T)                                              \
614   if (offsetof(XCOFFAuxiliaryHeader32, T) +                                    \
615           sizeof(XCOFFAuxiliaryHeader32::T) <=                                 \
616       AuxSize)                                                                 \
617     W.print##H(S, AuxHeader->T);                                               \
618   else if (offsetof(XCOFFAuxiliaryHeader32, T) < AuxSize) {                    \
619     PartialFieldOffset = offsetof(XCOFFAuxiliaryHeader32, T);                  \
620     PartialFieldName = S;                                                      \
621   }
622 
623   PrintAuxMember32(Hex, "Magic", AuxMagic);
624   PrintAuxMember32(Hex, "Version", Version);
625   PrintAuxMember32(Hex, "Size of .text section", TextSize);
626   PrintAuxMember32(Hex, "Size of .data section", InitDataSize);
627   PrintAuxMember32(Hex, "Size of .bss section", BssDataSize);
628   PrintAuxMember32(Hex, "Entry point address", EntryPointAddr);
629   PrintAuxMember32(Hex, ".text section start address", TextStartAddr);
630   PrintAuxMember32(Hex, ".data section start address", DataStartAddr);
631   PrintAuxMember32(Hex, "TOC anchor address", TOCAnchorAddr);
632   PrintAuxMember32(Number, "Section number of entryPoint", SecNumOfEntryPoint);
633   PrintAuxMember32(Number, "Section number of .text", SecNumOfText);
634   PrintAuxMember32(Number, "Section number of .data", SecNumOfData);
635   PrintAuxMember32(Number, "Section number of TOC", SecNumOfTOC);
636   PrintAuxMember32(Number, "Section number of loader data", SecNumOfLoader);
637   PrintAuxMember32(Number, "Section number of .bss", SecNumOfBSS);
638   PrintAuxMember32(Hex, "Maxium alignment of .text", MaxAlignOfText);
639   PrintAuxMember32(Hex, "Maxium alignment of .data", MaxAlignOfData);
640   PrintAuxMember32(Hex, "Module type", ModuleType);
641   PrintAuxMember32(Hex, "CPU type of objects", CpuFlag);
642   PrintAuxMember32(Hex, "(Reserved)", CpuType);
643   PrintAuxMember32(Hex, "Maximum stack size", MaxStackSize);
644   PrintAuxMember32(Hex, "Maximum data size", MaxDataSize);
645   PrintAuxMember32(Hex, "Reserved for debugger", ReservedForDebugger);
646   PrintAuxMember32(Hex, "Text page size", TextPageSize);
647   PrintAuxMember32(Hex, "Data page size", DataPageSize);
648   PrintAuxMember32(Hex, "Stack page size", StackPageSize);
649   if (offsetof(XCOFFAuxiliaryHeader32, FlagAndTDataAlignment) +
650           sizeof(XCOFFAuxiliaryHeader32::FlagAndTDataAlignment) <=
651       AuxSize) {
652     W.printHex("Flag", AuxHeader->getFlag());
653     W.printHex("Alignment of thread-local storage",
654                AuxHeader->getTDataAlignment());
655   }
656 
657   PrintAuxMember32(Number, "Section number for .tdata", SecNumOfTData);
658   PrintAuxMember32(Number, "Section number for .tbss", SecNumOfTBSS);
659 
660   // Deal with error.
661   if (PartialFieldOffset < AuxSize) {
662     std::string ErrInfo;
663     llvm::raw_string_ostream StringOS(ErrInfo);
664     StringOS << "Only partial field for " << PartialFieldName << " at offset ("
665              << PartialFieldOffset << ").";
666     StringOS.flush();
667     reportWarning(
668         make_error<GenericBinaryError>(ErrInfo, object_error::parse_failed),
669         "-");
670     W.printBinary(
671         "Raw data", "",
672         ArrayRef<uint8_t>((const uint8_t *)(AuxHeader) + PartialFieldOffset,
673                           AuxSize - PartialFieldOffset));
674   } else if (sizeof(XCOFFAuxiliaryHeader32) < AuxSize) {
675     reportWarning(make_error<GenericBinaryError>(
676                       "There are extra data beyond auxiliary header",
677                       object_error::parse_failed),
678                   "-");
679     W.printBinary("Extra raw data", "",
680                   ArrayRef<uint8_t>((const uint8_t *)(AuxHeader) +
681                                         sizeof(XCOFFAuxiliaryHeader32),
682                                     AuxSize - sizeof(XCOFFAuxiliaryHeader32)));
683   }
684 
685 #undef PrintAuxMember32
686 }
687 
688 void XCOFFDumper::printAuxiliaryHeader(
689     const XCOFFAuxiliaryHeader64 *AuxHeader) {
690   if (AuxHeader == nullptr)
691     return;
692   uint16_t AuxSize = Obj.getOptionalHeaderSize();
693   uint16_t PartialFieldOffset = AuxSize;
694   const char *PartialFieldName = nullptr;
695 
696   DictScope DS(W, "AuxiliaryHeader");
697 
698 #define PrintAuxMember64(H, S, T)                                              \
699   if (offsetof(XCOFFAuxiliaryHeader64, T) +                                    \
700           sizeof(XCOFFAuxiliaryHeader64::T) <=                                 \
701       AuxSize)                                                                 \
702     W.print##H(S, AuxHeader->T);                                               \
703   else if (offsetof(XCOFFAuxiliaryHeader64, T) < AuxSize) {                    \
704     PartialFieldOffset = offsetof(XCOFFAuxiliaryHeader64, T);                  \
705     PartialFieldName = S;                                                      \
706   }
707 
708   PrintAuxMember64(Hex, "Magic", AuxMagic);
709   PrintAuxMember64(Hex, "Version", Version);
710   PrintAuxMember64(Hex, "Reserved for debugger", ReservedForDebugger);
711   PrintAuxMember64(Hex, ".text section start address", TextStartAddr);
712   PrintAuxMember64(Hex, ".data section start address", DataStartAddr);
713   PrintAuxMember64(Hex, "TOC anchor address", TOCAnchorAddr);
714   PrintAuxMember64(Number, "Section number of entryPoint", SecNumOfEntryPoint);
715   PrintAuxMember64(Number, "Section number of .text", SecNumOfText);
716   PrintAuxMember64(Number, "Section number of .data", SecNumOfData);
717   PrintAuxMember64(Number, "Section number of TOC", SecNumOfTOC);
718   PrintAuxMember64(Number, "Section number of loader data", SecNumOfLoader);
719   PrintAuxMember64(Number, "Section number of .bss", SecNumOfBSS);
720   PrintAuxMember64(Hex, "Maxium alignment of .text", MaxAlignOfText);
721   PrintAuxMember64(Hex, "Maxium alignment of .data", MaxAlignOfData);
722   PrintAuxMember64(Hex, "Module type", ModuleType);
723   PrintAuxMember64(Hex, "CPU type of objects", CpuFlag);
724   PrintAuxMember64(Hex, "(Reserved)", CpuType);
725   PrintAuxMember64(Hex, "Text page size", TextPageSize);
726   PrintAuxMember64(Hex, "Data page size", DataPageSize);
727   PrintAuxMember64(Hex, "Stack page size", StackPageSize);
728   if (offsetof(XCOFFAuxiliaryHeader64, FlagAndTDataAlignment) +
729           sizeof(XCOFFAuxiliaryHeader64::FlagAndTDataAlignment) <=
730       AuxSize) {
731     W.printHex("Flag", AuxHeader->getFlag());
732     W.printHex("Alignment of thread-local storage",
733                AuxHeader->getTDataAlignment());
734   }
735   PrintAuxMember64(Hex, "Size of .text section", TextSize);
736   PrintAuxMember64(Hex, "Size of .data section", InitDataSize);
737   PrintAuxMember64(Hex, "Size of .bss section", BssDataSize);
738   PrintAuxMember64(Hex, "Entry point address", EntryPointAddr);
739   PrintAuxMember64(Hex, "Maximum stack size", MaxStackSize);
740   PrintAuxMember64(Hex, "Maximum data size", MaxDataSize);
741   PrintAuxMember64(Number, "Section number for .tdata", SecNumOfTData);
742   PrintAuxMember64(Number, "Section number for .tbss", SecNumOfTBSS);
743   PrintAuxMember64(Hex, "Additional flags 64-bit XCOFF", XCOFF64Flag);
744 
745   if (PartialFieldOffset < AuxSize) {
746     std::string ErrInfo;
747     llvm::raw_string_ostream StringOS(ErrInfo);
748     StringOS << "Only partial field for " << PartialFieldName << " at offset ("
749              << PartialFieldOffset << ").";
750     StringOS.flush();
751     reportWarning(
752         make_error<GenericBinaryError>(ErrInfo, object_error::parse_failed),
753         "-");
754     ;
755     W.printBinary(
756         "Raw data", "",
757         ArrayRef<uint8_t>((const uint8_t *)(AuxHeader) + PartialFieldOffset,
758                           AuxSize - PartialFieldOffset));
759   } else if (sizeof(XCOFFAuxiliaryHeader64) < AuxSize) {
760     reportWarning(make_error<GenericBinaryError>(
761                       "There are extra data beyond auxiliary header",
762                       object_error::parse_failed),
763                   "-");
764     W.printBinary("Extra raw data", "",
765                   ArrayRef<uint8_t>((const uint8_t *)(AuxHeader) +
766                                         sizeof(XCOFFAuxiliaryHeader64),
767                                     AuxSize - sizeof(XCOFFAuxiliaryHeader64)));
768   }
769 
770 #undef PrintAuxMember64
771 }
772 
773 template <typename T>
774 void XCOFFDumper::printSectionHeaders(ArrayRef<T> Sections) {
775   ListScope Group(W, "Sections");
776 
777   uint16_t Index = 1;
778   for (const T &Sec : Sections) {
779     DictScope SecDS(W, "Section");
780 
781     W.printNumber("Index", Index++);
782     uint16_t SectionType = Sec.getSectionType();
783     switch (SectionType) {
784     case XCOFF::STYP_OVRFLO:
785       printOverflowSectionHeader(Sec);
786       break;
787     case XCOFF::STYP_LOADER:
788     case XCOFF::STYP_EXCEPT:
789     case XCOFF::STYP_TYPCHK:
790       // TODO The interpretation of loader, exception and type check section
791       // headers are different from that of generic section headers. We will
792       // implement them later. We interpret them as generic section headers for
793       // now.
794     default:
795       printGenericSectionHeader(Sec);
796       break;
797     }
798     if (Sec.isReservedSectionType())
799       W.printHex("Flags", "Reserved", SectionType);
800     else
801       W.printEnum("Type", SectionType, makeArrayRef(SectionTypeFlagsNames));
802   }
803 
804   if (opts::SectionRelocations)
805     report_fatal_error("Dumping section relocations is unimplemented");
806 
807   if (opts::SectionSymbols)
808     report_fatal_error("Dumping symbols is unimplemented");
809 
810   if (opts::SectionData)
811     report_fatal_error("Dumping section data is unimplemented");
812 }
813 
814 namespace llvm {
815 std::unique_ptr<ObjDumper>
816 createXCOFFDumper(const object::XCOFFObjectFile &XObj, ScopedPrinter &Writer) {
817   return std::make_unique<XCOFFDumper>(XObj, Writer);
818 }
819 } // namespace llvm
820