diff options
Diffstat (limited to 'llvm/tools/llvm-objdump')
-rw-r--r-- | llvm/tools/llvm-objdump/ObjdumpOpts.td | 6 | ||||
-rw-r--r-- | llvm/tools/llvm-objdump/SourcePrinter.cpp | 4 | ||||
-rw-r--r-- | llvm/tools/llvm-objdump/XCOFFDump.cpp | 304 | ||||
-rw-r--r-- | llvm/tools/llvm-objdump/XCOFFDump.h | 7 | ||||
-rw-r--r-- | llvm/tools/llvm-objdump/llvm-objdump.cpp | 73 | ||||
-rw-r--r-- | llvm/tools/llvm-objdump/llvm-objdump.h | 7 |
6 files changed, 370 insertions, 31 deletions
diff --git a/llvm/tools/llvm-objdump/ObjdumpOpts.td b/llvm/tools/llvm-objdump/ObjdumpOpts.td index c6627c7..e3e7476 100644 --- a/llvm/tools/llvm-objdump/ObjdumpOpts.td +++ b/llvm/tools/llvm-objdump/ObjdumpOpts.td @@ -65,7 +65,11 @@ def : Flag<["-"], "D">, Alias<disassemble_all>, def symbol_description : Flag<["--"], "symbol-description">, HelpText<"Add symbol description for disassembly. This " - "option is for XCOFF files only.">; + "option is for XCOFF files only">; + +def traceback_table : Flag<["--"], "traceback-table">, + HelpText<"Decode traceback table in disassembly. Implies --disassemble. " + "This option is for XCOFF files only">; def disassemble_symbols_EQ : Joined<["--"], "disassemble-symbols=">, HelpText<"List of symbols to disassemble. " diff --git a/llvm/tools/llvm-objdump/SourcePrinter.cpp b/llvm/tools/llvm-objdump/SourcePrinter.cpp index 6736cbc..04c7676 100644 --- a/llvm/tools/llvm-objdump/SourcePrinter.cpp +++ b/llvm/tools/llvm-objdump/SourcePrinter.cpp @@ -26,10 +26,6 @@ namespace llvm { namespace objdump { -unsigned getInstStartColumn(const MCSubtargetInfo &STI) { - return !ShowRawInsn ? 16 : STI.getTargetTriple().isX86() ? 40 : 24; -} - bool LiveVariable::liveAtAddress(object::SectionedAddress Addr) { if (LocExpr.Range == std::nullopt) return false; diff --git a/llvm/tools/llvm-objdump/XCOFFDump.cpp b/llvm/tools/llvm-objdump/XCOFFDump.cpp index 4849b20..91891e3 100644 --- a/llvm/tools/llvm-objdump/XCOFFDump.cpp +++ b/llvm/tools/llvm-objdump/XCOFFDump.cpp @@ -15,9 +15,17 @@ #include "llvm-objdump.h" #include "llvm/Demangle/Demangle.h" +#include "llvm/MC/MCInstPrinter.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/FormattedStream.h" +#include <algorithm> using namespace llvm; using namespace llvm::object; +using namespace llvm::XCOFF; +using namespace llvm::support; Error objdump::getXCOFFRelocationValueString(const XCOFFObjectFile &Obj, const RelocationRef &Rel, @@ -107,3 +115,299 @@ std::string objdump::getXCOFFSymbolDescription(const SymbolInfoTy &SymbolInfo, return Result; } + +#define PRINTBOOL(Prefix, Obj, Field) \ + OS << Prefix << " " << ((Obj.Field()) ? "+" : "-") << #Field + +#define PRINTGET(Prefix, Obj, Field) \ + OS << Prefix << " " << #Field << " = " \ + << static_cast<unsigned>(Obj.get##Field()) + +#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(); \ + } + +void objdump::dumpTracebackTable(ArrayRef<uint8_t> Bytes, uint64_t Address, + formatted_raw_ostream &OS, uint64_t End, + const MCSubtargetInfo &STI, + const XCOFFObjectFile *Obj) { + uint64_t Index = 0; + unsigned TabStop = getInstStartColumn(STI) - 1; + // Print traceback table boundary. + printRawData(Bytes.slice(Index, 4), Address, OS, STI); + OS << "\t# Traceback table start\n"; + Index += 4; + + uint64_t Size = End - Address; + bool Is64Bit = Obj->is64Bit(); + + // XCOFFTracebackTable::create modifies the size parameter, so ensure Size + // isn't changed. + uint64_t SizeCopy = End - Address; + Expected<XCOFFTracebackTable> TTOrErr = + XCOFFTracebackTable::create(Bytes.data() + Index, SizeCopy, Is64Bit); + + if (!TTOrErr) { + std::string WarningMsgStr; + raw_string_ostream WarningStream(WarningMsgStr); + WarningStream << "failure parsing traceback table with address: 0x" + << utohexstr(Address) + "\n>>> " + << toString(TTOrErr.takeError()) + << "\n>>> Raw traceback table data is:\n"; + + uint64_t LastNonZero = Index; + for (uint64_t I = Index; I < Size; I += 4) + if (support::endian::read32be(Bytes.slice(I, 4).data()) != 0) + LastNonZero = I + 4 > Size ? Size : I + 4; + + if (Size - LastNonZero <= 4) + LastNonZero = Size; + + formatted_raw_ostream FOS(WarningStream); + while (Index < LastNonZero) { + printRawData(Bytes.slice(Index, 4), Address + Index, FOS, STI); + Index += 4; + WarningStream << '\n'; + } + + // Print all remaining zeroes as ... + if (Size - LastNonZero >= 8) + WarningStream << "\t\t...\n"; + + reportWarning(WarningMsgStr, Obj->getFileName()); + return; + } + + auto PrintBytes = [&](uint64_t N) { + printRawData(Bytes.slice(Index, N), Address + Index, OS, STI); + Index += N; + }; + + XCOFFTracebackTable TbTable = *TTOrErr; + // Print the first of the 8 bytes of mandatory fields. + PrintBytes(1); + OS << format("\t# Version = %i", TbTable.getVersion()) << '\n'; + + // Print the second of the 8 bytes of mandatory fields. + PrintBytes(1); + TracebackTable::LanguageID LangId = + static_cast<TracebackTable::LanguageID>(TbTable.getLanguageID()); + OS << "\t# Language = " << getNameForTracebackTableLanguageId(LangId) << '\n'; + + auto Split = [&]() { + OS << '\n'; + OS.indent(TabStop); + }; + + // Print the third of the 8 bytes of mandatory fields. + PrintBytes(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 the 4th of the 8 bytes of mandatory fields. + PrintBytes(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 the 5th of the 8 bytes of mandatory fields. + PrintBytes(1); + PRINTBOOL("\t#", TbTable, isBackChainStored); + PRINTBOOL(",", TbTable, isFixup); + PRINTGET(",", TbTable, NumOfFPRsSaved); + OS << '\n'; + + // Print the 6th of the 8 bytes of mandatory fields. + PrintBytes(1); + PRINTBOOL("\t#", TbTable, hasExtensionTable); + PRINTBOOL(",", TbTable, hasVectorInfo); + PRINTGET(",", TbTable, NumOfGPRsSaved); + OS << '\n'; + + // Print the 7th of the 8 bytes of mandatory fields. + PrintBytes(1); + PRINTGET("\t#", TbTable, NumberOfFixedParms); + OS << '\n'; + + // Print the 8th of the 8 bytes of mandatory fields. + PrintBytes(1); + PRINTGET("\t#", TbTable, NumberOfFPParms); + PRINTBOOL(",", TbTable, hasParmsOnStack); + + PRINTOPTIONAL(ParmsType); + PRINTOPTIONAL(TraceBackTableOffset); + PRINTOPTIONAL(HandlerMask); + PRINTOPTIONAL(NumOfCtlAnchors); + + if (TbTable.getControlledStorageInfoDisp()) { + SmallVector<uint32_t, 8> Disp = *TbTable.getControlledStorageInfoDisp(); + for (unsigned I = 0; I < Disp.size(); ++I) { + OS << '\n'; + PrintBytes(4); + OS << "\t" << (I ? " " : "#") << " ControlledStorageInfoDisp[" << I + << "] = " << Disp[I]; + } + } + + // If there is a name, print the function name and function name length. + if (TbTable.isFuncNamePresent()) { + uint16_t FunctionNameLen = TbTable.getFunctionName()->size(); + if (FunctionNameLen == 0) { + OS << '\n'; + reportWarning( + "the length of the function name must be greater than zero if the " + "isFuncNamePresent bit is set in the traceback table", + Obj->getFileName()); + return; + } + + OS << '\n'; + PrintBytes(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(); + HasPrinted = true; + } + } + } + + if (TbTable.isAllocaUsed()) { + OS << '\n'; + PrintBytes(1); + OS << format("\t# AllocaRegister = %u", *TbTable.getAllocaRegister()); + } + + if (TbTable.getVectorExt()) { + OS << '\n'; + TBVectorExt VecExt = *TbTable.getVectorExt(); + // Print first byte of VectorExt. + PrintBytes(1); + PRINTGET("\t#", VecExt, NumberOfVRSaved); + PRINTBOOL(",", VecExt, isVRSavedOnStack); + PRINTBOOL(",", VecExt, hasVarArgs); + OS << '\n'; + + // Print the second byte of VectorExt. + PrintBytes(1); + PRINTGET("\t#", VecExt, NumberOfVectorParms); + PRINTBOOL(",", VecExt, hasVMXInstruction); + OS << '\n'; + + PrintBytes(4); + OS << "\t# VectorParmsInfoString = " << VecExt.getVectorParmsInfo(); + + // There are two bytes of padding after vector info. + OS << '\n'; + PrintBytes(2); + OS << "\t# Padding"; + } + + if (TbTable.getExtensionTable()) { + OS << '\n'; + PrintBytes(1); + ExtendedTBTableFlag Flag = + static_cast<ExtendedTBTableFlag>(*TbTable.getExtensionTable()); + OS << "\t# ExtensionTable = " << getExtendedTBTableFlagString(Flag); + } + + if (TbTable.getEhInfoDisp()) { + // There are 4 bytes alignment before eh info displacement. + if (Index % 4) { + OS << '\n'; + PrintBytes(4 - Index % 4); + OS << "\t# Alignment padding for eh info displacement"; + } + OS << '\n'; + // The size of the displacement (address) is 4 bytes in 32-bit object files, + // and 8 bytes in 64-bit object files. + PrintBytes(4); + OS << "\t# EH info displacement"; + if (Is64Bit) { + OS << '\n'; + PrintBytes(4); + } + } + + OS << '\n'; + if (End == Address + Index) + return; + + Size = End - Address; + + const char *LineSuffix = "\t# Padding\n"; + auto IsWordZero = [&](uint64_t WordPos) { + if (WordPos >= Size) + return false; + uint64_t LineLength = std::min(4 - WordPos % 4, Size - WordPos); + return std::all_of(Bytes.begin() + WordPos, + Bytes.begin() + WordPos + LineLength, + [](uint8_t Byte) { return Byte == 0; }); + }; + + bool AreWordsZero[] = {IsWordZero(Index), IsWordZero(alignTo(Index, 4) + 4), + IsWordZero(alignTo(Index, 4) + 8)}; + bool ShouldPrintLine = true; + while (true) { + // Determine the length of the line (4, except for the first line, which + // will be just enough to align to the word boundary, and the last line, + // which will be the remainder of the data). + uint64_t LineLength = std::min(4 - Index % 4, Size - Index); + if (ShouldPrintLine) { + // Print the line. + printRawData(Bytes.slice(Index, LineLength), Address + Index, OS, STI); + OS << LineSuffix; + LineSuffix = "\n"; + } + + Index += LineLength; + if (Index == Size) + return; + + // For 3 or more consecutive lines of zeros, skip all but the first one, and + // replace them with "...". + if (AreWordsZero[0] && AreWordsZero[1] && AreWordsZero[2]) { + if (ShouldPrintLine) + OS << std::string(8, ' ') << "...\n"; + ShouldPrintLine = false; + } else if (!AreWordsZero[1]) { + // We have reached the end of a skipped block of zeros. + ShouldPrintLine = true; + } + AreWordsZero[0] = AreWordsZero[1]; + AreWordsZero[1] = AreWordsZero[2]; + AreWordsZero[2] = IsWordZero(Index + 8); + } +} +#undef PRINTBOOL +#undef PRINTGET +#undef PRINTOPTIONAL diff --git a/llvm/tools/llvm-objdump/XCOFFDump.h b/llvm/tools/llvm-objdump/XCOFFDump.h index 35d1c0f..cf5b19f9 100644 --- a/llvm/tools/llvm-objdump/XCOFFDump.h +++ b/llvm/tools/llvm-objdump/XCOFFDump.h @@ -13,6 +13,8 @@ namespace llvm { +class formatted_raw_ostream; +class MCSubtargetInfo; struct SymbolInfoTy; namespace objdump { @@ -32,6 +34,11 @@ std::string getXCOFFSymbolDescription(const SymbolInfoTy &SymbolInfo, Error getXCOFFRelocationValueString(const object::XCOFFObjectFile &Obj, const object::RelocationRef &RelRef, llvm::SmallVectorImpl<char> &Result); + +void dumpTracebackTable(ArrayRef<uint8_t> Bytes, uint64_t Address, + formatted_raw_ostream &OS, uint64_t End, + const MCSubtargetInfo &STI, + const object::XCOFFObjectFile *Obj); } // namespace objdump } // namespace llvm #endif diff --git a/llvm/tools/llvm-objdump/llvm-objdump.cpp b/llvm/tools/llvm-objdump/llvm-objdump.cpp index 7b6edb3..d77b000 100644 --- a/llvm/tools/llvm-objdump/llvm-objdump.cpp +++ b/llvm/tools/llvm-objdump/llvm-objdump.cpp @@ -48,7 +48,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/MC/TargetRegistry.h" #include "llvm/Object/Archive.h" @@ -196,6 +195,7 @@ bool objdump::Demangle; bool objdump::Disassemble; bool objdump::DisassembleAll; bool objdump::SymbolDescription; +bool objdump::TracebackTable; static std::vector<std::string> DisassembleSymbols; static bool DisassembleZeroes; static std::vector<std::string> DisassemblerOptions; @@ -442,14 +442,36 @@ static bool getHidden(RelocationRef RelRef) { 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) { +unsigned objdump::getInstStartColumn(const MCSubtargetInfo &STI) { return !ShowRawInsn ? 16 : STI.getTargetTriple().isX86() ? 40 : 24; } +static void AlignToInstStartColumn(size_t Start, const MCSubtargetInfo &STI, + raw_ostream &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); +} + +void objdump::printRawData(ArrayRef<uint8_t> Bytes, uint64_t Address, + formatted_raw_ostream &OS, + MCSubtargetInfo const &STI) { + size_t Start = OS.tell(); + if (LeadingAddr) + OS << format("%8" PRIx64 ":", Address); + if (ShowRawInsn) { + OS << ' '; + dumpBytes(Bytes, OS); + } + AlignToInstStartColumn(Start, STI, OS); +} + +namespace { + static bool isAArch64Elf(const ObjectFile &Obj) { const auto *Elf = dyn_cast<ELFObjectFileBase>(&Obj); return Elf && Elf->getEMachine() == ELF::EM_AARCH64; @@ -489,15 +511,6 @@ static void printRelocation(formatted_raw_ostream &OS, StringRef FileName, OS << Name << "\t" << Val; } -static void AlignToInstStartColumn(size_t Start, const MCSubtargetInfo &STI, - raw_ostream &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); -} - class PrettyPrinter { public: virtual ~PrettyPrinter() = default; @@ -511,15 +524,7 @@ public: SP->printSourceLine(OS, Address, ObjectFilename, LVP); LVP.printBetweenInsts(OS, false); - size_t Start = OS.tell(); - if (LeadingAddr) - OS << format("%8" PRIx64 ":", Address.Address); - if (ShowRawInsn) { - OS << ' '; - dumpBytes(Bytes, OS); - } - - AlignToInstStartColumn(Start, STI, OS); + printRawData(Bytes, Address.Address, OS, STI); if (MI) { // See MCInstPrinter::printInst. On targets where a PC relative immediate @@ -806,7 +811,7 @@ PrettyPrinter &selectPrettyPrinter(Triple const &Triple) { return AArch64PrettyPrinterInst; } } -} +} // namespace static uint8_t getElfSymbolType(const ObjectFile &Obj, const SymbolRef &Sym) { assert(Obj.isELF()); @@ -1087,7 +1092,7 @@ SymbolInfoTy objdump::createSymbolInfo(const ObjectFile &Obj, 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<XCOFFObjectFile>(Obj); DataRefImpl SymbolDRI = Symbol.getRawDataRefImpl(); @@ -1108,7 +1113,7 @@ SymbolInfoTy objdump::createSymbolInfo(const ObjectFile &Obj, 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, std::nullopt, std::nullopt, false); else return SymbolInfoTy(Addr, Name, Type); @@ -1735,6 +1740,11 @@ static void disassembleObject(const Target *TheTarget, ObjectFile &Obj, } bool DumpARMELFData = false; + bool DumpTracebackTableForXCOFFFunction = + Obj.isXCOFF() && Section.isText() && TracebackTable && + Symbols[SI - 1].XCOFFSymInfo.StorageMappingClass && + (*Symbols[SI - 1].XCOFFSymInfo.StorageMappingClass == XCOFF::XMC_PR); + formatted_raw_ostream FOS(outs()); std::unordered_map<uint64_t, std::string> AllLabels; @@ -1787,6 +1797,16 @@ static void disassembleObject(const Target *TheTarget, ObjectFile &Obj, } } + if (DumpTracebackTableForXCOFFFunction && + doesXCOFFTracebackTableBegin(Bytes.slice(Index, 4))) { + dumpTracebackTable(Bytes.slice(Index), + SectionAddr + Index + VMAAdjustment, FOS, + SectionAddr + End + VMAAdjustment, *STI, + cast<XCOFFObjectFile>(&Obj)); + Index = End; + continue; + } + // Print local label if there's any. auto Iter1 = BBAddrMapLabels.find(SectionAddr + Index); if (Iter1 != BBAddrMapLabels.end()) { @@ -3018,6 +3038,7 @@ static void parseObjdumpOptions(const llvm::opt::InputArgList &InputArgs) { Disassemble = InputArgs.hasArg(OBJDUMP_disassemble); DisassembleAll = InputArgs.hasArg(OBJDUMP_disassemble_all); SymbolDescription = InputArgs.hasArg(OBJDUMP_symbol_description); + TracebackTable = InputArgs.hasArg(OBJDUMP_traceback_table); DisassembleSymbols = commaSeparatedValues(InputArgs, OBJDUMP_disassemble_symbols_EQ); DisassembleZeroes = InputArgs.hasArg(OBJDUMP_disassemble_zeroes); @@ -3218,7 +3239,7 @@ int main(int argc, char **argv) { ArchiveHeaders = FileHeaders = PrivateHeaders = Relocations = SectionHeaders = SymbolTable = true; - if (DisassembleAll || PrintSource || PrintLines || + if (DisassembleAll || PrintSource || PrintLines || TracebackTable || !DisassembleSymbols.empty()) Disassemble = true; diff --git a/llvm/tools/llvm-objdump/llvm-objdump.h b/llvm/tools/llvm-objdump/llvm-objdump.h index efb4451..51dd3aa 100644 --- a/llvm/tools/llvm-objdump/llvm-objdump.h +++ b/llvm/tools/llvm-objdump/llvm-objdump.h @@ -12,9 +12,11 @@ #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/Compiler.h" #include "llvm/Support/DataTypes.h" +#include "llvm/Support/FormattedStream.h" namespace llvm { class StringRef; @@ -55,6 +57,7 @@ extern bool SectionHeaders; extern bool SectionContents; extern bool ShowRawInsn; extern bool SymbolDescription; +extern bool TracebackTable; extern bool SymbolTable; extern std::string TripleName; extern bool UnwindInfo; @@ -156,6 +159,10 @@ std::string getFileNameForError(const object::Archive::Child &C, unsigned Index); SymbolInfoTy createSymbolInfo(const object::ObjectFile &Obj, const object::SymbolRef &Symbol); +unsigned getInstStartColumn(const MCSubtargetInfo &STI); +void printRawData(llvm::ArrayRef<uint8_t> Bytes, uint64_t Address, + llvm::formatted_raw_ostream &OS, + llvm::MCSubtargetInfo const &STI); } // namespace objdump } // end namespace llvm |