[Lldb-commits] [lldb] aa20767 - [lldb-dap] Implement command directives (#74808)
via lldb-commits
lldb-commits at lists.llvm.org
Thu Dec 14 12:04:40 PST 2023
Author: Walter Erquinigo
Date: 2023-12-14T15:04:35-05:00
New Revision: aa207674f9e6caf5bc29c1b4925183a398382d6f
URL: https://github.com/llvm/llvm-project/commit/aa207674f9e6caf5bc29c1b4925183a398382d6f
DIFF: https://github.com/llvm/llvm-project/commit/aa207674f9e6caf5bc29c1b4925183a398382d6f.diff
LOG: [lldb-dap] Implement command directives (#74808)
This adds support for optionally prefixing any command with `?` and/or
`!`.
- `?` prevents the output of a commands to be printed to the console
unless it fails.
- `!` aborts the dap if the command fails.
They come in handy when programmatically running commands on behalf of
the user without wanting them to know unless they fail, or when a
critical setup is required as part of launchCommands and it's better to
abort on failures than to silently skip.
Added:
lldb/test/API/tools/lldb-dap/commands/Makefile
lldb/test/API/tools/lldb-dap/commands/TestDAP_commands.py
lldb/test/API/tools/lldb-dap/commands/main.cpp
Modified:
lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py
lldb/tools/lldb-dap/DAP.cpp
lldb/tools/lldb-dap/DAP.h
lldb/tools/lldb-dap/LLDBUtils.cpp
lldb/tools/lldb-dap/LLDBUtils.h
lldb/tools/lldb-dap/lldb-dap.cpp
lldb/tools/lldb-dap/package.json
Removed:
################################################################################
diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py
index 4ccd6014e54be6..7436b9900e98b0 100644
--- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py
+++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py
@@ -291,6 +291,7 @@ def attach(
postRunCommands=None,
sourceMap=None,
sourceInitFile=False,
+ expectFailure=False,
):
"""Build the default Makefile target, create the DAP debug adaptor,
and attach to the process.
@@ -322,6 +323,8 @@ def cleanup():
postRunCommands=postRunCommands,
sourceMap=sourceMap,
)
+ if expectFailure:
+ return response
if not (response and response["success"]):
self.assertTrue(
response["success"], "attach failed (%s)" % (response["message"])
@@ -437,6 +440,8 @@ def build_and_launch(
commandEscapePrefix=None,
customFrameFormat=None,
customThreadFormat=None,
+ launchCommands=None,
+ expectFailure=False,
):
"""Build the default Makefile target, create the DAP debug adaptor,
and launch the process.
@@ -470,4 +475,6 @@ def build_and_launch(
commandEscapePrefix=commandEscapePrefix,
customFrameFormat=customFrameFormat,
customThreadFormat=customThreadFormat,
+ launchCommands=launchCommands,
+ expectFailure=expectFailure,
)
diff --git a/lldb/test/API/tools/lldb-dap/commands/Makefile b/lldb/test/API/tools/lldb-dap/commands/Makefile
new file mode 100644
index 00000000000000..99998b20bcb050
--- /dev/null
+++ b/lldb/test/API/tools/lldb-dap/commands/Makefile
@@ -0,0 +1,3 @@
+CXX_SOURCES := main.cpp
+
+include Makefile.rules
diff --git a/lldb/test/API/tools/lldb-dap/commands/TestDAP_commands.py b/lldb/test/API/tools/lldb-dap/commands/TestDAP_commands.py
new file mode 100644
index 00000000000000..226b9385fe719a
--- /dev/null
+++ b/lldb/test/API/tools/lldb-dap/commands/TestDAP_commands.py
@@ -0,0 +1,80 @@
+import os
+
+import dap_server
+import lldbdap_testcase
+from lldbsuite.test import lldbtest, lldbutil
+from lldbsuite.test.decorators import *
+
+
+class TestDAP_commands(lldbdap_testcase.DAPTestCaseBase):
+ def test_command_directive_quiet_on_success(self):
+ program = self.getBuildArtifact("a.out")
+ command_quiet = (
+ "settings set target.show-hex-variable-values-with-leading-zeroes false"
+ )
+ command_not_quiet = (
+ "settings set target.show-hex-variable-values-with-leading-zeroes true"
+ )
+ self.build_and_launch(
+ program,
+ initCommands=["?" + command_quiet, command_not_quiet],
+ terminateCommands=["?" + command_quiet, command_not_quiet],
+ stopCommands=["?" + command_quiet, command_not_quiet],
+ exitCommands=["?" + command_quiet, command_not_quiet],
+ )
+ full_output = self.collect_console(duration=1.0)
+ self.assertNotIn(command_quiet, full_output)
+ self.assertIn(command_not_quiet, full_output)
+
+ def do_test_abort_on_error(
+ self,
+ use_init_commands=False,
+ use_launch_commands=False,
+ use_pre_run_commands=False,
+ use_post_run_commands=False,
+ ):
+ program = self.getBuildArtifact("a.out")
+ command_quiet = (
+ "settings set target.show-hex-variable-values-with-leading-zeroes false"
+ )
+ command_abort_on_error = "settings set foo bar"
+ commands = ["?!" + command_quiet, "!" + command_abort_on_error]
+ self.build_and_launch(
+ program,
+ initCommands=commands if use_init_commands else None,
+ launchCommands=commands if use_launch_commands else None,
+ preRunCommands=commands if use_pre_run_commands else None,
+ postRunCommands=commands if use_post_run_commands else None,
+ expectFailure=True,
+ )
+ full_output = self.collect_console(duration=1.0)
+ self.assertNotIn(command_quiet, full_output)
+ self.assertIn(command_abort_on_error, full_output)
+
+ def test_command_directive_abort_on_error_init_commands(self):
+ self.do_test_abort_on_error(use_init_commands=True)
+
+ def test_command_directive_abort_on_error_launch_commands(self):
+ self.do_test_abort_on_error(use_launch_commands=True)
+
+ def test_command_directive_abort_on_error_pre_run_commands(self):
+ self.do_test_abort_on_error(use_pre_run_commands=True)
+
+ def test_command_directive_abort_on_error_post_run_commands(self):
+ self.do_test_abort_on_error(use_post_run_commands=True)
+
+ def test_command_directive_abort_on_error_attach_commands(self):
+ program = self.getBuildArtifact("a.out")
+ command_quiet = (
+ "settings set target.show-hex-variable-values-with-leading-zeroes false"
+ )
+ command_abort_on_error = "settings set foo bar"
+ self.build_and_create_debug_adaptor()
+ self.attach(
+ program,
+ attachCommands=["?!" + command_quiet, "!" + command_abort_on_error],
+ expectFailure=True,
+ )
+ full_output = self.collect_console(duration=1.0)
+ self.assertNotIn(command_quiet, full_output)
+ self.assertIn(command_abort_on_error, full_output)
diff --git a/lldb/test/API/tools/lldb-dap/commands/main.cpp b/lldb/test/API/tools/lldb-dap/commands/main.cpp
new file mode 100644
index 00000000000000..76e8197013aabc
--- /dev/null
+++ b/lldb/test/API/tools/lldb-dap/commands/main.cpp
@@ -0,0 +1 @@
+int main() { return 0; }
diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp
index 49266209739765..4b72c13f9215a8 100644
--- a/lldb/tools/lldb-dap/DAP.cpp
+++ b/lldb/tools/lldb-dap/DAP.cpp
@@ -434,20 +434,54 @@ ExpressionContext DAP::DetectExpressionContext(lldb::SBFrame &frame,
return ExpressionContext::Variable;
}
-void DAP::RunLLDBCommands(llvm::StringRef prefix,
- const std::vector<std::string> &commands) {
- SendOutput(OutputType::Console,
- llvm::StringRef(::RunLLDBCommands(prefix, commands)));
+bool DAP::RunLLDBCommands(llvm::StringRef prefix,
+ llvm::ArrayRef<std::string> commands) {
+ bool required_command_failed = false;
+ std::string output =
+ ::RunLLDBCommands(prefix, commands, required_command_failed);
+ SendOutput(OutputType::Console, output);
+ return !required_command_failed;
+}
+
+static llvm::Error createRunLLDBCommandsErrorMessage(llvm::StringRef category) {
+ return llvm::createStringError(
+ llvm::inconvertibleErrorCode(),
+ llvm::formatv(
+ "Failed to run {0} commands. See the Debug Console for more details.",
+ category)
+ .str()
+ .c_str());
+}
+
+llvm::Error
+DAP::RunAttachCommands(llvm::ArrayRef<std::string> attach_commands) {
+ if (!RunLLDBCommands("Running attachCommands:", attach_commands))
+ return createRunLLDBCommandsErrorMessage("attach");
+ return llvm::Error::success();
}
-void DAP::RunInitCommands() {
- RunLLDBCommands("Running initCommands:", init_commands);
+llvm::Error
+DAP::RunLaunchCommands(llvm::ArrayRef<std::string> launch_commands) {
+ if (!RunLLDBCommands("Running launchCommands:", launch_commands))
+ return createRunLLDBCommandsErrorMessage("launch");
+ return llvm::Error::success();
}
-void DAP::RunPreRunCommands() {
- RunLLDBCommands("Running preRunCommands:", pre_run_commands);
+llvm::Error DAP::RunInitCommands() {
+ if (!RunLLDBCommands("Running initCommands:", init_commands))
+ return createRunLLDBCommandsErrorMessage("initCommands");
+ return llvm::Error::success();
}
+llvm::Error DAP::RunPreRunCommands() {
+ if (!RunLLDBCommands("Running preRunCommands:", pre_run_commands))
+ return createRunLLDBCommandsErrorMessage("preRunCommands");
+ return llvm::Error::success();
+}
+
+void DAP::RunPostRunCommands() {
+ RunLLDBCommands("Running postRunCommands:", post_run_commands);
+}
void DAP::RunStopCommands() {
RunLLDBCommands("Running stopCommands:", stop_commands);
}
diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h
index c7d56a06bfa1fd..20817194de2d8d 100644
--- a/lldb/tools/lldb-dap/DAP.h
+++ b/lldb/tools/lldb-dap/DAP.h
@@ -158,6 +158,7 @@ struct DAP {
std::vector<ExceptionBreakpoint> exception_breakpoints;
std::vector<std::string> init_commands;
std::vector<std::string> pre_run_commands;
+ std::vector<std::string> post_run_commands;
std::vector<std::string> exit_commands;
std::vector<std::string> stop_commands;
std::vector<std::string> terminate_commands;
@@ -227,11 +228,17 @@ struct DAP {
ExpressionContext DetectExpressionContext(lldb::SBFrame &frame,
std::string &text);
- void RunLLDBCommands(llvm::StringRef prefix,
- const std::vector<std::string> &commands);
-
- void RunInitCommands();
- void RunPreRunCommands();
+ /// \return
+ /// \b false if a fatal error was found while executing these commands,
+ /// according to the rules of \a LLDBUtils::RunLLDBCommands.
+ bool RunLLDBCommands(llvm::StringRef prefix,
+ llvm::ArrayRef<std::string> commands);
+
+ llvm::Error RunAttachCommands(llvm::ArrayRef<std::string> attach_commands);
+ llvm::Error RunLaunchCommands(llvm::ArrayRef<std::string> launch_commands);
+ llvm::Error RunInitCommands();
+ llvm::Error RunPreRunCommands();
+ void RunPostRunCommands();
void RunStopCommands();
void RunExitCommands();
void RunTerminateCommands();
diff --git a/lldb/tools/lldb-dap/LLDBUtils.cpp b/lldb/tools/lldb-dap/LLDBUtils.cpp
index 955c11f636895b..35b7a986a8964b 100644
--- a/lldb/tools/lldb-dap/LLDBUtils.cpp
+++ b/lldb/tools/lldb-dap/LLDBUtils.cpp
@@ -11,40 +11,81 @@
namespace lldb_dap {
-void RunLLDBCommands(llvm::StringRef prefix,
+bool RunLLDBCommands(llvm::StringRef prefix,
const llvm::ArrayRef<std::string> &commands,
- llvm::raw_ostream &strm) {
+ llvm::raw_ostream &strm, bool parse_command_directives) {
if (commands.empty())
- return;
+ return true;
+
+ bool did_print_prefix = false;
+
lldb::SBCommandInterpreter interp = g_dap.debugger.GetCommandInterpreter();
- if (!prefix.empty())
- strm << prefix << "\n";
- for (const auto &command : commands) {
+ for (llvm::StringRef command : commands) {
lldb::SBCommandReturnObject result;
- strm << "(lldb) " << command << "\n";
- interp.HandleCommand(command.c_str(), result);
- auto output_len = result.GetOutputSize();
- if (output_len) {
- const char *output = result.GetOutput();
- strm << output;
+ bool quiet_on_success = false;
+ bool check_error = false;
+
+ while (parse_command_directives) {
+ if (command.starts_with("?")) {
+ command = command.drop_front();
+ quiet_on_success = true;
+ } else if (command.starts_with("!")) {
+ command = command.drop_front();
+ check_error = true;
+ } else {
+ break;
+ }
}
- auto error_len = result.GetErrorSize();
- if (error_len) {
- const char *error = result.GetError();
- strm << error;
+
+ interp.HandleCommand(command.str().c_str(), result);
+ const bool got_error = !result.Succeeded();
+ // The if statement below is assuming we always print out `!` prefixed
+ // lines. The only time we don't print is when we have `quiet_on_success ==
+ // true` and we don't have an error.
+ if (quiet_on_success ? got_error : true) {
+ if (!did_print_prefix && !prefix.empty()) {
+ strm << prefix << "\n";
+ did_print_prefix = true;
+ }
+ strm << "(lldb) " << command << "\n";
+ auto output_len = result.GetOutputSize();
+ if (output_len) {
+ const char *output = result.GetOutput();
+ strm << output;
+ }
+ auto error_len = result.GetErrorSize();
+ if (error_len) {
+ const char *error = result.GetError();
+ strm << error;
+ }
}
+ if (check_error && got_error)
+ return false; // Stop running commands.
}
+ return true;
}
std::string RunLLDBCommands(llvm::StringRef prefix,
- const llvm::ArrayRef<std::string> &commands) {
+ const llvm::ArrayRef<std::string> &commands,
+ bool &required_command_failed,
+ bool parse_command_directives) {
+ required_command_failed = false;
std::string s;
llvm::raw_string_ostream strm(s);
- RunLLDBCommands(prefix, commands, strm);
+ required_command_failed =
+ !RunLLDBCommands(prefix, commands, strm, parse_command_directives);
strm.flush();
return s;
}
+std::string
+RunLLDBCommandsVerbatim(llvm::StringRef prefix,
+ const llvm::ArrayRef<std::string> &commands) {
+ bool required_command_failed = false;
+ return RunLLDBCommands(prefix, commands, required_command_failed,
+ /*parse_command_directives=*/false);
+}
+
bool ThreadHasStopReason(lldb::SBThread &thread) {
switch (thread.GetStopReason()) {
case lldb::eStopReasonTrace:
diff --git a/lldb/tools/lldb-dap/LLDBUtils.h b/lldb/tools/lldb-dap/LLDBUtils.h
index a99f798835370d..ee701da2230fe0 100644
--- a/lldb/tools/lldb-dap/LLDBUtils.h
+++ b/lldb/tools/lldb-dap/LLDBUtils.h
@@ -23,6 +23,12 @@ namespace lldb_dap {
/// All output from every command, including the prompt + the command
/// is placed into the "strm" argument.
///
+/// Each individual command can be prefixed with \b ! and/or \b ? in no
+/// particular order. If \b ? is provided, then the output of that command is
+/// only emitted if it fails, and if \b ! is provided, then the output is
+/// emitted regardless, and \b false is returned without executing the
+/// remaining commands.
+///
/// \param[in] prefix
/// A string that will be printed into \a strm prior to emitting
/// the prompt + command and command output. Can be NULL.
@@ -33,9 +39,17 @@ namespace lldb_dap {
/// \param[in] strm
/// The stream that will receive the prefix, prompt + command and
/// all command output.
-void RunLLDBCommands(llvm::StringRef prefix,
+///
+/// \param[in] parse_command_directives
+/// If \b false, then command prefixes like \b ! or \b ? are not parsed and
+/// each command is executed verbatim.
+///
+/// \return
+/// \b true, unless a command prefixed with \b ! fails and parsing of
+/// command directives is enabled.
+bool RunLLDBCommands(llvm::StringRef prefix,
const llvm::ArrayRef<std::string> &commands,
- llvm::raw_ostream &strm);
+ llvm::raw_ostream &strm, bool parse_command_directives);
/// Run a list of LLDB commands in the LLDB command interpreter.
///
@@ -49,11 +63,26 @@ void RunLLDBCommands(llvm::StringRef prefix,
/// \param[in] commands
/// An array of LLDB commands to execute.
///
+/// \param[out] required_command_failed
+/// If parsing of command directives is enabled, this variable is set to
+/// \b true if one of the commands prefixed with \b ! fails.
+///
+/// \param[in] parse_command_directives
+/// If \b false, then command prefixes like \b ! or \b ? are not parsed and
+/// each command is executed verbatim.
+///
/// \return
/// A std::string that contains the prefix and all commands and
-/// command output
+/// command output.
std::string RunLLDBCommands(llvm::StringRef prefix,
- const llvm::ArrayRef<std::string> &commands);
+ 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(llvm::StringRef prefix,
+ const llvm::ArrayRef<std::string> &commands);
/// Check if a thread has a stop reason.
///
diff --git a/lldb/tools/lldb-dap/lldb-dap.cpp b/lldb/tools/lldb-dap/lldb-dap.cpp
index d6b593eba93eca..d36e9b4d1b0982 100644
--- a/lldb/tools/lldb-dap/lldb-dap.cpp
+++ b/lldb/tools/lldb-dap/lldb-dap.cpp
@@ -644,8 +644,7 @@ void request_attach(const llvm::json::Object &request) {
const uint64_t timeout_seconds = GetUnsigned(arguments, "timeout", 30);
g_dap.stop_at_entry =
core_file.empty() ? GetBoolean(arguments, "stopOnEntry", false) : true;
- std::vector<std::string> postRunCommands =
- GetStrings(arguments, "postRunCommands");
+ g_dap.post_run_commands = GetStrings(arguments, "postRunCommands");
const llvm::StringRef debuggerRoot = GetString(arguments, "debuggerRoot");
g_dap.enable_auto_variable_summaries =
GetBoolean(arguments, "enableAutoVariableSummaries", false);
@@ -664,7 +663,12 @@ void request_attach(const llvm::json::Object &request) {
llvm::sys::fs::set_current_path(debuggerRoot);
// Run any initialize LLDB commands the user specified in the launch.json
- g_dap.RunInitCommands();
+ if (llvm::Error err = g_dap.RunInitCommands()) {
+ response["success"] = false;
+ EmplaceSafeString(response, "message", llvm::toString(std::move(err)));
+ g_dap.SendJSON(llvm::json::Value(std::move(response)));
+ return;
+ }
SetSourceMapFromArguments(*arguments);
@@ -678,7 +682,12 @@ void request_attach(const llvm::json::Object &request) {
}
// Run any pre run LLDB commands the user specified in the launch.json
- g_dap.RunPreRunCommands();
+ if (llvm::Error err = g_dap.RunPreRunCommands()) {
+ response["success"] = false;
+ EmplaceSafeString(response, "message", llvm::toString(std::move(err)));
+ g_dap.SendJSON(llvm::json::Value(std::move(response)));
+ return;
+ }
if (pid == LLDB_INVALID_PROCESS_ID && wait_for) {
char attach_msg[256];
@@ -703,7 +712,12 @@ void request_attach(const llvm::json::Object &request) {
// We have "attachCommands" that are a set of commands that are expected
// to execute the commands after which a process should be created. If there
// is no valid process after running these commands, we have failed.
- g_dap.RunLLDBCommands("Running attachCommands:", attachCommands);
+ if (llvm::Error err = g_dap.RunAttachCommands(attachCommands)) {
+ response["success"] = false;
+ EmplaceSafeString(response, "message", llvm::toString(std::move(err)));
+ g_dap.SendJSON(llvm::json::Value(std::move(response)));
+ return;
+ }
// The custom commands might have created a new target so we should use the
// selected target after these commands are run.
g_dap.target = g_dap.debugger.GetSelectedTarget();
@@ -727,7 +741,7 @@ void request_attach(const llvm::json::Object &request) {
response["success"] = llvm::json::Value(false);
EmplaceSafeString(response, "message", std::string(error.GetCString()));
} else {
- g_dap.RunLLDBCommands("Running postRunCommands:", postRunCommands);
+ g_dap.RunPostRunCommands();
}
g_dap.SendJSON(llvm::json::Value(std::move(response)));
@@ -1270,7 +1284,8 @@ void request_evaluate(const llvm::json::Object &request) {
if (frame.IsValid()) {
g_dap.focus_tid = frame.GetThread().GetThreadID();
}
- auto result = RunLLDBCommands(llvm::StringRef(), {std::string(expression)});
+ auto result =
+ RunLLDBCommandsVerbatim(llvm::StringRef(), {std::string(expression)});
EmplaceSafeString(body, "result", result);
body.try_emplace("variablesReference", (int64_t)0);
} else {
@@ -1740,7 +1755,8 @@ lldb::SBError LaunchProcess(const llvm::json::Object &request) {
// Set the launch info so that run commands can access the configured
// launch details.
g_dap.target.SetLaunchInfo(launch_info);
- g_dap.RunLLDBCommands("Running launchCommands:", launchCommands);
+ if (llvm::Error err = g_dap.RunLaunchCommands(launchCommands))
+ error.SetErrorString(llvm::toString(std::move(err)).c_str());
// The custom commands might have created a new target so we should use the
// selected target after these commands are run.
g_dap.target = g_dap.debugger.GetSelectedTarget();
@@ -1797,8 +1813,7 @@ void request_launch(const llvm::json::Object &request) {
g_dap.stop_commands = GetStrings(arguments, "stopCommands");
g_dap.exit_commands = GetStrings(arguments, "exitCommands");
g_dap.terminate_commands = GetStrings(arguments, "terminateCommands");
- std::vector<std::string> postRunCommands =
- GetStrings(arguments, "postRunCommands");
+ g_dap.post_run_commands = GetStrings(arguments, "postRunCommands");
g_dap.stop_at_entry = GetBoolean(arguments, "stopOnEntry", false);
const llvm::StringRef debuggerRoot = GetString(arguments, "debuggerRoot");
g_dap.enable_auto_variable_summaries =
@@ -1820,7 +1835,12 @@ void request_launch(const llvm::json::Object &request) {
// Run any initialize LLDB commands the user specified in the launch.json.
// This is run before target is created, so commands can't do anything with
// the targets - preRunCommands are run with the target.
- g_dap.RunInitCommands();
+ if (llvm::Error err = g_dap.RunInitCommands()) {
+ response["success"] = false;
+ EmplaceSafeString(response, "message", llvm::toString(std::move(err)));
+ g_dap.SendJSON(llvm::json::Value(std::move(response)));
+ return;
+ }
SetSourceMapFromArguments(*arguments);
@@ -1834,7 +1854,12 @@ void request_launch(const llvm::json::Object &request) {
}
// Run any pre run LLDB commands the user specified in the launch.json
- g_dap.RunPreRunCommands();
+ if (llvm::Error err = g_dap.RunPreRunCommands()) {
+ response["success"] = false;
+ EmplaceSafeString(response, "message", llvm::toString(std::move(err)));
+ g_dap.SendJSON(llvm::json::Value(std::move(response)));
+ return;
+ }
status = LaunchProcess(request);
@@ -1842,7 +1867,7 @@ void request_launch(const llvm::json::Object &request) {
response["success"] = llvm::json::Value(false);
EmplaceSafeString(response, "message", std::string(status.GetCString()));
} else {
- g_dap.RunLLDBCommands("Running postRunCommands:", postRunCommands);
+ g_dap.RunPostRunCommands();
}
g_dap.SendJSON(llvm::json::Value(std::move(response)));
diff --git a/lldb/tools/lldb-dap/package.json b/lldb/tools/lldb-dap/package.json
index ebb1103d695e17..68cdade4439924 100644
--- a/lldb/tools/lldb-dap/package.json
+++ b/lldb/tools/lldb-dap/package.json
@@ -204,32 +204,32 @@
},
"initCommands": {
"type": "array",
- "description": "Initialization commands executed upon debugger startup.",
+ "description": "Initialization commands executed upon debugger startup. Each command can be prefixed with `!` and/or `?` in no particular order. If `?` is provided, then the output of the command is only emitted if it fails, and if `!` is provided, the debug session terminates if the command fails, in which case the output of the command is emitted regardless.",
"default": []
},
"preRunCommands": {
"type": "array",
- "description": "Commands executed just before the program is launched.",
+ "description": "Commands executed just before the program is launched. Each command can be prefixed with `!` and/or `?` in no particular order. If `?` is provided, then the output of the command is only emitted if it fails, and if `!` is provided, the debug session terminates if the command fails, in which case the output of the command is emitted regardless.",
"default": []
},
"postRunCommands": {
"type": "array",
- "description": "Commands executed just as soon as the program is successfully launched when it's in a stopped state prior to any automatic continuation.",
+ "description": "Commands executed just as soon as the program is successfully launched when it's in a stopped state prior to any automatic continuation. If a command is prefixed with `?`, then its output is only emitted if it fails. Unlike `initCommands` or `launchCommands`, the `!` prefix is ignored.",
"default": []
},
"launchCommands": {
"type": "array",
- "description": "Custom commands that are executed instead of launching a process. A target will be created with the launch arguments prior to executing these commands. The commands may optionally create a new target and must perform a launch. A valid process must exist after these commands complete or the \"launch\" will fail. Launch the process with \"process launch -s\" to make the process to at the entry point since lldb-dap will auto resume if necessary.",
+ "description": "Custom commands that are executed instead of launching a process. A target will be created with the launch arguments prior to executing these commands. The commands may optionally create a new target and must perform a launch. A valid process must exist after these commands complete or the \"launch\" will fail. Launch the process with \"process launch -s\" to make the process to at the entry point since lldb-dap will auto resume if necessary. Each command can be prefixed with `!` and/or `?` in no particular order. If `?` is provided, then the output of the command is only emitted if it fails, and if `!` is provided, the debug session terminates if the command fails, in which case the output of the command is emitted regardless.",
"default": []
},
"stopCommands": {
"type": "array",
- "description": "Commands executed each time the program stops.",
+ "description": "Commands executed each time the program stops. If a command is prefixed with `?`, then its output is only emitted if it fails. Unlike `initCommands` or `launchCommands`, the `!` prefix is ignored.",
"default": []
},
"exitCommands": {
"type": "array",
- "description": "Commands executed at the end of debugging session.",
+ "description": "Commands executed at the end of debugging session. If a command is prefixed with `?`, then its output is only emitted if it fails. Unlike `initCommands` or `launchCommands`, the `!` prefix is ignored.",
"default": []
},
"runInTerminal": {
@@ -309,32 +309,32 @@
},
"attachCommands": {
"type": "array",
- "description": "Custom commands that are executed instead of attaching to a process ID or to a process by name. These commands may optionally create a new target and must perform an attach. A valid process must exist after these commands complete or the \"attach\" will fail.",
+ "description": "Custom commands that are executed instead of attaching to a process ID or to a process by name. These commands may optionally create a new target and must perform an attach. A valid process must exist after these commands complete or the \"attach\" will fail. Each command can be prefixed with `!` and/or `?` in no particular order. If `?` is provided, then the output of the command is only emitted if it fails, and if `!` is provided, the debug session terminates if the command fails, in which case the output of the command is emitted regardless.",
"default": []
},
"initCommands": {
"type": "array",
- "description": "Initialization commands executed upon debugger startup.",
+ "description": "Initialization commands executed upon debugger startup. Each command can be prefixed with `!` and/or `?` in no particular order. If `?` is provided, then the output of the command is only emitted if it fails, and if `!` is provided, the debug session terminates if the command fails, in which case the output of the command is emitted regardless.",
"default": []
},
"preRunCommands": {
"type": "array",
- "description": "Commands executed just before the program is attached to.",
+ "description": "Commands executed just before the program is attached to. Each command can be prefixed with `!` and/or `?` in no particular order. If `?` is provided, then the output of the command is only emitted if it fails, and if `!` is provided, the debug session terminates if the command fails, in which case the output of the command is emitted regardless.",
"default": []
},
"postRunCommands": {
"type": "array",
- "description": "Commands executed just as soon as the program is successfully attached when it's in a stopped state prior to any automatic continuation.",
+ "description": "Commands executed just as soon as the program is successfully attached when it's in a stopped state prior to any automatic continuation. Each command can be prefixed with `!` and/or `?` in no particular order. If `?` is provided, then the output of the command is only emitted if it fails, and if `!` is provided, the debug session terminates if the command fails, in which case the output of the command is emitted regardless.",
"default": []
},
"stopCommands": {
"type": "array",
- "description": "Commands executed each time the program stops.",
+ "description": "Commands executed each time the program stops. If a command is prefixed with `?`, then its output is only emitted if it fails. Unlike `initCommands` or `attachCommands`, the `!` prefix is ignored.",
"default": []
},
"exitCommands": {
"type": "array",
- "description": "Commands executed at the end of debugging session.",
+ "description": "Commands executed at the end of debugging session. If a command is prefixed with `?`, then its output is only emitted if it fails. Unlike `initCommands` or `attachCommands`, the `!` prefix is ignored.",
"default": []
},
"coreFile": {
More information about the lldb-commits
mailing list