Skip to content

Commit dd8735e

Browse files
committed
use stop-disassembly-display setting to determine when to show disassembly
1 parent cbcebed commit dd8735e

File tree

14 files changed

+300
-17
lines changed

14 files changed

+300
-17
lines changed

lldb/test/API/tools/lldb-dap/coreFile/TestDAP_coreFile.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,33 +19,31 @@ def test_core_file(self):
1919
core_file = os.path.join(current_dir, "linux-x86_64.core")
2020

2121
self.create_debug_adapter()
22-
23-
source_map = [["/home/labath/test", current_dir]]
24-
self.attach(exe_file, coreFile=core_file, sourceMap=source_map)
22+
self.attach(exe_file, coreFile=core_file)
2523

2624
expected_frames = [
2725
{
2826
"column": 0,
2927
"id": 524288,
3028
"line": 4,
3129
"name": "bar",
32-
"source": {"name": "main.c", "path": os.path.join(current_dir, "main.c")},
30+
"source": {"name": "main.c", "path": "/home/labath/test/main.c"},
3331
"instructionPointerReference": "0x40011C",
3432
},
3533
{
3634
"column": 0,
3735
"id": 524289,
3836
"line": 10,
3937
"name": "foo",
40-
"source": {"name": "main.c", "path": os.path.join(current_dir, "main.c")},
38+
"source": {"name": "main.c", "path": "/home/labath/test/main.c"},
4139
"instructionPointerReference": "0x400142",
4240
},
4341
{
4442
"column": 0,
4543
"id": 524290,
4644
"line": 16,
4745
"name": "_start",
48-
"source": {"name": "main.c", "path": os.path.join(current_dir, "main.c")},
46+
"source": {"name": "main.c", "path": "/home/labath/test/main.c"},
4947
"instructionPointerReference": "0x40015F",
5048
},
5149
]
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
C_SOURCES := main.c other.c
2+
3+
include Makefile.rules
Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
"""
2+
Test lldb-dap stack trace when some of the source paths are missing
3+
"""
4+
5+
from lldbsuite.test.decorators import skipIfWindows
6+
from lldbsuite.test.lldbtest import line_number
7+
import lldbdap_testcase
8+
from contextlib import contextmanager
9+
import os
10+
11+
12+
OTHER_C_SOURCE_CODE = """
13+
int fibonacci(int n) {
14+
if (n < 0) return -1;
15+
if (n == 0) return 0;
16+
if (n == 1) return 1;
17+
int a = 0, b = 1, c;
18+
for (int i = 2; i <= n; ++i) {
19+
c = a + b;
20+
a = b;
21+
b = c;
22+
}
23+
24+
return b; // Break here
25+
}
26+
"""
27+
28+
29+
@contextmanager
30+
def delete_file_on_exit(path):
31+
try:
32+
yield path
33+
finally:
34+
if os.path.exists(path):
35+
os.remove(path)
36+
37+
38+
class TestDAP_stackTraceMissingSourcePath(lldbdap_testcase.DAPTestCaseBase):
39+
def build_and_run_until_breakpoint(self, stop_disassembly_display: str):
40+
"""
41+
Build the program and run until the breakpoint is hit, and return the stack frames.
42+
"""
43+
other_source_file = "other.c"
44+
with delete_file_on_exit(other_source_file):
45+
with open(other_source_file, "w") as f:
46+
f.write(OTHER_C_SOURCE_CODE)
47+
48+
breakpoint_line = line_number(other_source_file, "// Break here")
49+
50+
program = self.getBuildArtifact("a.out")
51+
init_commands = [
52+
f"settings set stop-disassembly-display {stop_disassembly_display}"
53+
]
54+
self.build_and_launch(program, initCommands=init_commands)
55+
56+
breakpoint_ids = self.set_source_breakpoints(
57+
other_source_file, [breakpoint_line]
58+
)
59+
self.assertEqual(
60+
len(breakpoint_ids), 1, "expect correct number of breakpoints"
61+
)
62+
63+
self.continue_to_breakpoints(breakpoint_ids)
64+
65+
frames = self.get_stackFrames()
66+
self.assertLessEqual(2, len(frames), "expect at least 2 frames")
67+
68+
self.assertIn(
69+
"path",
70+
frames[0]["source"],
71+
"Expect source path to always be in frame (other.c)",
72+
)
73+
self.assertIn(
74+
"path",
75+
frames[1]["source"],
76+
"Expect source path in always be in frame (main.c)",
77+
)
78+
79+
return frames
80+
81+
@skipIfWindows
82+
def test_stopDisassemblyDispay_noSource(self):
83+
"""
84+
Test that with with stop-disassembly-display = no-source - frames without source available give assembly code.
85+
"""
86+
frames = self.build_and_run_until_breakpoint("no-source")
87+
88+
self.assertNotIn(
89+
"other.c",
90+
frames[0]["source"]["path"],
91+
"Expect original source path to not be in unavailable source frame (other.c)",
92+
)
93+
self.assertIn(
94+
"sourceReference",
95+
frames[0]["source"],
96+
"Expect sourceReference source path in to be in unavailable source frame (other.c)",
97+
)
98+
99+
self.assertIn(
100+
"main.c",
101+
frames[1]["source"]["path"],
102+
"Expect original source path to be in source code frame (main.c)",
103+
)
104+
self.assertNotIn(
105+
"sourceReference",
106+
frames[1]["source"],
107+
"Expect no sourceReference in source code frame (main.c)",
108+
)
109+
110+
@skipIfWindows
111+
def test_stopDisassemblyDispay_noDebuginfo(self):
112+
"""
113+
Test that with with stop-disassembly-display = no-debuginfo - all frames give source code even when source not available.
114+
"""
115+
frames = self.build_and_run_until_breakpoint("no-debuginfo")
116+
117+
self.assertIn(
118+
"other.c",
119+
frames[0]["source"]["path"],
120+
"Expect original source path to be in unavailable source frame (other.c)",
121+
)
122+
self.assertNotIn(
123+
"sourceReference",
124+
frames[0]["source"],
125+
"Expect sourceReference source path in to be in unavailable source frame (other.c)",
126+
)
127+
128+
self.assertIn(
129+
"main.c",
130+
frames[1]["source"]["path"],
131+
"Expect original source path to be in source code frame (main.c)",
132+
)
133+
self.assertNotIn(
134+
"sourceReference",
135+
frames[1]["source"],
136+
"Expect no sourceReference in source code frame (main.c)",
137+
)
138+
139+
@skipIfWindows
140+
def test_stopDisassemblyDispay_never(self):
141+
"""
142+
Test that with with stop-disassembly-display = never - all frames don't give assembly code.
143+
"""
144+
frames = self.build_and_run_until_breakpoint("never")
145+
146+
self.assertIn(
147+
"other.c",
148+
frames[0]["source"]["path"],
149+
"Expect original source path to be in unavailable source frame (other.c)",
150+
)
151+
self.assertNotIn(
152+
"sourceReference",
153+
frames[0]["source"],
154+
"Expect sourceReference source path in to be in unavailable source frame (other.c)",
155+
)
156+
157+
self.assertIn(
158+
"main.c",
159+
frames[1]["source"]["path"],
160+
"Expect original source path to be in source code frame (main.c)",
161+
)
162+
self.assertNotIn(
163+
"sourceReference",
164+
frames[1]["source"],
165+
"Expect no sourceReference in source code frame (main.c)",
166+
)
167+
168+
@skipIfWindows
169+
def test_stopDisassemblyDispay_always(self):
170+
"""
171+
Test that with with stop-disassembly-display = always - all frames give source code.
172+
"""
173+
frames = self.build_and_run_until_breakpoint("always")
174+
175+
self.assertNotIn(
176+
"other.c",
177+
frames[0]["source"]["path"],
178+
"Expect original source path to not be in unavailable source frame (other.c)",
179+
)
180+
self.assertIn(
181+
"sourceReference",
182+
frames[0]["source"],
183+
"Expect sourceReference source path in to be in unavailable source frame (other.c)",
184+
)
185+
186+
self.assertNotIn(
187+
"main.c",
188+
frames[1]["source"]["path"],
189+
"Expect original source path to not be in source code frame (main.c)",
190+
)
191+
self.assertIn(
192+
"sourceReference",
193+
frames[1]["source"],
194+
"Expect sourceReference in source code frame (main.c)",
195+
)
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#include <stdint.h>
2+
#include <stdio.h>
3+
4+
int fibonacci(int n);
5+
6+
int main(int argc, char const *argv[]) {
7+
int result = fibonacci(10);
8+
printf("Fibonacci of 10 is: %d\n", result);
9+
return 0;
10+
}

