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