[lldb] Fix source display for artificial locations (#115876)

When retrieving the location of the function declaration, we were
dropping the file component on the floor, which resulted in an amusingly
confusing situation were we displayed the file containing the
implementation of the function, but used the line number of the
declaration. This patch fixes that.

It required a small refactor Function::GetStartLineSourceLineInfo to
return a SupportFile (instead of just the file spec), which in turn
necessitated changes in a couple of other places as well.
This commit is contained in:
Pavel Labath 2024-11-13 09:56:00 +01:00 committed by GitHub
parent 12dcaa2e1e
commit 39b2979a43
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 63 additions and 38 deletions

View File

@ -457,7 +457,8 @@ public:
/// ///
/// \param[out] line_no /// \param[out] line_no
/// The line number. /// The line number.
void GetStartLineSourceInfo(FileSpec &source_file, uint32_t &line_no); void GetStartLineSourceInfo(lldb::SupportFileSP &source_file_sp,
uint32_t &line_no);
/// Find the file and line number of the source location of the end of the /// Find the file and line number of the source location of the end of the
/// function. /// function.

View File

@ -139,21 +139,23 @@ void BreakpointResolverFileLine::FilterContexts(SymbolContextList &sc_list) {
if (!sc.block) if (!sc.block)
continue; continue;
FileSpec file; SupportFileSP file_sp;
uint32_t line; uint32_t line;
const Block *inline_block = sc.block->GetContainingInlinedBlock(); const Block *inline_block = sc.block->GetContainingInlinedBlock();
if (inline_block) { if (inline_block) {
const Declaration &inline_declaration = inline_block->GetInlinedFunctionInfo()->GetDeclaration(); const Declaration &inline_declaration = inline_block->GetInlinedFunctionInfo()->GetDeclaration();
if (!inline_declaration.IsValid()) if (!inline_declaration.IsValid())
continue; continue;
file = inline_declaration.GetFile(); file_sp = std::make_shared<SupportFile>(inline_declaration.GetFile());
line = inline_declaration.GetLine(); line = inline_declaration.GetLine();
} else if (sc.function) } else if (sc.function)
sc.function->GetStartLineSourceInfo(file, line); sc.function->GetStartLineSourceInfo(file_sp, line);
else else
continue; continue;
if (file != sc.line_entry.GetFile()) { if (!file_sp ||
!file_sp->Equal(*sc.line_entry.file_sp,
SupportFile::eEqualFileSpecAndChecksumIfSet)) {
LLDB_LOG(log, "unexpected symbol context file {0}", LLDB_LOG(log, "unexpected symbol context file {0}",
sc.line_entry.GetFile()); sc.line_entry.GetFile());
continue; continue;
@ -190,7 +192,8 @@ void BreakpointResolverFileLine::FilterContexts(SymbolContextList &sc_list) {
const int decl_line_is_too_late_fudge = 1; const int decl_line_is_too_late_fudge = 1;
if (line && if (line &&
m_location_spec.GetLine() < line - decl_line_is_too_late_fudge) { m_location_spec.GetLine() < line - decl_line_is_too_late_fudge) {
LLDB_LOG(log, "removing symbol context at {0}:{1}", file, line); LLDB_LOG(log, "removing symbol context at {0}:{1}",
file_sp->GetSpecOnly(), line);
sc_list.RemoveContextAtIndex(i); sc_list.RemoveContextAtIndex(i);
--i; --i;
} }

View File

@ -784,9 +784,7 @@ protected:
if (sc.block == nullptr) { if (sc.block == nullptr) {
// Not an inlined function // Not an inlined function
FileSpec function_file_spec; sc.function->GetStartLineSourceInfo(start_file, start_line);
sc.function->GetStartLineSourceInfo(function_file_spec, start_line);
start_file = std::make_shared<SupportFile>(function_file_spec);
if (start_line == 0) { if (start_line == 0) {
result.AppendErrorWithFormat("Could not find line information for " result.AppendErrorWithFormat("Could not find line information for "
"start of function: \"%s\".\n", "start of function: \"%s\".\n",

View File

@ -205,16 +205,20 @@ Disassembler::GetFunctionDeclLineEntry(const SymbolContext &sc) {
return {}; return {};
LineEntry prologue_end_line = sc.line_entry; LineEntry prologue_end_line = sc.line_entry;
FileSpec func_decl_file; SupportFileSP func_decl_file_sp;
uint32_t func_decl_line; uint32_t func_decl_line;
sc.function->GetStartLineSourceInfo(func_decl_file, func_decl_line); sc.function->GetStartLineSourceInfo(func_decl_file_sp, func_decl_line);
if (func_decl_file != prologue_end_line.GetFile() && if (!func_decl_file_sp)
func_decl_file != prologue_end_line.original_file_sp->GetSpecOnly()) return {};
if (!func_decl_file_sp->Equal(*prologue_end_line.file_sp,
SupportFile::eEqualFileSpecAndChecksumIfSet) &&
!func_decl_file_sp->Equal(*prologue_end_line.original_file_sp,
SupportFile::eEqualFileSpecAndChecksumIfSet))
return {}; return {};
SourceLine decl_line; SourceLine decl_line;
decl_line.file = func_decl_file; decl_line.file = func_decl_file_sp->GetSpecOnly();
decl_line.line = func_decl_line; decl_line.line = func_decl_line;
// TODO: Do we care about column on these entries? If so, we need to plumb // TODO: Do we care about column on these entries? If so, we need to plumb
// that through GetStartLineSourceInfo. // that through GetStartLineSourceInfo.
@ -410,20 +414,24 @@ void Disassembler::PrintInstructions(Debugger &debugger, const ArchSpec &arch,
LineEntry prologue_end_line = sc.line_entry; LineEntry prologue_end_line = sc.line_entry;
if (!ElideMixedSourceAndDisassemblyLine(exe_ctx, sc, if (!ElideMixedSourceAndDisassemblyLine(exe_ctx, sc,
prologue_end_line)) { prologue_end_line)) {
FileSpec func_decl_file; SupportFileSP func_decl_file_sp;
uint32_t func_decl_line; uint32_t func_decl_line;
sc.function->GetStartLineSourceInfo(func_decl_file, sc.function->GetStartLineSourceInfo(func_decl_file_sp,
func_decl_line); func_decl_line);
if (func_decl_file == prologue_end_line.GetFile() || if (func_decl_file_sp &&
func_decl_file == (func_decl_file_sp->Equal(
prologue_end_line.original_file_sp->GetSpecOnly()) { *prologue_end_line.file_sp,
SupportFile::eEqualFileSpecAndChecksumIfSet) ||
func_decl_file_sp->Equal(
*prologue_end_line.original_file_sp,
SupportFile::eEqualFileSpecAndChecksumIfSet))) {
// Add all the lines between the function declaration and // Add all the lines between the function declaration and
// the first non-prologue source line to the list of lines // the first non-prologue source line to the list of lines
// to print. // to print.
for (uint32_t lineno = func_decl_line; for (uint32_t lineno = func_decl_line;
lineno <= prologue_end_line.line; lineno++) { lineno <= prologue_end_line.line; lineno++) {
SourceLine this_line; SourceLine this_line;
this_line.file = func_decl_file; this_line.file = func_decl_file_sp->GetSpecOnly();
this_line.line = lineno; this_line.line = lineno;
source_lines_to_display.lines.push_back(this_line); source_lines_to_display.lines.push_back(this_line);
} }

View File

@ -287,10 +287,10 @@ Function::Function(CompileUnit *comp_unit, lldb::user_id_t func_uid,
Function::~Function() = default; Function::~Function() = default;
void Function::GetStartLineSourceInfo(FileSpec &source_file, void Function::GetStartLineSourceInfo(SupportFileSP &source_file_sp,
uint32_t &line_no) { uint32_t &line_no) {
line_no = 0; line_no = 0;
source_file.Clear(); source_file_sp.reset();
if (m_comp_unit == nullptr) if (m_comp_unit == nullptr)
return; return;
@ -299,7 +299,8 @@ void Function::GetStartLineSourceInfo(FileSpec &source_file,
GetType(); GetType();
if (m_type != nullptr && m_type->GetDeclaration().GetLine() != 0) { if (m_type != nullptr && m_type->GetDeclaration().GetLine() != 0) {
source_file = m_type->GetDeclaration().GetFile(); source_file_sp =
std::make_shared<SupportFile>(m_type->GetDeclaration().GetFile());
line_no = m_type->GetDeclaration().GetLine(); line_no = m_type->GetDeclaration().GetLine();
} else { } else {
LineTable *line_table = m_comp_unit->GetLineTable(); LineTable *line_table = m_comp_unit->GetLineTable();
@ -310,7 +311,7 @@ void Function::GetStartLineSourceInfo(FileSpec &source_file,
if (line_table->FindLineEntryByAddress(GetAddressRange().GetBaseAddress(), if (line_table->FindLineEntryByAddress(GetAddressRange().GetBaseAddress(),
line_entry, nullptr)) { line_entry, nullptr)) {
line_no = line_entry.line; line_no = line_entry.line;
source_file = line_entry.GetFile(); source_file_sp = line_entry.file_sp;
} }
} }
} }

View File

@ -1918,15 +1918,15 @@ bool StackFrame::GetStatus(Stream &strm, bool show_frame_info, bool show_source,
if (m_sc.comp_unit && m_sc.line_entry.IsValid()) { if (m_sc.comp_unit && m_sc.line_entry.IsValid()) {
have_debuginfo = true; have_debuginfo = true;
if (source_lines_before > 0 || source_lines_after > 0) { if (source_lines_before > 0 || source_lines_after > 0) {
SupportFileSP source_file_sp = m_sc.line_entry.file_sp;
uint32_t start_line = m_sc.line_entry.line; uint32_t start_line = m_sc.line_entry.line;
if (!start_line && m_sc.function) { if (!start_line && m_sc.function) {
FileSpec source_file; m_sc.function->GetStartLineSourceInfo(source_file_sp, start_line);
m_sc.function->GetStartLineSourceInfo(source_file, start_line);
} }
size_t num_lines = size_t num_lines =
target->GetSourceManager().DisplaySourceLinesWithLineNumbers( target->GetSourceManager().DisplaySourceLinesWithLineNumbers(
m_sc.line_entry.file_sp, start_line, m_sc.line_entry.column, source_file_sp, start_line, m_sc.line_entry.column,
source_lines_before, source_lines_after, "->", &strm); source_lines_before, source_lines_after, "->", &strm);
if (num_lines != 0) if (num_lines != 0)
have_source = true; have_source = true;

View File

@ -314,19 +314,28 @@ class SourceManagerTestCase(TestBase):
) )
def test_artificial_source_location(self): def test_artificial_source_location(self):
src_file = "artificial_location.c" src_file = "artificial_location.cpp"
d = {"C_SOURCES": src_file} d = {"C_SOURCES": "", "CXX_SOURCES": src_file}
self.build(dictionary=d) self.build(dictionary=d)
lldbutil.run_to_source_breakpoint( target = lldbutil.run_to_breakpoint_make_target(self)
self, "main", lldb.SBFileSpec(src_file, False)
) # Find the instruction with line=0 and put a breakpoint there.
sc_list = target.FindFunctions("A::foo")
self.assertEqual(len(sc_list), 1)
insns = sc_list[0].function.GetInstructions(target)
insn0 = next(filter(lambda insn: insn.addr.line_entry.line == 0, insns))
bkpt = target.BreakpointCreateBySBAddress(insn0.addr)
self.assertGreater(bkpt.GetNumLocations(), 0)
lldbutil.run_to_breakpoint_do_run(self, target, bkpt)
self.expect( self.expect(
"process status", "process status",
substrs=[ substrs=[
"stop reason = breakpoint", "stop reason = breakpoint",
f"{src_file}:0", f"{src_file}:0",
"static int foo();",
"Note: this address is compiler-generated code in function", "Note: this address is compiler-generated code in function",
"that has no source code associated with it.", "that has no source code associated with it.",
], ],

View File

@ -1,6 +0,0 @@
int foo() { return 42; }
int main() {
#line 0
return foo();
}

View File

@ -0,0 +1,8 @@
#include "artificial_location.h"
int A::foo() {
#line 0
return 42;
}
int main() { return A::foo(); }

View File

@ -0,0 +1,3 @@
struct A {
static int foo();
};