diff --git a/include/llvm/DebugInfo/DIContext.h b/include/llvm/DebugInfo/DIContext.h index 5cb1a17432d..a2c3f03ee81 100644 --- a/include/llvm/DebugInfo/DIContext.h +++ b/include/llvm/DebugInfo/DIContext.h @@ -58,6 +58,8 @@ public: } }; +typedef SmallVector, 16> DILineInfoTable; + /// DIInliningInfo - a format-neutral container for inlined code description. class DIInliningInfo { SmallVector Frames; @@ -126,6 +128,8 @@ public: 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; }; diff --git a/lib/DebugInfo/DWARFContext.cpp b/lib/DebugInfo/DWARFContext.cpp index 66d299bad28..768427fab07 100644 --- a/lib/DebugInfo/DWARFContext.cpp +++ b/lib/DebugInfo/DWARFContext.cpp @@ -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 = ""; + 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(""), + 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 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 = ""; + 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); diff --git a/lib/DebugInfo/DWARFContext.h b/lib/DebugInfo/DWARFContext.h index d6314b87c33..9ff094bd484 100644 --- a/lib/DebugInfo/DWARFContext.h +++ b/lib/DebugInfo/DWARFContext.h @@ -90,6 +90,8 @@ public: 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()); diff --git a/lib/DebugInfo/DWARFDebugLine.cpp b/lib/DebugInfo/DWARFDebugLine.cpp index 16ef896ca7e..7b32d4fe9ed 100644 --- a/lib/DebugInfo/DWARFDebugLine.cpp +++ b/lib/DebugInfo/DWARFDebugLine.cpp @@ -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& 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, diff --git a/lib/DebugInfo/DWARFDebugLine.h b/lib/DebugInfo/DWARFDebugLine.h index dbaf91d321f..2990756bd7c 100644 --- a/lib/DebugInfo/DWARFDebugLine.h +++ b/lib/DebugInfo/DWARFDebugLine.h @@ -178,6 +178,10 @@ public: // 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& result) const; + // Extracts filename by its index in filename table in prologue. // Returns true on success. bool getFileNameByIndex(uint64_t FileIndex, diff --git a/test/DebugInfo/Inputs/test-parameters.o b/test/DebugInfo/Inputs/test-parameters.o new file mode 100644 index 00000000000..7f4b6702df2 Binary files /dev/null and b/test/DebugInfo/Inputs/test-parameters.o differ diff --git a/test/DebugInfo/debuglineinfo.test b/test/DebugInfo/debuglineinfo.test index 78de390a8b1..14d2f82b04a 100644 --- a/test/DebugInfo/debuglineinfo.test +++ b/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 diff --git a/tools/llvm-rtdyld/llvm-rtdyld.cpp b/tools/llvm-rtdyld/llvm-rtdyld.cpp index 8b71a4f3641..4d8d345894d 100644 --- a/tools/llvm-rtdyld/llvm-rtdyld.cpp +++ b/tools/llvm-rtdyld/llvm-rtdyld.cpp @@ -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"; + } } } }