xref: /llvm-project/llvm/tools/llvm-objdump/XCOFFDump.cpp (revision b92cc780606ea7fa1afdff49a2c84934841ece6f)
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 
27 using namespace llvm;
28 using namespace llvm::object;
29 using namespace llvm::XCOFF;
30 using namespace llvm::support;
31 
32 namespace {
33 class XCOFFDumper : public objdump::Dumper {
34   enum PrintStyle { Hex, Number };
35   const XCOFFObjectFile &Obj;
36   unsigned Width;
37 
38 public:
39   XCOFFDumper(const object::XCOFFObjectFile &O) : Dumper(O), Obj(O) {}
40 
41 private:
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 
67 void XCOFFDumper::printPrivateHeaders() {
68   printFileHeader();
69   printAuxiliaryHeader();
70   printLoaderSectionHeader();
71 }
72 
73 FormattedString XCOFFDumper::formatName(StringRef Name) {
74   return FormattedString(Name, Width, FormattedString::JustifyLeft);
75 }
76 
77 void XCOFFDumper::printHex(StringRef Name, uint64_t Value) {
78   outs() << formatName(Name) << format_hex(Value, 0) << "\n";
79 }
80 
81 void XCOFFDumper::printNumber(StringRef Name, uint64_t Value) {
82   outs() << formatName(Name) << format_decimal(Value, 0) << "\n";
83 }
84 
85 void XCOFFDumper::printStrHex(StringRef Name, StringRef Str, uint64_t Value) {
86   outs() << formatName(Name) << Str << " (" << format_decimal(Value, 0)
87          << ")\n";
88 }
89 
90 void XCOFFDumper::printBinary(StringRef Name, ArrayRef<uint8_t> Data) {
91   unsigned OrgWidth = Width;
92   Width = 0;
93   outs() << formatName(Name) << " (" << format_bytes(Data) << ")\n";
94   Width = OrgWidth;
95 }
96 
97 void XCOFFDumper::printAuxiliaryHeader() {
98   Width = 36;
99   if (Obj.is64Bit())
100     printAuxiliaryHeader(Obj.auxiliaryHeader64());
101   else
102     printAuxiliaryHeader(Obj.auxiliaryHeader32());
103 }
104 
105 template <typename AuxHeaderMemberType, typename XCOFFAuxiliaryHeader>
106 void 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(MemberName, Member);
117     else
118       printNumber(MemberName, Member);
119   } else if (Offset < AuxSize) {
120     PartialFieldOffset = Offset;
121     PartialFieldName = MemberName;
122   }
123 }
124 
125 template <typename XCOFFAuxiliaryHeader>
126 void 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               ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(&AuxHeader) +
136                                     PartialFieldOffset,
137                                 AuxSize - PartialFieldOffset))
138        << ")\n";
139     reportUniqueWarning(Twine("only partial field for ") + PartialFieldName +
140                         " at offset (" + Twine(PartialFieldOffset) + ")\n" +
141                         OS.str());
142   } else if (sizeof(AuxHeader) < AuxSize) {
143     printBinary(
144         "Extra raw data",
145         ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(&AuxHeader) +
146                               sizeof(AuxHeader),
147                           AuxSize - sizeof(AuxHeader)));
148   }
149 }
150 
151 void 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("Flag:", AuxHeader->getFlag());
197     printHex("Alignment of thread-local storage:",
198              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);
207 }
208 
209 void 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("Flag:", AuxHeader->getFlag());
249     printHex("Alignment of thread-local storage:",
250              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);
265 }
266 
267 void XCOFFDumper::printLoaderSectionHeader() {
268   Expected<uintptr_t> LoaderSectionAddrOrError =
269       Obj.getSectionFileOffsetToRawData(XCOFF::STYP_LOADER);
270   if (!LoaderSectionAddrOrError) {
271     reportUniqueWarning(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("Version:", LDHeader->Version);
281     printNumber("NumberOfSymbolEntries:", LDHeader->NumberOfSymTabEnt);
282     printNumber("NumberOfRelocationEntries:", LDHeader->NumberOfRelTabEnt);
283     printNumber("LengthOfImportFileIDStringTable:",
284                 LDHeader->LengthOfImpidStrTbl);
285     printNumber("NumberOfImportFileIDs:", LDHeader->NumberOfImpid);
286     printHex("OffsetToImportFileIDs:", LDHeader->OffsetToImpid);
287     printNumber("LengthOfStringTable:", LDHeader->LengthOfStrTbl);
288     printHex("OffsetToStringTable:", 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("OffsetToSymbolTable", LoaderSec64->OffsetToSymTbl);
298     printHex("OffsetToRelocationEntries", LoaderSec64->OffsetToRelEnt);
299   } else {
300     const LoaderSectionHeader32 *LoaderSec32 =
301         reinterpret_cast<const LoaderSectionHeader32 *>(LoaderSectionAddr);
302     PrintLoadSecHeaderCommon(LoaderSec32);
303   }
304 }
305 
306 void XCOFFDumper::printFileHeader() {
307   Width = 20;
308   outs() << "\n---File Header:\n";
309   printHex("Magic:", Obj.getMagic());
310   printNumber("NumberOfSections:", 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(FormattedTime, sizeof(FormattedTime),
322                                           "%F %T", std::gmtime(&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("Timestamp:", FormattedTime, Timestamp);
327   } else {
328     // Negative timestamp values are reserved for future use.
329     printStrHex("Timestamp:", Timestamp == 0 ? "None" : "Reserved Value",
330                 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("SymbolTableOffset:", Obj.getSymbolTableOffset64());
338     printNumber("SymbolTableEntries:", Obj.getNumberOfSymbolTableEntries64());
339   } else {
340     printHex("SymbolTableOffset:", Obj.getSymbolTableOffset32());
341     int32_t SymTabEntries = Obj.getRawNumberOfSymbolTableEntries32();
342     if (SymTabEntries >= 0)
343       printNumber("SymbolTableEntries:", SymTabEntries);
344     else
345       printStrHex("SymbolTableEntries:", "Reserved Value", SymTabEntries);
346   }
347 
348   printHex("OptionalHeaderSize:", Obj.getOptionalHeaderSize());
349   printHex("Flags:", Obj.getFlags());
350 }
351 
352 } // namespace
353 
354 std::unique_ptr<objdump::Dumper>
355 objdump::createXCOFFDumper(const object::XCOFFObjectFile &Obj) {
356   return std::make_unique<XCOFFDumper>(Obj);
357 }
358 
359 Error 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         "invalid symbol reference in relocation entry",
367         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(*SymNameOrErr) : SymNameOrErr->str();
375   if (SymbolDescription)
376     SymName = getXCOFFSymbolDescription(createSymbolInfo(Obj, *SymI), SymName);
377 
378   Result.append(SymName.begin(), SymName.end());
379   return Error::success();
380 }
381 
382 std::optional<XCOFF::StorageMappingClass>
383 objdump::getXCOFFSymbolCsectSMC(const XCOFFObjectFile &Obj,
384                                 const SymbolRef &Sym) {
385   const XCOFFSymbolRef SymRef = Obj.toSymbolRef(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 
397 std::optional<object::SymbolRef>
398 objdump::getXCOFFSymbolContainingSymbolRef(const XCOFFObjectFile &Obj,
399                                            const SymbolRef &Sym) {
400   const XCOFFSymbolRef SymRef = Obj.toSymbolRef(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 
414 bool objdump::isLabel(const XCOFFObjectFile &Obj, const SymbolRef &Sym) {
415   const XCOFFSymbolRef SymRef = Obj.toSymbolRef(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 
426 std::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(SymbolName.begin(), SymbolName.end());
438 
439   if (SymbolInfo.XCOFFSymInfo.StorageMappingClass &&
440       !SymbolInfo.XCOFFSymInfo.IsLabel) {
441     const XCOFF::StorageMappingClass Smc =
442         *SymbolInfo.XCOFFSymInfo.StorageMappingClass;
443     Result.append(("[" + XCOFF::getMappingClassString(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 
464 void 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.slice(Index, 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(Bytes.data() + Index, SizeCopy, 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(Address) + "\n>>> "
489                   << toString(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(Bytes.slice(I, 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.slice(Index, 4), Address + Index, 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(WarningMsgStr, Obj->getFileName());
512     return;
513   }
514 
515   auto PrintBytes = [&](uint64_t N) {
516     printRawData(Bytes.slice(Index, N), 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("\t# Version = %i", 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(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           "the length of the function name must be greater than zero if the "
609           "isFuncNamePresent bit is set in the traceback table",
610           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.slice(Index, PrintLen), 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("\t# AllocaRegister = %u", *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(4 - WordPos % 4, Size - WordPos);
702     return std::all_of(Bytes.begin() + WordPos,
703                        Bytes.begin() + WordPos + LineLength,
704                        [](uint8_t Byte) { return Byte == 0; });
705   };
706 
707   bool AreWordsZero[] = {IsWordZero(Index), IsWordZero(alignTo(Index, 4) + 4),
708                          IsWordZero(alignTo(Index, 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(4 - Index % 4, Size - Index);
715     if (ShouldPrintLine) {
716       // Print the line.
717       printRawData(Bytes.slice(Index, LineLength), 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