From 8c93097c4c5e6dddc8c239295a1b42217b082ad3 Mon Sep 17 00:00:00 2001 From: Benjamin Kramer Date: Wed, 21 Sep 2011 01:13:19 +0000 Subject: [PATCH] llvm-objdump: Output line info next to the disassembly if available. MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit MachO-only at the moment, sorry. Usage: $ llvm-objdump -d -m -g -dsym=a.out.dSYM/Contents/Resources/DWARF/a.out a.out _main: 100000e90: 55 pushq %rbp ## test.c:11:3 … git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@140224 91177308-0d34-0410-b5e6-96231b3b80d8 --- tools/llvm-objdump/CMakeLists.txt | 1 + tools/llvm-objdump/MachODump.cpp | 205 ++++++++++++++++++++++-------- tools/llvm-objdump/Makefile | 3 +- 3 files changed, 156 insertions(+), 53 deletions(-) diff --git a/tools/llvm-objdump/CMakeLists.txt b/tools/llvm-objdump/CMakeLists.txt index db788646cfe..f3b2e1fe419 100644 --- a/tools/llvm-objdump/CMakeLists.txt +++ b/tools/llvm-objdump/CMakeLists.txt @@ -1,5 +1,6 @@ set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} + DebugInfo MC MCParser MCDisassembler diff --git a/tools/llvm-objdump/MachODump.cpp b/tools/llvm-objdump/MachODump.cpp index a0fff215ea8..7e3bb20d3e1 100644 --- a/tools/llvm-objdump/MachODump.cpp +++ b/tools/llvm-objdump/MachODump.cpp @@ -18,6 +18,7 @@ #include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/Triple.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/DebugInfo/DIContext.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCDisassembler.h" #include "llvm/MC/MCInst.h" @@ -44,6 +45,12 @@ static cl::opt CFG("cfg", cl::desc("Create a CFG for every symbol in the object file and" "write it to a graphviz file (MachO-only)")); +static cl::opt + UseDbg("g", cl::desc("Print line information from debug info if available")); + +static cl::opt + DSYMFile("dsym", cl::desc("Use .dSYM file for debug info")); + static const Target *GetTarget(const MachOObject *MachOObj) { // Figure out the target triple. llvm::Triple TT("unknown-unknown-unknown"); @@ -94,7 +101,6 @@ struct Symbol { bool operator<(const Symbol &RHS) const { return Value < RHS.Value; } }; - template static Section copySection(const T &Sect) { Section S; @@ -205,6 +211,67 @@ static void emitDOTFile(const char *FileName, const MCFunction &f, Out << "}\n"; } +static void getSectionsAndSymbols(const macho::Header &Header, + MachOObject *MachOObj, + InMemoryStruct *SymtabLC, + std::vector
&Sections, + std::vector &Symbols, + SmallVectorImpl &FoundFns) { + // Make a list of all symbols in the object file. + for (unsigned i = 0; i != Header.NumLoadCommands; ++i) { + const MachOObject::LoadCommandInfo &LCI = MachOObj->getLoadCommandInfo(i); + if (LCI.Command.Type == macho::LCT_Segment) { + InMemoryStruct SegmentLC; + MachOObj->ReadSegmentLoadCommand(LCI, SegmentLC); + + // Store the sections in this segment. + for (unsigned SectNum = 0; SectNum != SegmentLC->NumSections; ++SectNum) { + InMemoryStruct Sect; + MachOObj->ReadSection(LCI, SectNum, Sect); + Sections.push_back(copySection(Sect)); + + // Store the symbols in this section. + if (SymtabLC) { + for (unsigned i = 0; i != (*SymtabLC)->NumSymbolTableEntries; ++i) { + InMemoryStruct STE; + MachOObj->ReadSymbolTableEntry((*SymtabLC)->SymbolTableOffset, i, + STE); + Symbols.push_back(copySymbol(STE)); + } + } + } + } else if (LCI.Command.Type == macho::LCT_Segment64) { + InMemoryStruct Segment64LC; + MachOObj->ReadSegment64LoadCommand(LCI, Segment64LC); + + // Store the sections in this segment. + for (unsigned SectNum = 0; SectNum != Segment64LC->NumSections; + ++SectNum) { + InMemoryStruct Sect64; + MachOObj->ReadSection64(LCI, SectNum, Sect64); + Sections.push_back(copySection(Sect64)); + + // Store the symbols in this section. + if (SymtabLC) { + for (unsigned i = 0; i != (*SymtabLC)->NumSymbolTableEntries; ++i) { + InMemoryStruct STE; + MachOObj->ReadSymbol64TableEntry((*SymtabLC)->SymbolTableOffset, i, + STE); + Symbols.push_back(copySymbol(STE)); + } + } + } + } else if (LCI.Command.Type == macho::LCT_FunctionStarts) { + // We found a function starts segment, parse the addresses for later + // consumption. + InMemoryStruct LLC; + MachOObj->ReadLinkeditDataLoadCommand(LCI, LLC); + + MachOObj->ReadULEB128s(LLC->DataOffset, FoundFns); + } + } +} + void llvm::DisassembleInputMachO(StringRef Filename) { OwningPtr Buff; @@ -260,60 +327,13 @@ void llvm::DisassembleInputMachO(StringRef Filename) { std::vector
Sections; std::vector Symbols; - std::vector UnsortedSymbols; // FIXME: duplication SmallVector FoundFns; - // Make a list of all symbols in the object file. - for (unsigned i = 0; i != Header.NumLoadCommands; ++i) { - const MachOObject::LoadCommandInfo &LCI = MachOObj->getLoadCommandInfo(i); - if (LCI.Command.Type == macho::LCT_Segment) { - InMemoryStruct SegmentLC; - MachOObj->ReadSegmentLoadCommand(LCI, SegmentLC); - - // Store the sections in this segment. - for (unsigned SectNum = 0; SectNum != SegmentLC->NumSections; ++SectNum) { - InMemoryStruct Sect; - MachOObj->ReadSection(LCI, SectNum, Sect); - Sections.push_back(copySection(Sect)); - - // Store the symbols in this section. - for (unsigned i = 0; i != SymtabLC->NumSymbolTableEntries; ++i) { - InMemoryStruct STE; - MachOObj->ReadSymbolTableEntry(SymtabLC->SymbolTableOffset, i, STE); - Symbols.push_back(copySymbol(STE)); - UnsortedSymbols.push_back(Symbols.back()); - } - } - } else if (LCI.Command.Type == macho::LCT_Segment64) { - InMemoryStruct Segment64LC; - MachOObj->ReadSegment64LoadCommand(LCI, Segment64LC); - - // Store the sections in this segment. - for (unsigned SectNum = 0; SectNum != Segment64LC->NumSections; - ++SectNum) { - InMemoryStruct Sect64; - MachOObj->ReadSection64(LCI, SectNum, Sect64); - Sections.push_back(copySection(Sect64)); - - // Store the symbols in this section. - for (unsigned i = 0; i != SymtabLC->NumSymbolTableEntries; ++i) { - InMemoryStruct STE; - MachOObj->ReadSymbol64TableEntry(SymtabLC->SymbolTableOffset, i, STE); - Symbols.push_back(copySymbol(STE)); - UnsortedSymbols.push_back(Symbols.back()); - } - } - } else if (LCI.Command.Type == macho::LCT_FunctionStarts) { - // We found a function starts segment, parse the addresses for later - // consumption. - InMemoryStruct LLC; - MachOObj->ReadLinkeditDataLoadCommand(LCI, LLC); - - MachOObj->ReadULEB128s(LLC->DataOffset, FoundFns); - } - } - + getSectionsAndSymbols(Header, MachOObj.get(), &SymtabLC, Sections, Symbols, + FoundFns); + // Make a copy of the unsorted symbol list. FIXME: duplication + std::vector UnsortedSymbols(Symbols); // Sort the symbols by address, just in case they didn't come in that way. array_pod_sort(Symbols.begin(), Symbols.end()); @@ -323,6 +343,61 @@ void llvm::DisassembleInputMachO(StringRef Filename) { raw_ostream &DebugOut = nulls(); #endif + StringRef DebugAbbrevSection, DebugInfoSection, DebugArangesSection, + DebugLineSection, DebugStrSection; + OwningPtr diContext; + // Try to find debug info and set up the DIContext for it. + if (UseDbg) { + ArrayRef
DebugSections = Sections; + std::vector
DSYMSections; + OwningPtr DSYMObj; + + // A separate DSym file path was specified, parse it as a macho file, + // get the sections and supply it to the section name parsing machinery. + if (!DSYMFile.empty()) { + OwningPtr Buf; + if (error_code ec = MemoryBuffer::getFileOrSTDIN(DSYMFile.c_str(), Buf)) { + errs() << "llvm-objdump: " << Filename << ": " << ec.message() << '\n'; + return; + } + DSYMObj.reset(MachOObject::LoadFromBuffer(Buf.take())); + const macho::Header &Header = DSYMObj->getHeader(); + + std::vector Symbols; + SmallVector FoundFns; + getSectionsAndSymbols(Header, DSYMObj.get(), 0, DSYMSections, Symbols, + FoundFns); + DebugSections = DSYMSections; + } + + // Find the named debug info sections. + for (unsigned SectIdx = 0; SectIdx != DebugSections.size(); SectIdx++) { + if (!strcmp(DebugSections[SectIdx].Name, "__debug_abbrev")) + DebugAbbrevSection = DSYMObj->getData(DebugSections[SectIdx].Offset, + DebugSections[SectIdx].Size); + else if (!strcmp(DebugSections[SectIdx].Name, "__debug_info")) + DebugInfoSection = DSYMObj->getData(DebugSections[SectIdx].Offset, + DebugSections[SectIdx].Size); + else if (!strcmp(DebugSections[SectIdx].Name, "__debug_aranges")) + DebugArangesSection = DSYMObj->getData(DebugSections[SectIdx].Offset, + DebugSections[SectIdx].Size); + else if (!strcmp(DebugSections[SectIdx].Name, "__debug_line")) + DebugLineSection = DSYMObj->getData(DebugSections[SectIdx].Offset, + DebugSections[SectIdx].Size); + else if (!strcmp(DebugSections[SectIdx].Name, "__debug_str")) + DebugStrSection = DSYMObj->getData(DebugSections[SectIdx].Offset, + DebugSections[SectIdx].Size); + } + + // Setup the DIContext. + diContext.reset(DIContext::getDWARFContext(MachOObj->isLittleEndian(), + DebugInfoSection, + DebugAbbrevSection, + DebugArangesSection, + DebugLineSection, + DebugStrSection)); + } + FunctionMapTy FunctionMap; FunctionListTy Functions; @@ -374,6 +449,7 @@ void llvm::DisassembleInputMachO(StringRef Filename) { // Normal disassembly, print addresses, bytes and mnemonic form. outs() << MachOObj->getStringAtIndex(Symbols[SymIdx].StringIndex) << ":\n"; + DILineInfo lastLine; for (uint64_t Index = Start; Index < End; Index += Size) { MCInst Inst; @@ -382,6 +458,18 @@ void llvm::DisassembleInputMachO(StringRef Filename) { outs() << format("%8llx:\t", Sections[SectIdx].Address + Index); DumpBytes(StringRef(Bytes.data() + Index, Size)); IP->printInst(&Inst, outs(), ""); + + // Print debug info. + if (diContext) { + DILineInfo dli = + diContext->getLineInfoForAddress(Sections[SectIdx].Address + + Index); + // Print valid line info if it changed. + if (dli != lastLine && dli.getLine() != 0) + outs() << "\t## " << dli.getFileName() << ':' + << dli.getLine() << ':' << dli.getColumn(); + lastLine = dli; + } outs() << "\n"; } else { errs() << "llvm-objdump: warning: invalid instruction encoding\n"; @@ -464,6 +552,7 @@ void llvm::DisassembleInputMachO(StringRef Filename) { if (fi->second.contains(fi->first)) // Print a header for simple loops outs() << "# Loop begin:\n"; + DILineInfo lastLine; // Walk over the instructions and print them. for (unsigned ii = 0, ie = fi->second.getInsts().size(); ii != ie; ++ii) { @@ -506,6 +595,18 @@ void llvm::DisassembleInputMachO(StringRef Filename) { if (targ != -1ULL) DumpAddress(targ, Sections, MachOObj.get(), outs()); + // Print debug info. + if (diContext) { + DILineInfo dli = + diContext->getLineInfoForAddress(Sections[SectIdx].Address + + Inst.Address); + // Print valid line info if it changed. + if (dli != lastLine && dli.getLine() != 0) + outs() << "\t## " << dli.getFileName() << ':' + << dli.getLine() << ':' << dli.getColumn(); + lastLine = dli; + } + outs() << '\n'; } } diff --git a/tools/llvm-objdump/Makefile b/tools/llvm-objdump/Makefile index 4d7cd34eac9..703bf6c8a4f 100644 --- a/tools/llvm-objdump/Makefile +++ b/tools/llvm-objdump/Makefile @@ -9,7 +9,8 @@ LEVEL = ../.. TOOLNAME = llvm-objdump -LINK_COMPONENTS = $(TARGETS_TO_BUILD) MC MCParser MCDisassembler Object +LINK_COMPONENTS = $(TARGETS_TO_BUILD) DebugInfo MC MCParser MCDisassembler \ + Object # This tool has no plugins, optimize startup time. TOOL_NO_EXPORTS = 1 -- 2.34.1