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