lldb/tools/lldb-dap/DAP.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,10 @@ struct DAP {
202202

203203
lldb::SBFormat frame_format;
204204
lldb::SBFormat thread_format;
205+
206+
/// The value of stop-disassembly-display setting in LLDB.
207+
std::string stop_disassembly_display;
208+
205209
// This is used to allow request_evaluate to handle empty expressions
206210
// (ie the user pressed 'return' and expects the previous expression to
207211
// repeat). If the previous expression was a command, this string will be

lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ void AttachRequestHandler::operator()(const llvm::json::Object &request) const {
108108
}
109109

110110
SetSourceMapFromArguments(*arguments);
111+
SetStopDisassemblyDisplayFromSettings();
111112

112113
lldb::SBError status;
113114
dap.SetTarget(dap.CreateTargetFromArguments(*arguments, status));

lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ void LaunchRequestHandler::operator()(const llvm::json::Object &request) const {
9595
}
9696

9797
SetSourceMapFromArguments(*arguments);
98+
SetStopDisassemblyDisplayFromSettings();
9899

99100
lldb::SBError status;
100101
dap.SetTarget(dap.CreateTargetFromArguments(*arguments, status));

lldb/tools/lldb-dap/Handler/RequestHandler.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,10 @@ void BaseRequestHandler::SetSourceMapFromArguments(
9898
}
9999
}
100100

