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 @@ -372,6 +372,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 @@ -13,6 +13,7 @@ #ifndef LLVM_BINARYFORMAT_XCOFF_H #define LLVM_BINARYFORMAT_XCOFF_H +#include "llvm/ADT/SmallString.h" #include #include @@ -294,6 +295,10 @@ StringRef getMappingClassString(XCOFF::StorageMappingClass SMC); StringRef getRelocationTypeString(XCOFF::RelocationType Type); +StringRef getTracebackTableLanguage(unsigned LangId); +SmallString<32> parseParmsTypeWithVecInfo(uint32_t Value, + unsigned int ParmsNum); +SmallString<32> parseParmsType(uint32_t Value, unsigned ParmsNum); struct TracebackTable { // Byte 1 diff --git a/llvm/lib/BinaryFormat/XCOFF.cpp b/llvm/lib/BinaryFormat/XCOFF.cpp --- a/llvm/lib/BinaryFormat/XCOFF.cpp +++ b/llvm/lib/BinaryFormat/XCOFF.cpp @@ -75,4 +75,77 @@ } return "Unknown"; } + +const char *SourceLanguageIdentifier[] = { + "C", "FORTRAN", "Pascal", "Ada", "PL/I", + "BASIC", "Lisp", "COBOL", "Modula2", "C++", + "RPG", "PL8", "Assembly", "Java", "Objective-C"}; + +StringRef XCOFF::getTracebackTableLanguage(unsigned LangId) { + return LangId < sizeof(SourceLanguageIdentifier) / sizeof(char *) + ? SourceLanguageIdentifier[LangId] + : "Unknown"; +} + +SmallString<32> XCOFF::parseParmsTypeWithVecInfo(uint32_t Value, + unsigned int ParmsNum) { + SmallString<32> ParmsType; + unsigned I = 0; + bool Begin = false; + while (I < ParmsNum || Value) { + if (Begin) + ParmsType += ", "; + else + Begin = true; + + switch (Value & TracebackTable::ParmTypeMask) { + case TracebackTable::ParmTypeIsFixedBits: + ParmsType += "i"; + ++I; + break; + case TracebackTable::ParmTypeIsVectorBits: + ParmsType += "v"; + break; + case TracebackTable::ParmTypeIsFloatingBits: + ParmsType += "f"; + ++I; + break; + case TracebackTable::ParmTypeIsDoubleBits: + ParmsType += "d"; + ++I; + break; + default: + assert(false && "Unrecognized bits in ParmsType."); + } + Value <<= 2; + } + assert(I == ParmsNum && + "The total parameters number of fixed-point or floating-point " + "parameters not equal to the number in the parameter type!"); + return ParmsType; +} + +SmallString<32> XCOFF::parseParmsType(uint32_t Value, unsigned ParmsNum) { + SmallString<32> ParmsType; + for (unsigned I = 0; I < ParmsNum; ++I) { + if (I != 0) + ParmsType += ", "; + if ((Value & TracebackTable::ParmTypeIsFloatingBit) == 0) { + // Fixed parameter type. + ParmsType += "i"; + Value <<= 1; + } else { + if ((Value & TracebackTable::ParmTypeFloatingIsDoubleBit) == 0) + // Float parameter type. + ParmsType += "f"; + else + // Double parameter type. + ParmsType += "d"; + + Value <<= 2; + } + } + return ParmsType; +} + #undef RELOC_CASE 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 @@ -904,67 +904,6 @@ return ParmsType; } -static SmallString<32> parseParmsTypeWithVecInfo(uint32_t Value, - unsigned int ParmsNum) { - SmallString<32> ParmsType; - unsigned I = 0; - bool Begin = false; - while (I < ParmsNum || Value) { - if (Begin) - ParmsType += ", "; - else - Begin = true; - - switch (Value & TracebackTable::ParmTypeMask) { - case TracebackTable::ParmTypeIsFixedBits: - ParmsType += "i"; - ++I; - break; - case TracebackTable::ParmTypeIsVectorBits: - ParmsType += "v"; - break; - case TracebackTable::ParmTypeIsFloatingBits: - ParmsType += "f"; - ++I; - break; - case TracebackTable::ParmTypeIsDoubleBits: - ParmsType += "d"; - ++I; - break; - default: - assert(false && "Unrecognized bits in ParmsType."); - } - Value <<= 2; - } - assert(I == ParmsNum && - "The total parameters number of fixed-point or floating-point " - "parameters not equal to the number in the parameter type!"); - return ParmsType; -} - -static SmallString<32> parseParmsType(uint32_t Value, unsigned ParmsNum) { - SmallString<32> ParmsType; - for (unsigned I = 0; I < ParmsNum; ++I) { - if (I != 0) - ParmsType += ", "; - if ((Value & TracebackTable::ParmTypeIsFloatingBit) == 0) { - // Fixed parameter type. - ParmsType += "i"; - Value <<= 1; - } else { - if ((Value & TracebackTable::ParmTypeFloatingIsDoubleBit) == 0) - // Float parameter type. - ParmsType += "f"; - else - // Double parameter type. - ParmsType += "d"; - - Value <<= 2; - } - } - return ParmsType; -} - Expected XCOFFTracebackTable::create(const uint8_t *Ptr, uint64_t &Size) { Error Err = Error::success(); diff --git a/llvm/test/tools/llvm-objdump/XCOFF/Inputs/xcoff-invalid-traceback-table.o b/llvm/test/tools/llvm-objdump/XCOFF/Inputs/xcoff-invalid-traceback-table.o new file mode 100644 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 GIT binary patch literal 0 Hc$@&1 | \ +# RUN: FileCheck --check-prefixes=CHECH,WARN %s + +## xcoff-invalid-traceback-table.o compiled with IBM XL C/C++ for AIX, V16.1.0 +## compiler command: xlc -o xcoff-invalid-traceback-table.o -c foo.c +## foo.c: +## float foo(int i1,float f1,double d1,int i2, float f2) { +## return i1+f1+d1+i2+f2; +## } +## And then modify the binary content of traceback table of the object file to make it as invalid trace back table. + +CHECK: 00000000 (idx: 12) .foo: +CHECK-NEXT: 0: 93 e1 ff fc stw 31, -4(1) +CHECK-NEXT: 4: 94 21 ff 90 stwu 1, -112(1) +CHECK-NEXT: 8: 83 e2 00 04 lwz 31, 4(2) + +CHECK: 70: c0 41 00 9c lfs 2, 156(1) +CHECK-NEXT: 74: fc 21 10 2a fadd 1, 1, 2 +CHECK-NEXT: 78: fc 20 08 18 frsp 1, 1 +CHECK-NEXT: 7c: 83 e1 00 6c lwz 31, 108(1) +CHECK-NEXT: 80: 38 21 00 70 addi 1, 1, 112 +CHECK-NEXT: 84: 4e 80 00 20 blr +CHECK-NEXT: 88: 00 00 00 00 # Traceback table begin +#WARN: Parse traceback table failure: unexpected end of data at offset 0x100 while reading [0x9a, 0x10d) +#WARN-NEXT: The raw data of traceback table as : +#WARN-NEXT: 8c: 00 00 22 40 +#WARN-NEXT: 90: 80 01 02 07 +#WARN-NEXT: 94: 5a 00 00 00 +#WARN-NEXT: 98: 00 00 00 88 +#WARN-NEXT: 9c: 00 73 66 6f +#WARN-NEXT: a0: 6f 00 00 00 +#WARN-NEXT: ... + +CHECK: Disassembly of section .data: +CHECK-NEXT: +CHECK-NEXT: 00000100 (idx: 22) foo[TC]: +CHECK-NEXT: 100: 00 00 01 08 diff --git a/llvm/test/tools/llvm-objdump/XCOFF/disassemble-traceback-table.test b/llvm/test/tools/llvm-objdump/XCOFF/disassemble-traceback-table.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-objdump/XCOFF/disassemble-traceback-table.test @@ -0,0 +1,60 @@ +# REQUIRES: powerpc-registered-target + +# RUN: llvm-objdump -D --traceback-table --symbol-description %p/Inputs/xcoff-traceback-table.o | \ +# RUN: FileCheck %s + +## xcoff-traceback-table.o compiled with IBM XL C/C++ for AIX, V16.1.0 +## compiler command: xlc -o xcoff-traceback-table.o -c foo.c +## foo.c: + +## #include +## vector float foo(int i1,float f1,double d1,int i2, float f2, vector float vf) { +## if (i1+f1+d1+i2+f2 > 0) +## return vec_abs(vf); +## } +## And modify the binary content of traceback table of the object file to add some +## ControlledStorageInfo, AllocaRegister, externsion table. + +CHECK: 00000000 (idx: 12) .foo: +CHECK-NEXT: 0: 93 e1 ff fc stw 31, -4(1) +CHECK-NEXT: 4: 93 c1 ff f8 stw 30, -8(1) +CHECK-NEXT: 8: 94 21 ff 80 stwu 1, -128(1) +CHECK-NEXT: c: 83 c2 00 04 lwz 30, 4(2) + +CHECK: a0: 10 40 00 2c vsldoi 2, 0, 0, 0 +CHECK-NEXT: a4: 48 00 00 04 b 0xa8 +CHECK-NEXT: a8: 83 c1 00 78 lwz 30, 120(1) +CHECK-NEXT: ac: 38 21 00 80 addi 1, 1, 128 +CHECK-NEXT: b0: 4e 80 00 20 blr +CHECK-NEXT: b4: 00 00 00 00 # Traceback table begin +CHECK-NEXT: b8: 00 # Version = 0 +CHECK-NEXT: b9: 00 # Language = C +CHECK-NEXT: ba: 2a # -isGlobalLinkage, -isOutOfLineEpilogOrPrologue +CHECK-NEXT: +hasTraceBackTableOffset, -isInternalProcedure +CHECK-NEXT: +hasControlledStorage, -isTOCless +CHECK-NEXT: +isFloatingPointPresent +CHECK-NEXT: -isFloatingPointOperationLogOrAbortEnabled +CHECK-NEXT: bb: 60 # -isInterruptHandler, +isFuncNamePresent, +isAllocaUsed +CHECK-NEXT: OnConditionDirective = 0, -isCRSaved, -isLRSaved +CHECK-NEXT: bc: 80 # +isBackChainStored, -isFixup, NumOfFPRsSaved = 0 +CHECK-NEXT: bd: c2 # +hasExtensionTable, +hasVectorInfo, NumOfGPRsSaved = 2 +CHECK-NEXT: be: 02 # NumberOfFixedParms = 2 +CHECK-NEXT: bf: 07 # NumberOfFPParms = 3, +hasParmsOnStack +CHECK-NEXT: c0: 2c 90 00 00 # ParmsType = i, f, d, i, f, v +CHECK-NEXT: c4: 00 00 00 b4 # TraceBackTableOffset = 180 +CHECK-NEXT: c8: 00 00 00 03 # NumOfCtlAnchors = 3 +CHECK-NEXT: cc: 6f 00 00 01 ControlledStorageInfoDisp[0] = 1862270977 +CHECK-NEXT: d0: 00 00 00 0a ControlledStorageInfoDisp[1] = 10 +CHECK-NEXT: d4: 00 00 01 00 ControlledStorageInfoDisp[2] = 256 +CHECK-NEXT: d8: 00 03 # FunctionNameLen = 3 +CHECK-NEXT: da: 66 6f 6f # FunctionName = foo +CHECK-NEXT: dd: 1f # AllocaRegister = 31 +CHECK-NEXT: de: 02 # NumberOfVRSaved = 0, +isVRSavedOnStack, -hasVarArgs +CHECK-NEXT: df: 03 # NumberOfVectorParms = 1, +hasVMXInstruction +CHECK-NEXT: e0: c0 00 00 00 # VectorParmsInfoString = vf +CHECK-NEXT: e4: 20 # ExtensionTable = TB_SSP_CANARY +CHECK-NEXT: ... + +CHECK: Disassembly of section .data: +CHECK: 00000100 (idx: 22) foo[TC]: +CHECK-NEXT: 100: 00 00 01 08 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 @@ -9,7 +9,9 @@ #ifndef LLVM_TOOLS_LLVM_OBJDUMP_XCOFFDUMP_H #define LLVM_TOOLS_LLVM_OBJDUMP_XCOFFDUMP_H +#include "llvm/MC/MCSubtargetInfo.h" #include "llvm/Object/XCOFFObjectFile.h" +#include "llvm/Support/FormattedStream.h" namespace llvm { @@ -28,6 +30,10 @@ Error getXCOFFRelocationValueString(const object::XCOFFObjectFile *Obj, const object::RelocationRef &RelRef, llvm::SmallVectorImpl &Result); + +void dumpTracebackTable(ArrayRef Bytes, uint64_t Address, + formatted_raw_ostream &OS, uint64_t End, + const MCSubtargetInfo &STI); } // 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,15 @@ #include "llvm-objdump.h" #include "llvm/Demangle/Demangle.h" +#include "llvm/MC/MCInstPrinter.h" +#include "llvm/Support/Endian.h" + +#include 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 +92,290 @@ return Result; } + +std::string getExtendedTBTableFlagString(ExtendedTBTableFlag Flag) { + std::string Res; + + if (Flag & ExtendedTBTableFlag::TB_LONGTBTABLE2) + Res += " TB_LONGTBTABLE2"; + if (Flag & ExtendedTBTableFlag::TB_OS2) + Res += " TB_OS2"; + if (Flag & ExtendedTBTableFlag::TB_SSP_CANARY) + Res += " TB_SSP_CANARY"; + if (Flag & ExtendedTBTableFlag::TB_RESERVED) + Res += " TB_RESERVED"; + + if (Flag & ExtendedTBTableFlag::TB_OS1) + Res += " TB_OS1"; + + return Res; +} + +std::string AddOffsetToValueInString(const std::string &StrMsg, + unsigned Offset) { + std::string Res; + size_t Pos = 0, PrePos = 0; + Pos = StrMsg.find("0x", Pos); + while (Pos != std::string::npos) { + Pos += 2; + Res += std::string(StrMsg, PrePos, Pos - PrePos); + PrePos = Pos; + while (Pos < StrMsg.size() && isdigit(StrMsg[Pos])) + Pos++; + std::string NumString = StrMsg.substr(PrePos, Pos - PrePos); + int num = std::stoi(NumString, 0, 16); + std::stringstream stream; + stream << std::hex << num + Offset; + Res += stream.str(); + PrePos = Pos; + Pos = StrMsg.find("0x", Pos); + } + + if (PrePos < StrMsg.size()) + Res += std::string(StrMsg, PrePos); + return Res; +} + +#define PRINTBOOL(Prefix, Obj, Field) \ + OS << Prefix << " " << ((Obj.Field()) ? "+" : "-") << #Field + +#define PRINTGET(Prefix, Obj, Field) \ + OS << Prefix << " " << #Field << " = " << (unsigned)(Obj.get##Field()) + +#define SPLIT \ + OS << "\n"; \ + OS.indent(TabStop) + +#define PRINTOPTIONAL(Field) \ + if (TbTable.get##Field()) { \ + OS << "\n"; \ + printRawData(Bytes.slice(Index, 4), Address + Index, OS, STI); \ + Index += 4; \ + OS << "\t# " << #Field << " = " << TbTable.get##Field().getValue(); \ + } + +void objdump::dumpTracebackTable(ArrayRef Bytes, uint64_t Address, + formatted_raw_ostream &OS, uint64_t End, + const MCSubtargetInfo &STI) { + uint64_t Index = 0; + unsigned TabStop = getInstStartColumn(STI) - 1; + // Print out backtrace table boundary. + printRawData(Bytes.slice(Index, 4), Address, OS, STI); + OS << "\t# Traceback table begin\n"; + Index += 4; + + uint64_t Size = End - Address; + + Expected TTOrErr = + XCOFFTracebackTable::create(Bytes.data() + Index, Size); + + if (!TTOrErr) { + + outs().flush(); + WithColor::warning(errs(), "") + << " Parse traceback table failure: " + << AddOffsetToValueInString(toString(TTOrErr.takeError()), Address) + << "\n\tThe raw data of traceback table as : \n"; + + uint64_t LastNoZero = Index; + + // The value of Size been changed in function XCOFFTracebackTable::create() + Size = End - Address; + + for (uint64_t I = Index; I < Size; I = I + 4) { + if (support::endian::read32be(Bytes.slice(I, 4).data()) != 0) + LastNoZero = (I + 4) > Size ? Size : (I + 4); + } + + if (Size - LastNoZero <= 4) + LastNoZero = Size; + + formatted_raw_ostream FOS(errs()); + while (Index < LastNoZero) { + printRawData(Bytes.slice(Index, 4), Address + Index, FOS, STI); + Index += 4; + errs() << "\n"; + } + + // Print out all remaining zero as ... + if (Size - LastNoZero >= 8) + errs() << "\t\t...\n"; + + return; + } + + XCOFFTracebackTable TbTable = *TTOrErr; + + auto PrintOutBytes = [&](uint64_t n) { + printRawData(Bytes.slice(Index, n), Address + Index, OS, STI); + Index += n; + }; + + // Print out the first byte of 8 bytes of mandatory fields. + PrintOutBytes(1); + OS << "\t# Version = " << static_cast(TbTable.getVersion()) << "\n"; + + // Print out the second byte of 8 bytes of mandatory fields. + PrintOutBytes(1); + unsigned LangId = TbTable.getLanguageID(); + OS << "\t# Language = " << getTracebackTableLanguage(LangId) << "\n"; + // Print out the third byte of 8 bytes of mandatory fields. + PrintOutBytes(1); + PRINTBOOL("\t#", TbTable, isGlobalLinkage); + PRINTBOOL(",", TbTable, isOutOfLineEpilogOrPrologue); + SPLIT; + PRINTBOOL("\t ", TbTable, hasTraceBackTableOffset); + PRINTBOOL(",", TbTable, isInternalProcedure); + SPLIT; + PRINTBOOL("\t ", TbTable, hasControlledStorage); + PRINTBOOL(",", TbTable, isTOCless); + SPLIT; + PRINTBOOL("\t ", TbTable, isFloatingPointPresent); + SPLIT; + PRINTBOOL("\t ", TbTable, isFloatingPointOperationLogOrAbortEnabled); + OS << "\n"; + + // Print out the 4th byte of 8 bytes of mandatory fields. + PrintOutBytes(1); + PRINTBOOL("\t#", TbTable, isInterruptHandler); + PRINTBOOL(",", TbTable, isFuncNamePresent); + PRINTBOOL(",", TbTable, isAllocaUsed); + SPLIT; + PRINTGET("\t ", TbTable, OnConditionDirective); + PRINTBOOL(",", TbTable, isCRSaved); + PRINTBOOL(",", TbTable, isLRSaved); + OS << "\n"; + + // Print out the 5th byte of 8 bytes of mandatory fields. + PrintOutBytes(1); + PRINTBOOL("\t#", TbTable, isBackChainStored); + PRINTBOOL(",", TbTable, isFixup); + PRINTGET(",", TbTable, NumOfFPRsSaved); + OS << "\n"; + + // Print out the 6th byte of 8 bytes of mandatory fields. + PrintOutBytes(1); + PRINTBOOL("\t#", TbTable, hasExtensionTable); + PRINTBOOL(",", TbTable, hasVectorInfo); + PRINTGET(",", TbTable, NumOfGPRsSaved); + OS << "\n"; + + // Print out the 7th byte of 8 bytes of mandatory fields. + PrintOutBytes(1); + PRINTGET("\t#", TbTable, NumberOfFixedParms); + OS << "\n"; + + // Print out the 8th byte of 8 bytes of mandatory fields. + PrintOutBytes(1); + PRINTGET("\t#", TbTable, NumberOfFPParms); + PRINTBOOL(",", TbTable, hasParmsOnStack); + + PRINTOPTIONAL(ParmsType); + PRINTOPTIONAL(TraceBackTableOffset); + PRINTOPTIONAL(HandlerMask); + PRINTOPTIONAL(NumOfCtlAnchors); + + if (TbTable.getControlledStorageInfoDisp()) { + SmallVector Disp = + TbTable.getControlledStorageInfoDisp().getValue(); + for (unsigned I = 0; I < Disp.size(); ++I) { + OS << "\n"; + PrintOutBytes(4); + OS << "\t ControlledStorageInfoDisp[" << I << "] = " << Disp[I]; + } + } + + // Print out function name length and function name if there is. + if (TbTable.isFuncNamePresent()) { + uint16_t FunctionNameLen = TbTable.getFunctionName().getValue().size(); + + assert(FunctionNameLen > 0 && + "The length of function name must large than zero."); + + OS << "\n"; + PrintOutBytes(2); + OS << "\t# FunctionNameLen = " << FunctionNameLen; + + uint16_t RemainingBytes = FunctionNameLen; + bool HasPrinted = false; + while (RemainingBytes > 0) { + OS << "\n"; + uint16_t PrintLen = RemainingBytes >= 4 ? 4 : RemainingBytes; + printRawData(Bytes.slice(Index, PrintLen), Address + Index, OS, STI); + Index += PrintLen; + RemainingBytes -= PrintLen; + + if (!HasPrinted) { + OS << "\t# FunctionName = " << TbTable.getFunctionName().getValue(); + HasPrinted = true; + } + } + } + + if (TbTable.isAllocaUsed()) { + OS << "\n"; + PrintOutBytes(1); + OS << "\t# AllocaRegister = " + << static_cast(TbTable.getAllocaRegister().getValue()); + } + + if (TbTable.getVectorExt()) { + OS << "\n"; + TBVectorExt VecExt = TbTable.getVectorExt().getValue(); + // Print first byte of VectorExt. + PrintOutBytes(1); + PRINTGET("\t#", VecExt, NumberOfVRSaved); + PRINTBOOL(",", VecExt, isVRSavedOnStack); + PRINTBOOL(",", VecExt, hasVarArgs); + OS << "\n"; + + // Print the second byte of VectorExt. + PrintOutBytes(1); + PRINTGET("\t#", VecExt, NumberOfVectorParms); + PRINTBOOL(",", VecExt, hasVMXInstruction); + OS << "\n"; + + PrintOutBytes(4); + OS << "\t# VectorParmsInfoString = " << VecExt.getVectorParmsInfoString(); + } + + if (TbTable.getExtensionTable()) { + OS << "\n"; + PrintOutBytes(1); + ExtendedTBTableFlag Flag = + (ExtendedTBTableFlag)TbTable.getExtensionTable().getValue(); + OS << "\t# ExtensionTable =" << getExtendedTBTableFlagString(Flag); + } + + if (End == Address + Index) { + OS << "\n"; + return; + } + + // Print out all padding. + OS << "\n"; + Size = End - Address; + uint64_t Remaining = Size - Index; + if (Remaining >= 8) { + while (Remaining > 0 && Bytes[Size - Remaining] == 0) + --Remaining; + if (Remaining == 0) { + OS << "\t\t...\n"; + return; + } + } + + uint16_t AlignmentLen = 4 - Index % 4; + printRawData(Bytes.slice(Index, AlignmentLen), Address + Index, OS, STI); + OS << "\t# Padding\n"; + Index += AlignmentLen; + while (Index < End - Address) { + printRawData(Bytes.slice(Index, 4), Address + Index, OS, STI); + OS << "\t# Padding\n"; + Index += 4; + } +} +#undef PRINTBOOL +#undef PRINTGET +#undef SPLIT +#undef PRINTOPTIONAL 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 @@ -11,10 +11,12 @@ #include "llvm/ADT/StringSet.h" #include "llvm/DebugInfo/DIContext.h" #include "llvm/MC/MCDisassembler/MCDisassembler.h" +#include "llvm/MC/MCSubtargetInfo.h" #include "llvm/Object/Archive.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/DataTypes.h" +#include "llvm/Support/FormattedStream.h" namespace llvm { class StringRef; @@ -46,6 +48,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; @@ -148,4 +151,9 @@ } // namespace objdump } // end namespace llvm +using namespace llvm; +unsigned getInstStartColumn(const MCSubtargetInfo &STI); +void printRawData(llvm::ArrayRef Bytes, uint64_t Address, + llvm::formatted_raw_ostream &OS, + llvm::MCSubtargetInfo const &STI); #endif 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 @@ -43,7 +43,6 @@ #include "llvm/MC/MCInstrInfo.h" #include "llvm/MC/MCObjectFileInfo.h" #include "llvm/MC/MCRegisterInfo.h" -#include "llvm/MC/MCSubtargetInfo.h" #include "llvm/MC/MCTargetOptions.h" #include "llvm/Object/Archive.h" #include "llvm/Object/COFF.h" @@ -142,6 +141,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. " @@ -582,14 +587,31 @@ return false; } -namespace { - /// Get the column at which we want to start printing the instruction /// disassembly, taking into account anything which appears to the left of it. unsigned getInstStartColumn(const MCSubtargetInfo &STI) { return NoShowRawInsn ? 16 : STI.getTargetTriple().isX86() ? 40 : 24; } +void printRawData(ArrayRef Bytes, uint64_t Address, + formatted_raw_ostream &OS, MCSubtargetInfo const &STI) { + 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 = getInstStartColumn(STI); + unsigned Column = OS.tell() - Start; + OS.indent(Column < TabStop - 1 ? TabStop - 1 - Column : 7 - Column % 8); +} + +namespace { + /// Stores a single expression representing the location of a source-level /// variable, along with the PC range for which that expression is valid. struct LiveVariable { @@ -1137,19 +1159,7 @@ SP->printSourceLine(OS, Address, ObjectFilename, LVP); LVP.printBetweenInsts(OS, false); - size_t Start = OS.tell(); - if (!NoLeadingAddr) - OS << format("%8" PRIx64 ":", Address.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 = getInstStartColumn(STI); - unsigned Column = OS.tell() - Start; - OS.indent(Column < TabStop - 1 ? TabStop - 1 - Column : 7 - Column % 8); + printRawData(Bytes, Address.Address, OS, STI); if (MI) { // See MCInstPrinter::printInst. On targets where a PC relative immediate @@ -1570,7 +1580,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(); @@ -1588,7 +1598,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); @@ -1933,6 +1943,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); + formatted_raw_ostream FOS(outs()); std::unordered_map AllLabels; @@ -1980,6 +1996,15 @@ } } + if (DumpTracebackTableForXCOFFFunction && + doesXCOFFTracebackTableBegin(Bytes.slice(Index, 4))) { + dumpTracebackTable(Bytes.slice(Index), + SectionAddr + Index + VMAAdjustment, FOS, End, + *STI); + Index = End; + continue; + } + // Print local label if there's any. auto Iter = AllLabels.find(SectionAddr + Index); if (Iter != AllLabels.end())