Skip to content

Commit d2062b8

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

File tree

14 files changed

+225
-17
lines changed

14 files changed

+225
-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: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
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+
@contextmanager
29+
def delete_file_on_exit(path):
30+
try:
31+
yield path
32+
finally:
33+
if os.path.exists(path):
34+
os.remove(path)
35+
36+
37+
class TestDAP_stackTraceMissingSourcePath(lldbdap_testcase.DAPTestCaseBase):
38+
def build_and_run_until_breakpoint(self, stop_disassembly_display: str):
39+
"""
40+
Build the program and run until the breakpoint is hit, and return the stack frames.
41+
"""
42+
other_source_file = "other.c"
43+
with delete_file_on_exit(other_source_file):
44+
with open(other_source_file, "w") as f:
45+
f.write(OTHER_C_SOURCE_CODE)
46+
47+
breakpoint_line = line_number(other_source_file, "// Break here")
48+
49+
program = self.getBuildArtifact("a.out")
50+
init_commands = [f"settings set stop-disassembly-display {stop_disassembly_display}"]
51+
self.build_and_launch(program, initCommands=init_commands)
52+
53+
breakpoint_ids = self.set_source_breakpoints(other_source_file, [breakpoint_line])
54+
self.assertEqual(
55+
len(breakpoint_ids), 1, "expect correct number of breakpoints"
56+
)
57+
58+
self.continue_to_breakpoints(breakpoint_ids)
59+
60+
frames = self.get_stackFrames()
61+
self.assertLessEqual(
62+
2, len(frames), "expect at least 2 frames"
63+
)
64+
65+
self.assertIn("path", frames[0]["source"], "Expect source path to always be in frame (other.c)")
66+
self.assertIn("path", frames[1]["source"], "Expect source path in always be in frame (main.c)")
67+
68+
return frames
69+
70+
@skipIfWindows
71+
def test_stopDisassemblyDispay_noSource(self):
72+
"""
73+
Test that with with stop-disassembly-display = no-source - frames without source available give assembly code.
74+
"""
75+
frames = self.build_and_run_until_breakpoint("no-source")
76+
77+
self.assertNotIn("other.c", frames[0]["source"]["path"], "Expect original source path to not be in unavailable source frame (other.c)")
78+
self.assertIn("sourceReference", frames[0]["source"], "Expect sourceReference source path in to be in unavailable source frame (other.c)")
79+
80+
self.assertIn("main.c", frames[1]["source"]["path"], "Expect original source path to be in source code frame (main.c)")
81+
self.assertNotIn("sourceReference", frames[1]["source"], "Expect no sourceReference in source code frame (main.c)")
82+
83+
@skipIfWindows
84+
def test_stopDisassemblyDispay_noDebuginfo(self):
85+
"""
86+
Test that with with stop-disassembly-display = no-debuginfo - all frames give source code even when source not available.
87+
"""
88+
frames = self.build_and_run_until_breakpoint("no-debuginfo")
89+
90+
self.assertIn("other.c", frames[0]["source"]["path"], "Expect original source path to be in unavailable source frame (other.c)")
91+
self.assertNotIn("sourceReference", frames[0]["source"], "Expect sourceReference source path in to be in unavailable source frame (other.c)")
92+
93+
self.assertIn("main.c", frames[1]["source"]["path"], "Expect original source path to be in source code frame (main.c)")
94+
self.assertNotIn("sourceReference", frames[1]["source"], "Expect no sourceReference in source code frame (main.c)")
95+
96+
@skipIfWindows
97+
def test_stopDisassemblyDispay_never(self):
98+
"""
99+
Test that with with stop-disassembly-display = never - all frames don't give assembly code.
100+
"""
101+
frames = self.build_and_run_until_breakpoint("never")
102+
103+
self.assertIn("other.c", frames[0]["source"]["path"], "Expect original source path to be in unavailable source frame (other.c)")
104+
self.assertNotIn("sourceReference", frames[0]["source"], "Expect sourceReference source path in to be in unavailable source frame (other.c)")
105+
106+
self.assertIn("main.c", frames[1]["source"]["path"], "Expect original source path to be in source code frame (main.c)")
107+
self.assertNotIn("sourceReference", frames[1]["source"], "Expect no sourceReference in source code frame (main.c)")
108+
109+
@skipIfWindows
110+
def test_stopDisassemblyDispay_always(self):
111+
"""
112+
Test that with with stop-disassembly-display = always - all frames give source code.
113+
"""
114+
frames = self.build_and_run_until_breakpoint("always")
115+
116+
self.assertNotIn("other.c", frames[0]["source"]["path"], "Expect original source path to not be in unavailable source frame (other.c)")
117+
self.assertIn("sourceReference", frames[0]["source"], "Expect sourceReference source path in to be in unavailable source frame (other.c)")
118+
119+
self.assertNotIn("main.c", frames[1]["source"]["path"], "Expect original source path to not be in source code frame (main.c)")
120+
self.assertIn("sourceReference", frames[1]["source"], "Expect sourceReference in source code frame (main.c)")
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
///

lldb/tools/lldb-dap/LLDBUtils.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,25 @@ GetEnvironmentFromArguments(const llvm::json::Object &arguments) {
163163
return envs;
164164
}
165165

166+
std::string GetStopDisassemblyDisplay(lldb::SBDebugger &debugger) {
167+
std::string stop_disassembly_display = "no-debuginfo"; // default value
168+
lldb::SBCommandReturnObject result;
169+
debugger.GetCommandInterpreter().HandleCommand(
170+
"settings show stop-disassembly-display", result);
171+
if (result.Succeeded()) {
172+
std::string output = result.GetOutput();
173+
size_t pos = output.find("stop-disassembly-display");
174+
if (pos != std::string::npos) {
175+
size_t start = output.find("= ", pos) + 2;
176+
size_t end = output.find("\n", start);
177+
stop_disassembly_display =
178+
output.substr(start, end - start); // trim whitespace
179+
}
180+
}
181+
182+
return stop_disassembly_display;
183+
}
184+
166185
llvm::Error ToError(const lldb::SBError &error) {
167186
if (error.Success())
168187
return llvm::Error::success();

lldb/tools/lldb-dap/LLDBUtils.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,15 @@ uint32_t GetLLDBFrameID(uint64_t dap_frame_id);
156156
lldb::SBEnvironment
157157
GetEnvironmentFromArguments(const llvm::json::Object &arguments);
158158

159+
/// Get the stop-disassembly-display settings
160+
///
161+
/// \param[in] debugger
162+
/// The debugger that will execute the lldb commands.
163+
///
164+
/// \return
165+
/// The value of the stop-disassembly-display setting
166+
std::string GetStopDisassemblyDisplay(lldb::SBDebugger &debugger);
167+
159168
/// Take ownership of the stored error.
160169
llvm::Error ToError(const lldb::SBError &error);
161170

0 commit comments

Comments
 (0)