1//===-- XCOFFDump.cpp - XCOFF-specific dumper -----------------------------===//
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/// \file
10/// This file implements the XCOFF-specific dumper for llvm-objdump.
11///
12//===----------------------------------------------------------------------===//
13
14#include "XCOFFDump.h"
15
16#include "llvm-objdump.h"
17#include "llvm/ADT/StringExtras.h"
18#include "llvm/Demangle/Demangle.h"
19#include "llvm/MC/MCInstPrinter.h"
20#include "llvm/MC/MCSubtargetInfo.h"
21#include "llvm/Support/Endian.h"
22#include "llvm/Support/Format.h"
23#include "llvm/Support/FormattedStream.h"
24#include "llvm/Support/raw_ostream.h"
25#include <algorithm>
26
27using namespace llvm;
28using namespace llvm::object;
29using namespace llvm::XCOFF;
30using namespace llvm::support;
31
32namespace {
33class XCOFFDumper : public objdump::Dumper {
34 enum PrintStyle { Hex, Number };
35 const XCOFFObjectFile &Obj;
36 unsigned Width;
37
38public:
39 XCOFFDumper(const object::XCOFFObjectFile &O) : Dumper(O), Obj(O) {}
40
41private:
42 void printPrivateHeaders() override;
43 void printFileHeader();
44 void printAuxiliaryHeader();
45 void printLoaderSectionHeader();
46 void printAuxiliaryHeader(const XCOFFAuxiliaryHeader32 *AuxHeader);
47 void printAuxiliaryHeader(const XCOFFAuxiliaryHeader64 *AuxHeader);
48 template <typename AuxHeaderMemberType, typename XCOFFAuxiliaryHeader>
49 void printAuxMemberHelper(PrintStyle Style, const char *MemberName,
50 const AuxHeaderMemberType &Member,
51 const XCOFFAuxiliaryHeader *AuxHeader,
52 uint16_t AuxSize, uint16_t &PartialFieldOffset,
53 const char *&PartialFieldName);
54 template <typename XCOFFAuxiliaryHeader>
55 void checkAndPrintAuxHeaderParseError(const char *PartialFieldName,
56 uint16_t PartialFieldOffset,
57 uint16_t AuxSize,
58 XCOFFAuxiliaryHeader &AuxHeader);
59
60 void printBinary(StringRef Name, ArrayRef<uint8_t> Data);
61 void printHex(StringRef Name, uint64_t Value);
62 void printNumber(StringRef Name, uint64_t Value);
63 FormattedString formatName(StringRef Name);
64 void printStrHex(StringRef Name, StringRef Str, uint64_t Value);
65};
66
67void XCOFFDumper::printPrivateHeaders() {
68 printFileHeader();
69 printAuxiliaryHeader();
70 printLoaderSectionHeader();
71}
72
73FormattedString XCOFFDumper::formatName(StringRef Name) {
74 return FormattedString(Name, Width, FormattedString::JustifyLeft);
75}
76
77void XCOFFDumper::printHex(StringRef Name, uint64_t Value) {
78 outs() << formatName(Name) << format_hex(N: Value, Width: 0) << "\n";
79}
80
81void XCOFFDumper::printNumber(StringRef Name, uint64_t Value) {
82 outs() << formatName(Name) << format_decimal(N: Value, Width: 0) << "\n";
83}
84
85void XCOFFDumper::printStrHex(StringRef Name, StringRef Str, uint64_t Value) {
86 outs() << formatName(Name) << Str << " (" << format_decimal(N: Value, Width: 0)
87 << ")\n";
88}
89
90void XCOFFDumper::printBinary(StringRef Name, ArrayRef<uint8_t> Data) {
91 unsigned OrgWidth = Width;
92 Width = 0;
93 outs() << formatName(Name) << " (" << format_bytes(Bytes: Data) << ")\n";
94 Width = OrgWidth;
95}
96
97void XCOFFDumper::printAuxiliaryHeader() {
98 Width = 36;
99 if (Obj.is64Bit())
100 printAuxiliaryHeader(AuxHeader: Obj.auxiliaryHeader64());
101 else
102 printAuxiliaryHeader(AuxHeader: Obj.auxiliaryHeader32());
103}
104
105template <typename AuxHeaderMemberType, typename XCOFFAuxiliaryHeader>
106void XCOFFDumper::printAuxMemberHelper(PrintStyle Style, const char *MemberName,
107 const AuxHeaderMemberType &Member,
108 const XCOFFAuxiliaryHeader *AuxHeader,
109 uint16_t AuxSize,
110 uint16_t &PartialFieldOffset,
111 const char *&PartialFieldName) {
112 ptrdiff_t Offset = reinterpret_cast<const char *>(&Member) -
113 reinterpret_cast<const char *>(AuxHeader);
114 if (Offset + sizeof(Member) <= AuxSize) {
115 if (Style == Hex)
116 printHex(Name: MemberName, Value: Member);
117 else
118 printNumber(Name: MemberName, Value: Member);
119 } else if (Offset < AuxSize) {
120 PartialFieldOffset = Offset;
121 PartialFieldName = MemberName;
122 }
123}
124
125template <typename XCOFFAuxiliaryHeader>
126void XCOFFDumper::checkAndPrintAuxHeaderParseError(
127 const char *PartialFieldName, uint16_t PartialFieldOffset, uint16_t AuxSize,
128 XCOFFAuxiliaryHeader &AuxHeader) {
129 if (PartialFieldOffset < AuxSize) {
130 std::string Buf;
131 raw_string_ostream OS(Buf);
132 OS.flush();
133 OS << FormattedString("Raw data", 0, FormattedString::JustifyLeft) << " ("
134 << format_bytes(
135 Bytes: ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(&AuxHeader) +
136 PartialFieldOffset,
137 AuxSize - PartialFieldOffset))
138 << ")\n";
139 reportUniqueWarning(Msg: Twine("only partial field for ") + PartialFieldName +
140 " at offset (" + Twine(PartialFieldOffset) + ")\n" +
141 OS.str());
142 } else if (sizeof(AuxHeader) < AuxSize) {
143 printBinary(
144 Name: "Extra raw data",
145 Data: ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(&AuxHeader) +
146 sizeof(AuxHeader),
147 AuxSize - sizeof(AuxHeader)));
148 }
149}
150
151void XCOFFDumper::printAuxiliaryHeader(
152 const XCOFFAuxiliaryHeader32 *AuxHeader) {
153 if (AuxHeader == nullptr)
154 return;
155 outs() << "\n---Auxiliary Header:\n";
156 uint16_t AuxSize = Obj.getOptionalHeaderSize();
157 uint16_t PartialFieldOffset = AuxSize;
158 const char *PartialFieldName = nullptr;
159
160 auto PrintAuxMember = [&](PrintStyle Style, const char *MemberName,
161 auto &Member) {
162 printAuxMemberHelper(Style, MemberName, Member, AuxHeader, AuxSize,
163 PartialFieldOffset, PartialFieldName);
164 };
165
166 PrintAuxMember(Hex, "Magic:", AuxHeader->AuxMagic);
167 PrintAuxMember(Hex, "Version:", AuxHeader->Version);
168 PrintAuxMember(Hex, "Size of .text section:", AuxHeader->TextSize);
169 PrintAuxMember(Hex, "Size of .data section:", AuxHeader->InitDataSize);
170 PrintAuxMember(Hex, "Size of .bss section:", AuxHeader->BssDataSize);
171 PrintAuxMember(Hex, "Entry point address:", AuxHeader->EntryPointAddr);
172 PrintAuxMember(Hex, ".text section start address:", AuxHeader->TextStartAddr);
173 PrintAuxMember(Hex, ".data section start address:", AuxHeader->DataStartAddr);
174 PrintAuxMember(Hex, "TOC anchor address:", AuxHeader->TOCAnchorAddr);
175 PrintAuxMember(
176 Number, "Section number of entryPoint:", AuxHeader->SecNumOfEntryPoint);
177 PrintAuxMember(Number, "Section number of .text:", AuxHeader->SecNumOfText);
178 PrintAuxMember(Number, "Section number of .data:", AuxHeader->SecNumOfData);
179 PrintAuxMember(Number, "Section number of TOC:", AuxHeader->SecNumOfTOC);
180 PrintAuxMember(Number,
181 "Section number of loader data:", AuxHeader->SecNumOfLoader);
182 PrintAuxMember(Number, "Section number of .bss:", AuxHeader->SecNumOfBSS);
183 PrintAuxMember(Hex, "Maxium alignment of .text:", AuxHeader->MaxAlignOfText);
184 PrintAuxMember(Hex, "Maxium alignment of .data:", AuxHeader->MaxAlignOfData);
185 PrintAuxMember(Hex, "Module type:", AuxHeader->ModuleType);
186 PrintAuxMember(Hex, "CPU type of objects:", AuxHeader->CpuFlag);
187 PrintAuxMember(Hex, "Maximum stack size:", AuxHeader->MaxStackSize);
188 PrintAuxMember(Hex, "Maximum data size:", AuxHeader->MaxDataSize);
189 PrintAuxMember(Hex, "Reserved for debugger:", AuxHeader->ReservedForDebugger);
190 PrintAuxMember(Hex, "Text page size:", AuxHeader->TextPageSize);
191 PrintAuxMember(Hex, "Data page size:", AuxHeader->DataPageSize);
192 PrintAuxMember(Hex, "Stack page size:", AuxHeader->StackPageSize);
193 if (offsetof(XCOFFAuxiliaryHeader32, FlagAndTDataAlignment) +
194 sizeof(XCOFFAuxiliaryHeader32::FlagAndTDataAlignment) <=
195 AuxSize) {
196 printHex(Name: "Flag:", Value: AuxHeader->getFlag());
197 printHex(Name: "Alignment of thread-local storage:",
198 Value: AuxHeader->getTDataAlignment());
199 }
200
201 PrintAuxMember(Number,
202 "Section number for .tdata:", AuxHeader->SecNumOfTData);
203 PrintAuxMember(Number, "Section number for .tbss:", AuxHeader->SecNumOfTBSS);
204
205 checkAndPrintAuxHeaderParseError(PartialFieldName, PartialFieldOffset,
206 AuxSize, AuxHeader: *AuxHeader);
207}
208
209void XCOFFDumper::printAuxiliaryHeader(
210 const XCOFFAuxiliaryHeader64 *AuxHeader) {
211 if (AuxHeader == nullptr)
212 return;
213 uint16_t AuxSize = Obj.getOptionalHeaderSize();
214 outs() << "\n---Auxiliary Header:\n";
215 uint16_t PartialFieldOffset = AuxSize;
216 const char *PartialFieldName = nullptr;
217
218 auto PrintAuxMember = [&](PrintStyle Style, const char *MemberName,
219 auto &Member) {
220 printAuxMemberHelper(Style, MemberName, Member, AuxHeader, AuxSize,
221 PartialFieldOffset, PartialFieldName);
222 };
223
224 PrintAuxMember(Hex, "Magic:", AuxHeader->AuxMagic);
225 PrintAuxMember(Hex, "Version:", AuxHeader->Version);
226 PrintAuxMember(Hex, "Reserved for debugger:", AuxHeader->ReservedForDebugger);
227 PrintAuxMember(Hex, ".text section start address:", AuxHeader->TextStartAddr);
228 PrintAuxMember(Hex, ".data section start address:", AuxHeader->DataStartAddr);
229 PrintAuxMember(Hex, "TOC anchor address:", AuxHeader->TOCAnchorAddr);
230 PrintAuxMember(
231 Number, "Section number of entryPoint:", AuxHeader->SecNumOfEntryPoint);
232 PrintAuxMember(Number, "Section number of .text:", AuxHeader->SecNumOfText);
233 PrintAuxMember(Number, "Section number of .data:", AuxHeader->SecNumOfData);
234 PrintAuxMember(Number, "Section number of TOC:", AuxHeader->SecNumOfTOC);
235 PrintAuxMember(Number,
236 "Section number of loader data:", AuxHeader->SecNumOfLoader);
237 PrintAuxMember(Number, "Section number of .bss:", AuxHeader->SecNumOfBSS);
238 PrintAuxMember(Hex, "Maxium alignment of .text:", AuxHeader->MaxAlignOfText);
239 PrintAuxMember(Hex, "Maxium alignment of .data:", AuxHeader->MaxAlignOfData);
240 PrintAuxMember(Hex, "Module type:", AuxHeader->ModuleType);
241 PrintAuxMember(Hex, "CPU type of objects:", AuxHeader->CpuFlag);
242 PrintAuxMember(Hex, "Text page size:", AuxHeader->TextPageSize);
243 PrintAuxMember(Hex, "Data page size:", AuxHeader->DataPageSize);
244 PrintAuxMember(Hex, "Stack page size:", AuxHeader->StackPageSize);
245 if (offsetof(XCOFFAuxiliaryHeader64, FlagAndTDataAlignment) +
246 sizeof(XCOFFAuxiliaryHeader64::FlagAndTDataAlignment) <=
247 AuxSize) {
248 printHex(Name: "Flag:", Value: AuxHeader->getFlag());
249 printHex(Name: "Alignment of thread-local storage:",
250 Value: AuxHeader->getTDataAlignment());
251 }
252 PrintAuxMember(Hex, "Size of .text section:", AuxHeader->TextSize);
253 PrintAuxMember(Hex, "Size of .data section:", AuxHeader->InitDataSize);
254 PrintAuxMember(Hex, "Size of .bss section:", AuxHeader->BssDataSize);
255 PrintAuxMember(Hex, "Entry point address:", AuxHeader->EntryPointAddr);
256 PrintAuxMember(Hex, "Maximum stack size:", AuxHeader->MaxStackSize);
257 PrintAuxMember(Hex, "Maximum data size:", AuxHeader->MaxDataSize);
258 PrintAuxMember(Number,
259 "Section number for .tdata:", AuxHeader->SecNumOfTData);
260 PrintAuxMember(Number, "Section number for .tbss:", AuxHeader->SecNumOfTBSS);
261 PrintAuxMember(Hex, "Additional flags 64-bit XCOFF:", AuxHeader->XCOFF64Flag);
262
263 checkAndPrintAuxHeaderParseError(PartialFieldName, PartialFieldOffset,
264 AuxSize, AuxHeader: *AuxHeader);
265}
266
267void XCOFFDumper::printLoaderSectionHeader() {
268 Expected<uintptr_t> LoaderSectionAddrOrError =
269 Obj.getSectionFileOffsetToRawData(SectType: XCOFF::STYP_LOADER);
270 if (!LoaderSectionAddrOrError) {
271 reportUniqueWarning(Err: LoaderSectionAddrOrError.takeError());
272 return;
273 }
274 uintptr_t LoaderSectionAddr = LoaderSectionAddrOrError.get();
275
276 if (LoaderSectionAddr == 0)
277 return;
278
279 auto PrintLoadSecHeaderCommon = [&](const auto *LDHeader) {
280 printNumber(Name: "Version:", Value: LDHeader->Version);
281 printNumber(Name: "NumberOfSymbolEntries:", Value: LDHeader->NumberOfSymTabEnt);
282 printNumber(Name: "NumberOfRelocationEntries:", Value: LDHeader->NumberOfRelTabEnt);
283 printNumber(Name: "LengthOfImportFileIDStringTable:",
284 Value: LDHeader->LengthOfImpidStrTbl);
285 printNumber(Name: "NumberOfImportFileIDs:", Value: LDHeader->NumberOfImpid);
286 printHex(Name: "OffsetToImportFileIDs:", Value: LDHeader->OffsetToImpid);
287 printNumber(Name: "LengthOfStringTable:", Value: LDHeader->LengthOfStrTbl);
288 printHex(Name: "OffsetToStringTable:", Value: LDHeader->OffsetToStrTbl);
289 };
290
291 Width = 35;
292 outs() << "\n---Loader Section Header:\n";
293 if (Obj.is64Bit()) {
294 const LoaderSectionHeader64 *LoaderSec64 =
295 reinterpret_cast<const LoaderSectionHeader64 *>(LoaderSectionAddr);
296 PrintLoadSecHeaderCommon(LoaderSec64);
297 printHex(Name: "OffsetToSymbolTable", Value: LoaderSec64->OffsetToSymTbl);
298 printHex(Name: "OffsetToRelocationEntries", Value: LoaderSec64->OffsetToRelEnt);
299 } else {
300 const LoaderSectionHeader32 *LoaderSec32 =
301 reinterpret_cast<const LoaderSectionHeader32 *>(LoaderSectionAddr);
302 PrintLoadSecHeaderCommon(LoaderSec32);
303 }
304}
305
306void XCOFFDumper::printFileHeader() {
307 Width = 20;
308 outs() << "\n---File Header:\n";
309 printHex(Name: "Magic:", Value: Obj.getMagic());
310 printNumber(Name: "NumberOfSections:", Value: Obj.getNumberOfSections());
311
312 int32_t Timestamp = Obj.getTimeStamp();
313 if (Timestamp > 0) {
314 // This handling of the timestamp assumes that the host system's time_t is
315 // compatible with AIX time_t. If a platform is not compatible, the lit
316 // tests will let us know.
317 time_t TimeDate = Timestamp;
318
319 char FormattedTime[20] = {};
320
321 size_t BytesFormatted = std::strftime(s: FormattedTime, maxsize: sizeof(FormattedTime),
322 format: "%F %T", tp: std::gmtime(timer: &TimeDate));
323 assert(BytesFormatted && "The size of the buffer FormattedTime is less "
324 "than the size of the date/time string.");
325 (void)BytesFormatted;
326 printStrHex(Name: "Timestamp:", Str: FormattedTime, Value: Timestamp);
327 } else {
328 // Negative timestamp values are reserved for future use.
329 printStrHex(Name: "Timestamp:", Str: Timestamp == 0 ? "None" : "Reserved Value",
330 Value: Timestamp);
331 }
332
333 // The number of symbol table entries is an unsigned value in 64-bit objects
334 // and a signed value (with negative values being 'reserved') in 32-bit
335 // objects.
336 if (Obj.is64Bit()) {
337 printHex(Name: "SymbolTableOffset:", Value: Obj.getSymbolTableOffset64());
338 printNumber(Name: "SymbolTableEntries:", Value: Obj.getNumberOfSymbolTableEntries64());
339 } else {
340 printHex(Name: "SymbolTableOffset:", Value: Obj.getSymbolTableOffset32());
341 int32_t SymTabEntries = Obj.getRawNumberOfSymbolTableEntries32();
342 if (SymTabEntries >= 0)
343 printNumber(Name: "SymbolTableEntries:", Value: SymTabEntries);
344 else
345 printStrHex(Name: "SymbolTableEntries:", Str: "Reserved Value", Value: SymTabEntries);
346 }
347
348 printHex(Name: "OptionalHeaderSize:", Value: Obj.getOptionalHeaderSize());
349 printHex(Name: "Flags:", Value: Obj.getFlags());
350}
351
352} // namespace
353
354std::unique_ptr<objdump::Dumper>
355objdump::createXCOFFDumper(const object::XCOFFObjectFile &Obj) {
356 return std::make_unique<XCOFFDumper>(args: Obj);
357}
358
359Error objdump::getXCOFFRelocationValueString(const XCOFFObjectFile &Obj,
360 const RelocationRef &Rel,
361 bool SymbolDescription,
362 SmallVectorImpl<char> &Result) {
363 symbol_iterator SymI = Rel.getSymbol();
364 if (SymI == Obj.symbol_end())
365 return make_error<GenericBinaryError>(
366 Args: "invalid symbol reference in relocation entry",
367 Args: object_error::parse_failed);
368
369 Expected<StringRef> SymNameOrErr = SymI->getName();
370 if (!SymNameOrErr)
371 return SymNameOrErr.takeError();
372
373 std::string SymName =
374 Demangle ? demangle(MangledName: *SymNameOrErr) : SymNameOrErr->str();
375 if (SymbolDescription)
376 SymName = getXCOFFSymbolDescription(SymbolInfo: createSymbolInfo(Obj, Symbol: *SymI), SymbolName: SymName);
377
378 Result.append(in_start: SymName.begin(), in_end: SymName.end());
379 return Error::success();
380}
381
382std::optional<XCOFF::StorageMappingClass>
383objdump::getXCOFFSymbolCsectSMC(const XCOFFObjectFile &Obj,
384 const SymbolRef &Sym) {
385 const XCOFFSymbolRef SymRef = Obj.toSymbolRef(Ref: Sym.getRawDataRefImpl());
386
387 if (!SymRef.isCsectSymbol())
388 return std::nullopt;
389
390 auto CsectAuxEntOrErr = SymRef.getXCOFFCsectAuxRef();
391 if (!CsectAuxEntOrErr)
392 return std::nullopt;
393
394 return CsectAuxEntOrErr.get().getStorageMappingClass();
395}
396
397std::optional<object::SymbolRef>
398objdump::getXCOFFSymbolContainingSymbolRef(const XCOFFObjectFile &Obj,
399 const SymbolRef &Sym) {
400 const XCOFFSymbolRef SymRef = Obj.toSymbolRef(Ref: Sym.getRawDataRefImpl());
401 if (!SymRef.isCsectSymbol())
402 return std::nullopt;
403
404 Expected<XCOFFCsectAuxRef> CsectAuxEntOrErr = SymRef.getXCOFFCsectAuxRef();
405 if (!CsectAuxEntOrErr || !CsectAuxEntOrErr.get().isLabel())
406 return std::nullopt;
407 uint32_t Idx =
408 static_cast<uint32_t>(CsectAuxEntOrErr.get().getSectionOrLength());
409 DataRefImpl DRI;
410 DRI.p = Obj.getSymbolByIndex(Idx);
411 return SymbolRef(DRI, &Obj);
412}
413
414bool objdump::isLabel(const XCOFFObjectFile &Obj, const SymbolRef &Sym) {
415 const XCOFFSymbolRef SymRef = Obj.toSymbolRef(Ref: Sym.getRawDataRefImpl());
416 if (!SymRef.isCsectSymbol())
417 return false;
418
419 auto CsectAuxEntOrErr = SymRef.getXCOFFCsectAuxRef();
420 if (!CsectAuxEntOrErr)
421 return false;
422
423 return CsectAuxEntOrErr.get().isLabel();
424}
425
426std::string objdump::getXCOFFSymbolDescription(const SymbolInfoTy &SymbolInfo,
427 StringRef SymbolName) {
428 assert(SymbolInfo.isXCOFF() && "Must be a XCOFFSymInfo.");
429
430 std::string Result;
431 // Dummy symbols have no symbol index.
432 if (SymbolInfo.XCOFFSymInfo.Index)
433 Result =
434 ("(idx: " + Twine(*SymbolInfo.XCOFFSymInfo.Index) + ") " + SymbolName)
435 .str();
436 else
437 Result.append(first: SymbolName.begin(), last: SymbolName.end());
438
439 if (SymbolInfo.XCOFFSymInfo.StorageMappingClass &&
440 !SymbolInfo.XCOFFSymInfo.IsLabel) {
441 const XCOFF::StorageMappingClass Smc =
442 *SymbolInfo.XCOFFSymInfo.StorageMappingClass;
443 Result.append(str: ("[" + XCOFF::getMappingClassString(SMC: Smc) + "]").str());
444 }
445
446 return Result;
447}
448
449#define PRINTBOOL(Prefix, Obj, Field) \
450 OS << Prefix << " " << ((Obj.Field()) ? "+" : "-") << #Field
451
452#define PRINTGET(Prefix, Obj, Field) \
453 OS << Prefix << " " << #Field << " = " \
454 << static_cast<unsigned>(Obj.get##Field())
455
456#define PRINTOPTIONAL(Field) \
457 if (TbTable.get##Field()) { \
458 OS << '\n'; \
459 printRawData(Bytes.slice(Index, 4), Address + Index, OS, STI); \
460 Index += 4; \
461 OS << "\t# " << #Field << " = " << *TbTable.get##Field(); \
462 }
463
464void objdump::dumpTracebackTable(ArrayRef<uint8_t> Bytes, uint64_t Address,
465 formatted_raw_ostream &OS, uint64_t End,
466 const MCSubtargetInfo &STI,
467 const XCOFFObjectFile *Obj) {
468 uint64_t Index = 0;
469 unsigned TabStop = getInstStartColumn(STI) - 1;
470 // Print traceback table boundary.
471 printRawData(Bytes: Bytes.slice(N: Index, M: 4), Address, OS, STI);
472 OS << "\t# Traceback table start\n";
473 Index += 4;
474
475 uint64_t Size = End - Address;
476 bool Is64Bit = Obj->is64Bit();
477
478 // XCOFFTracebackTable::create modifies the size parameter, so ensure Size
479 // isn't changed.
480 uint64_t SizeCopy = End - Address;
481 Expected<XCOFFTracebackTable> TTOrErr =
482 XCOFFTracebackTable::create(Ptr: Bytes.data() + Index, Size&: SizeCopy, Is64Bits: Is64Bit);
483
484 if (!TTOrErr) {
485 std::string WarningMsgStr;
486 raw_string_ostream WarningStream(WarningMsgStr);
487 WarningStream << "failure parsing traceback table with address: 0x"
488 << utohexstr(X: Address) + "\n>>> "
489 << toString(E: TTOrErr.takeError())
490 << "\n>>> Raw traceback table data is:\n";
491
492 uint64_t LastNonZero = Index;
493 for (uint64_t I = Index; I < Size; I += 4)
494 if (support::endian::read32be(P: Bytes.slice(N: I, M: 4).data()) != 0)
495 LastNonZero = I + 4 > Size ? Size : I + 4;
496
497 if (Size - LastNonZero <= 4)
498 LastNonZero = Size;
499
500 formatted_raw_ostream FOS(WarningStream);
501 while (Index < LastNonZero) {
502 printRawData(Bytes: Bytes.slice(N: Index, M: 4), Address: Address + Index, OS&: FOS, STI);
503 Index += 4;
504 WarningStream << '\n';
505 }
506
507 // Print all remaining zeroes as ...
508 if (Size - LastNonZero >= 8)
509 WarningStream << "\t\t...\n";
510
511 reportWarning(Message: WarningMsgStr, File: Obj->getFileName());
512 return;
513 }
514
515 auto PrintBytes = [&](uint64_t N) {
516 printRawData(Bytes: Bytes.slice(N: Index, M: N), Address: Address + Index, OS, STI);
517 Index += N;
518 };
519
520 XCOFFTracebackTable TbTable = *TTOrErr;
521 // Print the first of the 8 bytes of mandatory fields.
522 PrintBytes(1);
523 OS << format(Fmt: "\t# Version = %i", Vals: TbTable.getVersion()) << '\n';
524
525 // Print the second of the 8 bytes of mandatory fields.
526 PrintBytes(1);
527 TracebackTable::LanguageID LangId =
528 static_cast<TracebackTable::LanguageID>(TbTable.getLanguageID());
529 OS << "\t# Language = " << getNameForTracebackTableLanguageId(LangId) << '\n';
530
531 auto Split = [&]() {
532 OS << '\n';
533 OS.indent(NumSpaces: TabStop);
534 };
535
536 // Print the third of the 8 bytes of mandatory fields.
537 PrintBytes(1);
538 PRINTBOOL("\t#", TbTable, isGlobalLinkage);
539 PRINTBOOL(",", TbTable, isOutOfLineEpilogOrPrologue);
540 Split();
541 PRINTBOOL("\t ", TbTable, hasTraceBackTableOffset);
542 PRINTBOOL(",", TbTable, isInternalProcedure);
543 Split();
544 PRINTBOOL("\t ", TbTable, hasControlledStorage);
545 PRINTBOOL(",", TbTable, isTOCless);
546 Split();
547 PRINTBOOL("\t ", TbTable, isFloatingPointPresent);
548 Split();
549 PRINTBOOL("\t ", TbTable, isFloatingPointOperationLogOrAbortEnabled);
550 OS << '\n';
551
552 // Print the 4th of the 8 bytes of mandatory fields.
553 PrintBytes(1);
554 PRINTBOOL("\t#", TbTable, isInterruptHandler);
555 PRINTBOOL(",", TbTable, isFuncNamePresent);
556 PRINTBOOL(",", TbTable, isAllocaUsed);
557 Split();
558 PRINTGET("\t ", TbTable, OnConditionDirective);
559 PRINTBOOL(",", TbTable, isCRSaved);
560 PRINTBOOL(",", TbTable, isLRSaved);
561 OS << '\n';
562
563 // Print the 5th of the 8 bytes of mandatory fields.
564 PrintBytes(1);
565 PRINTBOOL("\t#", TbTable, isBackChainStored);
566 PRINTBOOL(",", TbTable, isFixup);
567 PRINTGET(",", TbTable, NumOfFPRsSaved);
568 OS << '\n';
569
570 // Print the 6th of the 8 bytes of mandatory fields.
571 PrintBytes(1);
572 PRINTBOOL("\t#", TbTable, hasExtensionTable);
573 PRINTBOOL(",", TbTable, hasVectorInfo);
574 PRINTGET(",", TbTable, NumOfGPRsSaved);
575 OS << '\n';
576
577 // Print the 7th of the 8 bytes of mandatory fields.
578 PrintBytes(1);
579 PRINTGET("\t#", TbTable, NumberOfFixedParms);
580 OS << '\n';
581
582 // Print the 8th of the 8 bytes of mandatory fields.
583 PrintBytes(1);
584 PRINTGET("\t#", TbTable, NumberOfFPParms);
585 PRINTBOOL(",", TbTable, hasParmsOnStack);
586
587 PRINTOPTIONAL(ParmsType);
588 PRINTOPTIONAL(TraceBackTableOffset);
589 PRINTOPTIONAL(HandlerMask);
590 PRINTOPTIONAL(NumOfCtlAnchors);
591
592 if (TbTable.getControlledStorageInfoDisp()) {
593 SmallVector<uint32_t, 8> Disp = *TbTable.getControlledStorageInfoDisp();
594 for (unsigned I = 0; I < Disp.size(); ++I) {
595 OS << '\n';
596 PrintBytes(4);
597 OS << "\t" << (I ? " " : "#") << " ControlledStorageInfoDisp[" << I
598 << "] = " << Disp[I];
599 }
600 }
601
602 // If there is a name, print the function name and function name length.
603 if (TbTable.isFuncNamePresent()) {
604 uint16_t FunctionNameLen = TbTable.getFunctionName()->size();
605 if (FunctionNameLen == 0) {
606 OS << '\n';
607 reportWarning(
608 Message: "the length of the function name must be greater than zero if the "
609 "isFuncNamePresent bit is set in the traceback table",
610 File: Obj->getFileName());
611 return;
612 }
613
614 OS << '\n';
615 PrintBytes(2);
616 OS << "\t# FunctionNameLen = " << FunctionNameLen;
617
618 uint16_t RemainingBytes = FunctionNameLen;
619 bool HasPrinted = false;
620 while (RemainingBytes > 0) {
621 OS << '\n';
622 uint16_t PrintLen = RemainingBytes >= 4 ? 4 : RemainingBytes;
623 printRawData(Bytes: Bytes.slice(N: Index, M: PrintLen), Address: Address + Index, OS, STI);
624 Index += PrintLen;
625 RemainingBytes -= PrintLen;
626
627 if (!HasPrinted) {
628 OS << "\t# FunctionName = " << *TbTable.getFunctionName();
629 HasPrinted = true;
630 }
631 }
632 }
633
634 if (TbTable.isAllocaUsed()) {
635 OS << '\n';
636 PrintBytes(1);
637 OS << format(Fmt: "\t# AllocaRegister = %u", Vals: *TbTable.getAllocaRegister());
638 }
639
640 if (TbTable.getVectorExt()) {
641 OS << '\n';
642 TBVectorExt VecExt = *TbTable.getVectorExt();
643 // Print first byte of VectorExt.
644 PrintBytes(1);
645 PRINTGET("\t#", VecExt, NumberOfVRSaved);
646 PRINTBOOL(",", VecExt, isVRSavedOnStack);
647 PRINTBOOL(",", VecExt, hasVarArgs);
648 OS << '\n';
649
650 // Print the second byte of VectorExt.
651 PrintBytes(1);
652 PRINTGET("\t#", VecExt, NumberOfVectorParms);
653 PRINTBOOL(",", VecExt, hasVMXInstruction);
654 OS << '\n';
655
656 PrintBytes(4);
657 OS << "\t# VectorParmsInfoString = " << VecExt.getVectorParmsInfo();
658
659 // There are two bytes of padding after vector info.
660 OS << '\n';
661 PrintBytes(2);
662 OS << "\t# Padding";
663 }
664
665 if (TbTable.getExtensionTable()) {
666 OS << '\n';
667 PrintBytes(1);
668 ExtendedTBTableFlag Flag =
669 static_cast<ExtendedTBTableFlag>(*TbTable.getExtensionTable());
670 OS << "\t# ExtensionTable = " << getExtendedTBTableFlagString(Flag);
671 }
672
673 if (TbTable.getEhInfoDisp()) {
674 // There are 4 bytes alignment before eh info displacement.
675 if (Index % 4) {
676 OS << '\n';
677 PrintBytes(4 - Index % 4);
678 OS << "\t# Alignment padding for eh info displacement";
679 }
680 OS << '\n';
681 // The size of the displacement (address) is 4 bytes in 32-bit object files,
682 // and 8 bytes in 64-bit object files.
683 PrintBytes(4);
684 OS << "\t# EH info displacement";
685 if (Is64Bit) {
686 OS << '\n';
687 PrintBytes(4);
688 }
689 }
690
691 OS << '\n';
692 if (End == Address + Index)
693 return;
694
695 Size = End - Address;
696
697 const char *LineSuffix = "\t# Padding\n";
698 auto IsWordZero = [&](uint64_t WordPos) {
699 if (WordPos >= Size)
700 return false;
701 uint64_t LineLength = std::min(a: 4 - WordPos % 4, b: Size - WordPos);
702 return std::all_of(first: Bytes.begin() + WordPos,
703 last: Bytes.begin() + WordPos + LineLength,
704 pred: [](uint8_t Byte) { return Byte == 0; });
705 };
706
707 bool AreWordsZero[] = {IsWordZero(Index), IsWordZero(alignTo(Value: Index, Align: 4) + 4),
708 IsWordZero(alignTo(Value: Index, Align: 4) + 8)};
709 bool ShouldPrintLine = true;
710 while (true) {
711 // Determine the length of the line (4, except for the first line, which
712 // will be just enough to align to the word boundary, and the last line,
713 // which will be the remainder of the data).
714 uint64_t LineLength = std::min(a: 4 - Index % 4, b: Size - Index);
715 if (ShouldPrintLine) {
716 // Print the line.
717 printRawData(Bytes: Bytes.slice(N: Index, M: LineLength), Address: Address + Index, OS, STI);
718 OS << LineSuffix;
719 LineSuffix = "\n";
720 }
721
722 Index += LineLength;
723 if (Index == Size)
724 return;
725
726 // For 3 or more consecutive lines of zeros, skip all but the first one, and
727 // replace them with "...".
728 if (AreWordsZero[0] && AreWordsZero[1] && AreWordsZero[2]) {
729 if (ShouldPrintLine)
730 OS << std::string(8, ' ') << "...\n";
731 ShouldPrintLine = false;
732 } else if (!AreWordsZero[1]) {
733 // We have reached the end of a skipped block of zeros.
734 ShouldPrintLine = true;
735 }
736 AreWordsZero[0] = AreWordsZero[1];
737 AreWordsZero[1] = AreWordsZero[2];
738 AreWordsZero[2] = IsWordZero(Index + 8);
739 }
740}
741#undef PRINTBOOL
742#undef PRINTGET
743#undef PRINTOPTIONAL
744