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