101+
void BaseRequestHandler::SetStopDisassemblyDisplayFromSettings() const {
102+
dap.stop_disassembly_display = GetStopDisassemblyDisplay(dap.debugger);
103+
}
104+
101105
static llvm::Error RunInTerminal(DAP &dap,
102106
const llvm::json::Object &launch_request,
103107
const uint64_t timeout_seconds) {

lldb/tools/lldb-dap/Handler/RequestHandler.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,9 @@ class BaseRequestHandler {
6363
/// argument (or neither), from which we need to set the target.source-map.
6464
void SetSourceMapFromArguments(const llvm::json::Object &arguments) const;
6565

66+
/// Sets the stop-disassembly-display setting
67+
void SetStopDisassemblyDisplayFromSettings() const;
68+
6669
/// Prints a welcome message on the editor if the preprocessor variable
6770
/// LLDB_DAP_WELCOME_MESSAGE is defined.
6871
void PrintWelcomeMessage() const;

lldb/tools/lldb-dap/Handler/StackTraceRequestHandler.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,8 @@ static bool FillStackFrames(DAP &dap, lldb::SBThread &thread,
6767
break;
6868
}
6969

70-
stack_frames.emplace_back(CreateStackFrame(frame, dap.frame_format));
70+
stack_frames.emplace_back(CreateStackFrame(frame, dap.frame_format,
71+
dap.stop_disassembly_display));
7172
}
7273

7374
if (dap.configuration.displayExtendedBacktrace && reached_end_of_stack) {

lldb/tools/lldb-dap/JSONUtils.cpp

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -658,6 +658,28 @@ llvm::json::Value CreateSource(llvm::StringRef source_path) {
658658
return llvm::json::Value(std::move(source));
659659
}
660660

661+
bool ShouldDisplayAssemblySource(const lldb::SBLineEntry &line_entry,
662+
const std::string &stop_disassembly_display) {
663+
if (stop_disassembly_display == "never")
664+
return false;
665+
666+
if (stop_disassembly_display == "always")
667+
return true;
668+
669+
// A line entry of 0 indicates the line is compiler generated i.e. no source
670+
// file is associated with the frame.
671+
auto file_spec = line_entry.GetFileSpec();
672+
if (!file_spec.IsValid() || line_entry.GetLine() == 0 ||
673+
line_entry.GetLine() == LLDB_INVALID_LINE_NUMBER)
674+
return true;
675+
676+
if (stop_disassembly_display == "no-source" && !file_spec.Exists()) {
677+
return true;
678+
}
679+
680+
return false;
681+
}
682+
661683
// "StackFrame": {
662684
// "type": "object",
663685
// "description": "A Stackframe contains the source location.",
@@ -719,8 +741,9 @@ llvm::json::Value CreateSource(llvm::StringRef source_path) {
719741
// },
720742
// "required": [ "id", "name", "line", "column" ]
721743
// }
722-
llvm::json::Value CreateStackFrame(lldb::SBFrame &frame,
723-
lldb::SBFormat &format) {
744+
llvm::json::Value
745+
CreateStackFrame(lldb::SBFrame &frame, lldb::SBFormat &format,
746+
const std::string &stop_disassembly_display) {
724747
llvm::json::Object object;
725748
int64_t frame_id = MakeDAPFrameID(frame);
726749
object.try_emplace("id", frame_id);
@@ -750,12 +773,7 @@ llvm::json::Value CreateStackFrame(lldb::SBFrame &frame,
750773
EmplaceSafeString(object, "name", frame_name);
751774

752775
auto line_entry = frame.GetLineEntry();
753-
auto file_spec = line_entry.GetFileSpec();
754-
// A line entry of 0 indicates the line is compiler generated i.e. no source
755-
// file is associated with the frame.
756-
if (file_spec.IsValid() && file_spec.Exists() &&
757-
(line_entry.GetLine() != 0 ||
758-
line_entry.GetLine() != LLDB_INVALID_LINE_NUMBER)) {
776+
if (!ShouldDisplayAssemblySource(line_entry, stop_disassembly_display)) {
759777
object.try_emplace("source", CreateSource(line_entry));
760778
object.try_emplace("line", line_entry.GetLine());
761779
auto column = line_entry.GetColumn();

lldb/tools/lldb-dap/JSONUtils.h

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,20 @@ llvm::json::Value CreateSource(const lldb::SBLineEntry &line_entry);
345345
/// definition outlined by Microsoft.
346346
llvm::json::Value CreateSource(llvm::StringRef source_path);
347347

348+
/// Return true if the given line entry should be displayed as assembly.
349+
///
350+
/// \param[in] line_entry
351+
/// The LLDB line entry to check.
352+
///
353+
/// \param[in] stop_disassembly_display
354+
/// The value of the "stop-disassembly-display" setting.
355+
///
356+
/// \return
357+
/// True if the line entry should be displayed as assembly, false
358+
/// otherwise.
359+
bool ShouldDisplayAssemblySource(const lldb::SBLineEntry &line_entry,
360+
const std::string &stop_disassembly_display);
361+
348362
/// Create a "StackFrame" object for a LLDB frame object.
349363
///
350364
/// This function will fill in the following keys in the returned
@@ -363,11 +377,14 @@ llvm::json::Value CreateSource(llvm::StringRef source_path);
363377
/// The LLDB format to use when populating out the "StackFrame"
364378
/// object.
365379
///
380+
/// \param[in] stop_disassembly_display
381+
/// The value of the "stop-disassembly-display" setting.
382+
///
366383
/// \return
367384
/// A "StackFrame" JSON object with that follows the formal JSON
368385
/// definition outlined by Microsoft.
369-
llvm::json::Value CreateStackFrame(lldb::SBFrame &frame,
370-
lldb::SBFormat &format);
386+
llvm::json::Value CreateStackFrame(lldb::SBFrame &frame, lldb::SBFormat &format,
387+
const std::string &stop_disassembly_display);
371388

372389
/// Create a "StackFrame" label object for a LLDB thread.
373390
///

0 commit comments

Comments
 (0)