Skip to content
This repository has been archived by the owner on Apr 23, 2020. It is now read-only.

Commit

Permalink
Add DIContext::getLineInfoForAddressRange() function and test. This f…
Browse files Browse the repository at this point in the history
…unction allows a caller to obtain a table of line information for a function using the function's address and size.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@173537 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
andykaylor committed Jan 26, 2013
1 parent 32a5795 commit e27a787
Show file tree
Hide file tree
Showing 8 changed files with 191 additions and 8 deletions.
4 changes: 4 additions & 0 deletions include/llvm/DebugInfo/DIContext.h
Expand Up @@ -58,6 +58,8 @@ class DILineInfo {
}
};

typedef SmallVector<std::pair<uint64_t, DILineInfo>, 16> DILineInfoTable;

/// DIInliningInfo - a format-neutral container for inlined code description.
class DIInliningInfo {
SmallVector<DILineInfo, 4> Frames;
Expand Down Expand Up @@ -126,6 +128,8 @@ class DIContext {

virtual DILineInfo getLineInfoForAddress(uint64_t Address,
DILineInfoSpecifier Specifier = DILineInfoSpecifier()) = 0;
virtual DILineInfoTable getLineInfoForAddressRange(uint64_t Address,
uint64_t Size, DILineInfoSpecifier Specifier = DILineInfoSpecifier()) = 0;
virtual DIInliningInfo getInliningInfoForAddress(uint64_t Address,
DILineInfoSpecifier Specifier = DILineInfoSpecifier()) = 0;
};
Expand Down
58 changes: 58 additions & 0 deletions lib/DebugInfo/DWARFContext.cpp
Expand Up @@ -325,6 +325,64 @@ DILineInfo DWARFContext::getLineInfoForAddress(uint64_t Address,
Line, Column);
}

DILineInfoTable DWARFContext::getLineInfoForAddressRange(uint64_t Address,
uint64_t Size,
DILineInfoSpecifier Specifier) {
DILineInfoTable Lines;
DWARFCompileUnit *CU = getCompileUnitForAddress(Address);
if (!CU)
return Lines;

std::string FunctionName = "<invalid>";
if (Specifier.needs(DILineInfoSpecifier::FunctionName)) {
// The address may correspond to instruction in some inlined function,
// so we have to build the chain of inlined functions and take the
// name of the topmost function in it.
const DWARFDebugInfoEntryMinimal::InlinedChain &InlinedChain =
CU->getInlinedChainForAddress(Address);
if (InlinedChain.size() > 0) {
const DWARFDebugInfoEntryMinimal &TopFunctionDIE = InlinedChain[0];
if (const char *Name = TopFunctionDIE.getSubroutineName(CU))
FunctionName = Name;
}
}

StringRef FuncNameRef = StringRef(FunctionName);

// If the Specifier says we don't need FileLineInfo, just
// return the top-most function at the starting address.
if (!Specifier.needs(DILineInfoSpecifier::FileLineInfo)) {
Lines.push_back(std::make_pair(Address,
DILineInfo(StringRef("<invalid>"),
FuncNameRef, 0, 0)));
return Lines;
}

const DWARFLineTable *LineTable = getLineTableForCompileUnit(CU);
const bool NeedsAbsoluteFilePath =
Specifier.needs(DILineInfoSpecifier::AbsoluteFilePath);

// Get the index of row we're looking for in the line table.
std::vector<uint32_t> RowVector;
if (!LineTable->lookupAddressRange(Address, Size, RowVector))
return Lines;

uint32_t NumRows = RowVector.size();
for (uint32_t i = 0; i < NumRows; ++i) {
uint32_t RowIndex = RowVector[i];
// Take file number and line/column from the row.
const DWARFDebugLine::Row &Row = LineTable->Rows[RowIndex];
std::string FileName = "<invalid>";
getFileNameForCompileUnit(CU, LineTable, Row.File,
NeedsAbsoluteFilePath, FileName);
Lines.push_back(std::make_pair(Row.Address,
DILineInfo(StringRef(FileName),
FuncNameRef, Row.Line, Row.Column)));
}

return Lines;
}

