aboutsummaryrefslogtreecommitdiffstats
path: root/lib/DebugInfo
diff options
context:
space:
mode:
Diffstat (limited to 'lib/DebugInfo')
-rw-r--r--lib/DebugInfo/DWARFCompileUnit.cpp25
-rw-r--r--lib/DebugInfo/DWARFCompileUnit.h9
-rw-r--r--lib/DebugInfo/DWARFContext.cpp76
-rw-r--r--lib/DebugInfo/DWARFContext.h3
-rw-r--r--lib/DebugInfo/DWARFDebugAranges.cpp2
-rw-r--r--lib/DebugInfo/DWARFDebugInfoEntry.cpp51
-rw-r--r--lib/DebugInfo/DWARFDebugInfoEntry.h9
-rw-r--r--lib/DebugInfo/DWARFDebugLine.h7
8 files changed, 152 insertions, 30 deletions
diff --git a/lib/DebugInfo/DWARFCompileUnit.cpp b/lib/DebugInfo/DWARFCompileUnit.cpp
index 24bf97f..b27d57b 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) {
@@ -97,6 +97,13 @@ void DWARFCompileUnit::dump(raw_ostream &OS) {
getCompileUnitDIE(false)->dump(OS, this, -1U);
}
+const char *DWARFCompileUnit::getCompilationDir() {
+ extractDIEsIfNeeded(true);
+ if (DieArray.empty())
+ return 0;
+ return DieArray[0].getAttributeValueAsString(this, DW_AT_comp_dir, 0);
+}
+
void DWARFCompileUnit::setDIERelations() {
if (DieArray.empty())
return;
@@ -201,7 +208,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 +234,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 +243,13 @@ DWARFCompileUnit::buildAddressRangeTable(DWARFDebugAranges *debug_aranges,
if (clear_dies)
clearDIEs(true);
}
+
+const DWARFDebugInfoEntryMinimal*
+DWARFCompileUnit::getFunctionDIEForAddress(int64_t address) {
+ extractDIEsIfNeeded(false);
+ for (size_t i = 0, n = DieArray.size(); 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 d916729..b34a596 100644
--- a/lib/DebugInfo/DWARFCompileUnit.h
+++ b/lib/DebugInfo/DWARFCompileUnit.h
@@ -43,7 +43,7 @@ public:
const DWARFAbbreviationDeclarationSet *abbrevs);
/// extractDIEsIfNeeded - Parses a compile unit and indexes its DIEs if it
- /// hasn't already been done.
+ /// hasn't already been done. Returns the number of DIEs parsed at this call.
size_t extractDIEsIfNeeded(bool cu_die_only);
void clear();
void dump(raw_ostream &OS);
@@ -78,6 +78,8 @@ public:
return &DieArray[0];
}
+ const char *getCompilationDir();
+
/// setDIERelations - We read in all of the DIE entries into our flat list
/// of DIE entries and now we need to go back through all of them and set the
/// parent, sibling and child pointers for quick DIE navigation.
@@ -104,6 +106,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 dccadc4..a4e0d8e 100644
--- a/lib/DebugInfo/DWARFContext.cpp
+++ b/lib/DebugInfo/DWARFContext.cpp
@@ -8,8 +8,10 @@
//===----------------------------------------------------------------------===//
#include "DWARFContext.h"
+#include "llvm/ADT/SmallString.h"
#include "llvm/Support/Dwarf.h"
#include "llvm/Support/Format.h"
+#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
using namespace llvm;
@@ -140,30 +142,66 @@ 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();
+ SmallString<16> fileName("<invalid>");
+ SmallString<16> 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) {
+ if (const char *name = function_die->getSubprogramName(cu))
+ functionName = name;
+ }
+ }
+ 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.
+ const DWARFDebugLine::FileNameEntry &fileNameEntry =
+ lineTable->Prologue.FileNames[row.File - 1];
+ fileName = fileNameEntry.Name;
+ if (specifier.needs(DILineInfoSpecifier::AbsoluteFilePath) &&
+ sys::path::is_relative(fileName.str())) {
+ // Append include directory of file (if it is present in line table)
+ // and compilation directory of compile unit to make path absolute.
+ const char *includeDir = 0;
+ if (uint64_t includeDirIndex = fileNameEntry.DirIdx) {
+ includeDir = lineTable->Prologue
+ .IncludeDirectories[includeDirIndex - 1];
+ }
+ SmallString<16> absFileName;
+ if (includeDir == 0 || sys::path::is_relative(includeDir)) {
+ if (const char *compilationDir = cu->getCompilationDir())
+ sys::path::append(absFileName, compilationDir);
+ }
+ if (includeDir) {
+ sys::path::append(absFileName, includeDir);
+ }
+ sys::path::append(absFileName, fileName.str());
+ fileName = absFileName;
+ }
+ 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 d2e763a..e55a27e 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 1788145..ef470e5 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 236db97..429a36c 100644
--- a/lib/DebugInfo/DWARFDebugInfoEntry.cpp
+++ b/lib/DebugInfo/DWARFDebugInfoEntry.cpp
@@ -440,3 +440,54 @@ 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;
+}
+
+const char*
+DWARFDebugInfoEntryMinimal::getSubprogramName(
+ const DWARFCompileUnit *cu) const {
+ if (isNULL() || getTag() != DW_TAG_subprogram)
+ return 0;
+ // Try to get mangled name if possible.
+ if (const char *name =
+ getAttributeValueAsString(cu, DW_AT_MIPS_linkage_name, 0))
+ return name;
+ if (const char *name = getAttributeValueAsString(cu, DW_AT_linkage_name, 0))
+ return name;
+ if (const char *name = getAttributeValueAsString(cu, DW_AT_name, 0))
+ return name;
+ // Try to get name from specification DIE.
+ uint32_t spec_ref =
+ getAttributeValueAsReference(cu, DW_AT_specification, -1U);
+ if (spec_ref != -1U) {
+ DWARFDebugInfoEntryMinimal spec_die;
+ if (spec_die.extract(cu, &spec_ref)) {
+ if (const char *name = spec_die.getSubprogramName(cu))
+ return name;
+ }
+ }
+ // Try to get name from abstract origin DIE.
+ uint32_t abs_origin_ref =
+ getAttributeValueAsReference(cu, DW_AT_abstract_origin, -1U);
+ if (abs_origin_ref != -1U) {
+ DWARFDebugInfoEntryMinimal abs_origin_die;
+ if (abs_origin_die.extract(cu, &abs_origin_ref)) {
+ if (const char *name = abs_origin_die.getSubprogramName(cu))
+ return name;
+ }
+ }
+ return 0;
+}
diff --git a/lib/DebugInfo/DWARFDebugInfoEntry.h b/lib/DebugInfo/DWARFDebugInfoEntry.h
index 37b3bcd..d5d86b9 100644
--- a/lib/DebugInfo/DWARFDebugInfoEntry.h
+++ b/lib/DebugInfo/DWARFDebugInfoEntry.h
@@ -128,6 +128,15 @@ 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 subprogram, returns its mangled name
+ // (or short name, if mangled is missing). This name may be fetched
+ // from specification or abstract origin for this subprogram.
+ // Returns null if no name is found.
+ const char* getSubprogramName(const DWARFCompileUnit *cu) const;
};
}
diff --git a/lib/DebugInfo/DWARFDebugLine.h b/lib/DebugInfo/DWARFDebugLine.h
index bc6a70b..a8c0669 100644
--- a/lib/DebugInfo/DWARFDebugLine.h
+++ b/lib/DebugInfo/DWARFDebugLine.h
@@ -12,7 +12,6 @@
#include "llvm/Support/DataExtractor.h"
#include <map>
-#include <string>
#include <vector>
namespace llvm {
@@ -22,9 +21,9 @@ class raw_ostream;
class DWARFDebugLine {
public:
struct FileNameEntry {
- FileNameEntry() : DirIdx(0), ModTime(0), Length(0) {}
+ FileNameEntry() : Name(0), DirIdx(0), ModTime(0), Length(0) {}
- std::string Name;
+ const char *Name;
uint64_t DirIdx;
uint64_t ModTime;
uint64_t Length;
@@ -56,7 +55,7 @@ public:
// The number assigned to the first special opcode.
uint8_t OpcodeBase;
std::vector<uint8_t> StandardOpcodeLengths;
- std::vector<std::string> IncludeDirectories;
+ std::vector<const char*> IncludeDirectories;
std::vector<FileNameEntry> FileNames;
// Length of the prologue in bytes.