Skip to content

Commit dc25ab3

Browse files
authored
[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.
1 parent 59f8af3 commit dc25ab3

File tree

2 files changed

+85
-11
lines changed

2 files changed

+85
-11
lines changed

lldb/source/Commands/CommandObjectSource.cpp

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1108,9 +1108,15 @@ class CommandObjectSourceList : public CommandObjectParsed {
11081108
}
11091109
}
11101110
} else {
1111-
const char *filename = m_options.file_name.c_str();
1112-
1111+
// const char *filename = m_options.file_name.c_str();
1112+
FileSpec file_spec(m_options.file_name);
11131113
bool check_inlines = false;
1114+
const InlineStrategy inline_strategy = target.GetInlineStrategy();
1115+
if (inline_strategy == eInlineBreakpointsAlways ||
1116+
(inline_strategy == eInlineBreakpointsHeaders &&
1117+
!file_spec.IsSourceImplementationFile()))
1118+
check_inlines = true;
1119+
11141120
SymbolContextList sc_list;
11151121
size_t num_matches = 0;
11161122

@@ -1122,17 +1128,20 @@ class CommandObjectSourceList : public CommandObjectParsed {
11221128
ModuleSpec module_spec(module_file_spec);
11231129
matching_modules.Clear();
11241130
target.GetImages().FindModules(module_spec, matching_modules);
1125-
num_matches += matching_modules.ResolveSymbolContextForFilePath(
1126-
filename, 0, check_inlines,
1131+
num_matches += matching_modules.ResolveSymbolContextsForFileSpec(
1132+
file_spec, 1, check_inlines,
11271133
SymbolContextItem(eSymbolContextModule |
1128-
eSymbolContextCompUnit),
1134+
eSymbolContextCompUnit |
1135+
eSymbolContextLineEntry),
11291136
sc_list);
11301137
}
11311138
}
11321139
} else {
1133-
num_matches = target.GetImages().ResolveSymbolContextForFilePath(
1134-
filename, 0, check_inlines,
1135-
eSymbolContextModule | eSymbolContextCompUnit, sc_list);
1140+
num_matches = target.GetImages().ResolveSymbolContextsForFileSpec(
1141+
file_spec, 1, check_inlines,
1142+
eSymbolContextModule | eSymbolContextCompUnit |
1143+
eSymbolContextLineEntry,
1144+
sc_list);
11361145
}
11371146

11381147
if (num_matches == 0) {
@@ -1179,10 +1188,18 @@ class CommandObjectSourceList : public CommandObjectParsed {
11791188
if (m_options.num_lines == 0)
11801189
m_options.num_lines = 10;
11811190
const uint32_t column = 0;
1191+
1192+
// Headers aren't always in the DWARF but if they have
1193+
// executable code (eg., inlined-functions) then the callsite's
1194+
// file(s) will be found and assigned to
1195+
// sc.comp_unit->GetPrimarySupportFile, which is NOT what we want to
1196+
// print. Instead, we want to print the one from the line entry.
1197+
lldb::SupportFileSP found_file_sp = sc.line_entry.file_sp;
1198+
11821199
target.GetSourceManager().DisplaySourceLinesWithLineNumbers(
1183-
sc.comp_unit->GetPrimarySupportFile(),
1184-
m_options.start_line, column, 0, m_options.num_lines, "",
1185-
&result.GetOutputStream(), GetBreakpointLocations());
1200+
found_file_sp, m_options.start_line, column, 0,
1201+
m_options.num_lines, "", &result.GetOutputStream(),
1202+
GetBreakpointLocations());
11861203

11871204
result.SetStatus(eReturnStatusSuccessFinishResult);
11881205
} else {
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
## Test that `list header.h:<line>` works correctly when header is available.
2+
##
3+
# RUN: split-file %s %t
4+
5+
# RUN: %clang_host -g %t/main_with_inlined.cc %t/foo.cc -o %t/main_with_inlined.out
6+
# RUN: %clang_host -g %t/main_no_inlined.cc %t/foo.cc -o %t/main_no_inlined.out
7+
8+
# RUN: %lldb %t/main_with_inlined.out -o "list foo.h:2" -o "exit" 2>&1 \
9+
# RUN: | FileCheck %s --check-prefix=CHECK-INLINED
10+
11+
## Would be nice if this listed the header too - but probably not something
12+
## we want to support right now.
13+
# RUN: echo quit | %lldb %t/main_no_inlined.out -o "list foo.h:2" -o "exit" 2>&1 \
14+
# RUN: | FileCheck %s --check-prefix=CHECK-NO-INLINED
15+
16+
# CHECK-INLINED: 2 extern int* ptr;
17+
# CHECK-INLINED: 3 void f(int x);
18+
# CHECK-INLINED: 4
19+
# CHECK-INLINED: 5 inline void g(int x) {
20+
# CHECK-INLINED: 6 *ptr = x; // should crash here
21+
# CHECK-INLINED: 7 }
22+
23+
# CHECK-NO-INLINED: error: Could not find source file "foo.h".
24+
25+
#--- foo.h
26+
// foo.h
27+
extern int* ptr;
28+
void f(int x);
29+
30+
inline void g(int x) {
31+
*ptr = x; // should crash here
32+
}
33+
34+
#--- foo.cc
35+
#include "foo.h"
36+
37+
int* ptr;
38+
39+
void f(int x) {
40+
*ptr = x;
41+
}
42+
43+
#--- main_with_inlined.cc
44+
#include "foo.h"
45+
46+
int main() {
47+
g(123); // Call the inlined function
48+
return 0;
49+
}
50+
51+
#--- main_no_inlined.cc
52+
#include "foo.h"
53+
54+
int main() {
55+
f(234);
56+
return 0;
57+
}

0 commit comments

Comments
 (0)