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
getScopedPrinter() const43 ScopedPrinter &getScopedPrinter() const { return W; }
44
45 private:
46 template <typename T> void printSectionHeaders(ArrayRef<T> Sections);
47 template <typename T> void printGenericSectionHeader(T &Sec) const;
48 template <typename T> void printOverflowSectionHeader(T &Sec) const;
49 template <typename T> const T *getAuxEntPtr(uintptr_t AuxAddress);
50 void printFileAuxEnt(const XCOFFFileAuxEnt *AuxEntPtr);
51 void printCsectAuxEnt(XCOFFCsectAuxRef AuxEntRef);
52 void printSectAuxEntForStat(const XCOFFSectAuxEntForStat *AuxEntPtr);
53 void printExceptionAuxEnt(const XCOFFExceptionAuxEnt *AuxEntPtr);
54 void printFunctionAuxEnt(const XCOFFFunctionAuxEnt32 *AuxEntPtr);
55 void printFunctionAuxEnt(const XCOFFFunctionAuxEnt64 *AuxEntPtr);
56 void printBlockAuxEnt(const XCOFFBlockAuxEnt32 *AuxEntPtr);
57 void printBlockAuxEnt(const XCOFFBlockAuxEnt64 *AuxEntPtr);
58 template <typename T> void printSectAuxEntForDWARF(const T *AuxEntPtr);
59 void printSymbol(const SymbolRef &);
60 template <typename RelTy> void printRelocation(RelTy Reloc);
61 template <typename Shdr, typename RelTy>
62 void printRelocations(ArrayRef<Shdr> Sections);
63 void printAuxiliaryHeader(const XCOFFAuxiliaryHeader32 *AuxHeader);
64 void printAuxiliaryHeader(const XCOFFAuxiliaryHeader64 *AuxHeader);
65 const XCOFFObjectFile &Obj;
66 };
67 } // anonymous namespace
68
printFileHeaders()69 void XCOFFDumper::printFileHeaders() {
70 DictScope DS(W, "FileHeader");
71 W.printHex("Magic", Obj.getMagic());
72 W.printNumber("NumberOfSections", Obj.getNumberOfSections());
73
74 // Negative timestamp values are reserved for future use.
75 int32_t TimeStamp = Obj.getTimeStamp();
76 if (TimeStamp > 0) {
77 // This handling of the time stamp assumes that the host system's time_t is
78 // compatible with AIX time_t. If a platform is not compatible, the lit
79 // tests will let us know.
80 time_t TimeDate = TimeStamp;
81
82 char FormattedTime[21] = {};
83 size_t BytesWritten =
84 strftime(FormattedTime, 21, "%Y-%m-%dT%H:%M:%SZ", gmtime(&TimeDate));
85 if (BytesWritten)
86 W.printHex("TimeStamp", FormattedTime, TimeStamp);
87 else
88 W.printHex("Timestamp", TimeStamp);
89 } else {
90 W.printHex("TimeStamp", TimeStamp == 0 ? "None" : "Reserved Value",
91 TimeStamp);
92 }
93
94 // The number of symbol table entries is an unsigned value in 64-bit objects
95 // and a signed value (with negative values being 'reserved') in 32-bit
96 // objects.
97 if (Obj.is64Bit()) {
98 W.printHex("SymbolTableOffset", Obj.getSymbolTableOffset64());
99 W.printNumber("SymbolTableEntries", Obj.getNumberOfSymbolTableEntries64());
100 } else {
101 W.printHex("SymbolTableOffset", Obj.getSymbolTableOffset32());
102 int32_t SymTabEntries = Obj.getRawNumberOfSymbolTableEntries32();
103 if (SymTabEntries >= 0)
104 W.printNumber("SymbolTableEntries", SymTabEntries);
105 else
106 W.printHex("SymbolTableEntries", "Reserved Value", SymTabEntries);
107 }
108
109 W.printHex("OptionalHeaderSize", Obj.getOptionalHeaderSize());
110 W.printHex("Flags", Obj.getFlags());
111
112 // TODO FIXME Add support for the auxiliary header (if any) once
113 // XCOFFObjectFile has the necessary support.
114 }
115
printAuxiliaryHeader()116 void XCOFFDumper::printAuxiliaryHeader() {
117 DictScope DS(W, "AuxiliaryHeader");
118
119 if (Obj.is64Bit())
120 printAuxiliaryHeader(Obj.auxiliaryHeader64());
121 else
122 printAuxiliaryHeader(Obj.auxiliaryHeader32());
123 }
124
printSectionHeaders()125 void XCOFFDumper::printSectionHeaders() {
126 if (Obj.is64Bit())
127 printSectionHeaders(Obj.sections64());
128 else
129 printSectionHeaders(Obj.sections32());
130 }
131
printRelocations()132 void XCOFFDumper::printRelocations() {
133 if (Obj.is64Bit())
134 printRelocations<XCOFFSectionHeader64, XCOFFRelocation64>(Obj.sections64());
135 else
136 printRelocations<XCOFFSectionHeader32, XCOFFRelocation32>(Obj.sections32());
137 }
138
139 const EnumEntry<XCOFF::RelocationType> RelocationTypeNameclass[] = {
140 #define ECase(X) \
141 { #X, XCOFF::X }
142 ECase(R_POS), ECase(R_RL), ECase(R_RLA), ECase(R_NEG),
143 ECase(R_REL), ECase(R_TOC), ECase(R_TRL), ECase(R_TRLA),
144 ECase(R_GL), ECase(R_TCL), ECase(R_REF), ECase(R_BA),
145 ECase(R_BR), ECase(R_RBA), ECase(R_RBR), ECase(R_TLS),
146 ECase(R_TLS_IE), ECase(R_TLS_LD), ECase(R_TLS_LE), ECase(R_TLSM),
147 ECase(R_TLSML), ECase(R_TOCU), ECase(R_TOCL)
148 #undef ECase
149 };
150
printRelocation(RelTy Reloc)151 template <typename RelTy> void XCOFFDumper::printRelocation(RelTy Reloc) {
152 Expected<StringRef> ErrOrSymbolName =
153 Obj.getSymbolNameByIndex(Reloc.SymbolIndex);
154 if (Error E = ErrOrSymbolName.takeError()) {
155 reportUniqueWarning(std::move(E));
156 return;
157 }
158 StringRef SymbolName = *ErrOrSymbolName;
159 StringRef RelocName = XCOFF::getRelocationTypeString(Reloc.Type);
160 if (opts::ExpandRelocs) {
161 DictScope Group(W, "Relocation");
162 W.printHex("Virtual Address", Reloc.VirtualAddress);
163 W.printNumber("Symbol", SymbolName, Reloc.SymbolIndex);
164 W.printString("IsSigned", Reloc.isRelocationSigned() ? "Yes" : "No");
165 W.printNumber("FixupBitValue", Reloc.isFixupIndicated() ? 1 : 0);
166 W.printNumber("Length", Reloc.getRelocatedLength());
167 W.printEnum("Type", (uint8_t)Reloc.Type,
168 makeArrayRef(RelocationTypeNameclass));
169 } else {
170 raw_ostream &OS = W.startLine();
171 OS << W.hex(Reloc.VirtualAddress) << " " << RelocName << " " << SymbolName
172 << "(" << Reloc.SymbolIndex << ") " << W.hex(Reloc.Info) << "\n";
173 }
174 }
175
176 template <typename Shdr, typename RelTy>
printRelocations(ArrayRef<Shdr> Sections)177 void XCOFFDumper::printRelocations(ArrayRef<Shdr> Sections) {
178 ListScope LS(W, "Relocations");
179 uint16_t Index = 0;
180 for (const Shdr &Sec : Sections) {
181 ++Index;
182 // Only the .text, .data, .tdata, and STYP_DWARF sections have relocation.
183 if (Sec.Flags != XCOFF::STYP_TEXT && Sec.Flags != XCOFF::STYP_DATA &&
184 Sec.Flags != XCOFF::STYP_TDATA && Sec.Flags != XCOFF::STYP_DWARF)
185 continue;
186 Expected<ArrayRef<RelTy>> ErrOrRelocations = Obj.relocations<Shdr, RelTy>(Sec);
187 if (Error E = ErrOrRelocations.takeError()) {
188 reportUniqueWarning(std::move(E));
189 continue;
190 }
191
192 const ArrayRef<RelTy> Relocations = *ErrOrRelocations;
193 if (Relocations.empty())
194 continue;
195
196 W.startLine() << "Section (index: " << Index << ") " << Sec.getName()
197 << " {\n";
198 W.indent();
199
200 for (const RelTy Reloc : Relocations)
201 printRelocation(Reloc);
202
203 W.unindent();
204 W.startLine() << "}\n";
205 }
206 }
207
208 const EnumEntry<XCOFF::CFileStringType> FileStringType[] = {
209 #define ECase(X) \
210 { #X, XCOFF::X }
211 ECase(XFT_FN), ECase(XFT_CT), ECase(XFT_CV), ECase(XFT_CD)
212 #undef ECase
213 };
214
215 const EnumEntry<XCOFF::SymbolAuxType> SymAuxType[] = {
216 #define ECase(X) \
217 { #X, XCOFF::X }
218 ECase(AUX_EXCEPT), ECase(AUX_FCN), ECase(AUX_SYM), ECase(AUX_FILE),
219 ECase(AUX_CSECT), ECase(AUX_SECT)
220 #undef ECase
221 };
222
printFileAuxEnt(const XCOFFFileAuxEnt * AuxEntPtr)223 void XCOFFDumper::printFileAuxEnt(const XCOFFFileAuxEnt *AuxEntPtr) {
224 assert((!Obj.is64Bit() || AuxEntPtr->AuxType == XCOFF::AUX_FILE) &&
225 "Mismatched auxiliary type!");
226 StringRef FileName =
227 unwrapOrError(Obj.getFileName(), Obj.getCFileName(AuxEntPtr));
228 DictScope SymDs(W, "File Auxiliary Entry");
229 W.printNumber("Index",
230 Obj.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr)));
231 W.printString("Name", FileName);
232 W.printEnum("Type", static_cast<uint8_t>(AuxEntPtr->Type),
233 makeArrayRef(FileStringType));
234 if (Obj.is64Bit()) {
235 W.printEnum("Auxiliary Type", static_cast<uint8_t>(AuxEntPtr->AuxType),
236 makeArrayRef(SymAuxType));
237 }
238 }
239
240 static const EnumEntry<XCOFF::StorageMappingClass> CsectStorageMappingClass[] =
241 {
242 #define ECase(X) \
243 { #X, XCOFF::X }
244 ECase(XMC_PR), ECase(XMC_RO), ECase(XMC_DB), ECase(XMC_GL),
245 ECase(XMC_XO), ECase(XMC_SV), ECase(XMC_SV64), ECase(XMC_SV3264),
246 ECase(XMC_TI), ECase(XMC_TB), ECase(XMC_RW), ECase(XMC_TC0),
247 ECase(XMC_TC), ECase(XMC_TD), ECase(XMC_DS), ECase(XMC_UA),
248 ECase(XMC_BS), ECase(XMC_UC), ECase(XMC_TL), ECase(XMC_UL),
249 ECase(XMC_TE)
250 #undef ECase
251 };
252
253 const EnumEntry<XCOFF::SymbolType> CsectSymbolTypeClass[] = {
254 #define ECase(X) \
255 { #X, XCOFF::X }
256 ECase(XTY_ER), ECase(XTY_SD), ECase(XTY_LD), ECase(XTY_CM)
257 #undef ECase
258 };
259
printCsectAuxEnt(XCOFFCsectAuxRef AuxEntRef)260 void XCOFFDumper::printCsectAuxEnt(XCOFFCsectAuxRef AuxEntRef) {
261 assert((!Obj.is64Bit() || AuxEntRef.getAuxType64() == XCOFF::AUX_CSECT) &&
262 "Mismatched auxiliary type!");
263
264 DictScope SymDs(W, "CSECT Auxiliary Entry");
265 W.printNumber("Index", Obj.getSymbolIndex(AuxEntRef.getEntryAddress()));
266 W.printNumber(AuxEntRef.isLabel() ? "ContainingCsectSymbolIndex"
267 : "SectionLen",
268 AuxEntRef.getSectionOrLength());
269 W.printHex("ParameterHashIndex", AuxEntRef.getParameterHashIndex());
270 W.printHex("TypeChkSectNum", AuxEntRef.getTypeChkSectNum());
271 // Print out symbol alignment and type.
272 W.printNumber("SymbolAlignmentLog2", AuxEntRef.getAlignmentLog2());
273 W.printEnum("SymbolType", AuxEntRef.getSymbolType(),
274 makeArrayRef(CsectSymbolTypeClass));
275 W.printEnum("StorageMappingClass",
276 static_cast<uint8_t>(AuxEntRef.getStorageMappingClass()),
277 makeArrayRef(CsectStorageMappingClass));
278
279 if (Obj.is64Bit()) {
280 W.printEnum("Auxiliary Type", static_cast<uint8_t>(XCOFF::AUX_CSECT),
281 makeArrayRef(SymAuxType));
282 } else {
283 W.printHex("StabInfoIndex", AuxEntRef.getStabInfoIndex32());
284 W.printHex("StabSectNum", AuxEntRef.getStabSectNum32());
285 }
286 }
287
printSectAuxEntForStat(const XCOFFSectAuxEntForStat * AuxEntPtr)288 void XCOFFDumper::printSectAuxEntForStat(
289 const XCOFFSectAuxEntForStat *AuxEntPtr) {
290 assert(!Obj.is64Bit() && "32-bit interface called on 64-bit object file.");
291
292 DictScope SymDs(W, "Sect Auxiliary Entry For Stat");
293 W.printNumber("Index",
294 Obj.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr)));
295 W.printNumber("SectionLength", AuxEntPtr->SectionLength);
296
297 // Unlike the corresponding fields in the section header, NumberOfRelocEnt
298 // and NumberOfLineNum do not handle values greater than 65535.
299 W.printNumber("NumberOfRelocEnt", AuxEntPtr->NumberOfRelocEnt);
300 W.printNumber("NumberOfLineNum", AuxEntPtr->NumberOfLineNum);
301 }
302
printExceptionAuxEnt(const XCOFFExceptionAuxEnt * AuxEntPtr)303 void XCOFFDumper::printExceptionAuxEnt(const XCOFFExceptionAuxEnt *AuxEntPtr) {
304 assert(Obj.is64Bit() && "64-bit interface called on 32-bit object file.");
305
306 DictScope SymDs(W, "Exception Auxiliary Entry");
307 W.printNumber("Index",
308 Obj.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr)));
309 W.printHex("OffsetToExceptionTable", AuxEntPtr->OffsetToExceptionTbl);
310 W.printHex("SizeOfFunction", AuxEntPtr->SizeOfFunction);
311 W.printNumber("SymbolIndexOfNextBeyond", AuxEntPtr->SymIdxOfNextBeyond);
312 W.printEnum("Auxiliary Type", static_cast<uint8_t>(AuxEntPtr->AuxType),
313 makeArrayRef(SymAuxType));
314 }
315
printFunctionAuxEnt(const XCOFFFunctionAuxEnt32 * AuxEntPtr)316 void XCOFFDumper::printFunctionAuxEnt(const XCOFFFunctionAuxEnt32 *AuxEntPtr) {
317 assert(!Obj.is64Bit() && "32-bit interface called on 64-bit object file.");
318
319 DictScope SymDs(W, "Function Auxiliary Entry");
320 W.printNumber("Index",
321 Obj.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr)));
322 W.printHex("OffsetToExceptionTable", AuxEntPtr->OffsetToExceptionTbl);
323 W.printHex("SizeOfFunction", AuxEntPtr->SizeOfFunction);
324 W.printHex("PointerToLineNum", AuxEntPtr->PtrToLineNum);
325 W.printNumber("SymbolIndexOfNextBeyond", AuxEntPtr->SymIdxOfNextBeyond);
326 }
327
printFunctionAuxEnt(const XCOFFFunctionAuxEnt64 * AuxEntPtr)328 void XCOFFDumper::printFunctionAuxEnt(const XCOFFFunctionAuxEnt64 *AuxEntPtr) {
329 assert(Obj.is64Bit() && "64-bit interface called on 32-bit object file.");
330
331 DictScope SymDs(W, "Function Auxiliary Entry");
332 W.printNumber("Index",
333 Obj.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr)));
334 W.printHex("SizeOfFunction", AuxEntPtr->SizeOfFunction);
335 W.printHex("PointerToLineNum", AuxEntPtr->PtrToLineNum);
336 W.printNumber("SymbolIndexOfNextBeyond", AuxEntPtr->SymIdxOfNextBeyond);
337 W.printEnum("Auxiliary Type", static_cast<uint8_t>(AuxEntPtr->AuxType),
338 makeArrayRef(SymAuxType));
339 }
340
printBlockAuxEnt(const XCOFFBlockAuxEnt32 * AuxEntPtr)341 void XCOFFDumper::printBlockAuxEnt(const XCOFFBlockAuxEnt32 *AuxEntPtr) {
342 assert(!Obj.is64Bit() && "32-bit interface called on 64-bit object file.");
343
344 DictScope SymDs(W, "Block Auxiliary Entry");
345 W.printNumber("Index",
346 Obj.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr)));
347 W.printHex("LineNumber (High 2 Bytes)", AuxEntPtr->LineNumHi);
348 W.printHex("LineNumber (Low 2 Bytes)", AuxEntPtr->LineNumLo);
349 }
350
printBlockAuxEnt(const XCOFFBlockAuxEnt64 * AuxEntPtr)351 void XCOFFDumper::printBlockAuxEnt(const XCOFFBlockAuxEnt64 *AuxEntPtr) {
352 assert(Obj.is64Bit() && "64-bit interface called on 32-bit object file.");
353
354 DictScope SymDs(W, "Block Auxiliary Entry");
355 W.printNumber("Index",
356 Obj.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr)));
357 W.printHex("LineNumber", AuxEntPtr->LineNum);
358 W.printEnum("Auxiliary Type", static_cast<uint8_t>(AuxEntPtr->AuxType),
359 makeArrayRef(SymAuxType));
360 }
361
362 template <typename T>
printSectAuxEntForDWARF(const T * AuxEntPtr)363 void XCOFFDumper::printSectAuxEntForDWARF(const T *AuxEntPtr) {
364 DictScope SymDs(W, "Sect Auxiliary Entry For DWARF");
365 W.printNumber("Index",
366 Obj.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr)));
367 W.printHex("LengthOfSectionPortion", AuxEntPtr->LengthOfSectionPortion);
368 W.printNumber("NumberOfRelocEntries", AuxEntPtr->NumberOfRelocEnt);
369 if (Obj.is64Bit())
370 W.printEnum("Auxiliary Type", static_cast<uint8_t>(XCOFF::AUX_SECT),
371 makeArrayRef(SymAuxType));
372 }
373
374 const EnumEntry<XCOFF::StorageClass> SymStorageClass[] = {
375 #define ECase(X) \
376 { #X, XCOFF::X }
377 ECase(C_NULL), ECase(C_AUTO), ECase(C_EXT), ECase(C_STAT),
378 ECase(C_REG), ECase(C_EXTDEF), ECase(C_LABEL), ECase(C_ULABEL),
379 ECase(C_MOS), ECase(C_ARG), ECase(C_STRTAG), ECase(C_MOU),
380 ECase(C_UNTAG), ECase(C_TPDEF), ECase(C_USTATIC), ECase(C_ENTAG),
381 ECase(C_MOE), ECase(C_REGPARM), ECase(C_FIELD), ECase(C_BLOCK),
382 ECase(C_FCN), ECase(C_EOS), ECase(C_FILE), ECase(C_LINE),
383 ECase(C_ALIAS), ECase(C_HIDDEN), ECase(C_HIDEXT), ECase(C_BINCL),
384 ECase(C_EINCL), ECase(C_INFO), ECase(C_WEAKEXT), ECase(C_DWARF),
385 ECase(C_GSYM), ECase(C_LSYM), ECase(C_PSYM), ECase(C_RSYM),
386 ECase(C_RPSYM), ECase(C_STSYM), ECase(C_TCSYM), ECase(C_BCOMM),
387 ECase(C_ECOML), ECase(C_ECOMM), ECase(C_DECL), ECase(C_ENTRY),
388 ECase(C_FUN), ECase(C_BSTAT), ECase(C_ESTAT), ECase(C_GTLS),
389 ECase(C_STTLS), ECase(C_EFCN)
390 #undef ECase
391 };
392
GetSymbolValueName(XCOFF::StorageClass SC)393 static StringRef GetSymbolValueName(XCOFF::StorageClass SC) {
394 switch (SC) {
395 case XCOFF::C_EXT:
396 case XCOFF::C_WEAKEXT:
397 case XCOFF::C_HIDEXT:
398 case XCOFF::C_STAT:
399 case XCOFF::C_FCN:
400 case XCOFF::C_BLOCK:
401 return "Value (RelocatableAddress)";
402 case XCOFF::C_FILE:
403 return "Value (SymbolTableIndex)";
404 case XCOFF::C_DWARF:
405 return "Value (OffsetInDWARF)";
406 case XCOFF::C_FUN:
407 case XCOFF::C_STSYM:
408 case XCOFF::C_BINCL:
409 case XCOFF::C_EINCL:
410 case XCOFF::C_INFO:
411 case XCOFF::C_BSTAT:
412 case XCOFF::C_LSYM:
413 case XCOFF::C_PSYM:
414 case XCOFF::C_RPSYM:
415 case XCOFF::C_RSYM:
416 case XCOFF::C_ECOML:
417 assert(false && "This StorageClass for the symbol is not yet implemented.");
418 return "";
419 default:
420 return "Value";
421 }
422 }
423
424 const EnumEntry<XCOFF::CFileLangId> CFileLangIdClass[] = {
425 #define ECase(X) \
426 { #X, XCOFF::X }
427 ECase(TB_C), ECase(TB_CPLUSPLUS)
428 #undef ECase
429 };
430
431 const EnumEntry<XCOFF::CFileCpuId> CFileCpuIdClass[] = {
432 #define ECase(X) \
433 { #X, XCOFF::X }
434 ECase(TCPU_PPC64), ECase(TCPU_COM), ECase(TCPU_970)
435 #undef ECase
436 };
437
getAuxEntPtr(uintptr_t AuxAddress)438 template <typename T> const T *XCOFFDumper::getAuxEntPtr(uintptr_t AuxAddress) {
439 const T *AuxEntPtr = reinterpret_cast<const T *>(AuxAddress);
440 Obj.checkSymbolEntryPointer(reinterpret_cast<uintptr_t>(AuxEntPtr));
441 return AuxEntPtr;
442 }
443
printUnexpectedRawAuxEnt(ScopedPrinter & W,uintptr_t AuxAddress)444 static void printUnexpectedRawAuxEnt(ScopedPrinter &W, uintptr_t AuxAddress) {
445 W.startLine() << "!Unexpected raw auxiliary entry data:\n";
446 W.startLine() << format_bytes(
447 ArrayRef<uint8_t>(
448 reinterpret_cast<const uint8_t *>(AuxAddress),
449 XCOFF::SymbolTableEntrySize),
450 None, XCOFF::SymbolTableEntrySize)
451 << "\n";
452 }
453
printSymbol(const SymbolRef & S)454 void XCOFFDumper::printSymbol(const SymbolRef &S) {
455 DataRefImpl SymbolDRI = S.getRawDataRefImpl();
456 XCOFFSymbolRef SymbolEntRef = Obj.toSymbolRef(SymbolDRI);
457
458 uint8_t NumberOfAuxEntries = SymbolEntRef.getNumberOfAuxEntries();
459
460 DictScope SymDs(W, "Symbol");
461
462 StringRef SymbolName =
463 unwrapOrError(Obj.getFileName(), SymbolEntRef.getName());
464
465 uint32_t SymbolIdx = Obj.getSymbolIndex(SymbolEntRef.getEntryAddress());
466 XCOFF::StorageClass SymbolClass = SymbolEntRef.getStorageClass();
467
468 W.printNumber("Index", SymbolIdx);
469 W.printString("Name", SymbolName);
470 W.printHex(GetSymbolValueName(SymbolClass), SymbolEntRef.getValue());
471
472 StringRef SectionName =
473 unwrapOrError(Obj.getFileName(), Obj.getSymbolSectionName(SymbolEntRef));
474
475 W.printString("Section", SectionName);
476 if (SymbolClass == XCOFF::C_FILE) {
477 W.printEnum("Source Language ID", SymbolEntRef.getLanguageIdForCFile(),
478 makeArrayRef(CFileLangIdClass));
479 W.printEnum("CPU Version ID", SymbolEntRef.getCPUTypeIddForCFile(),
480 makeArrayRef(CFileCpuIdClass));
481 } else
482 W.printHex("Type", SymbolEntRef.getSymbolType());
483
484 W.printEnum("StorageClass", static_cast<uint8_t>(SymbolClass),
485 makeArrayRef(SymStorageClass));
486 W.printNumber("NumberOfAuxEntries", NumberOfAuxEntries);
487
488 if (NumberOfAuxEntries == 0)
489 return;
490
491 auto checkNumOfAux = [=] {
492 if (NumberOfAuxEntries > 1)
493 reportUniqueWarning("the " +
494 enumToString(static_cast<uint8_t>(SymbolClass),
495 makeArrayRef(SymStorageClass)) +
496 " symbol at index " + Twine(SymbolIdx) +
497 " should not have more than 1 "
498 "auxiliary entry");
499 };
500
501 switch (SymbolClass) {
502 case XCOFF::C_FILE:
503 // If the symbol is C_FILE and has auxiliary entries...
504 for (int I = 1; I <= NumberOfAuxEntries; I++) {
505 uintptr_t AuxAddress = XCOFFObjectFile::getAdvancedSymbolEntryAddress(
506 SymbolEntRef.getEntryAddress(), I);
507
508 if (Obj.is64Bit() &&
509 *Obj.getSymbolAuxType(AuxAddress) != XCOFF::SymbolAuxType::AUX_FILE) {
510 printUnexpectedRawAuxEnt(W, AuxAddress);
511 continue;
512 }
513
514 const XCOFFFileAuxEnt *FileAuxEntPtr =
515 getAuxEntPtr<XCOFFFileAuxEnt>(AuxAddress);
516 printFileAuxEnt(FileAuxEntPtr);
517 }
518 break;
519 case XCOFF::C_EXT:
520 case XCOFF::C_WEAKEXT:
521 case XCOFF::C_HIDEXT: {
522 if (!SymbolEntRef.isFunction() && NumberOfAuxEntries > 1)
523 reportUniqueWarning("the non-function " +
524 enumToString(static_cast<uint8_t>(SymbolClass),
525 makeArrayRef(SymStorageClass)) +
526 " symbol at index " + Twine(SymbolIdx) +
527 " should have only 1 auxiliary entry, i.e. the CSECT "
528 "auxiliary entry");
529
530 // For 32-bit objects, print the function auxiliary symbol table entry. The
531 // last one must be a CSECT auxiliary entry.
532 // For 64-bit objects, both a function auxiliary entry and an exception
533 // auxiliary entry may appear, print them in the loop and skip printing the
534 // CSECT auxiliary entry, which will be printed outside the loop.
535 for (int I = 1; I <= NumberOfAuxEntries; I++) {
536 if ((I == NumberOfAuxEntries && !Obj.is64Bit()) ||
537 !SymbolEntRef.isFunction())
538 break;
539
540 uintptr_t AuxAddress = XCOFFObjectFile::getAdvancedSymbolEntryAddress(
541 SymbolEntRef.getEntryAddress(), I);
542
543 if (Obj.is64Bit()) {
544 XCOFF::SymbolAuxType Type = *Obj.getSymbolAuxType(AuxAddress);
545 if (Type == XCOFF::SymbolAuxType::AUX_CSECT)
546 continue;
547 if (Type == XCOFF::SymbolAuxType::AUX_FCN) {
548 const XCOFFFunctionAuxEnt64 *AuxEntPtr =
549 getAuxEntPtr<XCOFFFunctionAuxEnt64>(AuxAddress);
550 printFunctionAuxEnt(AuxEntPtr);
551 } else if (Type == XCOFF::SymbolAuxType::AUX_EXCEPT) {
552 const XCOFFExceptionAuxEnt *AuxEntPtr =
553 getAuxEntPtr<XCOFFExceptionAuxEnt>(AuxAddress);
554 printExceptionAuxEnt(AuxEntPtr);
555 } else {
556 printUnexpectedRawAuxEnt(W, AuxAddress);
557 }
558 } else {
559 const XCOFFFunctionAuxEnt32 *AuxEntPtr =
560 getAuxEntPtr<XCOFFFunctionAuxEnt32>(AuxAddress);
561 printFunctionAuxEnt(AuxEntPtr);
562 }
563 }
564
565 // Print the CSECT auxiliary entry.
566 auto ErrOrCsectAuxRef = SymbolEntRef.getXCOFFCsectAuxRef();
567 if (!ErrOrCsectAuxRef)
568 reportUniqueWarning(ErrOrCsectAuxRef.takeError());
569 else
570 printCsectAuxEnt(*ErrOrCsectAuxRef);
571
572 break;
573 }
574 case XCOFF::C_STAT: {
575 checkNumOfAux();
576
577 const XCOFFSectAuxEntForStat *StatAuxEntPtr =
578 getAuxEntPtr<XCOFFSectAuxEntForStat>(
579 XCOFFObjectFile::getAdvancedSymbolEntryAddress(
580 SymbolEntRef.getEntryAddress(), 1));
581 printSectAuxEntForStat(StatAuxEntPtr);
582 break;
583 }
584 case XCOFF::C_DWARF: {
585 checkNumOfAux();
586
587 uintptr_t AuxAddress = XCOFFObjectFile::getAdvancedSymbolEntryAddress(
588 SymbolEntRef.getEntryAddress(), 1);
589
590 if (Obj.is64Bit()) {
591 const XCOFFSectAuxEntForDWARF64 *AuxEntPtr =
592 getAuxEntPtr<XCOFFSectAuxEntForDWARF64>(AuxAddress);
593 printSectAuxEntForDWARF<XCOFFSectAuxEntForDWARF64>(AuxEntPtr);
594 } else {
595 const XCOFFSectAuxEntForDWARF32 *AuxEntPtr =
596 getAuxEntPtr<XCOFFSectAuxEntForDWARF32>(AuxAddress);
597 printSectAuxEntForDWARF<XCOFFSectAuxEntForDWARF32>(AuxEntPtr);
598 }
599 break;
600 }
601 case XCOFF::C_BLOCK:
602 case XCOFF::C_FCN: {
603 checkNumOfAux();
604
605 uintptr_t AuxAddress = XCOFFObjectFile::getAdvancedSymbolEntryAddress(
606 SymbolEntRef.getEntryAddress(), 1);
607
608 if (Obj.is64Bit()) {
609 const XCOFFBlockAuxEnt64 *AuxEntPtr =
610 getAuxEntPtr<XCOFFBlockAuxEnt64>(AuxAddress);
611 printBlockAuxEnt(AuxEntPtr);
612 } else {
613 const XCOFFBlockAuxEnt32 *AuxEntPtr =
614 getAuxEntPtr<XCOFFBlockAuxEnt32>(AuxAddress);
615 printBlockAuxEnt(AuxEntPtr);
616 }
617 break;
618 }
619 default:
620 for (int i = 1; i <= NumberOfAuxEntries; i++) {
621 printUnexpectedRawAuxEnt(W,
622 XCOFFObjectFile::getAdvancedSymbolEntryAddress(
623 SymbolEntRef.getEntryAddress(), i));
624 }
625 break;
626 }
627 }
628
printSymbols()629 void XCOFFDumper::printSymbols() {
630 ListScope Group(W, "Symbols");
631 for (const SymbolRef &S : Obj.symbols())
632 printSymbol(S);
633 }
634
printStringTable()635 void XCOFFDumper::printStringTable() {
636 DictScope DS(W, "StringTable");
637 StringRef StrTable = Obj.getStringTable();
638 uint32_t StrTabSize = StrTable.size();
639 W.printNumber("Length", StrTabSize);
640 // Print strings from the fifth byte, since the first four bytes contain the
641 // length (in bytes) of the string table (including the length field).
642 if (StrTabSize > 4)
643 printAsStringList(StrTable, 4);
644 }
645
printDynamicSymbols()646 void XCOFFDumper::printDynamicSymbols() {
647 llvm_unreachable("Unimplemented functionality for XCOFFDumper");
648 }
649
printUnwindInfo()650 void XCOFFDumper::printUnwindInfo() {
651 llvm_unreachable("Unimplemented functionality for XCOFFDumper");
652 }
653
printStackMap() const654 void XCOFFDumper::printStackMap() const {
655 llvm_unreachable("Unimplemented functionality for XCOFFDumper");
656 }
657
printNeededLibraries()658 void XCOFFDumper::printNeededLibraries() {
659 ListScope D(W, "NeededLibraries");
660 auto ImportFilesOrError = Obj.getImportFileTable();
661 if (!ImportFilesOrError) {
662 reportUniqueWarning(ImportFilesOrError.takeError());
663 return;
664 }
665
666 StringRef ImportFileTable = ImportFilesOrError.get();
667 const char *CurrentStr = ImportFileTable.data();
668 const char *TableEnd = ImportFileTable.end();
669 // Default column width for names is 13 even if no names are that long.
670 size_t BaseWidth = 13;
671
672 // Get the max width of BASE columns.
673 for (size_t StrIndex = 0; CurrentStr < TableEnd; ++StrIndex) {
674 size_t CurrentLen = strlen(CurrentStr);
675 CurrentStr += strlen(CurrentStr) + 1;
676 if (StrIndex % 3 == 1)
677 BaseWidth = std::max(BaseWidth, CurrentLen);
678 }
679
680 auto &OS = static_cast<formatted_raw_ostream &>(W.startLine());
681 // Each entry consists of 3 strings: the path_name, base_name and
682 // archive_member_name. The first entry is a default LIBPATH value and other
683 // entries have no path_name. We just dump the base_name and
684 // archive_member_name here.
685 OS << left_justify("BASE", BaseWidth) << " MEMBER\n";
686 CurrentStr = ImportFileTable.data();
687 for (size_t StrIndex = 0; CurrentStr < TableEnd;
688 ++StrIndex, CurrentStr += strlen(CurrentStr) + 1) {
689 if (StrIndex >= 3 && StrIndex % 3 != 0) {
690 if (StrIndex % 3 == 1)
691 OS << " " << left_justify(CurrentStr, BaseWidth) << " ";
692 else
693 OS << CurrentStr << "\n";
694 }
695 }
696 }
697
698 const EnumEntry<XCOFF::SectionTypeFlags> SectionTypeFlagsNames[] = {
699 #define ECase(X) \
700 { #X, XCOFF::X }
701 ECase(STYP_PAD), ECase(STYP_DWARF), ECase(STYP_TEXT),
702 ECase(STYP_DATA), ECase(STYP_BSS), ECase(STYP_EXCEPT),
703 ECase(STYP_INFO), ECase(STYP_TDATA), ECase(STYP_TBSS),
704 ECase(STYP_LOADER), ECase(STYP_DEBUG), ECase(STYP_TYPCHK),
705 ECase(STYP_OVRFLO)
706 #undef ECase
707 };
708
709 template <typename T>
printOverflowSectionHeader(T & Sec) const710 void XCOFFDumper::printOverflowSectionHeader(T &Sec) const {
711 if (Obj.is64Bit()) {
712 reportWarning(make_error<StringError>("An 64-bit XCOFF object file may not "
713 "contain an overflow section header.",
714 object_error::parse_failed),
715 Obj.getFileName());
716 }
717
718 W.printString("Name", Sec.getName());
719 W.printNumber("NumberOfRelocations", Sec.PhysicalAddress);
720 W.printNumber("NumberOfLineNumbers", Sec.VirtualAddress);
721 W.printHex("Size", Sec.SectionSize);
722 W.printHex("RawDataOffset", Sec.FileOffsetToRawData);
723 W.printHex("RelocationPointer", Sec.FileOffsetToRelocationInfo);
724 W.printHex("LineNumberPointer", Sec.FileOffsetToLineNumberInfo);
725 W.printNumber("IndexOfSectionOverflowed", Sec.NumberOfRelocations);
726 W.printNumber("IndexOfSectionOverflowed", Sec.NumberOfLineNumbers);
727 }
728
729 template <typename T>
printGenericSectionHeader(T & Sec) const730 void XCOFFDumper::printGenericSectionHeader(T &Sec) const {
731 W.printString("Name", Sec.getName());
732 W.printHex("PhysicalAddress", Sec.PhysicalAddress);
733 W.printHex("VirtualAddress", Sec.VirtualAddress);
734 W.printHex("Size", Sec.SectionSize);
735 W.printHex("RawDataOffset", Sec.FileOffsetToRawData);
736 W.printHex("RelocationPointer", Sec.FileOffsetToRelocationInfo);
737 W.printHex("LineNumberPointer", Sec.FileOffsetToLineNumberInfo);
738 W.printNumber("NumberOfRelocations", Sec.NumberOfRelocations);
739 W.printNumber("NumberOfLineNumbers", Sec.NumberOfLineNumbers);
740 }
741
742 enum PrintStyle { Hex, Number };
743 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)744 static void printAuxMemberHelper(PrintStyle Style, const char *MemberName,
745 const T &Member, const V *AuxHeader,
746 uint16_t AuxSize, uint16_t &PartialFieldOffset,
747 const char *&PartialFieldName,
748 ScopedPrinter &W) {
749 ptrdiff_t Offset = reinterpret_cast<const char *>(&Member) -
750 reinterpret_cast<const char *>(AuxHeader);
751 if (Offset + sizeof(Member) <= AuxSize)
752 Style == Hex ? W.printHex(MemberName, Member)
753 : W.printNumber(MemberName, Member);
754 else if (Offset < AuxSize) {
755 PartialFieldOffset = Offset;
756 PartialFieldName = MemberName;
757 }
758 }
759
760 template <class T>
checkAndPrintAuxHeaderParseError(const char * PartialFieldName,uint16_t PartialFieldOffset,uint16_t AuxSize,T & AuxHeader,XCOFFDumper * Dumper)761 void checkAndPrintAuxHeaderParseError(const char *PartialFieldName,
762 uint16_t PartialFieldOffset,
763 uint16_t AuxSize, T &AuxHeader,
764 XCOFFDumper *Dumper) {
765 if (PartialFieldOffset < AuxSize) {
766 Dumper->reportUniqueWarning(Twine("only partial field for ") +
767 PartialFieldName + " at offset (" +
768 Twine(PartialFieldOffset) + ")");
769 Dumper->getScopedPrinter().printBinary(
770 "Raw data", "",
771 ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(&AuxHeader) +
772 PartialFieldOffset,
773 AuxSize - PartialFieldOffset));
774 } else if (sizeof(AuxHeader) < AuxSize)
775 Dumper->getScopedPrinter().printBinary(
776 "Extra raw data", "",
777 ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(&AuxHeader) +
778 sizeof(AuxHeader),
779 AuxSize - sizeof(AuxHeader)));
780 }
781
printAuxiliaryHeader(const XCOFFAuxiliaryHeader32 * AuxHeader)782 void XCOFFDumper::printAuxiliaryHeader(
783 const XCOFFAuxiliaryHeader32 *AuxHeader) {
784 if (AuxHeader == nullptr)
785 return;
786 uint16_t AuxSize = Obj.getOptionalHeaderSize();
787 uint16_t PartialFieldOffset = AuxSize;
788 const char *PartialFieldName = nullptr;
789
790 auto PrintAuxMember = [&](PrintStyle Style, const char *MemberName,
791 auto &Member) {
792 printAuxMemberHelper(Style, MemberName, Member, AuxHeader, AuxSize,
793 PartialFieldOffset, PartialFieldName, W);
794 };
795
796 PrintAuxMember(Hex, "Magic", AuxHeader->AuxMagic);
797 PrintAuxMember(Hex, "Version", AuxHeader->Version);
798 PrintAuxMember(Hex, "Size of .text section", AuxHeader->TextSize);
799 PrintAuxMember(Hex, "Size of .data section", AuxHeader->InitDataSize);
800 PrintAuxMember(Hex, "Size of .bss section", AuxHeader->BssDataSize);
801 PrintAuxMember(Hex, "Entry point address", AuxHeader->EntryPointAddr);
802 PrintAuxMember(Hex, ".text section start address", AuxHeader->TextStartAddr);
803 PrintAuxMember(Hex, ".data section start address", AuxHeader->DataStartAddr);
804 PrintAuxMember(Hex, "TOC anchor address", AuxHeader->TOCAnchorAddr);
805 PrintAuxMember(Number, "Section number of entryPoint",
806 AuxHeader->SecNumOfEntryPoint);
807 PrintAuxMember(Number, "Section number of .text", AuxHeader->SecNumOfText);
808 PrintAuxMember(Number, "Section number of .data", AuxHeader->SecNumOfData);
809 PrintAuxMember(Number, "Section number of TOC", AuxHeader->SecNumOfTOC);
810 PrintAuxMember(Number, "Section number of loader data",
811 AuxHeader->SecNumOfLoader);
812 PrintAuxMember(Number, "Section number of .bss", AuxHeader->SecNumOfBSS);
813 PrintAuxMember(Hex, "Maxium alignment of .text", AuxHeader->MaxAlignOfText);
814 PrintAuxMember(Hex, "Maxium alignment of .data", AuxHeader->MaxAlignOfData);
815 PrintAuxMember(Hex, "Module type", AuxHeader->ModuleType);
816 PrintAuxMember(Hex, "CPU type of objects", AuxHeader->CpuFlag);
817 PrintAuxMember(Hex, "(Reserved)", AuxHeader->CpuType);
818 PrintAuxMember(Hex, "Maximum stack size", AuxHeader->MaxStackSize);
819 PrintAuxMember(Hex, "Maximum data size", AuxHeader->MaxDataSize);
820 PrintAuxMember(Hex, "Reserved for debugger", AuxHeader->ReservedForDebugger);
821 PrintAuxMember(Hex, "Text page size", AuxHeader->TextPageSize);
822 PrintAuxMember(Hex, "Data page size", AuxHeader->DataPageSize);
823 PrintAuxMember(Hex, "Stack page size", AuxHeader->StackPageSize);
824 if (offsetof(XCOFFAuxiliaryHeader32, FlagAndTDataAlignment) +
825 sizeof(XCOFFAuxiliaryHeader32::FlagAndTDataAlignment) <=
826 AuxSize) {
827 W.printHex("Flag", AuxHeader->getFlag());
828 W.printHex("Alignment of thread-local storage",
829 AuxHeader->getTDataAlignment());
830 }
831
832 PrintAuxMember(Number, "Section number for .tdata", AuxHeader->SecNumOfTData);
833 PrintAuxMember(Number, "Section number for .tbss", AuxHeader->SecNumOfTBSS);
834
835 checkAndPrintAuxHeaderParseError(PartialFieldName, PartialFieldOffset,
836 AuxSize, *AuxHeader, this);
837 }
838
printAuxiliaryHeader(const XCOFFAuxiliaryHeader64 * AuxHeader)839 void XCOFFDumper::printAuxiliaryHeader(
840 const XCOFFAuxiliaryHeader64 *AuxHeader) {
841 if (AuxHeader == nullptr)
842 return;
843 uint16_t AuxSize = Obj.getOptionalHeaderSize();
844 uint16_t PartialFieldOffset = AuxSize;
845 const char *PartialFieldName = nullptr;
846
847 auto PrintAuxMember = [&](PrintStyle Style, const char *MemberName,
848 auto &Member) {
849 printAuxMemberHelper(Style, MemberName, Member, AuxHeader, AuxSize,
850 PartialFieldOffset, PartialFieldName, W);
851 };
852
853 PrintAuxMember(Hex, "Magic", AuxHeader->AuxMagic);
854 PrintAuxMember(Hex, "Version", AuxHeader->Version);
855 PrintAuxMember(Hex, "Reserved for debugger", AuxHeader->ReservedForDebugger);
856 PrintAuxMember(Hex, ".text section start address", AuxHeader->TextStartAddr);
857 PrintAuxMember(Hex, ".data section start address", AuxHeader->DataStartAddr);
858 PrintAuxMember(Hex, "TOC anchor address", AuxHeader->TOCAnchorAddr);
859 PrintAuxMember(Number, "Section number of entryPoint",
860 AuxHeader->SecNumOfEntryPoint);
861 PrintAuxMember(Number, "Section number of .text", AuxHeader->SecNumOfText);
862 PrintAuxMember(Number, "Section number of .data", AuxHeader->SecNumOfData);
863 PrintAuxMember(Number, "Section number of TOC", AuxHeader->SecNumOfTOC);
864 PrintAuxMember(Number, "Section number of loader data",
865 AuxHeader->SecNumOfLoader);
866 PrintAuxMember(Number, "Section number of .bss", AuxHeader->SecNumOfBSS);
867 PrintAuxMember(Hex, "Maxium alignment of .text", AuxHeader->MaxAlignOfText);
868 PrintAuxMember(Hex, "Maxium alignment of .data", AuxHeader->MaxAlignOfData);
869 PrintAuxMember(Hex, "Module type", AuxHeader->ModuleType);
870 PrintAuxMember(Hex, "CPU type of objects", AuxHeader->CpuFlag);
871 PrintAuxMember(Hex, "(Reserved)", AuxHeader->CpuType);
872 PrintAuxMember(Hex, "Text page size", AuxHeader->TextPageSize);
873 PrintAuxMember(Hex, "Data page size", AuxHeader->DataPageSize);
874 PrintAuxMember(Hex, "Stack page size", AuxHeader->StackPageSize);
875 if (offsetof(XCOFFAuxiliaryHeader64, FlagAndTDataAlignment) +
876 sizeof(XCOFFAuxiliaryHeader64::FlagAndTDataAlignment) <=
877 AuxSize) {
878 W.printHex("Flag", AuxHeader->getFlag());
879 W.printHex("Alignment of thread-local storage",
880 AuxHeader->getTDataAlignment());
881 }
882 PrintAuxMember(Hex, "Size of .text section", AuxHeader->TextSize);
883 PrintAuxMember(Hex, "Size of .data section", AuxHeader->InitDataSize);
884 PrintAuxMember(Hex, "Size of .bss section", AuxHeader->BssDataSize);
885 PrintAuxMember(Hex, "Entry point address", AuxHeader->EntryPointAddr);
886 PrintAuxMember(Hex, "Maximum stack size", AuxHeader->MaxStackSize);
887 PrintAuxMember(Hex, "Maximum data size", AuxHeader->MaxDataSize);
888 PrintAuxMember(Number, "Section number for .tdata", AuxHeader->SecNumOfTData);
889 PrintAuxMember(Number, "Section number for .tbss", AuxHeader->SecNumOfTBSS);
890 PrintAuxMember(Hex, "Additional flags 64-bit XCOFF", AuxHeader->XCOFF64Flag);
891
892 checkAndPrintAuxHeaderParseError(PartialFieldName, PartialFieldOffset,
893 AuxSize, *AuxHeader, this);
894 }
895
896 template <typename T>
printSectionHeaders(ArrayRef<T> Sections)897 void XCOFFDumper::printSectionHeaders(ArrayRef<T> Sections) {
898 ListScope Group(W, "Sections");
899
900 uint16_t Index = 1;
901 for (const T &Sec : Sections) {
902 DictScope SecDS(W, "Section");
903
904 W.printNumber("Index", Index++);
905 uint16_t SectionType = Sec.getSectionType();
906 switch (SectionType) {
907 case XCOFF::STYP_OVRFLO:
908 printOverflowSectionHeader(Sec);
909 break;
910 case XCOFF::STYP_LOADER:
911 case XCOFF::STYP_EXCEPT:
912 case XCOFF::STYP_TYPCHK:
913 // TODO The interpretation of loader, exception and type check section
914 // headers are different from that of generic section headers. We will
915 // implement them later. We interpret them as generic section headers for
916 // now.
917 default:
918 printGenericSectionHeader(Sec);
919 break;
920 }
921 if (Sec.isReservedSectionType())
922 W.printHex("Flags", "Reserved", SectionType);
923 else
924 W.printEnum("Type", SectionType, makeArrayRef(SectionTypeFlagsNames));
925 }
926
927 if (opts::SectionRelocations)
928 report_fatal_error("Dumping section relocations is unimplemented");
929
930 if (opts::SectionSymbols)
931 report_fatal_error("Dumping symbols is unimplemented");
932
933 if (opts::SectionData)
934 report_fatal_error("Dumping section data is unimplemented");
935 }
936
937 namespace llvm {
938 std::unique_ptr<ObjDumper>
createXCOFFDumper(const object::XCOFFObjectFile & XObj,ScopedPrinter & Writer)939 createXCOFFDumper(const object::XCOFFObjectFile &XObj, ScopedPrinter &Writer) {
940 return std::make_unique<XCOFFDumper>(XObj, Writer);
941 }
942 } // namespace llvm
943