aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexey Samsonov <samsonov@google.com>2012-07-02 05:54:45 +0000
committerAlexey Samsonov <samsonov@google.com>2012-07-02 05:54:45 +0000
commit3e25c4a1e3e58bc1d00d894854a29dd2e4e7e88a (patch)
tree742a54896b5de0397c3d8cbf4809e0e225ea016e
parent9c3d5a70f40f9e7bb90f3cb8ec1d87cff6e3f0ae (diff)
This patch extends the libLLVMDebugInfo which contains a minimalistic DWARF parser:
1) DIContext is now able to return function name for a given instruction address (besides file/line info). 2) llvm-dwarfdump accepts flag --functions that prints the function name (if address is specified by --address flag). 3) test case that checks the basic functionality of llvm-dwarfdump added git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@159512 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/llvm/DebugInfo/DIContext.h34
-rw-r--r--lib/DebugInfo/DWARFCompileUnit.cpp18
-rw-r--r--lib/DebugInfo/DWARFCompileUnit.h5
-rw-r--r--lib/DebugInfo/DWARFContext.cpp50
-rw-r--r--lib/DebugInfo/DWARFContext.h3
-rw-r--r--lib/DebugInfo/DWARFDebugAranges.cpp2
-rw-r--r--lib/DebugInfo/DWARFDebugInfoEntry.cpp48
-rw-r--r--lib/DebugInfo/DWARFDebugInfoEntry.h7
-rwxr-xr-xtest/DebugInfo/Inputs/dwarfdump-test.elf-x86-64bin0 -> 10246 bytes
-rwxr-xr-xtest/DebugInfo/Inputs/dwarfdump-test2.elf-x86-64bin0 -> 7774 bytes
-rw-r--r--test/DebugInfo/dwarfdump-test.test25
-rw-r--r--tools/llvm-dwarfdump/llvm-dwarfdump.cpp13
12 files changed, 174 insertions, 31 deletions
diff --git a/include/llvm/DebugInfo/DIContext.h b/include/llvm/DebugInfo/DIContext.h
index 64f80c5065..6377acb634 100644
--- a/include/llvm/DebugInfo/DIContext.h
+++ b/include/llvm/DebugInfo/DIContext.h
@@ -26,26 +26,49 @@ class raw_ostream;
/// DILineInfo - a format-neutral container for source line information.
class DILineInfo {
const char *FileName;
+ const char *FunctionName;
uint32_t Line;
uint32_t Column;
public:
- DILineInfo() : FileName("<invalid>"), Line(0), Column(0) {}
- DILineInfo(const char *fileName, uint32_t line, uint32_t column)
- : FileName(fileName), Line(line), Column(column) {}
+ DILineInfo()
+ : FileName("<invalid>"), FunctionName("<invalid>"),
+ Line(0), Column(0) {}
+ DILineInfo(const char *fileName, const char *functionName,
+ uint32_t line, uint32_t column)
+ : FileName(fileName), FunctionName(functionName),
+ Line(line), Column(column) {}
const char *getFileName() const { return FileName; }
+ const char *getFunctionName() const { return FunctionName; }
uint32_t getLine() const { return Line; }
uint32_t getColumn() const { return Column; }
bool operator==(const DILineInfo &RHS) const {
return Line == RHS.Line && Column == RHS.Column &&
- std::strcmp(FileName, RHS.FileName) == 0;
+ std::strcmp(FileName, RHS.FileName) == 0 &&
+ std::strcmp(FunctionName, RHS.FunctionName) == 0;
}
bool operator!=(const DILineInfo &RHS) const {
return !(*this == RHS);
}
};
+/// DILineInfoSpecifier - controls which fields of DILineInfo container
+/// should be filled with data.
+class DILineInfoSpecifier {
+ const uint32_t Flags; // Or'ed flags that set the info we want to fetch.
+public:
+ enum Specification {
+ FileLineInfo = 1 << 0,
+ FunctionName = 1 << 1
+ };
+ // Use file/line info by default.
+ DILineInfoSpecifier(uint32_t flags = FileLineInfo) : Flags(flags) {}
+ bool needs(Specification spec) const {
+ return (Flags & spec) > 0;
+ }
+};
+
class DIContext {
public:
virtual ~DIContext();
@@ -60,7 +83,8 @@ public:
virtual void dump(raw_ostream &OS) = 0;
- virtual DILineInfo getLineInfoForAddress(uint64_t address) = 0;
+ virtual DILineInfo getLineInfoForAddress(uint64_t address,
+ DILineInfoSpecifier specifier = DILineInfoSpecifier()) = 0;
};
}
diff --git a/lib/DebugInfo/DWARFCompileUnit.cpp b/lib/DebugInfo/DWARFCompileUnit.cpp
index 24bf97ff60..2683990e58 100644
--- a/lib/DebugInfo/DWARFCompileUnit.cpp
+++ b/lib/DebugInfo/DWARFCompileUnit.cpp
@@ -82,7 +82,7 @@ void DWARFCompileUnit::clear() {
Abbrevs = 0;
AddrSize = 0;
BaseAddr = 0;
- DieArray.clear();
+ clearDIEs(false);
}
void DWARFCompileUnit::dump(raw_ostream &OS) {
@@ -201,7 +201,7 @@ size_t DWARFCompileUnit::extractDIEsIfNeeded(bool cu_die_only) {
}
void DWARFCompileUnit::clearDIEs(bool keep_compile_unit_die) {
- if (DieArray.size() > 1) {
+ if (DieArray.size() > (unsigned)keep_compile_unit_die) {
// std::vectors never get any smaller when resized to a smaller size,
// or when clear() or erase() are called, the size will report that it
// is smaller, but the memory allocated remains intact (call capacity()
@@ -227,8 +227,8 @@ DWARFCompileUnit::buildAddressRangeTable(DWARFDebugAranges *debug_aranges,
// all compile units to stay loaded when they weren't needed. So we can end
// up parsing the DWARF and then throwing them all away to keep memory usage
// down.
- const bool clear_dies = extractDIEsIfNeeded(false) > 1;
-
+ const bool clear_dies = extractDIEsIfNeeded(false) > 1 &&
+ clear_dies_if_already_not_parsed;
DieArray[0].buildAddressRangeTable(this, debug_aranges);
// Keep memory down by clearing DIEs if this generate function
@@ -236,3 +236,13 @@ DWARFCompileUnit::buildAddressRangeTable(DWARFDebugAranges *debug_aranges,
if (clear_dies)
clearDIEs(true);
}
+
+const DWARFDebugInfoEntryMinimal*
+DWARFCompileUnit::getFunctionDIEForAddress(int64_t address) {
+ size_t n = extractDIEsIfNeeded(false);
+ for (size_t i = 0; i != n; i++) {
+ if (DieArray[i].addressRangeContainsAddress(this, address))
+ return &DieArray[i];
+ }
+ return 0;
+}
diff --git a/lib/DebugInfo/DWARFCompileUnit.h b/lib/DebugInfo/DWARFCompileUnit.h
index d9167292a9..dc558da714 100644
--- a/lib/DebugInfo/DWARFCompileUnit.h
+++ b/lib/DebugInfo/DWARFCompileUnit.h
@@ -104,6 +104,11 @@ public:
void buildAddressRangeTable(DWARFDebugAranges *debug_aranges,
bool clear_dies_if_already_not_parsed);
+ /// getFunctionDIEForAddress - Returns pointer to parsed subprogram DIE,
+ /// address ranges of which contain the provided address,
+ /// or NULL if there is no such subprogram. The pointer
+ /// is valid until DWARFCompileUnit::clear() or clearDIEs() is called.
+ const DWARFDebugInfoEntryMinimal *getFunctionDIEForAddress(int64_t address);
};
}
diff --git a/lib/DebugInfo/DWARFContext.cpp b/lib/DebugInfo/DWARFContext.cpp
index dccadc4ea4..6be230e73a 100644
--- a/lib/DebugInfo/DWARFContext.cpp
+++ b/lib/DebugInfo/DWARFContext.cpp
@@ -140,30 +140,42 @@ DWARFCompileUnit *DWARFContext::getCompileUnitForOffset(uint32_t offset) {
return 0;
}
-DILineInfo DWARFContext::getLineInfoForAddress(uint64_t address) {
+DILineInfo DWARFContext::getLineInfoForAddress(uint64_t address,
+ DILineInfoSpecifier specifier) {
// First, get the offset of the compile unit.
uint32_t cuOffset = getDebugAranges()->findAddress(address);
// Retrieve the compile unit.
DWARFCompileUnit *cu = getCompileUnitForOffset(cuOffset);
if (!cu)
- return DILineInfo("<invalid>", 0, 0);
- // Get the line table for this compile unit.
- const DWARFDebugLine::LineTable *lineTable = getLineTableForCompileUnit(cu);
- if (!lineTable)
- return DILineInfo("<invalid>", 0, 0);
- // Get the index of the row we're looking for in the line table.
- uint64_t hiPC =
- cu->getCompileUnitDIE()->getAttributeValueAsUnsigned(cu, DW_AT_high_pc,
- -1ULL);
- uint32_t rowIndex = lineTable->lookupAddress(address, hiPC);
- if (rowIndex == -1U)
- return DILineInfo("<invalid>", 0, 0);
-
- // From here, contruct the DILineInfo.
- const DWARFDebugLine::Row &row = lineTable->Rows[rowIndex];
- const std::string &fileName = lineTable->Prologue.FileNames[row.File-1].Name;
-
- return DILineInfo(fileName.c_str(), row.Line, row.Column);
+ return DILineInfo();
+ const char *fileName = "<invalid>";
+ const char *functionName = "<invalid>";
+ uint32_t line = 0;
+ uint32_t column = 0;
+ if (specifier.needs(DILineInfoSpecifier::FunctionName)) {
+ const DWARFDebugInfoEntryMinimal *function_die =
+ cu->getFunctionDIEForAddress(address);
+ if (function_die)
+ functionName = function_die->getSubprogramName(cu);
+ }
+ if (specifier.needs(DILineInfoSpecifier::FileLineInfo)) {
+ // Get the line table for this compile unit.
+ const DWARFDebugLine::LineTable *lineTable = getLineTableForCompileUnit(cu);
+ if (lineTable) {
+ // Get the index of the row we're looking for in the line table.
+ uint64_t hiPC = cu->getCompileUnitDIE()->getAttributeValueAsUnsigned(
+ cu, DW_AT_high_pc, -1ULL);
+ uint32_t rowIndex = lineTable->lookupAddress(address, hiPC);
+ if (rowIndex != -1U) {
+ const DWARFDebugLine::Row &row = lineTable->Rows[rowIndex];
+ // Take file/line info from the line table.
+ fileName = lineTable->Prologue.FileNames[row.File - 1].Name.c_str();
+ line = row.Line;
+ column = row.Column;
+ }
+ }
+ }
+ return DILineInfo(fileName, functionName, line, column);
}
void DWARFContextInMemory::anchor() { }
diff --git a/lib/DebugInfo/DWARFContext.h b/lib/DebugInfo/DWARFContext.h
index d2e763a87a..e55a27e698 100644
--- a/lib/DebugInfo/DWARFContext.h
+++ b/lib/DebugInfo/DWARFContext.h
@@ -66,7 +66,8 @@ public:
const DWARFDebugLine::LineTable *
getLineTableForCompileUnit(DWARFCompileUnit *cu);
- virtual DILineInfo getLineInfoForAddress(uint64_t address);
+ virtual DILineInfo getLineInfoForAddress(uint64_t address,
+ DILineInfoSpecifier specifier = DILineInfoSpecifier());
bool isLittleEndian() const { return IsLittleEndian; }
diff --git a/lib/DebugInfo/DWARFDebugAranges.cpp b/lib/DebugInfo/DWARFDebugAranges.cpp
index 1788145356..ef470e5799 100644
--- a/lib/DebugInfo/DWARFDebugAranges.cpp
+++ b/lib/DebugInfo/DWARFDebugAranges.cpp
@@ -93,6 +93,7 @@ bool DWARFDebugAranges::generate(DWARFContext *ctx) {
cu->buildAddressRangeTable(this, true);
}
}
+ sort(true, /* overlap size */ 0);
return !isEmpty();
}
@@ -221,4 +222,3 @@ bool DWARFDebugAranges::getMaxRange(uint64_t &LoPC, uint64_t &HiPC) const {
HiPC = Aranges.back().HiPC();
return true;
}
-
diff --git a/lib/DebugInfo/DWARFDebugInfoEntry.cpp b/lib/DebugInfo/DWARFDebugInfoEntry.cpp
index 236db97c44..1024b45255 100644
--- a/lib/DebugInfo/DWARFDebugInfoEntry.cpp
+++ b/lib/DebugInfo/DWARFDebugInfoEntry.cpp
@@ -440,3 +440,51 @@ DWARFDebugInfoEntryMinimal::buildAddressRangeTable(const DWARFCompileUnit *cu,
}
}
}
+
+bool
+DWARFDebugInfoEntryMinimal::addressRangeContainsAddress(
+ const DWARFCompileUnit *cu, const uint64_t address) const {
+ if (!isNULL() && getTag() == DW_TAG_subprogram) {
+ uint64_t hi_pc = -1ULL;
+ uint64_t lo_pc = getAttributeValueAsUnsigned(cu, DW_AT_low_pc, -1ULL);
+ if (lo_pc != -1ULL)
+ hi_pc = getAttributeValueAsUnsigned(cu, DW_AT_high_pc, -1ULL);
+ if (hi_pc != -1ULL) {
+ return (lo_pc <= address && address < hi_pc);
+ }
+ }
+ return false;
+}
+
+static inline const char*
+getSubprogramNameFromDie(const DWARFCompileUnit *cu,
+ const DWARFDebugInfoEntryMinimal *die) {
+ const char *result = 0;
+ if (!die->isNULL() && die->getTag() == DW_TAG_subprogram) {
+ // Try to get mangled name if possible.
+ result = die->getAttributeValueAsString(cu, DW_AT_MIPS_linkage_name, 0);
+ if (result == 0)
+ result = die->getAttributeValueAsString(cu, DW_AT_linkage_name, 0);
+ if (result == 0)
+ result = die->getAttributeValueAsString(cu, DW_AT_name, 0);
+ }
+ return result;
+}
+
+const char*
+DWARFDebugInfoEntryMinimal::getSubprogramName(
+ const DWARFCompileUnit *cu) const {
+ if (isNULL() || getTag() != DW_TAG_subprogram)
+ return 0;
+ const char *name = getSubprogramNameFromDie(cu, this);
+ if (name == 0) {
+ // Try to get name from specification DIE.
+ uint32_t ref = getAttributeValueAsReference(cu, DW_AT_specification, -1U);
+ if (ref != -1U) {
+ DWARFDebugInfoEntryMinimal spec_die;
+ if (spec_die.extract(cu, &ref))
+ name = getSubprogramNameFromDie(cu, &spec_die);
+ }
+ }
+ return name;
+}
diff --git a/lib/DebugInfo/DWARFDebugInfoEntry.h b/lib/DebugInfo/DWARFDebugInfoEntry.h
index 37b3bcdd96..1a040a53a3 100644
--- a/lib/DebugInfo/DWARFDebugInfoEntry.h
+++ b/lib/DebugInfo/DWARFDebugInfoEntry.h
@@ -128,6 +128,13 @@ public:
void buildAddressRangeTable(const DWARFCompileUnit *cu,
DWARFDebugAranges *debug_aranges) const;
+
+ bool addressRangeContainsAddress(const DWARFCompileUnit *cu,
+ const uint64_t address) const;
+
+ // If a DIE represents a subroutine, returns its mangled name
+ // (or short name, if mangled is missing). Otherwise returns null.
+ const char* getSubprogramName(const DWARFCompileUnit *cu) const;
};
}
diff --git a/test/DebugInfo/Inputs/dwarfdump-test.elf-x86-64 b/test/DebugInfo/Inputs/dwarfdump-test.elf-x86-64
new file mode 100755
index 0000000000..7cee968072
--- /dev/null
+++ b/test/DebugInfo/Inputs/dwarfdump-test.elf-x86-64
Binary files differ
diff --git a/test/DebugInfo/Inputs/dwarfdump-test2.elf-x86-64 b/test/DebugInfo/Inputs/dwarfdump-test2.elf-x86-64
new file mode 100755
index 0000000000..a226e79f3b
--- /dev/null
+++ b/test/DebugInfo/Inputs/dwarfdump-test2.elf-x86-64
Binary files differ
diff --git a/test/DebugInfo/dwarfdump-test.test b/test/DebugInfo/dwarfdump-test.test
new file mode 100644
index 0000000000..84fe7f3ec8
--- /dev/null
+++ b/test/DebugInfo/dwarfdump-test.test
@@ -0,0 +1,25 @@
+RUN: llvm-dwarfdump %p/Inputs/dwarfdump-test.elf-x86-64 \
+RUN: --address=0x400589 --functions | FileCheck %s -check-prefix MAIN
+RUN: llvm-dwarfdump %p/Inputs/dwarfdump-test.elf-x86-64 \
+RUN: --address=0x400558 --functions | FileCheck %s -check-prefix FUNCTION
+RUN: llvm-dwarfdump %p/Inputs/dwarfdump-test.elf-x86-64 \
+RUN: --address=0x4005b6 --functions | FileCheck %s -check-prefix CTOR_WITH_SPEC
+RUN: llvm-dwarfdump %p/Inputs/dwarfdump-test2.elf-x86-64 \
+RUN: --address=0x4004b8 --functions | FileCheck %s -check-prefix MANY_CU_1
+RUN: llvm-dwarfdump %p/Inputs/dwarfdump-test2.elf-x86-64 \
+RUN: --address=0x4004c4 --functions | FileCheck %s -check-prefix MANY_CU_2
+
+MAIN: main
+MAIN-NEXT: dwarfdump-test.cc:16:10
+
+FUNCTION: _Z1fii
+FUNCTION-NEXT: dwarfdump-test.cc:11:18
+
+CTOR_WITH_SPEC: _ZN10DummyClassC1Ei
+CTOR_WITH_SPEC-NEXT: dwarfdump-test.cc:4:30
+
+MANY_CU_1: a
+MANY_CU_1-NEXT: a.cc:2:0
+
+MANY_CU_2: main
+MANY_CU_2-NEXT: main.cc:4:0
diff --git a/tools/llvm-dwarfdump/llvm-dwarfdump.cpp b/tools/llvm-dwarfdump/llvm-dwarfdump.cpp
index ca0493de5d..b6536fa1d7 100644
--- a/tools/llvm-dwarfdump/llvm-dwarfdump.cpp
+++ b/tools/llvm-dwarfdump/llvm-dwarfdump.cpp
@@ -39,6 +39,11 @@ static cl::opt<unsigned long long>
Address("address", cl::init(-1ULL),
cl::desc("Print line information for a given address"));
+static cl::opt<bool>
+PrintFunctions("functions", cl::init(false),
+ cl::desc("Print function names as well as line information "
+ "for a given address"));
+
static void DumpInput(const StringRef &Filename) {
OwningPtr<MemoryBuffer> Buff;
@@ -92,7 +97,13 @@ static void DumpInput(const StringRef &Filename) {
dictx->dump(outs());
} else {
// Print line info for the specified address.
- DILineInfo dli = dictx->getLineInfoForAddress(Address);
+ int spec_flags = DILineInfoSpecifier::FileLineInfo;
+ if (PrintFunctions)
+ spec_flags |= DILineInfoSpecifier::FunctionName;
+ DILineInfo dli = dictx->getLineInfoForAddress(Address, spec_flags);
+ if (PrintFunctions)
+ outs() << (dli.getFunctionName() ? dli.getFunctionName() : "<unknown>")
+ << "\n";
outs() << (dli.getFileName() ? dli.getFileName() : "<unknown>") << ':'
<< dli.getLine() << ':' << dli.getColumn() << '\n';
}