diff --git a/llvm/docs/CommandGuide/llvm-objdump.rst b/llvm/docs/CommandGuide/llvm-objdump.rst --- a/llvm/docs/CommandGuide/llvm-objdump.rst +++ b/llvm/docs/CommandGuide/llvm-objdump.rst @@ -332,6 +332,10 @@ Add symbol description to disassembly output. +.. option:: --traceback-table + + Decode traceback table for disassembly output. + BUGS ---- diff --git a/llvm/include/llvm/BinaryFormat/XCOFF.h b/llvm/include/llvm/BinaryFormat/XCOFF.h --- a/llvm/include/llvm/BinaryFormat/XCOFF.h +++ b/llvm/include/llvm/BinaryFormat/XCOFF.h @@ -284,6 +284,59 @@ StringRef getMappingClassString(XCOFF::StorageMappingClass SMC); StringRef getRelocationTypeString(XCOFF::RelocationType Type); +struct Traceback_Table { + + // Byte 1 + static constexpr uint32_t Version_Mask = 0xFF000000; + static constexpr uint8_t Version_Shift = 24; + + // Byte 2 + static constexpr uint32_t LanguageId_Mask = 0xFF0000; + static constexpr uint8_t LanguageId_Shift = 16; + + // Byte 3 + static constexpr uint32_t GlobaLinkage_Mask = 0x8000; + static constexpr uint32_t Is_Eprol_Mask = 0x4000; + static constexpr uint32_t Has_CodeLen_Mask = 0x2000; + static constexpr uint32_t Int_Proc_Mask = 0x1000; + static constexpr uint32_t Has_Ctl_Mask = 0x0800; + static constexpr uint32_t TOCLess_Mask = 0x0400; + static constexpr uint32_t FP_Present_Mask = 0x0200; + static constexpr uint32_t Log_Abort_Mask = 0x0100; + + // Byte 4 + static constexpr uint32_t Int_Handler_Mask = 0x80; + static constexpr uint32_t Name_Present_Mask = 0x40; + static constexpr uint32_t Used_Alloca_Mask = 0x20; + static constexpr uint32_t Cl_Dis_Inv_Mask = 0x1C; + static constexpr uint32_t Saves_CR_Mask = 0x02; + static constexpr uint32_t Saves_LR_Mask = 0x01; + + static constexpr uint8_t Cl_Dis_Inv_Shift = 2; + + // Byte 5 + static constexpr uint32_t Stores_BC_Mask = 0x80000000; + static constexpr uint32_t Fixup_Mask = 0x40000000; + static constexpr uint32_t FP_Saved_Mask = 0x3F000000; + + // Byte 6 + static constexpr uint32_t Has_Vec_Info_Mask = 0x800000; + static constexpr uint32_t Spare4_Mask = 0x400000; + static constexpr uint32_t GP_SAVED_Mask = 0x3F0000; + + // Byte 7 + static constexpr uint32_t NumberOfFixedPara_Mask = 0xFF00; + static constexpr uint8_t NumberOfFixedPara_Shift = 8; + + // Byte 8 + static constexpr uint32_t NumberOfFPPara_Mask = 0xFE; + static constexpr uint32_t ParmsOnStack_Mask = 0x01; + static constexpr uint8_t NumberOfFPPara_Shift = 01; + + static constexpr uint32_t FixedParaTypeBit = 0x80000000; + static constexpr uint32_t FloatPointParaTypeBit = 0x40000000; +}; + } // end namespace XCOFF } // end namespace llvm diff --git a/llvm/include/llvm/Object/XCOFFObjectFile.h b/llvm/include/llvm/Object/XCOFFObjectFile.h --- a/llvm/include/llvm/Object/XCOFFObjectFile.h +++ b/llvm/include/llvm/Object/XCOFFObjectFile.h @@ -391,6 +391,28 @@ bool isFunction() const; }; +class XCOFFTracebackTable { + void *Tb_ptr; + +public: + XCOFFTracebackTable(void *Ptr) : Tb_ptr(Ptr){}; + + // The 3th bytes fields + bool hasFunctionCodeLen(); + bool hasCtl(); + + // The 4th byte fields + bool isInterruptHandler(); + bool isFuncNamePresent(); + bool usedAlloca(); + + // The 7th byte + unsigned getNumberOfFixedPara(); + + // The 8th byte + unsigned getNumberOfFPPara(); +}; + } // namespace object } // namespace llvm diff --git a/llvm/lib/Object/XCOFFObjectFile.cpp b/llvm/lib/Object/XCOFFObjectFile.cpp --- a/llvm/lib/Object/XCOFFObjectFile.cpp +++ b/llvm/lib/Object/XCOFFObjectFile.cpp @@ -16,6 +16,9 @@ #include namespace llvm { + +using namespace XCOFF; + namespace object { static const uint8_t FunctionSym = 0x20; @@ -834,5 +837,41 @@ template struct XCOFFSectionHeader; template struct XCOFFSectionHeader; +bool XCOFFTracebackTable::hasFunctionCodeLen() { + return (support::ubig32_t::ref(Tb_ptr) & Traceback_Table::Has_CodeLen_Mask) > + 0; +} + +bool XCOFFTracebackTable::hasCtl() { + return (support::ubig32_t::ref(Tb_ptr) & Traceback_Table::Has_Ctl_Mask) > 0; +} + +bool XCOFFTracebackTable::isInterruptHandler() { + return (support::ubig32_t::ref(Tb_ptr) & Traceback_Table::Int_Handler_Mask) > + 0; +} + +bool XCOFFTracebackTable::isFuncNamePresent() { + return (support::ubig32_t::ref(Tb_ptr) & Traceback_Table::Name_Present_Mask) > + 0; +} + +bool XCOFFTracebackTable::usedAlloca() { + return (support::ubig32_t::ref(Tb_ptr) & Traceback_Table::Used_Alloca_Mask) > + 0; +} + +unsigned XCOFFTracebackTable::getNumberOfFixedPara() { + return (support::ubig32_t::ref((char *)Tb_ptr + 4) & + Traceback_Table::NumberOfFixedPara_Mask) >> + Traceback_Table::NumberOfFixedPara_Shift; +} + +unsigned XCOFFTracebackTable::getNumberOfFPPara() { + return (support::ubig32_t::ref((char *)Tb_ptr + 4) & + Traceback_Table::NumberOfFPPara_Mask) >> + Traceback_Table::NumberOfFPPara_Shift; +} + } // namespace object } // namespace llvm diff --git a/llvm/test/tools/llvm-objdump/XCOFF/Inputs/xcoff-func-tracebacktable.o b/llvm/test/tools/llvm-objdump/XCOFF/Inputs/xcoff-func-tracebacktable.o new file mode 100755 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 GIT binary patch literal 0 Hc$@ cat test.c +## double add_all(int value,float fvalue, double dvalue) { +## return dvalue+fvalue+value; +## } +## +## int go(int v1,int v2) { +## return v1+v2; +## } +## +## double g(double a,double b) { +## return a+b; +## } +## +## int main() { +## return add_all(1,2.0,3.0)+1.0; +## } + +CHECK-LABEL: 00000000 (idx: 12) .add_all: +CHECK: 40: 00 00 00 00 # Traceback table begin +CHECK-NEXT: 44: 00 00 22 40 # Version=0 +CHECK-NEXT: # Language = C +CHECK-NEXT: # -GlobaLinkage, -Is_Eprol, +Has_CodeLen, -Int_Proc +CHECK-NEXT: , -Has_Ctl, -TOCLess, +FP_Present, -Log_Abort +CHECK-NEXT: # -Int_Handler, +Name_Present, -Used_Alloca, Cl_Dis_Inv=0 +CHECK-NEXT: , -Saves_CR, -Saves_LR +CHECK-NEXT: 48: 80 00 01 05 # +Stores_BC, -Fixup, FP_Saved=0 +CHECK-NEXT: # Has_Vec_Info=0, GP_SAVED=0 +CHECK-NEXT: # NumberOfFixedPara=1 +CHECK-NEXT: # NumberOfFPPara=2, +ParmsOnStack +CHECK-NEXT: 4c: 58 00 00 00 # Parameter Type: i, f, d +CHECK-NEXT: 50: 00 00 00 40 # Code Len = 64 +CHECK-NEXT: 54: 00 07 61 64 # Length of function name = 7 +CHECK-NEXT: # Function Name: ad +CHECK-NEXT: 58: 64 5f 61 6c # d_al +CHECK-NEXT: 5c: 6c 00 00 00 # l +CHECK-NEXT: # Padding + +CHECK-LABEL: 00000060 (idx: 14) .main: +CHECK: ac: 00 00 00 00 # Traceback table begin +CHECK-NEXT: b0: 00 00 22 41 # Version=0 +CHECK-NEXT: # Language = C +CHECK-NEXT: # -GlobaLinkage, -Is_Eprol, +Has_CodeLen, -Int_Proc +CHECK-NEXT: , -Has_Ctl, -TOCLess, +FP_Present, -Log_Abort +CHECK-NEXT: # -Int_Handler, +Name_Present, -Used_Alloca, Cl_Dis_Inv=0 +CHECK-NEXT: , -Saves_CR, +Saves_LR +CHECK-NEXT: b4: 80 01 00 01 # +Stores_BC, -Fixup, FP_Saved=0 +CHECK-NEXT: # Has_Vec_Info=0, GP_SAVED=65536 +CHECK-NEXT: # NumberOfFixedPara=0 +CHECK-NEXT: # NumberOfFPPara=0, +ParmsOnStack +CHECK-NEXT: b8: 00 00 00 4c # Code Len = 76 +CHECK-NEXT: bc: 00 04 6d 61 # Length of function name = 4 +CHECK-NEXT: # Function Name: ma +CHECK-NEXT: c0: 69 6e 00 00 # in +CHECK-NEXT: # Padding +CHECK-NEXT: ... + +CHECK-LABEL: 000000e0 (idx: 16) .go: +CHECK: 100: 00 00 00 00 # Traceback table begin +CHECK-NEXT: 104: 00 00 20 40 # Version=0 +CHECK-NEXT: # Language = C +CHECK-NEXT: # -GlobaLinkage, -Is_Eprol, +Has_CodeLen, -Int_Proc +CHECK-NEXT: , -Has_Ctl, -TOCLess, -FP_Present, -Log_Abort +CHECK-NEXT: # -Int_Handler, +Name_Present, -Used_Alloca, Cl_Dis_Inv=0 +CHECK-NEXT: , -Saves_CR, -Saves_LR +CHECK-NEXT: 108: 80 00 02 01 # +Stores_BC, -Fixup, FP_Saved=0 +CHECK-NEXT: # Has_Vec_Info=0, GP_SAVED=0 +CHECK-NEXT: # NumberOfFixedPara=2 +CHECK-NEXT: # NumberOfFPPara=0, +ParmsOnStack +CHECK-NEXT: 10c: 00 00 00 00 # Parameter Type: i, i +CHECK-NEXT: 110: 00 00 00 20 # Code Len = 32 +CHECK-NEXT: 114: 00 02 67 6f # Length of function name = 2 +CHECK-NEXT: # Function Name: go +CHECK-NEXT: ... + +CHECK-LABEL: 00000120 (idx: 18) .g: +CHECK: 140: 00 00 00 00 # Traceback table begin +CHECK-NEXT: 144: 00 00 22 40 # Version=0 +CHECK-NEXT: # Language = C +CHECK-NEXT: # -GlobaLinkage, -Is_Eprol, +Has_CodeLen, -Int_Proc +CHECK-NEXT: , -Has_Ctl, -TOCLess, +FP_Present, -Log_Abort +CHECK-NEXT: # -Int_Handler, +Name_Present, -Used_Alloca, Cl_Dis_Inv=0 +CHECK-NEXT: , -Saves_CR, -Saves_LR +CHECK-NEXT: 148: 80 00 00 05 # +Stores_BC, -Fixup, FP_Saved=0 +CHECK-NEXT: # Has_Vec_Info=0, GP_SAVED=0 +CHECK-NEXT: # NumberOfFixedPara=0 +CHECK-NEXT: # NumberOfFPPara=2, +ParmsOnStack +CHECK-NEXT: 14c: f0 00 00 00 # Parameter Type: d, d +CHECK-NEXT: 150: 00 00 00 20 # Code Len = 32 +CHECK-NEXT: 154: 00 01 67 00 # Length of function name = 1 +CHECK-NEXT: # Function Name: g +CHECK-NEXT: # Padding +CHECK-NEXT: ... diff --git a/llvm/tools/llvm-objdump/XCOFFDump.h b/llvm/tools/llvm-objdump/XCOFFDump.h --- a/llvm/tools/llvm-objdump/XCOFFDump.h +++ b/llvm/tools/llvm-objdump/XCOFFDump.h @@ -10,6 +10,7 @@ #define LLVM_TOOLS_LLVM_OBJDUMP_XCOFFDUMP_H #include "llvm/Object/XCOFFObjectFile.h" +#include "llvm/Support/raw_ostream.h" namespace llvm { @@ -28,6 +29,13 @@ Error getXCOFFRelocationValueString(const object::XCOFFObjectFile *Obj, const object::RelocationRef &RelRef, llvm::SmallVectorImpl &Result); +void formatTracebackTableOutput(ArrayRef Bytes, uint64_t Address, + raw_ostream &OS); + +void dumpTracebackTable(ArrayRef Bytes, uint64_t Address, + raw_ostream &OS, uint64_t End); + +bool doesXCOFFTracebackTableBegin(ArrayRef Bytes); } // namespace objdump } // namespace llvm #endif diff --git a/llvm/tools/llvm-objdump/XCOFFDump.cpp b/llvm/tools/llvm-objdump/XCOFFDump.cpp --- a/llvm/tools/llvm-objdump/XCOFFDump.cpp +++ b/llvm/tools/llvm-objdump/XCOFFDump.cpp @@ -15,9 +15,13 @@ #include "llvm-objdump.h" #include "llvm/Demangle/Demangle.h" +#include "llvm/MC/MCInstPrinter.h" +#include "llvm/Support/Endian.h" using namespace llvm; using namespace llvm::object; +using namespace llvm::XCOFF; +using namespace llvm::support; Error objdump::getXCOFFRelocationValueString(const XCOFFObjectFile *Obj, const RelocationRef &Rel, @@ -86,3 +90,262 @@ return Result; } + +bool objdump::doesXCOFFTracebackTableBegin(ArrayRef Bytes) { + // Traceback table begins with sizeof(long) bytes zero. + if (Bytes.size() == 4) + return (*reinterpret_cast(Bytes.data()) == 0); + + return (*reinterpret_cast(Bytes.data()) == 0); +} + +void objdump::formatTracebackTableOutput(ArrayRef Bytes, + uint64_t Address, raw_ostream &OS) { + size_t Start = OS.tell(); + if (!NoLeadingAddr) + OS << format("%8" PRIx64 ":", Address); + if (!NoShowRawInsn) { + OS << ' '; + dumpBytes(Bytes, OS); + } + + // The output of printInst starts with a tab. Print some spaces so that + // the tab has 1 column and advances to the target tab stop. + unsigned TabStop = NoShowRawInsn ? 16 : 40; + unsigned Column = OS.tell() - Start; + OS.indent(Column < TabStop - 1 ? TabStop - 1 - Column : 7 - Column % 8); +} + +std::string SourceLanguageIdentifier[] = { + "C", "FORTRAN", "Pascal", "ADA", "PL/I", + "BASIC", "LISP", "COBOL", "Modulas2", "C++", + "RPG", "PL8", "Assembler", "Java", "Objective C"}; + +#define BITCONTENT_ONEBIT(Prefix, field) \ + OS << Prefix << " " << (Value & Traceback_Table::field##_Mask ? "+" : "-") \ + << #field + +#define BITCONTENT_SHIFT(Prefix, field) \ + OS << Prefix << " " << #field << "=" \ + << ((Value & Traceback_Table::field##_Mask) >> \ + Traceback_Table::field##_Shift) + +#define BITCONTENT_END(Prefix, field) \ + OS << Prefix << " " << #field << "=" \ + << (Value & Traceback_Table::field##_Mask) + +void objdump::dumpTracebackTable(ArrayRef Bytes, uint64_t Address, + raw_ostream &OS, uint64_t End) { + unsigned int Index = 0; + unsigned TabStop = (NoShowRawInsn ? 16 : 40) - 1; + + // Backtrace table boundary. + formatTracebackTableOutput(Bytes.slice(Index, 4), Address, OS); + OS << "# Traceback table begin\n"; + Index += 4; + + XCOFFTracebackTable Tb(const_cast(Bytes.data() + Index)); + uint32_t Value; + ArrayRef CurrentBytes = Bytes.slice(Index, 4); + formatTracebackTableOutput(CurrentBytes, Address + Index, OS); + Value = + support::ubig32_t::ref(const_cast(CurrentBytes.data())); + Index += 4; + + BITCONTENT_SHIFT("#", Version); + OS << "\n"; + + OS.indent(TabStop); + unsigned LangId = (Value & Traceback_Table::LanguageId_Mask) >> + Traceback_Table::LanguageId_Shift; + + OS << "# Language = " + << (LangId < sizeof(SourceLanguageIdentifier) / sizeof(char *) + ? SourceLanguageIdentifier[LangId] + : "Unknown") + << "\n"; + + // Print the 3rd byte. + OS.indent(TabStop); + BITCONTENT_ONEBIT("#", GlobaLinkage); + BITCONTENT_ONEBIT(",", Is_Eprol); + BITCONTENT_ONEBIT(",", Has_CodeLen); + BITCONTENT_ONEBIT(",", Int_Proc); + OS << "\n"; + OS.indent(TabStop); + BITCONTENT_ONEBIT(",", Has_Ctl); + BITCONTENT_ONEBIT(",", TOCLess); + BITCONTENT_ONEBIT(",", FP_Present); + BITCONTENT_ONEBIT(",", Log_Abort); + OS << "\n"; + + // Print the 4th byte. + OS.indent(TabStop); + BITCONTENT_ONEBIT("#", Int_Handler); + BITCONTENT_ONEBIT(",", Name_Present); + BITCONTENT_ONEBIT(",", Used_Alloca); + BITCONTENT_SHIFT(",", Cl_Dis_Inv); + OS << "\n"; + OS.indent(TabStop); + BITCONTENT_ONEBIT(",", Saves_CR); + BITCONTENT_ONEBIT(",", Saves_LR); + OS << "\n"; + + CurrentBytes = Bytes.slice(Index, 4); + formatTracebackTableOutput(CurrentBytes, Address + Index, OS); + Value = + support::ubig32_t::ref(const_cast(CurrentBytes.data())); + Index += 4; + + // Print the 5th byte. + BITCONTENT_ONEBIT("#", Stores_BC); + BITCONTENT_ONEBIT(",", Fixup); + BITCONTENT_END(",", FP_Saved); + OS << "\n"; + + // Print the 6th byte. + OS.indent(TabStop); + BITCONTENT_END("#", Has_Vec_Info); + BITCONTENT_END(",", GP_SAVED); + OS << "\n"; + + // Print the 7th byte. + OS.indent(TabStop); + BITCONTENT_SHIFT("#", NumberOfFixedPara); + OS << "\n"; + + // Print the 8th byte. + OS.indent(TabStop); + BITCONTENT_SHIFT("#", NumberOfFPPara); + BITCONTENT_ONEBIT(",", ParmsOnStack); + OS << "\n"; + + // Decode option bytes. + + // Decode parameter type if there is one. + if (Tb.getNumberOfFixedPara() || Tb.getNumberOfFPPara()) { + ArrayRef CurBytes = Bytes.slice(Index, 4); + Value = + support::ubig32_t::ref(const_cast(CurBytes.data())); + formatTracebackTableOutput(CurBytes, Address + Index, OS); + OS << "# Parameter Type: "; + for (unsigned i = 0; i < Tb.getNumberOfFixedPara() + Tb.getNumberOfFPPara(); + ++i) { + if (i != 0) + OS << ", "; + if ((Value & Traceback_Table::FixedParaTypeBit) == 0) { + // Fixed parameter type. + OS << "i"; + Value <<= 1; + continue; + } else { + if ((Value & Traceback_Table::FloatPointParaTypeBit) == 0) + // Float parameter type. + OS << "f"; + else + // Double parameter type. + OS << "d"; + + Value <<= 2; + continue; + } + } + OS << "\n"; + Index += 4; + } + + // Decode function code len if there present. + if (Tb.hasFunctionCodeLen()) { + ArrayRef CurBytes = Bytes.slice(Index, 4); + Value = + support::ubig32_t::ref(const_cast(CurBytes.data())); + formatTracebackTableOutput(CurBytes, Address + Index, OS); + OS << "# Code Len = " << Value << "\n"; + Index += 4; + } + + if (Tb.isInterruptHandler()) { + formatTracebackTableOutput(Bytes.slice(Index, 4), Address + Index, OS); + OS << "# HAND_MASK\n"; + Index += 4; + } + + if (Tb.hasCtl()) { + formatTracebackTableOutput(Bytes.slice(Index, 4), Address + Index, OS); + OS << "# Number of CTL anchors\n"; + Index += 4; + } + + unsigned RemainingBytes = 0; + // Decode length of function name and the name of function if Name_Present + // is 1. + if (Tb.isFuncNamePresent()) { + formatTracebackTableOutput(Bytes.slice(Index, 4), Address + Index, OS); + uint16_t NameLen = support::ubig16_t::ref( + const_cast(Bytes.slice(Index, 2).data())); + assert(NameLen > 0 && "The length of file name must large than zero."); + OS << "# Length of function name = " << NameLen << "\n"; + RemainingBytes = 2; + OS.indent(TabStop); + OS << "# Function Name: "; + + if (NameLen >= 2) { + OS << StringRef((const char *)Bytes.slice(Index + 2, 2).data(), 2) + << "\n"; + NameLen -= 2; + RemainingBytes = 0; + } else { + OS << StringRef((const char *)Bytes.slice(Index + 2, NameLen).data(), + NameLen) + << "\n"; + RemainingBytes -= NameLen; + NameLen = 0; + } + + Index += 4; + + while (NameLen > 0) { + formatTracebackTableOutput(Bytes.slice(Index, 4), Address + Index, OS); + int Len = NameLen >= 4 ? 4 : NameLen; + OS << "# " << StringRef((const char *)Bytes.slice(Index, Len).data(), Len) + << "\n"; + NameLen -= Len; + Index += 4; + RemainingBytes = 4 - Len; + } + } + + if (Tb.usedAlloca()) { + if (RemainingBytes == 0) { + formatTracebackTableOutput(Bytes.slice(Index, 4), Address + Index, OS); + RemainingBytes = 3; + Index += 4; + } else { + OS.indent(TabStop); + --RemainingBytes; + } + + OS << "# Alloca_Reg\n"; + } + + if (RemainingBytes != 0) { + OS.indent(TabStop); + OS << "# Padding\n"; + } + + assert(End >= Address + Index && "Traceback table parse error."); + + if (End == Address + Index) + return; + + // Print out all padding. + if (End - Address + Index >= 8) + OS << "\t\t...\n"; + else { + formatTracebackTableOutput(Bytes.slice(Index, 4), Address + Index, OS); + OS << "# Padding\n"; + } +} +#undef BITCONTENT_ONEBIT +#undef BITCONTENT_SHIFT +#undef BITCONTENT_END diff --git a/llvm/tools/llvm-objdump/llvm-objdump.h b/llvm/tools/llvm-objdump/llvm-objdump.h --- a/llvm/tools/llvm-objdump/llvm-objdump.h +++ b/llvm/tools/llvm-objdump/llvm-objdump.h @@ -45,6 +45,7 @@ extern cl::opt SectionHeaders; extern cl::opt SectionContents; extern cl::opt SymbolDescription; +extern cl::opt TracebackTable; extern cl::opt SymbolTable; extern cl::opt TripleName; extern cl::opt UnwindInfo; diff --git a/llvm/tools/llvm-objdump/llvm-objdump.cpp b/llvm/tools/llvm-objdump/llvm-objdump.cpp --- a/llvm/tools/llvm-objdump/llvm-objdump.cpp +++ b/llvm/tools/llvm-objdump/llvm-objdump.cpp @@ -138,6 +138,12 @@ "option is for XCOFF files only"), cl::init(false), cl::cat(ObjdumpCat)); +cl::opt objdump::TracebackTable( + "traceback-table", + cl::desc("Decode traceback table for disassembly. This " + "option is for XCOFF files only"), + cl::init(false), cl::cat(ObjdumpCat)); + static cl::list DisassembleSymbols("disassemble-symbols", cl::CommaSeparated, cl::desc("List of symbols to disassemble. " @@ -1155,7 +1161,7 @@ const uint64_t Addr = unwrapOrError(Symbol.getAddress(), FileName); const StringRef Name = unwrapOrError(Symbol.getName(), FileName); - if (Obj->isXCOFF() && SymbolDescription) { + if (Obj->isXCOFF() && (SymbolDescription || TracebackTable)) { const auto *XCOFFObj = cast(Obj); DataRefImpl SymbolDRI = Symbol.getRawDataRefImpl(); @@ -1173,7 +1179,7 @@ static SymbolInfoTy createDummySymbolInfo(const ObjectFile *Obj, const uint64_t Addr, StringRef &Name, uint8_t Type) { - if (Obj->isXCOFF() && SymbolDescription) + if (Obj->isXCOFF() && (SymbolDescription || TracebackTable)) return SymbolInfoTy(Addr, Name, None, None, false); else return SymbolInfoTy(Addr, Name, Type); @@ -1452,6 +1458,12 @@ Symbols[SI].Type != ELF::STT_OBJECT && !DisassembleAll; bool DumpARMELFData = false; + bool DumpTracebackTableForXCOFFFunction = + Obj->isXCOFF() && Section.isText() && TracebackTable && + Symbols[SI].XCOFFSymInfo.StorageMappingClass && + Symbols[SI].XCOFFSymInfo.StorageMappingClass.getValue() == + XCOFF::XMC_PR; + while (Index < End) { // ARM and AArch64 ELF binaries can interleave data and text in the // same section. We rely on the markers introduced to understand what @@ -1492,6 +1504,16 @@ } } + if (DumpTracebackTableForXCOFFFunction && + doesXCOFFTracebackTableBegin(Bytes.slice( + Index, cast(Obj)->is64Bit() ? 8 : 4))) { + dumpTracebackTable(Bytes.slice(Index), + SectionAddr + Index + VMAAdjustment, outs(), + End); + Index = End; + continue; + } + // Disassemble a real instruction or a data when disassemble all is // provided MCInst Inst;