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