DIInliningInfo DWARFContext::getInliningInfoForAddress(uint64_t Address,
DILineInfoSpecifier Specifier) {
DWARFCompileUnit *CU = getCompileUnitForAddress(Address);
Expand Down
2 changes: 2 additions & 0 deletions lib/DebugInfo/DWARFContext.h
Expand Up @@ -90,6 +90,8 @@ class DWARFContext : public DIContext {

virtual DILineInfo getLineInfoForAddress(uint64_t Address,
DILineInfoSpecifier Specifier = DILineInfoSpecifier());
virtual DILineInfoTable getLineInfoForAddressRange(uint64_t Address,
uint64_t Size, DILineInfoSpecifier Specifier = DILineInfoSpecifier());
virtual DIInliningInfo getInliningInfoForAddress(uint64_t Address,
DILineInfoSpecifier Specifier = DILineInfoSpecifier());

Expand Down
75 changes: 75 additions & 0 deletions lib/DebugInfo/DWARFDebugLine.cpp
Expand Up @@ -524,6 +524,81 @@ DWARFDebugLine::LineTable::lookupAddress(uint64_t address) const {
return index;
}

bool
DWARFDebugLine::LineTable::lookupAddressRange(uint64_t address,
uint64_t size,
std::vector<uint32_t>& result) const {
if (Sequences.empty())
return false;
uint64_t end_addr = address + size;
// First, find an instruction sequence containing the given address.
DWARFDebugLine::Sequence sequence;
sequence.LowPC = address;
SequenceIter first_seq = Sequences.begin();
SequenceIter last_seq = Sequences.end();
SequenceIter seq_pos = std::lower_bound(first_seq, last_seq, sequence,
DWARFDebugLine::Sequence::orderByLowPC);
if (seq_pos == last_seq || seq_pos->LowPC != address) {
if (seq_pos == first_seq)
return false;
seq_pos--;
}
if (!seq_pos->containsPC(address))
return false;

SequenceIter start_pos = seq_pos;

// Add the rows from the first sequence to the vector, starting with the
// index we just calculated

while (seq_pos != last_seq && seq_pos->LowPC < end_addr) {
DWARFDebugLine::Sequence cur_seq = *seq_pos;
uint32_t first_row_index;
uint32_t last_row_index;
if (seq_pos == start_pos) {
// For the first sequence, we need to find which row in the sequence is the
// first in our range. Rows are stored in a vector, so we may use
// arithmetical operations with iterators.
DWARFDebugLine::Row row;
row.Address = address;
RowIter first_row = Rows.begin() + cur_seq.FirstRowIndex;
RowIter last_row = Rows.begin() + cur_seq.LastRowIndex;
RowIter row_pos = std::upper_bound(first_row, last_row, row,
DWARFDebugLine::Row::orderByAddress);
// The 'row_pos' iterator references the first row that is greater than
// our start address. Unless that's the first row, we want to start at
// the row before that.
first_row_index = cur_seq.FirstRowIndex + (row_pos - first_row);
if (row_pos != first_row)
--first_row_index;
} else
first_row_index = cur_seq.FirstRowIndex;

// For the last sequence in our range, we need to figure out the last row in
// range. For all other sequences we can go to the end of the sequence.
if (cur_seq.HighPC > end_addr) {
DWARFDebugLine::Row row;
row.Address = end_addr;
RowIter first_row = Rows.begin() + cur_seq.FirstRowIndex;
RowIter last_row = Rows.begin() + cur_seq.LastRowIndex;
RowIter row_pos = std::upper_bound(first_row, last_row, row,
DWARFDebugLine::Row::orderByAddress);
// The 'row_pos' iterator references the first row that is greater than
// our end address. The row before that is the last row we want.
last_row_index = cur_seq.FirstRowIndex + (row_pos - first_row) - 1;
} else
// Contrary to what you might expect, DWARFDebugLine::SequenceLastRowIndex
// isn't a valid index within the current sequence. It's that plus one.
last_row_index = cur_seq.LastRowIndex - 1;

for (uint32_t i = first_row_index; i <= last_row_index; ++i) {
result.push_back(i);
}

++seq_pos;
}
}

bool
DWARFDebugLine::LineTable::getFileNameByIndex(uint64_t FileIndex,
bool NeedsAbsoluteFilePath,
Expand Down
4 changes: 4 additions & 0 deletions lib/DebugInfo/DWARFDebugLine.h
Expand Up @@ -178,6 +178,10 @@ class DWARFDebugLine {
// or -1 if there is no such row.
uint32_t lookupAddress(uint64_t address) const;

bool lookupAddressRange(uint64_t address,
uint64_t size,
std::vector<uint32_t>& result) const;

// Extracts filename by its index in filename table in prologue.
// Returns true on success.
bool getFileNameByIndex(uint64_t FileIndex,
Expand Down
Binary file added test/DebugInfo/Inputs/test-parameters.o
Binary file not shown.
46 changes: 40 additions & 6 deletions test/DebugInfo/debuglineinfo.test
@@ -1,15 +1,49 @@
RUN: llvm-rtdyld -printline %p/Inputs/test-inline.o \
RUN: | FileCheck %s -check-prefix TEST_INLINE
RUN: llvm-rtdyld -printline %p/Inputs/test-parameters.o \
RUN: | FileCheck %s -check-prefix TEST_PARAMETERS

; This test verifies that relocations are correctly applied to the
; .debug_line section. If relocations are not applied the first two
; functions will be reported as both starting at address zero in the
; line number table.
; .debug_line section and exercises DIContext::getLineInfoForAddressRange().
; If relocations are not applied the first two functions will be reported as
; both starting at address zero in the; line number table.
TEST_INLINE: Function: _Z15test_parametersPfPA2_dR11char_structPPitm, Size = 170
TEST_INLINE-NEXT: Line info:test-inline.cpp, line:33
TEST_INLINE-NEXT: Line info @ 0: test-inline.cpp, line:33
TEST_INLINE-NEXT: Line info @ 35: test-inline.cpp, line:34
TEST_INLINE-NEXT: Line info @ 165: test-inline.cpp, line:35
TEST_INLINE-NEXT: Function: _Z3foov, Size = 3
TEST_INLINE-NEXT: Line info:test-inline.cpp, line:28
TEST_INLINE-NEXT: Line info @ 0: test-inline.cpp, line:28
TEST_INLINE-NEXT: Line info @ 2: test-inline.cpp, line:29
TEST_INLINE-NEXT: Line info @ 3: test-inline.cpp, line:29
TEST_INLINE-NEXT: Function: main, Size = 146
TEST_INLINE-NEXT: Line info:test-inline.cpp, line:39
TEST_INLINE-NEXT: Line info @ 0: test-inline.cpp, line:39
TEST_INLINE-NEXT: Line info @ 21: test-inline.cpp, line:41
TEST_INLINE-NEXT: Line info @ 39: test-inline.cpp, line:42
TEST_INLINE-NEXT: Line info @ 60: test-inline.cpp, line:44
TEST_INLINE-NEXT: Line info @ 80: test-inline.cpp, line:48
TEST_INLINE-NEXT: Line info @ 90: test-inline.cpp, line:45
TEST_INLINE-NEXT: Line info @ 95: test-inline.cpp, line:46
TEST_INLINE-NEXT: Line info @ 114: test-inline.cpp, line:48
TEST_INLINE-NEXT: Line info @ 141: test-inline.cpp, line:49
TEST_INLINE-NEXT: Line info @ 146: test-inline.cpp, line:49

; This test checks the case where all code is in a single section.
TEST_PARAMETERS: Function: _Z15test_parametersPfPA2_dR11char_structPPitm, Size = 170
TEST_PARAMETERS-NEXT: Line info @ 0: test-parameters.cpp, line:33
TEST_PARAMETERS-NEXT: Line info @ 35: test-parameters.cpp, line:34
TEST_PARAMETERS-NEXT: Line info @ 165: test-parameters.cpp, line:35
TEST_PARAMETERS-NEXT: Function: _Z3foov, Size = 3
TEST_PARAMETERS-NEXT: Line info @ 0: test-parameters.cpp, line:28
TEST_PARAMETERS-NEXT: Line info @ 2: test-parameters.cpp, line:29
TEST_PARAMETERS-NEXT: Function: main, Size = 146
TEST_PARAMETERS-NEXT: Line info @ 0: test-parameters.cpp, line:39
TEST_PARAMETERS-NEXT: Line info @ 21: test-parameters.cpp, line:41
TEST_PARAMETERS-NEXT: Line info @ 39: test-parameters.cpp, line:42
TEST_PARAMETERS-NEXT: Line info @ 60: test-parameters.cpp, line:44
TEST_PARAMETERS-NEXT: Line info @ 80: test-parameters.cpp, line:48
TEST_PARAMETERS-NEXT: Line info @ 90: test-parameters.cpp, line:45
TEST_PARAMETERS-NEXT: Line info @ 95: test-parameters.cpp, line:46
TEST_PARAMETERS-NEXT: Line info @ 114: test-parameters.cpp, line:48
TEST_PARAMETERS-NEXT: Line info @ 141: test-parameters.cpp, line:49
TEST_PARAMETERS-NEXT: Line info @ 146: test-parameters.cpp, line:49

10 changes: 8 additions & 2 deletions tools/llvm-rtdyld/llvm-rtdyld.cpp
Expand Up @@ -163,8 +163,14 @@ static int printLineInfoForInput() {

outs() << "Function: " << Name << ", Size = " << Size << "\n";

DILineInfo Result = Context->getLineInfoForAddress(Addr);
outs() << " Line info:" << Result.getFileName() << ", line:" << Result.getLine() << "\n";
DILineInfoTable Lines = Context->getLineInfoForAddressRange(Addr, Size);
DILineInfoTable::iterator Begin = Lines.begin();
DILineInfoTable::iterator End = Lines.end();
for (DILineInfoTable::iterator It = Begin; It != End; ++It) {
outs() << " Line info @ " << It->first - Addr << ": "
<< It->second.getFileName()
<< ", line:" << It->second.getLine() << "\n";
}
}
}
}
Expand Down

0 comments on commit e27a787

Please sign in to comment.