15ffd83dbSDimitry Andric //===-- XCOFFDump.cpp - XCOFF-specific dumper -----------------------------===//
25ffd83dbSDimitry Andric //
35ffd83dbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45ffd83dbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55ffd83dbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65ffd83dbSDimitry Andric //
75ffd83dbSDimitry Andric //===----------------------------------------------------------------------===//
85ffd83dbSDimitry Andric ///
95ffd83dbSDimitry Andric /// \file
105ffd83dbSDimitry Andric /// This file implements the XCOFF-specific dumper for llvm-objdump.
115ffd83dbSDimitry Andric ///
125ffd83dbSDimitry Andric //===----------------------------------------------------------------------===//
135ffd83dbSDimitry Andric 
145ffd83dbSDimitry Andric #include "XCOFFDump.h"
155ffd83dbSDimitry Andric 
165ffd83dbSDimitry Andric #include "llvm-objdump.h"
1706c3fb27SDimitry Andric #include "llvm/ADT/StringExtras.h"
185ffd83dbSDimitry Andric #include "llvm/Demangle/Demangle.h"
1906c3fb27SDimitry Andric #include "llvm/MC/MCInstPrinter.h"
2006c3fb27SDimitry Andric #include "llvm/MC/MCSubtargetInfo.h"
2106c3fb27SDimitry Andric #include "llvm/Support/Casting.h"
2206c3fb27SDimitry Andric #include "llvm/Support/Endian.h"
2306c3fb27SDimitry Andric #include "llvm/Support/FormattedStream.h"
2406c3fb27SDimitry Andric #include <algorithm>
255ffd83dbSDimitry Andric 
265ffd83dbSDimitry Andric using namespace llvm;
275ffd83dbSDimitry Andric using namespace llvm::object;
2806c3fb27SDimitry Andric using namespace llvm::XCOFF;
2906c3fb27SDimitry Andric using namespace llvm::support;
3006c3fb27SDimitry Andric 
3106c3fb27SDimitry Andric namespace {
3206c3fb27SDimitry Andric class XCOFFDumper : public objdump::Dumper {
3306c3fb27SDimitry Andric public:
XCOFFDumper(const object::XCOFFObjectFile & O)3406c3fb27SDimitry Andric   XCOFFDumper(const object::XCOFFObjectFile &O) : Dumper(O) {}
printPrivateHeaders()355f757f3fSDimitry Andric   void printPrivateHeaders() override {}
3606c3fb27SDimitry Andric };
3706c3fb27SDimitry Andric } // namespace
3806c3fb27SDimitry Andric 
3906c3fb27SDimitry Andric std::unique_ptr<objdump::Dumper>
createXCOFFDumper(const object::XCOFFObjectFile & Obj)4006c3fb27SDimitry Andric objdump::createXCOFFDumper(const object::XCOFFObjectFile &Obj) {
4106c3fb27SDimitry Andric   return std::make_unique<XCOFFDumper>(Obj);
4206c3fb27SDimitry Andric }
4306c3fb27SDimitry Andric 
getXCOFFRelocationValueString(const XCOFFObjectFile & Obj,const RelocationRef & Rel,bool SymbolDescription,SmallVectorImpl<char> & Result)44753f127fSDimitry Andric Error objdump::getXCOFFRelocationValueString(const XCOFFObjectFile &Obj,
455ffd83dbSDimitry Andric                                              const RelocationRef &Rel,
46*cb14a3feSDimitry Andric                                              bool SymbolDescription,
475ffd83dbSDimitry Andric                                              SmallVectorImpl<char> &Result) {
485ffd83dbSDimitry Andric   symbol_iterator SymI = Rel.getSymbol();
49753f127fSDimitry Andric   if (SymI == Obj.symbol_end())
505ffd83dbSDimitry Andric     return make_error<GenericBinaryError>(
515ffd83dbSDimitry Andric         "invalid symbol reference in relocation entry",
525ffd83dbSDimitry Andric         object_error::parse_failed);
535ffd83dbSDimitry Andric 
545ffd83dbSDimitry Andric   Expected<StringRef> SymNameOrErr = SymI->getName();
555ffd83dbSDimitry Andric   if (!SymNameOrErr)
565ffd83dbSDimitry Andric     return SymNameOrErr.takeError();
575ffd83dbSDimitry Andric 
5806c3fb27SDimitry Andric   std::string SymName =
5906c3fb27SDimitry Andric       Demangle ? demangle(*SymNameOrErr) : SymNameOrErr->str();
605ffd83dbSDimitry Andric   if (SymbolDescription)
615ffd83dbSDimitry Andric     SymName = getXCOFFSymbolDescription(createSymbolInfo(Obj, *SymI), SymName);
625ffd83dbSDimitry Andric 
635ffd83dbSDimitry Andric   Result.append(SymName.begin(), SymName.end());
645ffd83dbSDimitry Andric   return Error::success();
655ffd83dbSDimitry Andric }
665ffd83dbSDimitry Andric 
67bdd1243dSDimitry Andric std::optional<XCOFF::StorageMappingClass>
getXCOFFSymbolCsectSMC(const XCOFFObjectFile & Obj,const SymbolRef & Sym)68753f127fSDimitry Andric objdump::getXCOFFSymbolCsectSMC(const XCOFFObjectFile &Obj,
695ffd83dbSDimitry Andric                                 const SymbolRef &Sym) {
70753f127fSDimitry Andric   const XCOFFSymbolRef SymRef = Obj.toSymbolRef(Sym.getRawDataRefImpl());
715ffd83dbSDimitry Andric 
72fe6060f1SDimitry Andric   if (!SymRef.isCsectSymbol())
73bdd1243dSDimitry Andric     return std::nullopt;
74fe6060f1SDimitry Andric 
75fe6060f1SDimitry Andric   auto CsectAuxEntOrErr = SymRef.getXCOFFCsectAuxRef();
76fe6060f1SDimitry Andric   if (!CsectAuxEntOrErr)
77bdd1243dSDimitry Andric     return std::nullopt;
78fe6060f1SDimitry Andric 
79fe6060f1SDimitry Andric   return CsectAuxEntOrErr.get().getStorageMappingClass();
805ffd83dbSDimitry Andric }
815ffd83dbSDimitry Andric 
82bdd1243dSDimitry Andric std::optional<object::SymbolRef>
getXCOFFSymbolContainingSymbolRef(const XCOFFObjectFile & Obj,const SymbolRef & Sym)83753f127fSDimitry Andric objdump::getXCOFFSymbolContainingSymbolRef(const XCOFFObjectFile &Obj,
84349cc55cSDimitry Andric                                            const SymbolRef &Sym) {
85753f127fSDimitry Andric   const XCOFFSymbolRef SymRef = Obj.toSymbolRef(Sym.getRawDataRefImpl());
86349cc55cSDimitry Andric   if (!SymRef.isCsectSymbol())
87bdd1243dSDimitry Andric     return std::nullopt;
88349cc55cSDimitry Andric 
89349cc55cSDimitry Andric   Expected<XCOFFCsectAuxRef> CsectAuxEntOrErr = SymRef.getXCOFFCsectAuxRef();
90349cc55cSDimitry Andric   if (!CsectAuxEntOrErr || !CsectAuxEntOrErr.get().isLabel())
91bdd1243dSDimitry Andric     return std::nullopt;
92349cc55cSDimitry Andric   uint32_t Idx =
93349cc55cSDimitry Andric       static_cast<uint32_t>(CsectAuxEntOrErr.get().getSectionOrLength());
94349cc55cSDimitry Andric   DataRefImpl DRI;
95753f127fSDimitry Andric   DRI.p = Obj.getSymbolByIndex(Idx);
96753f127fSDimitry Andric   return SymbolRef(DRI, &Obj);
97349cc55cSDimitry Andric }
98349cc55cSDimitry Andric 
isLabel(const XCOFFObjectFile & Obj,const SymbolRef & Sym)99753f127fSDimitry Andric bool objdump::isLabel(const XCOFFObjectFile &Obj, const SymbolRef &Sym) {
100753f127fSDimitry Andric   const XCOFFSymbolRef SymRef = Obj.toSymbolRef(Sym.getRawDataRefImpl());
101fe6060f1SDimitry Andric   if (!SymRef.isCsectSymbol())
1025ffd83dbSDimitry Andric     return false;
103fe6060f1SDimitry Andric 
104fe6060f1SDimitry Andric   auto CsectAuxEntOrErr = SymRef.getXCOFFCsectAuxRef();
105fe6060f1SDimitry Andric   if (!CsectAuxEntOrErr)
106fe6060f1SDimitry Andric     return false;
107fe6060f1SDimitry Andric 
108fe6060f1SDimitry Andric   return CsectAuxEntOrErr.get().isLabel();
1095ffd83dbSDimitry Andric }
1105ffd83dbSDimitry Andric 
getXCOFFSymbolDescription(const SymbolInfoTy & SymbolInfo,StringRef SymbolName)1115ffd83dbSDimitry Andric std::string objdump::getXCOFFSymbolDescription(const SymbolInfoTy &SymbolInfo,
1125ffd83dbSDimitry Andric                                                StringRef SymbolName) {
1135ffd83dbSDimitry Andric   assert(SymbolInfo.isXCOFF() && "Must be a XCOFFSymInfo.");
1145ffd83dbSDimitry Andric 
1155ffd83dbSDimitry Andric   std::string Result;
1165ffd83dbSDimitry Andric   // Dummy symbols have no symbol index.
1175ffd83dbSDimitry Andric   if (SymbolInfo.XCOFFSymInfo.Index)
118bdd1243dSDimitry Andric     Result =
119bdd1243dSDimitry Andric         ("(idx: " + Twine(*SymbolInfo.XCOFFSymInfo.Index) + ") " + SymbolName)
1205ffd83dbSDimitry Andric             .str();
1215ffd83dbSDimitry Andric   else
1225ffd83dbSDimitry Andric     Result.append(SymbolName.begin(), SymbolName.end());
1235ffd83dbSDimitry Andric 
1245ffd83dbSDimitry Andric   if (SymbolInfo.XCOFFSymInfo.StorageMappingClass &&
1255ffd83dbSDimitry Andric       !SymbolInfo.XCOFFSymInfo.IsLabel) {
1265ffd83dbSDimitry Andric     const XCOFF::StorageMappingClass Smc =
12781ad6265SDimitry Andric         *SymbolInfo.XCOFFSymInfo.StorageMappingClass;
1285ffd83dbSDimitry Andric     Result.append(("[" + XCOFF::getMappingClassString(Smc) + "]").str());
1295ffd83dbSDimitry Andric   }
1305ffd83dbSDimitry Andric 
1315ffd83dbSDimitry Andric   return Result;
1325ffd83dbSDimitry Andric }
13306c3fb27SDimitry Andric 
13406c3fb27SDimitry Andric #define PRINTBOOL(Prefix, Obj, Field)                                          \
13506c3fb27SDimitry Andric   OS << Prefix << " " << ((Obj.Field()) ? "+" : "-") << #Field
13606c3fb27SDimitry Andric 
13706c3fb27SDimitry Andric #define PRINTGET(Prefix, Obj, Field)                                           \
13806c3fb27SDimitry Andric   OS << Prefix << " " << #Field << " = "                                       \
13906c3fb27SDimitry Andric      << static_cast<unsigned>(Obj.get##Field())
14006c3fb27SDimitry Andric 
14106c3fb27SDimitry Andric #define PRINTOPTIONAL(Field)                                                   \
14206c3fb27SDimitry Andric   if (TbTable.get##Field()) {                                                  \
14306c3fb27SDimitry Andric     OS << '\n';                                                                \
14406c3fb27SDimitry Andric     printRawData(Bytes.slice(Index, 4), Address + Index, OS, STI);             \
14506c3fb27SDimitry Andric     Index += 4;                                                                \
14606c3fb27SDimitry Andric     OS << "\t# " << #Field << " = " << *TbTable.get##Field();                  \
14706c3fb27SDimitry Andric   }
14806c3fb27SDimitry Andric 
dumpTracebackTable(ArrayRef<uint8_t> Bytes,uint64_t Address,formatted_raw_ostream & OS,uint64_t End,const MCSubtargetInfo & STI,const XCOFFObjectFile * Obj)14906c3fb27SDimitry Andric void objdump::dumpTracebackTable(ArrayRef<uint8_t> Bytes, uint64_t Address,
15006c3fb27SDimitry Andric                                  formatted_raw_ostream &OS, uint64_t End,
15106c3fb27SDimitry Andric                                  const MCSubtargetInfo &STI,
15206c3fb27SDimitry Andric                                  const XCOFFObjectFile *Obj) {
15306c3fb27SDimitry Andric   uint64_t Index = 0;
15406c3fb27SDimitry Andric   unsigned TabStop = getInstStartColumn(STI) - 1;
15506c3fb27SDimitry Andric   // Print traceback table boundary.
15606c3fb27SDimitry Andric   printRawData(Bytes.slice(Index, 4), Address, OS, STI);
15706c3fb27SDimitry Andric   OS << "\t# Traceback table start\n";
15806c3fb27SDimitry Andric   Index += 4;
15906c3fb27SDimitry Andric 
16006c3fb27SDimitry Andric   uint64_t Size = End - Address;
16106c3fb27SDimitry Andric   bool Is64Bit = Obj->is64Bit();
16206c3fb27SDimitry Andric 
16306c3fb27SDimitry Andric   // XCOFFTracebackTable::create modifies the size parameter, so ensure Size
16406c3fb27SDimitry Andric   // isn't changed.
16506c3fb27SDimitry Andric   uint64_t SizeCopy = End - Address;
16606c3fb27SDimitry Andric   Expected<XCOFFTracebackTable> TTOrErr =
16706c3fb27SDimitry Andric       XCOFFTracebackTable::create(Bytes.data() + Index, SizeCopy, Is64Bit);
16806c3fb27SDimitry Andric 
16906c3fb27SDimitry Andric   if (!TTOrErr) {
17006c3fb27SDimitry Andric     std::string WarningMsgStr;
17106c3fb27SDimitry Andric     raw_string_ostream WarningStream(WarningMsgStr);
17206c3fb27SDimitry Andric     WarningStream << "failure parsing traceback table with address: 0x"
17306c3fb27SDimitry Andric                   << utohexstr(Address) + "\n>>> "
17406c3fb27SDimitry Andric                   << toString(TTOrErr.takeError())
17506c3fb27SDimitry Andric                   << "\n>>> Raw traceback table data is:\n";
17606c3fb27SDimitry Andric 
17706c3fb27SDimitry Andric     uint64_t LastNonZero = Index;
17806c3fb27SDimitry Andric     for (uint64_t I = Index; I < Size; I += 4)
17906c3fb27SDimitry Andric       if (support::endian::read32be(Bytes.slice(I, 4).data()) != 0)
18006c3fb27SDimitry Andric         LastNonZero = I + 4 > Size ? Size : I + 4;
18106c3fb27SDimitry Andric 
18206c3fb27SDimitry Andric     if (Size - LastNonZero <= 4)
18306c3fb27SDimitry Andric       LastNonZero = Size;
18406c3fb27SDimitry Andric 
18506c3fb27SDimitry Andric     formatted_raw_ostream FOS(WarningStream);
18606c3fb27SDimitry Andric     while (Index < LastNonZero) {
18706c3fb27SDimitry Andric       printRawData(Bytes.slice(Index, 4), Address + Index, FOS, STI);
18806c3fb27SDimitry Andric       Index += 4;
18906c3fb27SDimitry Andric       WarningStream << '\n';
19006c3fb27SDimitry Andric     }
19106c3fb27SDimitry Andric 
19206c3fb27SDimitry Andric     // Print all remaining zeroes as ...
19306c3fb27SDimitry Andric     if (Size - LastNonZero >= 8)
19406c3fb27SDimitry Andric       WarningStream << "\t\t...\n";
19506c3fb27SDimitry Andric 
19606c3fb27SDimitry Andric     reportWarning(WarningMsgStr, Obj->getFileName());
19706c3fb27SDimitry Andric     return;
19806c3fb27SDimitry Andric   }
19906c3fb27SDimitry Andric 
20006c3fb27SDimitry Andric   auto PrintBytes = [&](uint64_t N) {
20106c3fb27SDimitry Andric     printRawData(Bytes.slice(Index, N), Address + Index, OS, STI);
20206c3fb27SDimitry Andric     Index += N;
20306c3fb27SDimitry Andric   };
20406c3fb27SDimitry Andric 
20506c3fb27SDimitry Andric   XCOFFTracebackTable TbTable = *TTOrErr;
20606c3fb27SDimitry Andric   // Print the first of the 8 bytes of mandatory fields.
20706c3fb27SDimitry Andric   PrintBytes(1);
20806c3fb27SDimitry Andric   OS << format("\t# Version = %i", TbTable.getVersion()) << '\n';
20906c3fb27SDimitry Andric 
21006c3fb27SDimitry Andric   // Print the second of the 8 bytes of mandatory fields.
21106c3fb27SDimitry Andric   PrintBytes(1);
21206c3fb27SDimitry Andric   TracebackTable::LanguageID LangId =
21306c3fb27SDimitry Andric       static_cast<TracebackTable::LanguageID>(TbTable.getLanguageID());
21406c3fb27SDimitry Andric   OS << "\t# Language = " << getNameForTracebackTableLanguageId(LangId) << '\n';
21506c3fb27SDimitry Andric 
21606c3fb27SDimitry Andric   auto Split = [&]() {
21706c3fb27SDimitry Andric     OS << '\n';
21806c3fb27SDimitry Andric     OS.indent(TabStop);
21906c3fb27SDimitry Andric   };
22006c3fb27SDimitry Andric 
22106c3fb27SDimitry Andric   // Print the third of the 8 bytes of mandatory fields.
22206c3fb27SDimitry Andric   PrintBytes(1);
22306c3fb27SDimitry Andric   PRINTBOOL("\t#", TbTable, isGlobalLinkage);
22406c3fb27SDimitry Andric   PRINTBOOL(",", TbTable, isOutOfLineEpilogOrPrologue);
22506c3fb27SDimitry Andric   Split();
22606c3fb27SDimitry Andric   PRINTBOOL("\t ", TbTable, hasTraceBackTableOffset);
22706c3fb27SDimitry Andric   PRINTBOOL(",", TbTable, isInternalProcedure);
22806c3fb27SDimitry Andric   Split();
22906c3fb27SDimitry Andric   PRINTBOOL("\t ", TbTable, hasControlledStorage);
23006c3fb27SDimitry Andric   PRINTBOOL(",", TbTable, isTOCless);
23106c3fb27SDimitry Andric   Split();
23206c3fb27SDimitry Andric   PRINTBOOL("\t ", TbTable, isFloatingPointPresent);
23306c3fb27SDimitry Andric   Split();
23406c3fb27SDimitry Andric   PRINTBOOL("\t ", TbTable, isFloatingPointOperationLogOrAbortEnabled);
23506c3fb27SDimitry Andric   OS << '\n';
23606c3fb27SDimitry Andric 
23706c3fb27SDimitry Andric   // Print the 4th of the 8 bytes of mandatory fields.
23806c3fb27SDimitry Andric   PrintBytes(1);
23906c3fb27SDimitry Andric   PRINTBOOL("\t#", TbTable, isInterruptHandler);
24006c3fb27SDimitry Andric   PRINTBOOL(",", TbTable, isFuncNamePresent);
24106c3fb27SDimitry Andric   PRINTBOOL(",", TbTable, isAllocaUsed);
24206c3fb27SDimitry Andric   Split();
24306c3fb27SDimitry Andric   PRINTGET("\t ", TbTable, OnConditionDirective);
24406c3fb27SDimitry Andric   PRINTBOOL(",", TbTable, isCRSaved);
24506c3fb27SDimitry Andric   PRINTBOOL(",", TbTable, isLRSaved);
24606c3fb27SDimitry Andric   OS << '\n';
24706c3fb27SDimitry Andric 
24806c3fb27SDimitry Andric   // Print the 5th of the 8 bytes of mandatory fields.
24906c3fb27SDimitry Andric   PrintBytes(1);
25006c3fb27SDimitry Andric   PRINTBOOL("\t#", TbTable, isBackChainStored);
25106c3fb27SDimitry Andric   PRINTBOOL(",", TbTable, isFixup);
25206c3fb27SDimitry Andric   PRINTGET(",", TbTable, NumOfFPRsSaved);
25306c3fb27SDimitry Andric   OS << '\n';
25406c3fb27SDimitry Andric 
25506c3fb27SDimitry Andric   // Print the 6th of the 8 bytes of mandatory fields.
25606c3fb27SDimitry Andric   PrintBytes(1);
25706c3fb27SDimitry Andric   PRINTBOOL("\t#", TbTable, hasExtensionTable);
25806c3fb27SDimitry Andric   PRINTBOOL(",", TbTable, hasVectorInfo);
25906c3fb27SDimitry Andric   PRINTGET(",", TbTable, NumOfGPRsSaved);
26006c3fb27SDimitry Andric   OS << '\n';
26106c3fb27SDimitry Andric 
26206c3fb27SDimitry Andric   // Print the 7th of the 8 bytes of mandatory fields.
26306c3fb27SDimitry Andric   PrintBytes(1);
26406c3fb27SDimitry Andric   PRINTGET("\t#", TbTable, NumberOfFixedParms);
26506c3fb27SDimitry Andric   OS << '\n';
26606c3fb27SDimitry Andric 
26706c3fb27SDimitry Andric   // Print the 8th of the 8 bytes of mandatory fields.
26806c3fb27SDimitry Andric   PrintBytes(1);
26906c3fb27SDimitry Andric   PRINTGET("\t#", TbTable, NumberOfFPParms);
27006c3fb27SDimitry Andric   PRINTBOOL(",", TbTable, hasParmsOnStack);
27106c3fb27SDimitry Andric 
27206c3fb27SDimitry Andric   PRINTOPTIONAL(ParmsType);
27306c3fb27SDimitry Andric   PRINTOPTIONAL(TraceBackTableOffset);
27406c3fb27SDimitry Andric   PRINTOPTIONAL(HandlerMask);
27506c3fb27SDimitry Andric   PRINTOPTIONAL(NumOfCtlAnchors);
27606c3fb27SDimitry Andric 
27706c3fb27SDimitry Andric   if (TbTable.getControlledStorageInfoDisp()) {
27806c3fb27SDimitry Andric     SmallVector<uint32_t, 8> Disp = *TbTable.getControlledStorageInfoDisp();
27906c3fb27SDimitry Andric     for (unsigned I = 0; I < Disp.size(); ++I) {
28006c3fb27SDimitry Andric       OS << '\n';
28106c3fb27SDimitry Andric       PrintBytes(4);
28206c3fb27SDimitry Andric       OS << "\t" << (I ? " " : "#") << " ControlledStorageInfoDisp[" << I
28306c3fb27SDimitry Andric          << "] = " << Disp[I];
28406c3fb27SDimitry Andric     }
28506c3fb27SDimitry Andric   }
28606c3fb27SDimitry Andric 
28706c3fb27SDimitry Andric   // If there is a name, print the function name and function name length.
28806c3fb27SDimitry Andric   if (TbTable.isFuncNamePresent()) {
28906c3fb27SDimitry Andric     uint16_t FunctionNameLen = TbTable.getFunctionName()->size();
29006c3fb27SDimitry Andric     if (FunctionNameLen == 0) {
29106c3fb27SDimitry Andric       OS << '\n';
29206c3fb27SDimitry Andric       reportWarning(
29306c3fb27SDimitry Andric           "the length of the function name must be greater than zero if the "
29406c3fb27SDimitry Andric           "isFuncNamePresent bit is set in the traceback table",
29506c3fb27SDimitry Andric           Obj->getFileName());
29606c3fb27SDimitry Andric       return;
29706c3fb27SDimitry Andric     }
29806c3fb27SDimitry Andric 
29906c3fb27SDimitry Andric     OS << '\n';
30006c3fb27SDimitry Andric     PrintBytes(2);
30106c3fb27SDimitry Andric     OS << "\t# FunctionNameLen = " << FunctionNameLen;
30206c3fb27SDimitry Andric 
30306c3fb27SDimitry Andric     uint16_t RemainingBytes = FunctionNameLen;
30406c3fb27SDimitry Andric     bool HasPrinted = false;
30506c3fb27SDimitry Andric     while (RemainingBytes > 0) {
30606c3fb27SDimitry Andric       OS << '\n';
30706c3fb27SDimitry Andric       uint16_t PrintLen = RemainingBytes >= 4 ? 4 : RemainingBytes;
30806c3fb27SDimitry Andric       printRawData(Bytes.slice(Index, PrintLen), Address + Index, OS, STI);
30906c3fb27SDimitry Andric       Index += PrintLen;
31006c3fb27SDimitry Andric       RemainingBytes -= PrintLen;
31106c3fb27SDimitry Andric 
31206c3fb27SDimitry Andric       if (!HasPrinted) {
31306c3fb27SDimitry Andric         OS << "\t# FunctionName = " << *TbTable.getFunctionName();
31406c3fb27SDimitry Andric         HasPrinted = true;
31506c3fb27SDimitry Andric       }
31606c3fb27SDimitry Andric     }
31706c3fb27SDimitry Andric   }
31806c3fb27SDimitry Andric 
31906c3fb27SDimitry Andric   if (TbTable.isAllocaUsed()) {
32006c3fb27SDimitry Andric     OS << '\n';
32106c3fb27SDimitry Andric     PrintBytes(1);
32206c3fb27SDimitry Andric     OS << format("\t# AllocaRegister = %u", *TbTable.getAllocaRegister());
32306c3fb27SDimitry Andric   }
32406c3fb27SDimitry Andric 
32506c3fb27SDimitry Andric   if (TbTable.getVectorExt()) {
32606c3fb27SDimitry Andric     OS << '\n';
32706c3fb27SDimitry Andric     TBVectorExt VecExt = *TbTable.getVectorExt();
32806c3fb27SDimitry Andric     // Print first byte of VectorExt.
32906c3fb27SDimitry Andric     PrintBytes(1);
33006c3fb27SDimitry Andric     PRINTGET("\t#", VecExt, NumberOfVRSaved);
33106c3fb27SDimitry Andric     PRINTBOOL(",", VecExt, isVRSavedOnStack);
33206c3fb27SDimitry Andric     PRINTBOOL(",", VecExt, hasVarArgs);
33306c3fb27SDimitry Andric     OS << '\n';
33406c3fb27SDimitry Andric 
33506c3fb27SDimitry Andric     // Print the second byte of VectorExt.
33606c3fb27SDimitry Andric     PrintBytes(1);
33706c3fb27SDimitry Andric     PRINTGET("\t#", VecExt, NumberOfVectorParms);
33806c3fb27SDimitry Andric     PRINTBOOL(",", VecExt, hasVMXInstruction);
33906c3fb27SDimitry Andric     OS << '\n';
34006c3fb27SDimitry Andric 
34106c3fb27SDimitry Andric     PrintBytes(4);
34206c3fb27SDimitry Andric     OS << "\t# VectorParmsInfoString = " << VecExt.getVectorParmsInfo();
34306c3fb27SDimitry Andric 
34406c3fb27SDimitry Andric     // There are two bytes of padding after vector info.
34506c3fb27SDimitry Andric     OS << '\n';
34606c3fb27SDimitry Andric     PrintBytes(2);
34706c3fb27SDimitry Andric     OS << "\t# Padding";
34806c3fb27SDimitry Andric   }
34906c3fb27SDimitry Andric 
35006c3fb27SDimitry Andric   if (TbTable.getExtensionTable()) {
35106c3fb27SDimitry Andric     OS << '\n';
35206c3fb27SDimitry Andric     PrintBytes(1);
35306c3fb27SDimitry Andric     ExtendedTBTableFlag Flag =
35406c3fb27SDimitry Andric         static_cast<ExtendedTBTableFlag>(*TbTable.getExtensionTable());
35506c3fb27SDimitry Andric     OS << "\t# ExtensionTable = " << getExtendedTBTableFlagString(Flag);
35606c3fb27SDimitry Andric   }
35706c3fb27SDimitry Andric 
35806c3fb27SDimitry Andric   if (TbTable.getEhInfoDisp()) {
35906c3fb27SDimitry Andric     // There are 4 bytes alignment before eh info displacement.
36006c3fb27SDimitry Andric     if (Index % 4) {
36106c3fb27SDimitry Andric       OS << '\n';
36206c3fb27SDimitry Andric       PrintBytes(4 - Index % 4);
36306c3fb27SDimitry Andric       OS << "\t# Alignment padding for eh info displacement";
36406c3fb27SDimitry Andric     }
36506c3fb27SDimitry Andric     OS << '\n';
36606c3fb27SDimitry Andric     // The size of the displacement (address) is 4 bytes in 32-bit object files,
36706c3fb27SDimitry Andric     // and 8 bytes in 64-bit object files.
36806c3fb27SDimitry Andric     PrintBytes(4);
36906c3fb27SDimitry Andric     OS << "\t# EH info displacement";
37006c3fb27SDimitry Andric     if (Is64Bit) {
37106c3fb27SDimitry Andric       OS << '\n';
37206c3fb27SDimitry Andric       PrintBytes(4);
37306c3fb27SDimitry Andric     }
37406c3fb27SDimitry Andric   }
37506c3fb27SDimitry Andric 
37606c3fb27SDimitry Andric   OS << '\n';
37706c3fb27SDimitry Andric   if (End == Address + Index)
37806c3fb27SDimitry Andric     return;
37906c3fb27SDimitry Andric 
38006c3fb27SDimitry Andric   Size = End - Address;
38106c3fb27SDimitry Andric 
38206c3fb27SDimitry Andric   const char *LineSuffix = "\t# Padding\n";
38306c3fb27SDimitry Andric   auto IsWordZero = [&](uint64_t WordPos) {
38406c3fb27SDimitry Andric     if (WordPos >= Size)
38506c3fb27SDimitry Andric       return false;
38606c3fb27SDimitry Andric     uint64_t LineLength = std::min(4 - WordPos % 4, Size - WordPos);
38706c3fb27SDimitry Andric     return std::all_of(Bytes.begin() + WordPos,
38806c3fb27SDimitry Andric                        Bytes.begin() + WordPos + LineLength,
38906c3fb27SDimitry Andric                        [](uint8_t Byte) { return Byte == 0; });
39006c3fb27SDimitry Andric   };
39106c3fb27SDimitry Andric 
39206c3fb27SDimitry Andric   bool AreWordsZero[] = {IsWordZero(Index), IsWordZero(alignTo(Index, 4) + 4),
39306c3fb27SDimitry Andric                          IsWordZero(alignTo(Index, 4) + 8)};
39406c3fb27SDimitry Andric   bool ShouldPrintLine = true;
39506c3fb27SDimitry Andric   while (true) {
39606c3fb27SDimitry Andric     // Determine the length of the line (4, except for the first line, which
39706c3fb27SDimitry Andric     // will be just enough to align to the word boundary, and the last line,
39806c3fb27SDimitry Andric     // which will be the remainder of the data).
39906c3fb27SDimitry Andric     uint64_t LineLength = std::min(4 - Index % 4, Size - Index);
40006c3fb27SDimitry Andric     if (ShouldPrintLine) {
40106c3fb27SDimitry Andric       // Print the line.
40206c3fb27SDimitry Andric       printRawData(Bytes.slice(Index, LineLength), Address + Index, OS, STI);
40306c3fb27SDimitry Andric       OS << LineSuffix;
40406c3fb27SDimitry Andric       LineSuffix = "\n";
40506c3fb27SDimitry Andric     }
40606c3fb27SDimitry Andric 
40706c3fb27SDimitry Andric     Index += LineLength;
40806c3fb27SDimitry Andric     if (Index == Size)
40906c3fb27SDimitry Andric       return;
41006c3fb27SDimitry Andric 
41106c3fb27SDimitry Andric     // For 3 or more consecutive lines of zeros, skip all but the first one, and
41206c3fb27SDimitry Andric     // replace them with "...".
41306c3fb27SDimitry Andric     if (AreWordsZero[0] && AreWordsZero[1] && AreWordsZero[2]) {
41406c3fb27SDimitry Andric       if (ShouldPrintLine)
41506c3fb27SDimitry Andric         OS << std::string(8, ' ') << "...\n";
41606c3fb27SDimitry Andric       ShouldPrintLine = false;
41706c3fb27SDimitry Andric     } else if (!AreWordsZero[1]) {
41806c3fb27SDimitry Andric       // We have reached the end of a skipped block of zeros.
41906c3fb27SDimitry Andric       ShouldPrintLine = true;
42006c3fb27SDimitry Andric     }
42106c3fb27SDimitry Andric     AreWordsZero[0] = AreWordsZero[1];
42206c3fb27SDimitry Andric     AreWordsZero[1] = AreWordsZero[2];
42306c3fb27SDimitry Andric     AreWordsZero[2] = IsWordZero(Index + 8);
42406c3fb27SDimitry Andric   }
42506c3fb27SDimitry Andric }
42606c3fb27SDimitry Andric #undef PRINTBOOL
42706c3fb27SDimitry Andric #undef PRINTGET
42806c3fb27SDimitry Andric #undef PRINTOPTIONAL
429