[Lldb-commits] [lldb] dc25ab3 - [lldb]Make `list` command work with headers when possible. (#139002)
via lldb-commits
lldb-commits at lists.llvm.org
Mon May 19 08:04:04 PDT 2025
Author: Vy Nguyen
Date: 2025-05-19T11:04:01-04:00
New Revision: dc25ab389c2d441ba378d4db56a4a61e3eedb889
URL: https://github.com/llvm/llvm-project/commit/dc25ab389c2d441ba378d4db56a4a61e3eedb889
DIFF: https://github.com/llvm/llvm-project/commit/dc25ab389c2d441ba378d4db56a4a61e3eedb889.diff
LOG: [lldb]Make `list` command work with headers when possible. (#139002)
Given this simple test case:
```
// foo.h
extern int* ptr;
inline void g(int x) {
*ptr = x; // should raise a SIGILL
}
//--------------
// foo.cc
#include "foo.h"
int* ptr;
//--------------
// main.cc
#include "foo.h"
int main() {
g(123); // Call the inlined function and crash
return 0;
}
$ clang -g main.cc foo.cc -o main.out
$ lldb main.out
```
When you run `main.out` under lldb, it'd stop inside `void g(int)`
because of the crash.
The stack trace would show that it had crashed in `foo.h`, but if you do
`list foo.h:2`, lldb would complain that it could not find the source
file, which is confusing.
This patch make `list` work with headers.
Added:
lldb/test/Shell/Commands/list-header.test
Modified:
lldb/source/Commands/CommandObjectSource.cpp
Removed:
################################################################################
diff --git a/lldb/source/Commands/CommandObjectSource.cpp b/lldb/source/Commands/CommandObjectSource.cpp
index 8c87af590a372..7e7d3f065b622 100644
--- a/lldb/source/Commands/CommandObjectSource.cpp
+++ b/lldb/source/Commands/CommandObjectSource.cpp
@@ -1108,9 +1108,15 @@ class CommandObjectSourceList : public CommandObjectParsed {
}
}
} else {
- const char *filename = m_options.file_name.c_str();
-
+ // const char *filename = m_options.file_name.c_str();
+ FileSpec file_spec(m_options.file_name);
bool check_inlines = false;
+ const InlineStrategy inline_strategy = target.GetInlineStrategy();
+ if (inline_strategy == eInlineBreakpointsAlways ||
+ (inline_strategy == eInlineBreakpointsHeaders &&
+ !file_spec.IsSourceImplementationFile()))
+ check_inlines = true;
+
SymbolContextList sc_list;
size_t num_matches = 0;
@@ -1122,17 +1128,20 @@ class CommandObjectSourceList : public CommandObjectParsed {
ModuleSpec module_spec(module_file_spec);
matching_modules.Clear();
target.GetImages().FindModules(module_spec, matching_modules);
- num_matches += matching_modules.ResolveSymbolContextForFilePath(
- filename, 0, check_inlines,
+ num_matches += matching_modules.ResolveSymbolContextsForFileSpec(
+ file_spec, 1, check_inlines,
SymbolContextItem(eSymbolContextModule |
- eSymbolContextCompUnit),
+ eSymbolContextCompUnit |
+ eSymbolContextLineEntry),
sc_list);
}
}
} else {
- num_matches = target.GetImages().ResolveSymbolContextForFilePath(
- filename, 0, check_inlines,
- eSymbolContextModule | eSymbolContextCompUnit, sc_list);
+ num_matches = target.GetImages().ResolveSymbolContextsForFileSpec(
+ file_spec, 1, check_inlines,
+ eSymbolContextModule | eSymbolContextCompUnit |
+ eSymbolContextLineEntry,
+ sc_list);
}
if (num_matches == 0) {
@@ -1179,10 +1188,18 @@ class CommandObjectSourceList : public CommandObjectParsed {
if (m_options.num_lines == 0)
m_options.num_lines = 10;
const uint32_t column = 0;
+
+ // Headers aren't always in the DWARF but if they have
+ // executable code (eg., inlined-functions) then the callsite's
+ // file(s) will be found and assigned to
+ // sc.comp_unit->GetPrimarySupportFile, which is NOT what we want to
+ // print. Instead, we want to print the one from the line entry.
+ lldb::SupportFileSP found_file_sp = sc.line_entry.file_sp;
+
target.GetSourceManager().DisplaySourceLinesWithLineNumbers(
- sc.comp_unit->GetPrimarySupportFile(),
- m_options.start_line, column, 0, m_options.num_lines, "",
- &result.GetOutputStream(), GetBreakpointLocations());
+ found_file_sp, m_options.start_line, column, 0,
+ m_options.num_lines, "", &result.GetOutputStream(),
+ GetBreakpointLocations());
result.SetStatus(eReturnStatusSuccessFinishResult);
} else {
diff --git a/lldb/test/Shell/Commands/list-header.test b/lldb/test/Shell/Commands/list-header.test
new file mode 100644
index 0000000000000..08bcedd3fc946
--- /dev/null
+++ b/lldb/test/Shell/Commands/list-header.test
@@ -0,0 +1,57 @@
+## Test that `list header.h:<line>` works correctly when header is available.
+##
+# RUN: split-file %s %t
+
+# RUN: %clang_host -g %t/main_with_inlined.cc %t/foo.cc -o %t/main_with_inlined.out
+# RUN: %clang_host -g %t/main_no_inlined.cc %t/foo.cc -o %t/main_no_inlined.out
+
+# RUN: %lldb %t/main_with_inlined.out -o "list foo.h:2" -o "exit" 2>&1 \
+# RUN: | FileCheck %s --check-prefix=CHECK-INLINED
+
+## Would be nice if this listed the header too - but probably not something
+## we want to support right now.
+# RUN: echo quit | %lldb %t/main_no_inlined.out -o "list foo.h:2" -o "exit" 2>&1 \
+# RUN: | FileCheck %s --check-prefix=CHECK-NO-INLINED
+
+# CHECK-INLINED: 2 extern int* ptr;
+# CHECK-INLINED: 3 void f(int x);
+# CHECK-INLINED: 4
+# CHECK-INLINED: 5 inline void g(int x) {
+# CHECK-INLINED: 6 *ptr = x; // should crash here
+# CHECK-INLINED: 7 }
+
+# CHECK-NO-INLINED: error: Could not find source file "foo.h".
+
+#--- foo.h
+// foo.h
+extern int* ptr;
+void f(int x);
+
+inline void g(int x) {
+ *ptr = x; // should crash here
+}
+
+#--- foo.cc
+#include "foo.h"
+
+int* ptr;
+
+void f(int x) {
+ *ptr = x;
+}
+
+#--- main_with_inlined.cc
+#include "foo.h"
+
+int main() {
+ g(123); // Call the inlined function
+ return 0;
+}
+
+#--- main_no_inlined.cc
+#include "foo.h"
+
+int main() {
+ f(234);
+ return 0;
+}
More information about the lldb-commits
mailing list