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