mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-11-02 07:17:36 +00:00
llvm-objdump: Output line info next to the disassembly if available.
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
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
set(LLVM_LINK_COMPONENTS
|
set(LLVM_LINK_COMPONENTS
|
||||||
${LLVM_TARGETS_TO_BUILD}
|
${LLVM_TARGETS_TO_BUILD}
|
||||||
|
DebugInfo
|
||||||
MC
|
MC
|
||||||
MCParser
|
MCParser
|
||||||
MCDisassembler
|
MCDisassembler
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
#include "llvm/ADT/OwningPtr.h"
|
#include "llvm/ADT/OwningPtr.h"
|
||||||
#include "llvm/ADT/Triple.h"
|
#include "llvm/ADT/Triple.h"
|
||||||
#include "llvm/ADT/STLExtras.h"
|
#include "llvm/ADT/STLExtras.h"
|
||||||
|
#include "llvm/DebugInfo/DIContext.h"
|
||||||
#include "llvm/MC/MCAsmInfo.h"
|
#include "llvm/MC/MCAsmInfo.h"
|
||||||
#include "llvm/MC/MCDisassembler.h"
|
#include "llvm/MC/MCDisassembler.h"
|
||||||
#include "llvm/MC/MCInst.h"
|
#include "llvm/MC/MCInst.h"
|
||||||
@@ -44,6 +45,12 @@ static cl::opt<bool>
|
|||||||
CFG("cfg", cl::desc("Create a CFG for every symbol in the object file and"
|
CFG("cfg", cl::desc("Create a CFG for every symbol in the object file and"
|
||||||
"write it to a graphviz file (MachO-only)"));
|
"write it to a graphviz file (MachO-only)"));
|
||||||
|
|
||||||
|
static cl::opt<bool>
|
||||||
|
UseDbg("g", cl::desc("Print line information from debug info if available"));
|
||||||
|
|
||||||
|
static cl::opt<std::string>
|
||||||
|
DSYMFile("dsym", cl::desc("Use .dSYM file for debug info"));
|
||||||
|
|
||||||
static const Target *GetTarget(const MachOObject *MachOObj) {
|
static const Target *GetTarget(const MachOObject *MachOObj) {
|
||||||
// Figure out the target triple.
|
// Figure out the target triple.
|
||||||
llvm::Triple TT("unknown-unknown-unknown");
|
llvm::Triple TT("unknown-unknown-unknown");
|
||||||
@@ -94,7 +101,6 @@ struct Symbol {
|
|||||||
bool operator<(const Symbol &RHS) const { return Value < RHS.Value; }
|
bool operator<(const Symbol &RHS) const { return Value < RHS.Value; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static Section copySection(const T &Sect) {
|
static Section copySection(const T &Sect) {
|
||||||
Section S;
|
Section S;
|
||||||
@@ -205,6 +211,67 @@ static void emitDOTFile(const char *FileName, const MCFunction &f,
|
|||||||
Out << "}\n";
|
Out << "}\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void getSectionsAndSymbols(const macho::Header &Header,
|
||||||
|
MachOObject *MachOObj,
|
||||||
|
InMemoryStruct<macho::SymtabLoadCommand> *SymtabLC,
|
||||||
|
std::vector<Section> &Sections,
|
||||||
|
std::vector<Symbol> &Symbols,
|
||||||
|
SmallVectorImpl<uint64_t> &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<macho::SegmentLoadCommand> SegmentLC;
|
||||||
|
MachOObj->ReadSegmentLoadCommand(LCI, SegmentLC);
|
||||||
|
|
||||||
|
// Store the sections in this segment.
|
||||||
|
for (unsigned SectNum = 0; SectNum != SegmentLC->NumSections; ++SectNum) {
|
||||||
|
InMemoryStruct<macho::Section> 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<macho::SymbolTableEntry> STE;
|
||||||
|
MachOObj->ReadSymbolTableEntry((*SymtabLC)->SymbolTableOffset, i,
|
||||||
|
STE);
|
||||||
|
Symbols.push_back(copySymbol(STE));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (LCI.Command.Type == macho::LCT_Segment64) {
|
||||||
|
InMemoryStruct<macho::Segment64LoadCommand> Segment64LC;
|
||||||
|
MachOObj->ReadSegment64LoadCommand(LCI, Segment64LC);
|
||||||
|
|
||||||
|
// Store the sections in this segment.
|
||||||
|
for (unsigned SectNum = 0; SectNum != Segment64LC->NumSections;
|
||||||
|
++SectNum) {
|
||||||
|
InMemoryStruct<macho::Section64> 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<macho::Symbol64TableEntry> 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<macho::LinkeditDataLoadCommand> LLC;
|
||||||
|
MachOObj->ReadLinkeditDataLoadCommand(LCI, LLC);
|
||||||
|
|
||||||
|
MachOObj->ReadULEB128s(LLC->DataOffset, FoundFns);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void llvm::DisassembleInputMachO(StringRef Filename) {
|
void llvm::DisassembleInputMachO(StringRef Filename) {
|
||||||
OwningPtr<MemoryBuffer> Buff;
|
OwningPtr<MemoryBuffer> Buff;
|
||||||
|
|
||||||
@@ -260,60 +327,13 @@ void llvm::DisassembleInputMachO(StringRef Filename) {
|
|||||||
|
|
||||||
std::vector<Section> Sections;
|
std::vector<Section> Sections;
|
||||||
std::vector<Symbol> Symbols;
|
std::vector<Symbol> Symbols;
|
||||||
std::vector<Symbol> UnsortedSymbols; // FIXME: duplication
|
|
||||||
SmallVector<uint64_t, 8> FoundFns;
|
SmallVector<uint64_t, 8> FoundFns;
|
||||||
|
|
||||||
// Make a list of all symbols in the object file.
|
getSectionsAndSymbols(Header, MachOObj.get(), &SymtabLC, Sections, Symbols,
|
||||||
for (unsigned i = 0; i != Header.NumLoadCommands; ++i) {
|
FoundFns);
|
||||||
const MachOObject::LoadCommandInfo &LCI = MachOObj->getLoadCommandInfo(i);
|
|
||||||
if (LCI.Command.Type == macho::LCT_Segment) {
|
|
||||||
InMemoryStruct<macho::SegmentLoadCommand> SegmentLC;
|
|
||||||
MachOObj->ReadSegmentLoadCommand(LCI, SegmentLC);
|
|
||||||
|
|
||||||
// Store the sections in this segment.
|
|
||||||
for (unsigned SectNum = 0; SectNum != SegmentLC->NumSections; ++SectNum) {
|
|
||||||
InMemoryStruct<macho::Section> 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<macho::SymbolTableEntry> 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<macho::Segment64LoadCommand> Segment64LC;
|
|
||||||
MachOObj->ReadSegment64LoadCommand(LCI, Segment64LC);
|
|
||||||
|
|
||||||
// Store the sections in this segment.
|
|
||||||
for (unsigned SectNum = 0; SectNum != Segment64LC->NumSections;
|
|
||||||
++SectNum) {
|
|
||||||
InMemoryStruct<macho::Section64> 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<macho::Symbol64TableEntry> 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<macho::LinkeditDataLoadCommand> LLC;
|
|
||||||
MachOObj->ReadLinkeditDataLoadCommand(LCI, LLC);
|
|
||||||
|
|
||||||
MachOObj->ReadULEB128s(LLC->DataOffset, FoundFns);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
// Make a copy of the unsorted symbol list. FIXME: duplication
|
||||||
|
std::vector<Symbol> UnsortedSymbols(Symbols);
|
||||||
// Sort the symbols by address, just in case they didn't come in that way.
|
// Sort the symbols by address, just in case they didn't come in that way.
|
||||||
array_pod_sort(Symbols.begin(), Symbols.end());
|
array_pod_sort(Symbols.begin(), Symbols.end());
|
||||||
|
|
||||||
@@ -323,6 +343,61 @@ void llvm::DisassembleInputMachO(StringRef Filename) {
|
|||||||
raw_ostream &DebugOut = nulls();
|
raw_ostream &DebugOut = nulls();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
StringRef DebugAbbrevSection, DebugInfoSection, DebugArangesSection,
|
||||||
|
DebugLineSection, DebugStrSection;
|
||||||
|
OwningPtr<DIContext> diContext;
|
||||||
|
// Try to find debug info and set up the DIContext for it.
|
||||||
|
if (UseDbg) {
|
||||||
|
ArrayRef<Section> DebugSections = Sections;
|
||||||
|
std::vector<Section> DSYMSections;
|
||||||
|
OwningPtr<MachOObject> 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<MemoryBuffer> 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<Symbol> Symbols;
|
||||||
|
SmallVector<uint64_t, 8> 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;
|
FunctionMapTy FunctionMap;
|
||||||
FunctionListTy Functions;
|
FunctionListTy Functions;
|
||||||
|
|
||||||
@@ -374,6 +449,7 @@ void llvm::DisassembleInputMachO(StringRef Filename) {
|
|||||||
// Normal disassembly, print addresses, bytes and mnemonic form.
|
// Normal disassembly, print addresses, bytes and mnemonic form.
|
||||||
outs() << MachOObj->getStringAtIndex(Symbols[SymIdx].StringIndex)
|
outs() << MachOObj->getStringAtIndex(Symbols[SymIdx].StringIndex)
|
||||||
<< ":\n";
|
<< ":\n";
|
||||||
|
DILineInfo lastLine;
|
||||||
for (uint64_t Index = Start; Index < End; Index += Size) {
|
for (uint64_t Index = Start; Index < End; Index += Size) {
|
||||||
MCInst Inst;
|
MCInst Inst;
|
||||||
|
|
||||||
@@ -382,6 +458,18 @@ void llvm::DisassembleInputMachO(StringRef Filename) {
|
|||||||
outs() << format("%8llx:\t", Sections[SectIdx].Address + Index);
|
outs() << format("%8llx:\t", Sections[SectIdx].Address + Index);
|
||||||
DumpBytes(StringRef(Bytes.data() + Index, Size));
|
DumpBytes(StringRef(Bytes.data() + Index, Size));
|
||||||
IP->printInst(&Inst, outs(), "");
|
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";
|
outs() << "\n";
|
||||||
} else {
|
} else {
|
||||||
errs() << "llvm-objdump: warning: invalid instruction encoding\n";
|
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
|
if (fi->second.contains(fi->first)) // Print a header for simple loops
|
||||||
outs() << "# Loop begin:\n";
|
outs() << "# Loop begin:\n";
|
||||||
|
|
||||||
|
DILineInfo lastLine;
|
||||||
// Walk over the instructions and print them.
|
// Walk over the instructions and print them.
|
||||||
for (unsigned ii = 0, ie = fi->second.getInsts().size(); ii != ie;
|
for (unsigned ii = 0, ie = fi->second.getInsts().size(); ii != ie;
|
||||||
++ii) {
|
++ii) {
|
||||||
@@ -506,6 +595,18 @@ void llvm::DisassembleInputMachO(StringRef Filename) {
|
|||||||
if (targ != -1ULL)
|
if (targ != -1ULL)
|
||||||
DumpAddress(targ, Sections, MachOObj.get(), outs());
|
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';
|
outs() << '\n';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,8 @@
|
|||||||
LEVEL = ../..
|
LEVEL = ../..
|
||||||
|
|
||||||
TOOLNAME = llvm-objdump
|
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.
|
# This tool has no plugins, optimize startup time.
|
||||||
TOOL_NO_EXPORTS = 1
|
TOOL_NO_EXPORTS = 1
|
||||||
|
|||||||
Reference in New Issue
Block a user