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 <ctime>
20 
21 using namespace llvm;
22 using namespace object;
23 
24 namespace {
25 
26 class XCOFFDumper : public ObjDumper {
27 
28 public:
XCOFFDumper(const XCOFFObjectFile & Obj,ScopedPrinter & Writer)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(bool ExtraSymInfo) override;
37   void printDynamicSymbols() override;
38   void printUnwindInfo() override;
39   void printStackMap() const override;
40   void printNeededLibraries() override;
41   void printStringTable() override;
42   void printExceptionSection() override;
43   void printLoaderSection(bool PrintHeader, bool PrintSymbols,
44                           bool PrintRelocations) override;
45 
getScopedPrinter() const46   ScopedPrinter &getScopedPrinter() const { return W; }
47 
48 private:
49   template <typename T> void printSectionHeaders(ArrayRef<T> Sections);
50   template <typename T> void printGenericSectionHeader(T &Sec) const;
51   template <typename T> void printOverflowSectionHeader(T &Sec) const;
52   template <typename T>
53   void printExceptionSectionEntry(const T &ExceptionSectEnt) const;
54   template <typename T> void printExceptionSectionEntries() const;
55   template <typename T> const T *getAuxEntPtr(uintptr_t AuxAddress);
56   void printFileAuxEnt(const XCOFFFileAuxEnt *AuxEntPtr);
57   void printCsectAuxEnt(XCOFFCsectAuxRef AuxEntRef);
58   void printSectAuxEntForStat(const XCOFFSectAuxEntForStat *AuxEntPtr);
59   void printExceptionAuxEnt(const XCOFFExceptionAuxEnt *AuxEntPtr);
60   void printFunctionAuxEnt(const XCOFFFunctionAuxEnt32 *AuxEntPtr);
61   void printFunctionAuxEnt(const XCOFFFunctionAuxEnt64 *AuxEntPtr);
62   void printBlockAuxEnt(const XCOFFBlockAuxEnt32 *AuxEntPtr);
63   void printBlockAuxEnt(const XCOFFBlockAuxEnt64 *AuxEntPtr);
64   template <typename T> void printSectAuxEntForDWARF(const T *AuxEntPtr);
65   void printSymbol(const SymbolRef &);
66   template <typename RelTy> void printRelocation(RelTy Reloc);
67   template <typename Shdr, typename RelTy>
68   void printRelocations(ArrayRef<Shdr> Sections);
69   void printAuxiliaryHeader(const XCOFFAuxiliaryHeader32 *AuxHeader);
70   void printAuxiliaryHeader(const XCOFFAuxiliaryHeader64 *AuxHeader);
71   void printLoaderSectionHeader(uintptr_t LoaderSectAddr);
72   void printLoaderSectionSymbols(uintptr_t LoaderSectAddr);
73   template <typename LoaderSectionSymbolEntry, typename LoaderSectionHeader>
74   void printLoaderSectionSymbolsHelper(uintptr_t LoaderSectAddr);
75   template <typename LoadSectionRelocTy>
76   void printLoaderSectionRelocationEntry(LoadSectionRelocTy *LoaderSecRelEntPtr,
77                                          StringRef SymbolName);
78   void printLoaderSectionRelocationEntries(uintptr_t LoaderSectAddr);
79   template <typename LoaderSectionHeader, typename LoaderSectionSymbolEntry,
80             typename LoaderSectionRelocationEntry>
81   void printLoaderSectionRelocationEntriesHelper(uintptr_t LoaderSectAddr);
82 
83   const XCOFFObjectFile &Obj;
84   const static int32_t FirstSymIdxOfLoaderSec = 3;
85 };
86 } // anonymous namespace
87 
printFileHeaders()88 void XCOFFDumper::printFileHeaders() {
89   DictScope DS(W, "FileHeader");
90   W.printHex("Magic", Obj.getMagic());
91   W.printNumber("NumberOfSections", Obj.getNumberOfSections());
92 
93   // Negative timestamp values are reserved for future use.
94   int32_t TimeStamp = Obj.getTimeStamp();
95   if (TimeStamp > 0) {
96     // This handling of the time stamp assumes that the host system's time_t is
97     // compatible with AIX time_t. If a platform is not compatible, the lit
98     // tests will let us know.
99     time_t TimeDate = TimeStamp;
100 
101     char FormattedTime[80] = {};
102 
103     size_t BytesFormatted =
104       strftime(FormattedTime, sizeof(FormattedTime), "%F %T", gmtime(&TimeDate));
105     if (BytesFormatted)
106       W.printHex("TimeStamp", FormattedTime, TimeStamp);
107     else
108       W.printHex("Timestamp", TimeStamp);
109   } else {
110     W.printHex("TimeStamp", TimeStamp == 0 ? "None" : "Reserved Value",
111                TimeStamp);
112   }
113 
114   // The number of symbol table entries is an unsigned value in 64-bit objects
115   // and a signed value (with negative values being 'reserved') in 32-bit
116   // objects.
117   if (Obj.is64Bit()) {
118     W.printHex("SymbolTableOffset", Obj.getSymbolTableOffset64());
119     W.printNumber("SymbolTableEntries", Obj.getNumberOfSymbolTableEntries64());
120   } else {
121     W.printHex("SymbolTableOffset", Obj.getSymbolTableOffset32());
122     int32_t SymTabEntries = Obj.getRawNumberOfSymbolTableEntries32();
123     if (SymTabEntries >= 0)
124       W.printNumber("SymbolTableEntries", SymTabEntries);
125     else
126       W.printHex("SymbolTableEntries", "Reserved Value", SymTabEntries);
127   }
128 
129   W.printHex("OptionalHeaderSize", Obj.getOptionalHeaderSize());
130   W.printHex("Flags", Obj.getFlags());
131 
132   // TODO FIXME Add support for the auxiliary header (if any) once
133   // XCOFFObjectFile has the necessary support.
134 }
135 
printAuxiliaryHeader()136 void XCOFFDumper::printAuxiliaryHeader() {
137   DictScope DS(W, "AuxiliaryHeader");
138 
139   if (Obj.is64Bit())
140     printAuxiliaryHeader(Obj.auxiliaryHeader64());
141   else
142     printAuxiliaryHeader(Obj.auxiliaryHeader32());
143 }
144 
printSectionHeaders()145 void XCOFFDumper::printSectionHeaders() {
146   if (Obj.is64Bit())
147     printSectionHeaders(Obj.sections64());
148   else
149     printSectionHeaders(Obj.sections32());
150 }
151 
printLoaderSection(bool PrintHeader,bool PrintSymbols,bool PrintRelocations)152 void XCOFFDumper::printLoaderSection(bool PrintHeader, bool PrintSymbols,
153                                      bool PrintRelocations) {
154   DictScope DS(W, "Loader Section");
155   Expected<uintptr_t> LoaderSectionAddrOrError =
156       Obj.getSectionFileOffsetToRawData(XCOFF::STYP_LOADER);
157   if (!LoaderSectionAddrOrError) {
158     reportUniqueWarning(LoaderSectionAddrOrError.takeError());
159     return;
160   }
161   uintptr_t LoaderSectionAddr = LoaderSectionAddrOrError.get();
162 
163   if (LoaderSectionAddr == 0)
164     return;
165 
166   W.indent();
167   if (PrintHeader)
168     printLoaderSectionHeader(LoaderSectionAddr);
169 
170   if (PrintSymbols)
171     printLoaderSectionSymbols(LoaderSectionAddr);
172 
173   if (PrintRelocations)
174     printLoaderSectionRelocationEntries(LoaderSectionAddr);
175 
176   W.unindent();
177 }
178 
printLoaderSectionHeader(uintptr_t LoaderSectionAddr)179 void XCOFFDumper::printLoaderSectionHeader(uintptr_t LoaderSectionAddr) {
180   DictScope DS(W, "Loader Section Header");
181 
182   auto PrintLoadSecHeaderCommon = [&](const auto *LDHeader) {
183     W.printNumber("Version", LDHeader->Version);
184     W.printNumber("NumberOfSymbolEntries", LDHeader->NumberOfSymTabEnt);
185     W.printNumber("NumberOfRelocationEntries", LDHeader->NumberOfRelTabEnt);
186     W.printNumber("LengthOfImportFileIDStringTable",
187                   LDHeader->LengthOfImpidStrTbl);
188     W.printNumber("NumberOfImportFileIDs", LDHeader->NumberOfImpid);
189     W.printHex("OffsetToImportFileIDs", LDHeader->OffsetToImpid);
190     W.printNumber("LengthOfStringTable", LDHeader->LengthOfStrTbl);
191     W.printHex("OffsetToStringTable", LDHeader->OffsetToStrTbl);
192   };
193 
194   if (Obj.is64Bit()) {
195     const LoaderSectionHeader64 *LoaderSec64 =
196         reinterpret_cast<const LoaderSectionHeader64 *>(LoaderSectionAddr);
197     PrintLoadSecHeaderCommon(LoaderSec64);
198     W.printHex("OffsetToSymbolTable", LoaderSec64->OffsetToSymTbl);
199     W.printHex("OffsetToRelocationEntries", LoaderSec64->OffsetToRelEnt);
200   } else {
201     const LoaderSectionHeader32 *LoaderSec32 =
202         reinterpret_cast<const LoaderSectionHeader32 *>(LoaderSectionAddr);
203     PrintLoadSecHeaderCommon(LoaderSec32);
204   }
205 }
206 
207 const EnumEntry<XCOFF::StorageClass> SymStorageClass[] = {
208 #define ECase(X)                                                               \
209   { #X, XCOFF::X }
210     ECase(C_NULL),  ECase(C_AUTO),    ECase(C_EXT),     ECase(C_STAT),
211     ECase(C_REG),   ECase(C_EXTDEF),  ECase(C_LABEL),   ECase(C_ULABEL),
212     ECase(C_MOS),   ECase(C_ARG),     ECase(C_STRTAG),  ECase(C_MOU),
213     ECase(C_UNTAG), ECase(C_TPDEF),   ECase(C_USTATIC), ECase(C_ENTAG),
214     ECase(C_MOE),   ECase(C_REGPARM), ECase(C_FIELD),   ECase(C_BLOCK),
215     ECase(C_FCN),   ECase(C_EOS),     ECase(C_FILE),    ECase(C_LINE),
216     ECase(C_ALIAS), ECase(C_HIDDEN),  ECase(C_HIDEXT),  ECase(C_BINCL),
217     ECase(C_EINCL), ECase(C_INFO),    ECase(C_WEAKEXT), ECase(C_DWARF),
218     ECase(C_GSYM),  ECase(C_LSYM),    ECase(C_PSYM),    ECase(C_RSYM),
219     ECase(C_RPSYM), ECase(C_STSYM),   ECase(C_TCSYM),   ECase(C_BCOMM),
220     ECase(C_ECOML), ECase(C_ECOMM),   ECase(C_DECL),    ECase(C_ENTRY),
221     ECase(C_FUN),   ECase(C_BSTAT),   ECase(C_ESTAT),   ECase(C_GTLS),
222     ECase(C_STTLS), ECase(C_EFCN)
223 #undef ECase
224 };
225 
226 template <typename LoaderSectionSymbolEntry, typename LoaderSectionHeader>
printLoaderSectionSymbolsHelper(uintptr_t LoaderSectionAddr)227 void XCOFFDumper::printLoaderSectionSymbolsHelper(uintptr_t LoaderSectionAddr) {
228   const LoaderSectionHeader *LoadSecHeader =
229       reinterpret_cast<const LoaderSectionHeader *>(LoaderSectionAddr);
230   const LoaderSectionSymbolEntry *LoadSecSymEntPtr =
231       reinterpret_cast<LoaderSectionSymbolEntry *>(
232           LoaderSectionAddr + uintptr_t(LoadSecHeader->getOffsetToSymTbl()));
233 
234   for (uint32_t i = 0; i < LoadSecHeader->NumberOfSymTabEnt;
235        ++i, ++LoadSecSymEntPtr) {
236     if (Error E = Binary::checkOffset(
237             Obj.getMemoryBufferRef(),
238             LoaderSectionAddr + uintptr_t(LoadSecHeader->getOffsetToSymTbl()) +
239                 (i * sizeof(LoaderSectionSymbolEntry)),
240             sizeof(LoaderSectionSymbolEntry))) {
241       reportUniqueWarning(std::move(E));
242       return;
243     }
244 
245     Expected<StringRef> SymbolNameOrErr =
246         LoadSecSymEntPtr->getSymbolName(LoadSecHeader);
247     if (!SymbolNameOrErr) {
248       reportUniqueWarning(SymbolNameOrErr.takeError());
249       return;
250     }
251 
252     DictScope DS(W, "Symbol");
253     W.printString("Name", SymbolNameOrErr.get());
254     W.printHex("Virtual Address", LoadSecSymEntPtr->Value);
255     W.printNumber("SectionNum", LoadSecSymEntPtr->SectionNumber);
256     W.printHex("SymbolType", LoadSecSymEntPtr->SymbolType);
257     W.printEnum("StorageClass",
258                 static_cast<uint8_t>(LoadSecSymEntPtr->StorageClass),
259                 ArrayRef(SymStorageClass));
260     W.printHex("ImportFileID", LoadSecSymEntPtr->ImportFileID);
261     W.printNumber("ParameterTypeCheck", LoadSecSymEntPtr->ParameterTypeCheck);
262   }
263 }
264 
printLoaderSectionSymbols(uintptr_t LoaderSectionAddr)265 void XCOFFDumper::printLoaderSectionSymbols(uintptr_t LoaderSectionAddr) {
266   DictScope DS(W, "Loader Section Symbols");
267   if (Obj.is64Bit())
268     printLoaderSectionSymbolsHelper<LoaderSectionSymbolEntry64,
269                                     LoaderSectionHeader64>(LoaderSectionAddr);
270   else
271     printLoaderSectionSymbolsHelper<LoaderSectionSymbolEntry32,
272                                     LoaderSectionHeader32>(LoaderSectionAddr);
273 }
274 
275 const EnumEntry<XCOFF::RelocationType> RelocationTypeNameclass[] = {
276 #define ECase(X)                                                               \
277   { #X, XCOFF::X }
278     ECase(R_POS),    ECase(R_RL),     ECase(R_RLA),    ECase(R_NEG),
279     ECase(R_REL),    ECase(R_TOC),    ECase(R_TRL),    ECase(R_TRLA),
280     ECase(R_GL),     ECase(R_TCL),    ECase(R_REF),    ECase(R_BA),
281     ECase(R_BR),     ECase(R_RBA),    ECase(R_RBR),    ECase(R_TLS),
282     ECase(R_TLS_IE), ECase(R_TLS_LD), ECase(R_TLS_LE), ECase(R_TLSM),
283     ECase(R_TLSML),  ECase(R_TOCU),   ECase(R_TOCL)
284 #undef ECase
285 };
286 
287 // From the XCOFF specification: there are five implicit external symbols, one
288 // each for the .text, .data, .bss, .tdata, and .tbss sections. These symbols
289 // are referenced from the relocation table entries using symbol table index
290 // values 0, 1, 2, -1, and -2, respectively.
getImplicitLoaderSectionSymName(int SymIndx)291 static const char *getImplicitLoaderSectionSymName(int SymIndx) {
292   switch (SymIndx) {
293   default:
294     return "Unkown Symbol Name";
295   case -2:
296     return ".tbss";
297   case -1:
298     return ".tdata";
299   case 0:
300     return ".text";
301   case 1:
302     return ".data";
303   case 2:
304     return ".bss";
305   }
306 }
307 
308 template <typename LoadSectionRelocTy>
printLoaderSectionRelocationEntry(LoadSectionRelocTy * LoaderSecRelEntPtr,StringRef SymbolName)309 void XCOFFDumper::printLoaderSectionRelocationEntry(
310     LoadSectionRelocTy *LoaderSecRelEntPtr, StringRef SymbolName) {
311   uint16_t Type = LoaderSecRelEntPtr->Type;
312   if (opts::ExpandRelocs) {
313     DictScope DS(W, "Relocation");
314     auto IsRelocationSigned = [](uint8_t Info) {
315       return Info & XCOFF::XR_SIGN_INDICATOR_MASK;
316     };
317     auto IsFixupIndicated = [](uint8_t Info) {
318       return Info & XCOFF::XR_FIXUP_INDICATOR_MASK;
319     };
320     auto GetRelocatedLength = [](uint8_t Info) {
321       // The relocation encodes the bit length being relocated minus 1. Add
322       // back
323       //   the 1 to get the actual length being relocated.
324       return (Info & XCOFF::XR_BIASED_LENGTH_MASK) + 1;
325     };
326 
327     uint8_t Info = Type >> 8;
328     W.printHex("Virtual Address", LoaderSecRelEntPtr->VirtualAddr);
329     W.printNumber("Symbol", SymbolName, LoaderSecRelEntPtr->SymbolIndex);
330     W.printString("IsSigned", IsRelocationSigned(Info) ? "Yes" : "No");
331     W.printNumber("FixupBitValue", IsFixupIndicated(Info) ? 1 : 0);
332     W.printNumber("Length", GetRelocatedLength(Info));
333     W.printEnum("Type", static_cast<uint8_t>(Type),
334                 ArrayRef(RelocationTypeNameclass));
335     W.printNumber("SectionNumber", LoaderSecRelEntPtr->SectionNum);
336   } else {
337     W.startLine() << format_hex(LoaderSecRelEntPtr->VirtualAddr,
338                                 Obj.is64Bit() ? 18 : 10)
339                   << " " << format_hex(Type, 6) << " ("
340                   << XCOFF::getRelocationTypeString(
341                          static_cast<XCOFF::RelocationType>(Type))
342                   << ")" << format_decimal(LoaderSecRelEntPtr->SectionNum, 8)
343                   << "    " << SymbolName << " ("
344                   << LoaderSecRelEntPtr->SymbolIndex << ")\n";
345   }
346 }
347 
348 template <typename LoaderSectionHeader, typename LoaderSectionSymbolEntry,
349           typename LoaderSectionRelocationEntry>
printLoaderSectionRelocationEntriesHelper(uintptr_t LoaderSectionAddr)350 void XCOFFDumper::printLoaderSectionRelocationEntriesHelper(
351     uintptr_t LoaderSectionAddr) {
352   const LoaderSectionHeader *LoaderSec =
353       reinterpret_cast<const LoaderSectionHeader *>(LoaderSectionAddr);
354   const LoaderSectionRelocationEntry *LoaderSecRelEntPtr =
355       reinterpret_cast<const LoaderSectionRelocationEntry *>(
356           LoaderSectionAddr + uintptr_t(LoaderSec->getOffsetToRelEnt()));
357 
358   if (!opts::ExpandRelocs)
359     W.startLine() << center_justify("Vaddr", Obj.is64Bit() ? 18 : 10)
360                   << center_justify("Type", 15) << right_justify("SecNum", 8)
361                   << center_justify("SymbolName (Index) ", 24) << "\n";
362 
363   for (uint32_t i = 0; i < LoaderSec->NumberOfRelTabEnt;
364        ++i, ++LoaderSecRelEntPtr) {
365     StringRef SymbolName;
366     if (LoaderSecRelEntPtr->SymbolIndex >= FirstSymIdxOfLoaderSec) {
367       // Because there are implicit symbol index values (-2, -1, 0, 1, 2),
368       // LoaderSecRelEnt.SymbolIndex - FirstSymIdxOfLoaderSec will get the
369       // real symbol from the symbol table.
370       const uint64_t SymOffset =
371           (LoaderSecRelEntPtr->SymbolIndex - FirstSymIdxOfLoaderSec) *
372           sizeof(LoaderSectionSymbolEntry);
373       const LoaderSectionSymbolEntry *LoaderSecRelSymEntPtr =
374           reinterpret_cast<LoaderSectionSymbolEntry *>(
375               LoaderSectionAddr + uintptr_t(LoaderSec->getOffsetToSymTbl()) +
376               SymOffset);
377 
378       Expected<StringRef> SymbolNameOrErr =
379           LoaderSecRelSymEntPtr->getSymbolName(LoaderSec);
380       if (!SymbolNameOrErr) {
381         reportUniqueWarning(SymbolNameOrErr.takeError());
382         return;
383       }
384       SymbolName = SymbolNameOrErr.get();
385     } else
386       SymbolName =
387           getImplicitLoaderSectionSymName(LoaderSecRelEntPtr->SymbolIndex);
388 
389     printLoaderSectionRelocationEntry(LoaderSecRelEntPtr, SymbolName);
390   }
391 }
392 
printLoaderSectionRelocationEntries(uintptr_t LoaderSectionAddr)393 void XCOFFDumper::printLoaderSectionRelocationEntries(
394     uintptr_t LoaderSectionAddr) {
395   DictScope DS(W, "Loader Section Relocations");
396 
397   if (Obj.is64Bit())
398     printLoaderSectionRelocationEntriesHelper<LoaderSectionHeader64,
399                                               LoaderSectionSymbolEntry64,
400                                               LoaderSectionRelocationEntry64>(
401         LoaderSectionAddr);
402   else
403     printLoaderSectionRelocationEntriesHelper<LoaderSectionHeader32,
404                                               LoaderSectionSymbolEntry32,
405                                               LoaderSectionRelocationEntry32>(
406         LoaderSectionAddr);
407 }
408 
409 template <typename T>
printExceptionSectionEntry(const T & ExceptionSectEnt) const410 void XCOFFDumper::printExceptionSectionEntry(const T &ExceptionSectEnt) const {
411   if (ExceptionSectEnt.getReason())
412     W.printHex("Trap Instr Addr", ExceptionSectEnt.getTrapInstAddr());
413   else {
414     uint32_t SymIdx = ExceptionSectEnt.getSymbolIndex();
415     Expected<StringRef> ErrOrSymbolName = Obj.getSymbolNameByIndex(SymIdx);
416     if (Error E = ErrOrSymbolName.takeError()) {
417       reportUniqueWarning(std::move(E));
418       return;
419     }
420     StringRef SymName = *ErrOrSymbolName;
421 
422     W.printNumber("Symbol", SymName, SymIdx);
423   }
424   W.printNumber("LangID", ExceptionSectEnt.getLangID());
425   W.printNumber("Reason", ExceptionSectEnt.getReason());
426 }
427 
printExceptionSectionEntries() const428 template <typename T> void XCOFFDumper::printExceptionSectionEntries() const {
429   Expected<ArrayRef<T>> ExceptSectEntsOrErr = Obj.getExceptionEntries<T>();
430   if (Error E = ExceptSectEntsOrErr.takeError()) {
431     reportUniqueWarning(std::move(E));
432     return;
433   }
434   ArrayRef<T> ExceptSectEnts = *ExceptSectEntsOrErr;
435 
436   DictScope DS(W, "Exception section");
437   if (ExceptSectEnts.empty())
438     return;
439   for (auto &Ent : ExceptSectEnts)
440     printExceptionSectionEntry(Ent);
441 }
442 
printExceptionSection()443 void XCOFFDumper::printExceptionSection() {
444   if (Obj.is64Bit())
445     printExceptionSectionEntries<ExceptionSectionEntry64>();
446   else
447     printExceptionSectionEntries<ExceptionSectionEntry32>();
448 }
449 
printRelocations()450 void XCOFFDumper::printRelocations() {
451   if (Obj.is64Bit())
452     printRelocations<XCOFFSectionHeader64, XCOFFRelocation64>(Obj.sections64());
453   else
454     printRelocations<XCOFFSectionHeader32, XCOFFRelocation32>(Obj.sections32());
455 }
456 
printRelocation(RelTy Reloc)457 template <typename RelTy> void XCOFFDumper::printRelocation(RelTy Reloc) {
458   Expected<StringRef> ErrOrSymbolName =
459       Obj.getSymbolNameByIndex(Reloc.SymbolIndex);
460   if (Error E = ErrOrSymbolName.takeError()) {
461     reportUniqueWarning(std::move(E));
462     return;
463   }
464   StringRef SymbolName = *ErrOrSymbolName;
465   StringRef RelocName = XCOFF::getRelocationTypeString(Reloc.Type);
466   if (opts::ExpandRelocs) {
467     DictScope Group(W, "Relocation");
468     W.printHex("Virtual Address", Reloc.VirtualAddress);
469     W.printNumber("Symbol", SymbolName, Reloc.SymbolIndex);
470     W.printString("IsSigned", Reloc.isRelocationSigned() ? "Yes" : "No");
471     W.printNumber("FixupBitValue", Reloc.isFixupIndicated() ? 1 : 0);
472     W.printNumber("Length", Reloc.getRelocatedLength());
473     W.printEnum("Type", (uint8_t)Reloc.Type, ArrayRef(RelocationTypeNameclass));
474   } else {
475     raw_ostream &OS = W.startLine();
476     OS << W.hex(Reloc.VirtualAddress) << " " << RelocName << " " << SymbolName
477        << "(" << Reloc.SymbolIndex << ") " << W.hex(Reloc.Info) << "\n";
478   }
479 }
480 
481 template <typename Shdr, typename RelTy>
printRelocations(ArrayRef<Shdr> Sections)482 void XCOFFDumper::printRelocations(ArrayRef<Shdr> Sections) {
483   ListScope LS(W, "Relocations");
484   uint16_t Index = 0;
485   for (const Shdr &Sec : Sections) {
486     ++Index;
487     // Only the .text, .data, .tdata, and STYP_DWARF sections have relocation.
488     if (Sec.Flags != XCOFF::STYP_TEXT && Sec.Flags != XCOFF::STYP_DATA &&
489         Sec.Flags != XCOFF::STYP_TDATA && Sec.Flags != XCOFF::STYP_DWARF)
490       continue;
491     Expected<ArrayRef<RelTy>> ErrOrRelocations = Obj.relocations<Shdr, RelTy>(Sec);
492     if (Error E = ErrOrRelocations.takeError()) {
493       reportUniqueWarning(std::move(E));
494       continue;
495     }
496 
497     const ArrayRef<RelTy> Relocations = *ErrOrRelocations;
498     if (Relocations.empty())
499       continue;
500 
501     W.startLine() << "Section (index: " << Index << ") " << Sec.getName()
502                   << " {\n";
503     W.indent();
504 
505     for (const RelTy Reloc : Relocations)
506       printRelocation(Reloc);
507 
508     W.unindent();
509     W.startLine() << "}\n";
510   }
511 }
512 
513 const EnumEntry<XCOFF::CFileStringType> FileStringType[] = {
514 #define ECase(X)                                                               \
515   { #X, XCOFF::X }
516     ECase(XFT_FN), ECase(XFT_CT), ECase(XFT_CV), ECase(XFT_CD)
517 #undef ECase
518 };
519 
520 const EnumEntry<XCOFF::SymbolAuxType> SymAuxType[] = {
521 #define ECase(X)                                                               \
522   { #X, XCOFF::X }
523     ECase(AUX_EXCEPT), ECase(AUX_FCN), ECase(AUX_SYM), ECase(AUX_FILE),
524     ECase(AUX_CSECT),  ECase(AUX_SECT)
525 #undef ECase
526 };
527 
printFileAuxEnt(const XCOFFFileAuxEnt * AuxEntPtr)528 void XCOFFDumper::printFileAuxEnt(const XCOFFFileAuxEnt *AuxEntPtr) {
529   assert((!Obj.is64Bit() || AuxEntPtr->AuxType == XCOFF::AUX_FILE) &&
530          "Mismatched auxiliary type!");
531   StringRef FileName =
532       unwrapOrError(Obj.getFileName(), Obj.getCFileName(AuxEntPtr));
533   DictScope SymDs(W, "File Auxiliary Entry");
534   W.printNumber("Index",
535                 Obj.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr)));
536   W.printString("Name", FileName);
537   W.printEnum("Type", static_cast<uint8_t>(AuxEntPtr->Type),
538               ArrayRef(FileStringType));
539   if (Obj.is64Bit()) {
540     W.printEnum("Auxiliary Type", static_cast<uint8_t>(AuxEntPtr->AuxType),
541                 ArrayRef(SymAuxType));
542   }
543 }
544 
545 static const EnumEntry<XCOFF::StorageMappingClass> CsectStorageMappingClass[] =
546     {
547 #define ECase(X)                                                               \
548   { #X, XCOFF::X }
549         ECase(XMC_PR), ECase(XMC_RO), ECase(XMC_DB),   ECase(XMC_GL),
550         ECase(XMC_XO), ECase(XMC_SV), ECase(XMC_SV64), ECase(XMC_SV3264),
551         ECase(XMC_TI), ECase(XMC_TB), ECase(XMC_RW),   ECase(XMC_TC0),
552         ECase(XMC_TC), ECase(XMC_TD), ECase(XMC_DS),   ECase(XMC_UA),
553         ECase(XMC_BS), ECase(XMC_UC), ECase(XMC_TL),   ECase(XMC_UL),
554         ECase(XMC_TE)
555 #undef ECase
556 };
557 
558 const EnumEntry<XCOFF::SymbolType> CsectSymbolTypeClass[] = {
559 #define ECase(X)                                                               \
560   { #X, XCOFF::X }
561     ECase(XTY_ER), ECase(XTY_SD), ECase(XTY_LD), ECase(XTY_CM)
562 #undef ECase
563 };
564 
printCsectAuxEnt(XCOFFCsectAuxRef AuxEntRef)565 void XCOFFDumper::printCsectAuxEnt(XCOFFCsectAuxRef AuxEntRef) {
566   assert((!Obj.is64Bit() || AuxEntRef.getAuxType64() == XCOFF::AUX_CSECT) &&
567          "Mismatched auxiliary type!");
568 
569   DictScope SymDs(W, "CSECT Auxiliary Entry");
570   W.printNumber("Index", Obj.getSymbolIndex(AuxEntRef.getEntryAddress()));
571   W.printNumber(AuxEntRef.isLabel() ? "ContainingCsectSymbolIndex"
572                                     : "SectionLen",
573                 AuxEntRef.getSectionOrLength());
574   W.printHex("ParameterHashIndex", AuxEntRef.getParameterHashIndex());
575   W.printHex("TypeChkSectNum", AuxEntRef.getTypeChkSectNum());
576   // Print out symbol alignment and type.
577   W.printNumber("SymbolAlignmentLog2", AuxEntRef.getAlignmentLog2());
578   W.printEnum("SymbolType", AuxEntRef.getSymbolType(),
579               ArrayRef(CsectSymbolTypeClass));
580   W.printEnum("StorageMappingClass",
581               static_cast<uint8_t>(AuxEntRef.getStorageMappingClass()),
582               ArrayRef(CsectStorageMappingClass));
583 
584   if (Obj.is64Bit()) {
585     W.printEnum("Auxiliary Type", static_cast<uint8_t>(XCOFF::AUX_CSECT),
586                 ArrayRef(SymAuxType));
587   } else {
588     W.printHex("StabInfoIndex", AuxEntRef.getStabInfoIndex32());
589     W.printHex("StabSectNum", AuxEntRef.getStabSectNum32());
590   }
591 }
592 
printSectAuxEntForStat(const XCOFFSectAuxEntForStat * AuxEntPtr)593 void XCOFFDumper::printSectAuxEntForStat(
594     const XCOFFSectAuxEntForStat *AuxEntPtr) {
595   assert(!Obj.is64Bit() && "32-bit interface called on 64-bit object file.");
596 
597   DictScope SymDs(W, "Sect Auxiliary Entry For Stat");
598   W.printNumber("Index",
599                 Obj.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr)));
600   W.printNumber("SectionLength", AuxEntPtr->SectionLength);
601 
602   // Unlike the corresponding fields in the section header, NumberOfRelocEnt
603   // and NumberOfLineNum do not handle values greater than 65535.
604   W.printNumber("NumberOfRelocEnt", AuxEntPtr->NumberOfRelocEnt);
605   W.printNumber("NumberOfLineNum", AuxEntPtr->NumberOfLineNum);
606 }
607 
printExceptionAuxEnt(const XCOFFExceptionAuxEnt * AuxEntPtr)608 void XCOFFDumper::printExceptionAuxEnt(const XCOFFExceptionAuxEnt *AuxEntPtr) {
609   assert(Obj.is64Bit() && "64-bit interface called on 32-bit object file.");
610 
611   DictScope SymDs(W, "Exception Auxiliary Entry");
612   W.printNumber("Index",
613                 Obj.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr)));
614   W.printHex("OffsetToExceptionTable", AuxEntPtr->OffsetToExceptionTbl);
615   W.printHex("SizeOfFunction", AuxEntPtr->SizeOfFunction);
616   W.printNumber("SymbolIndexOfNextBeyond", AuxEntPtr->SymIdxOfNextBeyond);
617   W.printEnum("Auxiliary Type", static_cast<uint8_t>(AuxEntPtr->AuxType),
618               ArrayRef(SymAuxType));
619 }
620 
printFunctionAuxEnt(const XCOFFFunctionAuxEnt32 * AuxEntPtr)621 void XCOFFDumper::printFunctionAuxEnt(const XCOFFFunctionAuxEnt32 *AuxEntPtr) {
622   assert(!Obj.is64Bit() && "32-bit interface called on 64-bit object file.");
623 
624   DictScope SymDs(W, "Function Auxiliary Entry");
625   W.printNumber("Index",
626                 Obj.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr)));
627   W.printHex("OffsetToExceptionTable", AuxEntPtr->OffsetToExceptionTbl);
628   W.printHex("SizeOfFunction", AuxEntPtr->SizeOfFunction);
629   W.printHex("PointerToLineNum", AuxEntPtr->PtrToLineNum);
630   W.printNumber("SymbolIndexOfNextBeyond", AuxEntPtr->SymIdxOfNextBeyond);
631 }
632 
printFunctionAuxEnt(const XCOFFFunctionAuxEnt64 * AuxEntPtr)633 void XCOFFDumper::printFunctionAuxEnt(const XCOFFFunctionAuxEnt64 *AuxEntPtr) {
634   assert(Obj.is64Bit() && "64-bit interface called on 32-bit object file.");
635 
636   DictScope SymDs(W, "Function Auxiliary Entry");
637   W.printNumber("Index",
638                 Obj.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr)));
639   W.printHex("SizeOfFunction", AuxEntPtr->SizeOfFunction);
640   W.printHex("PointerToLineNum", AuxEntPtr->PtrToLineNum);
641   W.printNumber("SymbolIndexOfNextBeyond", AuxEntPtr->SymIdxOfNextBeyond);
642   W.printEnum("Auxiliary Type", static_cast<uint8_t>(AuxEntPtr->AuxType),
643               ArrayRef(SymAuxType));
644 }
645 
printBlockAuxEnt(const XCOFFBlockAuxEnt32 * AuxEntPtr)646 void XCOFFDumper::printBlockAuxEnt(const XCOFFBlockAuxEnt32 *AuxEntPtr) {
647   assert(!Obj.is64Bit() && "32-bit interface called on 64-bit object file.");
648 
649   DictScope SymDs(W, "Block Auxiliary Entry");
650   W.printNumber("Index",
651                 Obj.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr)));
652   W.printHex("LineNumber (High 2 Bytes)", AuxEntPtr->LineNumHi);
653   W.printHex("LineNumber (Low 2 Bytes)", AuxEntPtr->LineNumLo);
654 }
655 
printBlockAuxEnt(const XCOFFBlockAuxEnt64 * AuxEntPtr)656 void XCOFFDumper::printBlockAuxEnt(const XCOFFBlockAuxEnt64 *AuxEntPtr) {
657   assert(Obj.is64Bit() && "64-bit interface called on 32-bit object file.");
658 
659   DictScope SymDs(W, "Block Auxiliary Entry");
660   W.printNumber("Index",
661                 Obj.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr)));
662   W.printHex("LineNumber", AuxEntPtr->LineNum);
663   W.printEnum("Auxiliary Type", static_cast<uint8_t>(AuxEntPtr->AuxType),
664               ArrayRef(SymAuxType));
665 }
666 
667 template <typename T>
printSectAuxEntForDWARF(const T * AuxEntPtr)668 void XCOFFDumper::printSectAuxEntForDWARF(const T *AuxEntPtr) {
669   DictScope SymDs(W, "Sect Auxiliary Entry For DWARF");
670   W.printNumber("Index",
671                 Obj.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr)));
672   W.printHex("LengthOfSectionPortion", AuxEntPtr->LengthOfSectionPortion);
673   W.printNumber("NumberOfRelocEntries", AuxEntPtr->NumberOfRelocEnt);
674   if (Obj.is64Bit())
675     W.printEnum("Auxiliary Type", static_cast<uint8_t>(XCOFF::AUX_SECT),
676                 ArrayRef(SymAuxType));
677 }
678 
GetSymbolValueName(XCOFF::StorageClass SC)679 static StringRef GetSymbolValueName(XCOFF::StorageClass SC) {
680   switch (SC) {
681   case XCOFF::C_EXT:
682   case XCOFF::C_WEAKEXT:
683   case XCOFF::C_HIDEXT:
684   case XCOFF::C_STAT:
685   case XCOFF::C_FCN:
686   case XCOFF::C_BLOCK:
687     return "Value (RelocatableAddress)";
688   case XCOFF::C_FILE:
689     return "Value (SymbolTableIndex)";
690   case XCOFF::C_DWARF:
691     return "Value (OffsetInDWARF)";
692   case XCOFF::C_FUN:
693   case XCOFF::C_STSYM:
694   case XCOFF::C_BINCL:
695   case XCOFF::C_EINCL:
696   case XCOFF::C_INFO:
697   case XCOFF::C_BSTAT:
698   case XCOFF::C_LSYM:
699   case XCOFF::C_PSYM:
700   case XCOFF::C_RPSYM:
701   case XCOFF::C_RSYM:
702   case XCOFF::C_ECOML:
703     assert(false && "This StorageClass for the symbol is not yet implemented.");
704     return "";
705   default:
706     return "Value";
707   }
708 }
709 
710 const EnumEntry<XCOFF::CFileLangId> CFileLangIdClass[] = {
711 #define ECase(X)                                                               \
712   { #X, XCOFF::X }
713     ECase(TB_C), ECase(TB_Fortran), ECase(TB_CPLUSPLUS)
714 #undef ECase
715 };
716 
717 const EnumEntry<XCOFF::CFileCpuId> CFileCpuIdClass[] = {
718 #define ECase(X)                                                               \
719   { #X, XCOFF::X }
720     ECase(TCPU_PPC64), ECase(TCPU_COM), ECase(TCPU_970)
721 #undef ECase
722 };
723 
getAuxEntPtr(uintptr_t AuxAddress)724 template <typename T> const T *XCOFFDumper::getAuxEntPtr(uintptr_t AuxAddress) {
725   const T *AuxEntPtr = reinterpret_cast<const T *>(AuxAddress);
726   Obj.checkSymbolEntryPointer(reinterpret_cast<uintptr_t>(AuxEntPtr));
727   return AuxEntPtr;
728 }
729 
printUnexpectedRawAuxEnt(ScopedPrinter & W,uintptr_t AuxAddress)730 static void printUnexpectedRawAuxEnt(ScopedPrinter &W, uintptr_t AuxAddress) {
731   W.startLine() << "!Unexpected raw auxiliary entry data:\n";
732   W.startLine() << format_bytes(
733                        ArrayRef<uint8_t>(
734                            reinterpret_cast<const uint8_t *>(AuxAddress),
735                            XCOFF::SymbolTableEntrySize),
736                        std::nullopt, XCOFF::SymbolTableEntrySize)
737                 << "\n";
738 }
739 
printSymbol(const SymbolRef & S)740 void XCOFFDumper::printSymbol(const SymbolRef &S) {
741   DataRefImpl SymbolDRI = S.getRawDataRefImpl();
742   XCOFFSymbolRef SymbolEntRef = Obj.toSymbolRef(SymbolDRI);
743 
744   uint8_t NumberOfAuxEntries = SymbolEntRef.getNumberOfAuxEntries();
745 
746   DictScope SymDs(W, "Symbol");
747 
748   StringRef SymbolName =
749       unwrapOrError(Obj.getFileName(), SymbolEntRef.getName());
750 
751   uint32_t SymbolIdx = Obj.getSymbolIndex(SymbolEntRef.getEntryAddress());
752   XCOFF::StorageClass SymbolClass = SymbolEntRef.getStorageClass();
753 
754   W.printNumber("Index", SymbolIdx);
755   W.printString("Name", SymbolName);
756   W.printHex(GetSymbolValueName(SymbolClass), SymbolEntRef.getValue());
757 
758   StringRef SectionName =
759       unwrapOrError(Obj.getFileName(), Obj.getSymbolSectionName(SymbolEntRef));
760 
761   W.printString("Section", SectionName);
762   if (SymbolClass == XCOFF::C_FILE) {
763     W.printEnum("Source Language ID", SymbolEntRef.getLanguageIdForCFile(),
764                 ArrayRef(CFileLangIdClass));
765     W.printEnum("CPU Version ID", SymbolEntRef.getCPUTypeIddForCFile(),
766                 ArrayRef(CFileCpuIdClass));
767   } else
768     W.printHex("Type", SymbolEntRef.getSymbolType());
769 
770   W.printEnum("StorageClass", static_cast<uint8_t>(SymbolClass),
771               ArrayRef(SymStorageClass));
772   W.printNumber("NumberOfAuxEntries", NumberOfAuxEntries);
773 
774   if (NumberOfAuxEntries == 0)
775     return;
776 
777   auto checkNumOfAux = [=] {
778     if (NumberOfAuxEntries > 1)
779       reportUniqueWarning("the " +
780                           enumToString(static_cast<uint8_t>(SymbolClass),
781                                        ArrayRef(SymStorageClass)) +
782                           " symbol at index " + Twine(SymbolIdx) +
783                           " should not have more than 1 "
784                           "auxiliary entry");
785   };
786 
787   switch (SymbolClass) {
788   case XCOFF::C_FILE:
789     // If the symbol is C_FILE and has auxiliary entries...
790     for (int I = 1; I <= NumberOfAuxEntries; I++) {
791       uintptr_t AuxAddress = XCOFFObjectFile::getAdvancedSymbolEntryAddress(
792           SymbolEntRef.getEntryAddress(), I);
793 
794       if (Obj.is64Bit() &&
795           *Obj.getSymbolAuxType(AuxAddress) != XCOFF::SymbolAuxType::AUX_FILE) {
796         printUnexpectedRawAuxEnt(W, AuxAddress);
797         continue;
798       }
799 
800       const XCOFFFileAuxEnt *FileAuxEntPtr =
801           getAuxEntPtr<XCOFFFileAuxEnt>(AuxAddress);
802       printFileAuxEnt(FileAuxEntPtr);
803     }
804     break;
805   case XCOFF::C_EXT:
806   case XCOFF::C_WEAKEXT:
807   case XCOFF::C_HIDEXT: {
808     // For 32-bit objects, print the function auxiliary symbol table entry. The
809     // last one must be a CSECT auxiliary entry.
810     // For 64-bit objects, both a function auxiliary entry and an exception
811     // auxiliary entry may appear, print them in the loop and skip printing the
812     // CSECT auxiliary entry, which will be printed outside the loop.
813     for (int I = 1; I <= NumberOfAuxEntries; I++) {
814       if (I == NumberOfAuxEntries && !Obj.is64Bit())
815         break;
816 
817       uintptr_t AuxAddress = XCOFFObjectFile::getAdvancedSymbolEntryAddress(
818           SymbolEntRef.getEntryAddress(), I);
819 
820       if (Obj.is64Bit()) {
821         XCOFF::SymbolAuxType Type = *Obj.getSymbolAuxType(AuxAddress);
822         if (Type == XCOFF::SymbolAuxType::AUX_CSECT)
823           continue;
824         if (Type == XCOFF::SymbolAuxType::AUX_FCN) {
825           const XCOFFFunctionAuxEnt64 *AuxEntPtr =
826               getAuxEntPtr<XCOFFFunctionAuxEnt64>(AuxAddress);
827           printFunctionAuxEnt(AuxEntPtr);
828         } else if (Type == XCOFF::SymbolAuxType::AUX_EXCEPT) {
829           const XCOFFExceptionAuxEnt *AuxEntPtr =
830               getAuxEntPtr<XCOFFExceptionAuxEnt>(AuxAddress);
831           printExceptionAuxEnt(AuxEntPtr);
832         } else {
833           printUnexpectedRawAuxEnt(W, AuxAddress);
834         }
835       } else {
836         const XCOFFFunctionAuxEnt32 *AuxEntPtr =
837             getAuxEntPtr<XCOFFFunctionAuxEnt32>(AuxAddress);
838         printFunctionAuxEnt(AuxEntPtr);
839       }
840     }
841 
842     // Print the CSECT auxiliary entry.
843     auto ErrOrCsectAuxRef = SymbolEntRef.getXCOFFCsectAuxRef();
844     if (!ErrOrCsectAuxRef)
845       reportUniqueWarning(ErrOrCsectAuxRef.takeError());
846     else
847       printCsectAuxEnt(*ErrOrCsectAuxRef);
848 
849     break;
850   }
851   case XCOFF::C_STAT: {
852     checkNumOfAux();
853 
854     const XCOFFSectAuxEntForStat *StatAuxEntPtr =
855         getAuxEntPtr<XCOFFSectAuxEntForStat>(
856             XCOFFObjectFile::getAdvancedSymbolEntryAddress(
857                 SymbolEntRef.getEntryAddress(), 1));
858     printSectAuxEntForStat(StatAuxEntPtr);
859     break;
860   }
861   case XCOFF::C_DWARF: {
862     checkNumOfAux();
863 
864     uintptr_t AuxAddress = XCOFFObjectFile::getAdvancedSymbolEntryAddress(
865         SymbolEntRef.getEntryAddress(), 1);
866 
867     if (Obj.is64Bit()) {
868       const XCOFFSectAuxEntForDWARF64 *AuxEntPtr =
869           getAuxEntPtr<XCOFFSectAuxEntForDWARF64>(AuxAddress);
870       printSectAuxEntForDWARF<XCOFFSectAuxEntForDWARF64>(AuxEntPtr);
871     } else {
872       const XCOFFSectAuxEntForDWARF32 *AuxEntPtr =
873           getAuxEntPtr<XCOFFSectAuxEntForDWARF32>(AuxAddress);
874       printSectAuxEntForDWARF<XCOFFSectAuxEntForDWARF32>(AuxEntPtr);
875     }
876     break;
877   }
878   case XCOFF::C_BLOCK:
879   case XCOFF::C_FCN: {
880     checkNumOfAux();
881 
882     uintptr_t AuxAddress = XCOFFObjectFile::getAdvancedSymbolEntryAddress(
883         SymbolEntRef.getEntryAddress(), 1);
884 
885     if (Obj.is64Bit()) {
886       const XCOFFBlockAuxEnt64 *AuxEntPtr =
887           getAuxEntPtr<XCOFFBlockAuxEnt64>(AuxAddress);
888       printBlockAuxEnt(AuxEntPtr);
889     } else {
890       const XCOFFBlockAuxEnt32 *AuxEntPtr =
891           getAuxEntPtr<XCOFFBlockAuxEnt32>(AuxAddress);
892       printBlockAuxEnt(AuxEntPtr);
893     }
894     break;
895   }
896   default:
897     for (int i = 1; i <= NumberOfAuxEntries; i++) {
898       printUnexpectedRawAuxEnt(W,
899                                XCOFFObjectFile::getAdvancedSymbolEntryAddress(
900                                    SymbolEntRef.getEntryAddress(), i));
901     }
902     break;
903   }
904 }
905 
printSymbols(bool)906 void XCOFFDumper::printSymbols(bool /*ExtraSymInfo*/) {
907   ListScope Group(W, "Symbols");
908   for (const SymbolRef &S : Obj.symbols())
909     printSymbol(S);
910 }
911 
printStringTable()912 void XCOFFDumper::printStringTable() {
913   DictScope DS(W, "StringTable");
914   StringRef StrTable = Obj.getStringTable();
915   uint32_t StrTabSize = StrTable.size();
916   W.printNumber("Length", StrTabSize);
917   // Print strings from the fifth byte, since the first four bytes contain the
918   // length (in bytes) of the string table (including the length field).
919   if (StrTabSize > 4)
920     printAsStringList(StrTable, 4);
921 }
922 
printDynamicSymbols()923 void XCOFFDumper::printDynamicSymbols() {
924   llvm_unreachable("Unimplemented functionality for XCOFFDumper");
925 }
926 
printUnwindInfo()927 void XCOFFDumper::printUnwindInfo() {
928   llvm_unreachable("Unimplemented functionality for XCOFFDumper");
929 }
930 
printStackMap() const931 void XCOFFDumper::printStackMap() const {
932   llvm_unreachable("Unimplemented functionality for XCOFFDumper");
933 }
934 
printNeededLibraries()935 void XCOFFDumper::printNeededLibraries() {
936   ListScope D(W, "NeededLibraries");
937   auto ImportFilesOrError = Obj.getImportFileTable();
938   if (!ImportFilesOrError) {
939     reportUniqueWarning(ImportFilesOrError.takeError());
940     return;
941   }
942 
943   StringRef ImportFileTable = ImportFilesOrError.get();
944   const char *CurrentStr = ImportFileTable.data();
945   const char *TableEnd = ImportFileTable.end();
946   // Default column width for names is 13 even if no names are that long.
947   size_t BaseWidth = 13;
948 
949   // Get the max width of BASE columns.
950   for (size_t StrIndex = 0; CurrentStr < TableEnd; ++StrIndex) {
951     size_t CurrentLen = strlen(CurrentStr);
952     CurrentStr += strlen(CurrentStr) + 1;
953     if (StrIndex % 3 == 1)
954       BaseWidth = std::max(BaseWidth, CurrentLen);
955   }
956 
957   auto &OS = static_cast<formatted_raw_ostream &>(W.startLine());
958   // Each entry consists of 3 strings: the path_name, base_name and
959   // archive_member_name. The first entry is a default LIBPATH value and other
960   // entries have no path_name. We just dump the base_name and
961   // archive_member_name here.
962   OS << left_justify("BASE", BaseWidth)  << " MEMBER\n";
963   CurrentStr = ImportFileTable.data();
964   for (size_t StrIndex = 0; CurrentStr < TableEnd;
965        ++StrIndex, CurrentStr += strlen(CurrentStr) + 1) {
966     if (StrIndex >= 3 && StrIndex % 3 != 0) {
967       if (StrIndex % 3 == 1)
968         OS << "  " << left_justify(CurrentStr, BaseWidth) << " ";
969       else
970         OS << CurrentStr << "\n";
971     }
972   }
973 }
974 
975 const EnumEntry<XCOFF::SectionTypeFlags> SectionTypeFlagsNames[] = {
976 #define ECase(X)                                                               \
977   { #X, XCOFF::X }
978     ECase(STYP_PAD),    ECase(STYP_DWARF), ECase(STYP_TEXT),
979     ECase(STYP_DATA),   ECase(STYP_BSS),   ECase(STYP_EXCEPT),
980     ECase(STYP_INFO),   ECase(STYP_TDATA), ECase(STYP_TBSS),
981     ECase(STYP_LOADER), ECase(STYP_DEBUG), ECase(STYP_TYPCHK),
982     ECase(STYP_OVRFLO)
983 #undef ECase
984 };
985 
986 template <typename T>
printOverflowSectionHeader(T & Sec) const987 void XCOFFDumper::printOverflowSectionHeader(T &Sec) const {
988   if (Obj.is64Bit()) {
989     reportWarning(make_error<StringError>("An 64-bit XCOFF object file may not "
990                                           "contain an overflow section header.",
991                                           object_error::parse_failed),
992                   Obj.getFileName());
993   }
994 
995   W.printString("Name", Sec.getName());
996   W.printNumber("NumberOfRelocations", Sec.PhysicalAddress);
997   W.printNumber("NumberOfLineNumbers", Sec.VirtualAddress);
998   W.printHex("Size", Sec.SectionSize);
999   W.printHex("RawDataOffset", Sec.FileOffsetToRawData);
1000   W.printHex("RelocationPointer", Sec.FileOffsetToRelocationInfo);
1001   W.printHex("LineNumberPointer", Sec.FileOffsetToLineNumberInfo);
1002   W.printNumber("IndexOfSectionOverflowed", Sec.NumberOfRelocations);
1003   W.printNumber("IndexOfSectionOverflowed", Sec.NumberOfLineNumbers);
1004 }
1005 
1006 template <typename T>
printGenericSectionHeader(T & Sec) const1007 void XCOFFDumper::printGenericSectionHeader(T &Sec) const {
1008   W.printString("Name", Sec.getName());
1009   W.printHex("PhysicalAddress", Sec.PhysicalAddress);
1010   W.printHex("VirtualAddress", Sec.VirtualAddress);
1011   W.printHex("Size", Sec.SectionSize);
1012   W.printHex("RawDataOffset", Sec.FileOffsetToRawData);
1013   W.printHex("RelocationPointer", Sec.FileOffsetToRelocationInfo);
1014   W.printHex("LineNumberPointer", Sec.FileOffsetToLineNumberInfo);
1015   W.printNumber("NumberOfRelocations", Sec.NumberOfRelocations);
1016   W.printNumber("NumberOfLineNumbers", Sec.NumberOfLineNumbers);
1017 }
1018 
1019 enum PrintStyle { Hex, Number };
1020 template <typename T, typename V>
printAuxMemberHelper(PrintStyle Style,const char * MemberName,const T & Member,const V * AuxHeader,uint16_t AuxSize,uint16_t & PartialFieldOffset,const char * & PartialFieldName,ScopedPrinter & W)1021 static void printAuxMemberHelper(PrintStyle Style, const char *MemberName,
1022                                  const T &Member, const V *AuxHeader,
1023                                  uint16_t AuxSize, uint16_t &PartialFieldOffset,
1024                                  const char *&PartialFieldName,
1025                                  ScopedPrinter &W) {
1026   ptrdiff_t Offset = reinterpret_cast<const char *>(&Member) -
1027                      reinterpret_cast<const char *>(AuxHeader);
1028   if (Offset + sizeof(Member) <= AuxSize)
1029     Style == Hex ? W.printHex(MemberName, Member)
1030                  : W.printNumber(MemberName, Member);
1031   else if (Offset < AuxSize) {
1032     PartialFieldOffset = Offset;
1033     PartialFieldName = MemberName;
1034   }
1035 }
1036 
1037 template <class T>
checkAndPrintAuxHeaderParseError(const char * PartialFieldName,uint16_t PartialFieldOffset,uint16_t AuxSize,T & AuxHeader,XCOFFDumper * Dumper)1038 void checkAndPrintAuxHeaderParseError(const char *PartialFieldName,
1039                                       uint16_t PartialFieldOffset,
1040                                       uint16_t AuxSize, T &AuxHeader,
1041                                       XCOFFDumper *Dumper) {
1042   if (PartialFieldOffset < AuxSize) {
1043     Dumper->reportUniqueWarning(Twine("only partial field for ") +
1044                                 PartialFieldName + " at offset (" +
1045                                 Twine(PartialFieldOffset) + ")");
1046     Dumper->getScopedPrinter().printBinary(
1047         "Raw data", "",
1048         ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(&AuxHeader) +
1049                               PartialFieldOffset,
1050                           AuxSize - PartialFieldOffset));
1051   } else if (sizeof(AuxHeader) < AuxSize)
1052     Dumper->getScopedPrinter().printBinary(
1053         "Extra raw data", "",
1054         ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(&AuxHeader) +
1055                               sizeof(AuxHeader),
1056                           AuxSize - sizeof(AuxHeader)));
1057 }
1058 
printAuxiliaryHeader(const XCOFFAuxiliaryHeader32 * AuxHeader)1059 void XCOFFDumper::printAuxiliaryHeader(
1060     const XCOFFAuxiliaryHeader32 *AuxHeader) {
1061   if (AuxHeader == nullptr)
1062     return;
1063   uint16_t AuxSize = Obj.getOptionalHeaderSize();
1064   uint16_t PartialFieldOffset = AuxSize;
1065   const char *PartialFieldName = nullptr;
1066 
1067   auto PrintAuxMember = [&](PrintStyle Style, const char *MemberName,
1068                             auto &Member) {
1069     printAuxMemberHelper(Style, MemberName, Member, AuxHeader, AuxSize,
1070                          PartialFieldOffset, PartialFieldName, W);
1071   };
1072 
1073   PrintAuxMember(Hex, "Magic", AuxHeader->AuxMagic);
1074   PrintAuxMember(Hex, "Version", AuxHeader->Version);
1075   PrintAuxMember(Hex, "Size of .text section", AuxHeader->TextSize);
1076   PrintAuxMember(Hex, "Size of .data section", AuxHeader->InitDataSize);
1077   PrintAuxMember(Hex, "Size of .bss section", AuxHeader->BssDataSize);
1078   PrintAuxMember(Hex, "Entry point address", AuxHeader->EntryPointAddr);
1079   PrintAuxMember(Hex, ".text section start address", AuxHeader->TextStartAddr);
1080   PrintAuxMember(Hex, ".data section start address", AuxHeader->DataStartAddr);
1081   PrintAuxMember(Hex, "TOC anchor address", AuxHeader->TOCAnchorAddr);
1082   PrintAuxMember(Number, "Section number of entryPoint",
1083                  AuxHeader->SecNumOfEntryPoint);
1084   PrintAuxMember(Number, "Section number of .text", AuxHeader->SecNumOfText);
1085   PrintAuxMember(Number, "Section number of .data", AuxHeader->SecNumOfData);
1086   PrintAuxMember(Number, "Section number of TOC", AuxHeader->SecNumOfTOC);
1087   PrintAuxMember(Number, "Section number of loader data",
1088                  AuxHeader->SecNumOfLoader);
1089   PrintAuxMember(Number, "Section number of .bss", AuxHeader->SecNumOfBSS);
1090   PrintAuxMember(Hex, "Maxium alignment of .text", AuxHeader->MaxAlignOfText);
1091   PrintAuxMember(Hex, "Maxium alignment of .data", AuxHeader->MaxAlignOfData);
1092   PrintAuxMember(Hex, "Module type", AuxHeader->ModuleType);
1093   PrintAuxMember(Hex, "CPU type of objects", AuxHeader->CpuFlag);
1094   PrintAuxMember(Hex, "(Reserved)", AuxHeader->CpuType);
1095   PrintAuxMember(Hex, "Maximum stack size", AuxHeader->MaxStackSize);
1096   PrintAuxMember(Hex, "Maximum data size", AuxHeader->MaxDataSize);
1097   PrintAuxMember(Hex, "Reserved for debugger", AuxHeader->ReservedForDebugger);
1098   PrintAuxMember(Hex, "Text page size", AuxHeader->TextPageSize);
1099   PrintAuxMember(Hex, "Data page size", AuxHeader->DataPageSize);
1100   PrintAuxMember(Hex, "Stack page size", AuxHeader->StackPageSize);
1101   if (offsetof(XCOFFAuxiliaryHeader32, FlagAndTDataAlignment) +
1102           sizeof(XCOFFAuxiliaryHeader32::FlagAndTDataAlignment) <=
1103       AuxSize) {
1104     W.printHex("Flag", AuxHeader->getFlag());
1105     W.printHex("Alignment of thread-local storage",
1106                AuxHeader->getTDataAlignment());
1107   }
1108 
1109   PrintAuxMember(Number, "Section number for .tdata", AuxHeader->SecNumOfTData);
1110   PrintAuxMember(Number, "Section number for .tbss", AuxHeader->SecNumOfTBSS);
1111 
1112   checkAndPrintAuxHeaderParseError(PartialFieldName, PartialFieldOffset,
1113                                    AuxSize, *AuxHeader, this);
1114 }
1115 
printAuxiliaryHeader(const XCOFFAuxiliaryHeader64 * AuxHeader)1116 void XCOFFDumper::printAuxiliaryHeader(
1117     const XCOFFAuxiliaryHeader64 *AuxHeader) {
1118   if (AuxHeader == nullptr)
1119     return;
1120   uint16_t AuxSize = Obj.getOptionalHeaderSize();
1121   uint16_t PartialFieldOffset = AuxSize;
1122   const char *PartialFieldName = nullptr;
1123 
1124   auto PrintAuxMember = [&](PrintStyle Style, const char *MemberName,
1125                             auto &Member) {
1126     printAuxMemberHelper(Style, MemberName, Member, AuxHeader, AuxSize,
1127                          PartialFieldOffset, PartialFieldName, W);
1128   };
1129 
1130   PrintAuxMember(Hex, "Magic", AuxHeader->AuxMagic);
1131   PrintAuxMember(Hex, "Version", AuxHeader->Version);
1132   PrintAuxMember(Hex, "Reserved for debugger", AuxHeader->ReservedForDebugger);
1133   PrintAuxMember(Hex, ".text section start address", AuxHeader->TextStartAddr);
1134   PrintAuxMember(Hex, ".data section start address", AuxHeader->DataStartAddr);
1135   PrintAuxMember(Hex, "TOC anchor address", AuxHeader->TOCAnchorAddr);
1136   PrintAuxMember(Number, "Section number of entryPoint",
1137                  AuxHeader->SecNumOfEntryPoint);
1138   PrintAuxMember(Number, "Section number of .text", AuxHeader->SecNumOfText);
1139   PrintAuxMember(Number, "Section number of .data", AuxHeader->SecNumOfData);
1140   PrintAuxMember(Number, "Section number of TOC", AuxHeader->SecNumOfTOC);
1141   PrintAuxMember(Number, "Section number of loader data",
1142                  AuxHeader->SecNumOfLoader);
1143   PrintAuxMember(Number, "Section number of .bss", AuxHeader->SecNumOfBSS);
1144   PrintAuxMember(Hex, "Maxium alignment of .text", AuxHeader->MaxAlignOfText);
1145   PrintAuxMember(Hex, "Maxium alignment of .data", AuxHeader->MaxAlignOfData);
1146   PrintAuxMember(Hex, "Module type", AuxHeader->ModuleType);
1147   PrintAuxMember(Hex, "CPU type of objects", AuxHeader->CpuFlag);
1148   PrintAuxMember(Hex, "(Reserved)", AuxHeader->CpuType);
1149   PrintAuxMember(Hex, "Text page size", AuxHeader->TextPageSize);
1150   PrintAuxMember(Hex, "Data page size", AuxHeader->DataPageSize);
1151   PrintAuxMember(Hex, "Stack page size", AuxHeader->StackPageSize);
1152   if (offsetof(XCOFFAuxiliaryHeader64, FlagAndTDataAlignment) +
1153           sizeof(XCOFFAuxiliaryHeader64::FlagAndTDataAlignment) <=
1154       AuxSize) {
1155     W.printHex("Flag", AuxHeader->getFlag());
1156     W.printHex("Alignment of thread-local storage",
1157                AuxHeader->getTDataAlignment());
1158   }
1159   PrintAuxMember(Hex, "Size of .text section", AuxHeader->TextSize);
1160   PrintAuxMember(Hex, "Size of .data section", AuxHeader->InitDataSize);
1161   PrintAuxMember(Hex, "Size of .bss section", AuxHeader->BssDataSize);
1162   PrintAuxMember(Hex, "Entry point address", AuxHeader->EntryPointAddr);
1163   PrintAuxMember(Hex, "Maximum stack size", AuxHeader->MaxStackSize);
1164   PrintAuxMember(Hex, "Maximum data size", AuxHeader->MaxDataSize);
1165   PrintAuxMember(Number, "Section number for .tdata", AuxHeader->SecNumOfTData);
1166   PrintAuxMember(Number, "Section number for .tbss", AuxHeader->SecNumOfTBSS);
1167   PrintAuxMember(Hex, "Additional flags 64-bit XCOFF", AuxHeader->XCOFF64Flag);
1168 
1169   checkAndPrintAuxHeaderParseError(PartialFieldName, PartialFieldOffset,
1170                                    AuxSize, *AuxHeader, this);
1171 }
1172 
1173 template <typename T>
printSectionHeaders(ArrayRef<T> Sections)1174 void XCOFFDumper::printSectionHeaders(ArrayRef<T> Sections) {
1175   ListScope Group(W, "Sections");
1176 
1177   uint16_t Index = 1;
1178   for (const T &Sec : Sections) {
1179     DictScope SecDS(W, "Section");
1180 
1181     W.printNumber("Index", Index++);
1182     uint16_t SectionType = Sec.getSectionType();
1183     switch (SectionType) {
1184     case XCOFF::STYP_OVRFLO:
1185       printOverflowSectionHeader(Sec);
1186       break;
1187     case XCOFF::STYP_LOADER:
1188     case XCOFF::STYP_EXCEPT:
1189     case XCOFF::STYP_TYPCHK:
1190       // TODO The interpretation of loader, exception and type check section
1191       // headers are different from that of generic section headers. We will
1192       // implement them later. We interpret them as generic section headers for
1193       // now.
1194     default:
1195       printGenericSectionHeader(Sec);
1196       break;
1197     }
1198     if (Sec.isReservedSectionType())
1199       W.printHex("Flags", "Reserved", SectionType);
1200     else
1201       W.printEnum("Type", SectionType, ArrayRef(SectionTypeFlagsNames));
1202   }
1203 
1204   if (opts::SectionRelocations)
1205     report_fatal_error("Dumping section relocations is unimplemented");
1206 
1207   if (opts::SectionSymbols)
1208     report_fatal_error("Dumping symbols is unimplemented");
1209 
1210   if (opts::SectionData)
1211     report_fatal_error("Dumping section data is unimplemented");
1212 }
1213 
1214 namespace llvm {
1215 std::unique_ptr<ObjDumper>
createXCOFFDumper(const object::XCOFFObjectFile & XObj,ScopedPrinter & Writer)1216 createXCOFFDumper(const object::XCOFFObjectFile &XObj, ScopedPrinter &Writer) {
1217   return std::make_unique<XCOFFDumper>(XObj, Writer);
1218 }
1219 } // namespace llvm
1220