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