Skip to content

[lldb][lldb-dap] fix repeating commands in repl mode #135008

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Apr 25, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ def run_test_evaluate_expressions(
if context == "repl":
# In the repl context expressions may be interpreted as lldb
# commands since no variables have the same name as the command.
self.assertEvaluate("list", r"\(lldb\) list\n.*")
self.assertEvaluate("list", r".*")
else:
self.assertEvaluateFailure("list") # local variable of a_function

Expand Down
4 changes: 1 addition & 3 deletions lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py
Original file line number Diff line number Diff line change
Expand Up @@ -522,11 +522,9 @@ def test_version(self):
)
version_eval_output = version_eval_response["body"]["result"]

# The first line is the prompt line like "(lldb) version", so we skip it.
version_eval_output_without_prompt_line = version_eval_output.splitlines()[1:]
version_string = self.dap_server.get_initialize_value("$__lldb_version")
self.assertEqual(
version_eval_output_without_prompt_line,
version_eval_output.splitlines(),
version_string.splitlines(),
"version string does not match",
)
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,12 @@ def test_completions(self):

self.set_source_breakpoints(source, [breakpoint1_line, breakpoint2_line])

self.assertEvaluate(
"`command regex user_command s/^$/platform/", r"\(lldb\) command regex"
)
self.assertEvaluate(
"`command alias alias_command platform", r"\(lldb\) command alias"
)
# The result of the commands should return the empty string.
self.assertEvaluate("`command regex user_command s/^$/platform/", r"^$")
self.assertEvaluate("`command alias alias_command platform", r"^$")
self.assertEvaluate(
"`command alias alias_command_with_arg platform select --sysroot %1 remote-linux",
r"\(lldb\) command alias",
r"^$",
)

self.continue_to_next_stop()
Expand Down
5 changes: 3 additions & 2 deletions lldb/tools/lldb-dap/DAP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -563,8 +563,9 @@ ReplMode DAP::DetectReplMode(lldb::SBFrame frame, std::string &expression,
bool DAP::RunLLDBCommands(llvm::StringRef prefix,
llvm::ArrayRef<std::string> commands) {
bool required_command_failed = false;
std::string output =
::RunLLDBCommands(debugger, prefix, commands, required_command_failed);
std::string output = ::RunLLDBCommands(
debugger, prefix, commands, required_command_failed,
/*parse_command_directives*/ true, /*echo_commands*/ true);
SendOutput(OutputType::Console, output);
return !required_command_failed;
}
Expand Down
8 changes: 6 additions & 2 deletions lldb/tools/lldb-dap/Handler/EvaluateRequestHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -163,8 +163,12 @@ void EvaluateRequestHandler::operator()(
if (frame.IsValid()) {
dap.focus_tid = frame.GetThread().GetThreadID();
}
auto result = RunLLDBCommandsVerbatim(dap.debugger, llvm::StringRef(),
{std::string(expression)});

bool required_command_failed = false;
std::string result = RunLLDBCommands(
dap.debugger, llvm::StringRef(), {expression}, required_command_failed,
/*parse_command_directives=*/false, /*echo_commands=*/false);

EmplaceSafeString(body, "result", result);
body.try_emplace("variablesReference", (int64_t)0);
} else {
Expand Down
39 changes: 26 additions & 13 deletions lldb/tools/lldb-dap/LLDBUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,29 @@ namespace lldb_dap {

bool RunLLDBCommands(lldb::SBDebugger &debugger, llvm::StringRef prefix,
const llvm::ArrayRef<std::string> &commands,
llvm::raw_ostream &strm, bool parse_command_directives) {
llvm::raw_ostream &strm, bool parse_command_directives,
bool echo_commands) {
if (commands.empty())
return true;

bool did_print_prefix = false;

// We only need the prompt when echoing commands.
std::string prompt_string;
if (echo_commands) {
prompt_string = "(lldb) ";

// Get the current prompt from settings.
if (const lldb::SBStructuredData prompt = debugger.GetSetting("prompt")) {
const size_t prompt_length = prompt.GetStringValue(nullptr, 0);

if (prompt_length != 0) {
prompt_string.resize(prompt_length + 1);
prompt.GetStringValue(prompt_string.data(), prompt_string.length());
}
}
}

lldb::SBCommandInterpreter interp = debugger.GetCommandInterpreter();
for (llvm::StringRef command : commands) {
lldb::SBCommandReturnObject result;
Expand Down Expand Up @@ -60,7 +77,10 @@ bool RunLLDBCommands(lldb::SBDebugger &debugger, llvm::StringRef prefix,
strm << prefix << "\n";
did_print_prefix = true;
}
strm << "(lldb) " << command << "\n";

if (echo_commands)
strm << prompt_string.c_str() << command << '\n';

auto output_len = result.GetOutputSize();
if (output_len) {
const char *output = result.GetOutput();
Expand All @@ -81,23 +101,16 @@ bool RunLLDBCommands(lldb::SBDebugger &debugger, llvm::StringRef prefix,
std::string RunLLDBCommands(lldb::SBDebugger &debugger, llvm::StringRef prefix,
const llvm::ArrayRef<std::string> &commands,
bool &required_command_failed,
bool parse_command_directives) {
bool parse_command_directives, bool echo_commands) {
required_command_failed = false;
std::string s;
llvm::raw_string_ostream strm(s);
required_command_failed = !RunLLDBCommands(debugger, prefix, commands, strm,
parse_command_directives);
required_command_failed =
!RunLLDBCommands(debugger, prefix, commands, strm,
parse_command_directives, echo_commands);
return s;
}

std::string
RunLLDBCommandsVerbatim(lldb::SBDebugger &debugger, llvm::StringRef prefix,
const llvm::ArrayRef<std::string> &commands) {
bool required_command_failed = false;
return RunLLDBCommands(debugger, prefix, commands, required_command_failed,
/*parse_command_directives=*/false);
}

bool ThreadHasStopReason(lldb::SBThread &thread) {
switch (thread.GetStopReason()) {
case lldb::eStopReasonTrace:
Expand Down
17 changes: 10 additions & 7 deletions lldb/tools/lldb-dap/LLDBUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,16 @@ namespace lldb_dap {
/// If \b false, then command prefixes like \b ! or \b ? are not parsed and
/// each command is executed verbatim.
///
/// \param[in] echo_commands
/// If \b true, the command are echoed to the stream.
///
/// \return
/// \b true, unless a command prefixed with \b ! fails and parsing of
/// command directives is enabled.
bool RunLLDBCommands(lldb::SBDebugger &debugger, llvm::StringRef prefix,
const llvm::ArrayRef<std::string> &commands,
llvm::raw_ostream &strm, bool parse_command_directives);
llvm::raw_ostream &strm, bool parse_command_directives,
bool echo_commands);

/// Run a list of LLDB commands in the LLDB command interpreter.
///
Expand All @@ -81,18 +85,17 @@ bool RunLLDBCommands(lldb::SBDebugger &debugger, llvm::StringRef prefix,
/// If \b false, then command prefixes like \b ! or \b ? are not parsed and
/// each command is executed verbatim.
///
/// \param[in] echo_commands
/// If \b true, the command are echoed to the stream.
///
/// \return
/// A std::string that contains the prefix and all commands and
/// command output.
std::string RunLLDBCommands(lldb::SBDebugger &debugger, llvm::StringRef prefix,
const llvm::ArrayRef<std::string> &commands,
bool &required_command_failed,
bool parse_command_directives = true);

/// Similar to the method above, but without parsing command directives.
std::string
RunLLDBCommandsVerbatim(lldb::SBDebugger &debugger, llvm::StringRef prefix,
const llvm::ArrayRef<std::string> &commands);
bool parse_command_directives = true,
bool echo_commands = false);

/// Check if a thread has a stop reason.
///
Expand Down
Loading