Skip to content

Commit a0aa5f8

Browse files
ashgtiJDevlieghere
andauthored
[lldb-dap] Refactoring lldb-dap 'launch' request to use typed RequestHandler<>. (#133624)
This converts a number of json::Value's into well defined types that are used throughout lldb-dap and updates the 'launch' command to use the new well defined types. --------- Co-authored-by: Jonas Devlieghere <[email protected]>
1 parent 785ab45 commit a0aa5f8

File tree

15 files changed

+535
-239
lines changed

15 files changed

+535
-239
lines changed

lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -860,7 +860,8 @@ def request_launch(
860860
args_dict["enableAutoVariableSummaries"] = enableAutoVariableSummaries
861861
args_dict["enableSyntheticChildDebugging"] = enableSyntheticChildDebugging
862862
args_dict["displayExtendedBacktrace"] = displayExtendedBacktrace
863-
args_dict["commandEscapePrefix"] = commandEscapePrefix
863+
if commandEscapePrefix:
864+
args_dict["commandEscapePrefix"] = commandEscapePrefix
864865
command_dict = {"command": "launch", "type": "request", "arguments": args_dict}
865866
response = self.send_recv(command_dict)
866867

lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -453,7 +453,8 @@ def cleanup():
453453

454454
if not (response and response["success"]):
455455
self.assertTrue(
456-
response["success"], "launch failed (%s)" % (response["message"])
456+
response["success"],
457+
"launch failed (%s)" % (response["body"]["error"]["format"]),
457458
)
458459
return response
459460

lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,34 @@ def test_default(self):
2727
lines = output.splitlines()
2828
self.assertIn(program, lines[0], "make sure program path is in first argument")
2929

30+
def test_failing_launch_program(self):
31+
"""
32+
Tests launching with an invalid program.
33+
"""
34+
program = self.getBuildArtifact("a.out")
35+
self.create_debug_adapter()
36+
response = self.launch(program, expectFailure=True)
37+
self.assertFalse(response["success"])
38+
self.assertEqual(
39+
"'{0}' does not exist".format(program), response["body"]["error"]["format"]
40+
)
41+
42+
def test_failing_launch_commands_and_run_in_terminal(self):
43+
"""
44+
Tests launching with an invalid program.
45+
"""
46+
program = self.getBuildArtifact("a.out")
47+
self.create_debug_adapter()
48+
response = self.launch(
49+
program, launchCommands=["a b c"], runInTerminal=True, expectFailure=True
50+
)
51+
self.assertFalse(response["success"])
52+
self.assertTrue(self.get_dict_value(response, ["body", "error", "showUser"]))
53+
self.assertEqual(
54+
"launchCommands and runInTerminal are mutually exclusive",
55+
self.get_dict_value(response, ["body", "error", "format"]),
56+
)
57+
3058
@skipIfWindows
3159
def test_termination(self):
3260
"""
@@ -42,7 +70,9 @@ def test_termination(self):
4270
self.dap_server.request_disconnect()
4371

4472
# Wait until the underlying lldb-dap process dies.
45-
self.dap_server.process.wait(timeout=lldbdap_testcase.DAPTestCaseBase.timeoutval)
73+
self.dap_server.process.wait(
74+
timeout=lldbdap_testcase.DAPTestCaseBase.timeoutval
75+
)
4676

4777
# Check the return code
4878
self.assertEqual(self.dap_server.process.poll(), 0)
@@ -460,7 +490,7 @@ def test_failing_launch_commands(self):
460490

461491
self.assertFalse(response["success"])
462492
self.assertRegex(
463-
response["message"],
493+
response["body"]["error"]["format"],
464494
r"Failed to run launch commands\. See the Debug Console for more details",
465495
)
466496

lldb/tools/lldb-dap/DAP.cpp

Lines changed: 38 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -660,9 +660,7 @@ void DAP::RunTerminateCommands() {
660660
configuration.terminateCommands);
661661
}
662662

663-
lldb::SBTarget
664-
DAP::CreateTargetFromArguments(const llvm::json::Object &arguments,
665-
lldb::SBError &error) {
663+
lldb::SBTarget DAP::CreateTarget(lldb::SBError &error) {
666664
// Grab the name of the program we need to debug and create a target using
667665
// the given program as an argument. Executable file can be a source of target
668666
// architecture and platform, if they differ from the host. Setting exe path
@@ -671,25 +669,15 @@ DAP::CreateTargetFromArguments(const llvm::json::Object &arguments,
671669
// creation. We also use target triple and platform from the launch
672670
// configuration, if given, since in some cases ELF file doesn't contain
673671
// enough information to determine correct arch and platform (or ELF can be
674-
// omitted at all), so it is good to leave the user an apportunity to specify
672+
// omitted at all), so it is good to leave the user an opportunity to specify
675673
// those. Any of those three can be left empty.
676-
const llvm::StringRef target_triple =
677-
GetString(arguments, "targetTriple").value_or("");
678-
const llvm::StringRef platform_name =
679-
GetString(arguments, "platformName").value_or("");
680-
const llvm::StringRef program = GetString(arguments, "program").value_or("");
681674
auto target = this->debugger.CreateTarget(
682-
program.data(), target_triple.data(), platform_name.data(),
675+
configuration.program.value_or("").data(),
676+
configuration.targetTriple.value_or("").data(),
677+
configuration.platformName.value_or("").data(),
683678
true, // Add dependent modules.
684679
error);
685680

686-
if (error.Fail()) {
687-
// Update message if there was an error.
688-
error.SetErrorStringWithFormat(
689-
"Could not create a target for a program '%s': %s.", program.data(),
690-
error.GetCString());
691-
}
692-
693681
return target;
694682
}
695683

@@ -945,7 +933,7 @@ llvm::Error DAP::Loop() {
945933
return queue_reader.get();
946934
}
947935

948-
lldb::SBError DAP::WaitForProcessToStop(uint32_t seconds) {
936+
lldb::SBError DAP::WaitForProcessToStop(std::chrono::seconds seconds) {
949937
lldb::SBError error;
950938
lldb::SBProcess process = target.GetProcess();
951939
if (!process.IsValid()) {
@@ -980,8 +968,8 @@ lldb::SBError DAP::WaitForProcessToStop(uint32_t seconds) {
980968
}
981969
std::this_thread::sleep_for(std::chrono::microseconds(250));
982970
}
983-
error.SetErrorStringWithFormat("process failed to stop within %u seconds",
984-
seconds);
971+
error.SetErrorStringWithFormat("process failed to stop within %lld seconds",
972+
seconds.count());
985973
return error;
986974
}
987975

@@ -1178,6 +1166,36 @@ bool SendEventRequestHandler::DoExecute(lldb::SBDebugger debugger,
11781166
return true;
11791167
}
11801168

1169+
void DAP::ConfigureSourceMaps() {
1170+
if (configuration.sourceMap.empty() && !configuration.sourcePath)
1171+
return;
1172+
1173+
std::string sourceMapCommand;
1174+
llvm::raw_string_ostream strm(sourceMapCommand);
1175+
strm << "settings set target.source-map ";
1176+
1177+
if (!configuration.sourceMap.empty()) {
1178+
for (const auto &kv : configuration.sourceMap) {
1179+
strm << "\"" << kv.first << "\" \"" << kv.second << "\" ";
1180+
}
1181+
} else if (configuration.sourcePath) {
1182+
strm << "\".\" \"" << *configuration.sourcePath << "\"";
1183+
}
1184+
1185+
RunLLDBCommands("Setting source map:", {sourceMapCommand});
1186+
}
1187+
1188+
void DAP::SetConfiguration(const protocol::Configuration &config,
1189+
bool is_attach) {
1190+
configuration = config;
1191+
this->is_attach = is_attach;
1192+
1193+
if (configuration.customFrameFormat)
1194+
SetFrameFormat(*configuration.customFrameFormat);
1195+
if (configuration.customThreadFormat)
1196+
SetThreadFormat(*configuration.customThreadFormat);
1197+
}
1198+
11811199
void DAP::SetFrameFormat(llvm::StringRef format) {
11821200
if (format.empty())
11831201
return;

lldb/tools/lldb-dap/DAP.h

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
#include "lldb/lldb-types.h"
3636
#include "llvm/ADT/DenseMap.h"
3737
#include "llvm/ADT/DenseSet.h"
38+
#include "llvm/ADT/FunctionExtras.h"
3839
#include "llvm/ADT/SmallSet.h"
3940
#include "llvm/ADT/StringMap.h"
4041
#include "llvm/ADT/StringRef.h"
@@ -175,9 +176,9 @@ struct DAP {
175176
llvm::once_flag init_exception_breakpoints_flag;
176177
// Map step in target id to list of function targets that user can choose.
177178
llvm::DenseMap<lldb::addr_t, std::string> step_in_targets;
178-
// A copy of the last LaunchRequest or AttachRequest so we can reuse its
179-
// arguments if we get a RestartRequest.
180-
std::optional<llvm::json::Object> last_launch_or_attach_request;
179+
// A copy of the last LaunchRequest so we can reuse its arguments if we get a
180+
// RestartRequest. Restarting an AttachRequest is not supported.
181+
std::optional<protocol::LaunchRequestArguments> last_launch_request;
181182
lldb::tid_t focus_tid;
182183
bool disconnecting = false;
183184
llvm::once_flag terminated_event_flag;
@@ -199,7 +200,6 @@ struct DAP {
199200
llvm::SmallDenseMap<int64_t, std::unique_ptr<ResponseHandler>>
200201
inflight_reverse_requests;
201202
ReplMode repl_mode;
202-
203203
lldb::SBFormat frame_format;
204204
lldb::SBFormat thread_format;
205205
// This is used to allow request_evaluate to handle empty expressions
@@ -248,6 +248,12 @@ struct DAP {
248248
/// Stop event handler threads.
249249
void StopEventHandlers();
250250

251+
/// Configures the debug adapter for launching/attaching.
252+
void SetConfiguration(const protocol::Configuration &confing, bool is_attach);
253+
254+
/// Configure source maps based on the current `DAPConfiguration`.
255+
void ConfigureSourceMaps();
256+
251257
/// Serialize the JSON value into a string and send the JSON packet to the
252258
/// "out" stream.
253259
void SendJSON(const llvm::json::Value &json);
@@ -311,17 +317,14 @@ struct DAP {
311317
void RunTerminateCommands();
312318

313319
/// Create a new SBTarget object from the given request arguments.
314-
/// \param[in] arguments
315-
/// Launch configuration arguments.
316320
///
317321
/// \param[out] error
318322
/// An SBError object that will contain an error description if
319323
/// function failed to create the target.
320324
///
321325
/// \return
322326
/// An SBTarget object.
323-
lldb::SBTarget CreateTargetFromArguments(const llvm::json::Object &arguments,
324-
lldb::SBError &error);
327+
lldb::SBTarget CreateTarget(lldb::SBError &error);
325328

326329
/// Set given target object as a current target for lldb-dap and start
327330
/// listeing for its breakpoint events.
@@ -395,7 +398,7 @@ struct DAP {
395398
/// The number of seconds to poll the process to wait until it is stopped.
396399
///
397400
/// \return Error if waiting for the process fails, no error if succeeds.
398-
lldb::SBError WaitForProcessToStop(uint32_t seconds);
401+
lldb::SBError WaitForProcessToStop(std::chrono::seconds seconds);
399402

400403
void SetFrameFormat(llvm::StringRef format);
401404

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

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,8 @@ namespace lldb_dap {
4343
// acknowledgement, so no body field is required."
4444
// }]
4545
// }
46-
4746
void AttachRequestHandler::operator()(const llvm::json::Object &request) const {
4847
dap.is_attach = true;
49-
dap.last_launch_or_attach_request = request;
5048
llvm::json::Object response;
5149
lldb::SBError error;
5250
FillResponse(request, response);
@@ -65,6 +63,7 @@ void AttachRequestHandler::operator()(const llvm::json::Object &request) const {
6563
attach_info.SetWaitForLaunch(wait_for, false /*async*/);
6664
dap.configuration.initCommands = GetStrings(arguments, "initCommands");
6765
dap.configuration.preRunCommands = GetStrings(arguments, "preRunCommands");
66+
dap.configuration.postRunCommands = GetStrings(arguments, "postRunCommands");
6867
dap.configuration.stopCommands = GetStrings(arguments, "stopCommands");
6968
dap.configuration.exitCommands = GetStrings(arguments, "exitCommands");
7069
dap.configuration.terminateCommands =
@@ -76,7 +75,6 @@ void AttachRequestHandler::operator()(const llvm::json::Object &request) const {
7675
dap.stop_at_entry = core_file.empty()
7776
? GetBoolean(arguments, "stopOnEntry").value_or(false)
7877
: true;
79-
dap.configuration.postRunCommands = GetStrings(arguments, "postRunCommands");
8078
const llvm::StringRef debuggerRoot =
8179
GetString(arguments, "debuggerRoot").value_or("");
8280
dap.configuration.enableAutoVariableSummaries =
@@ -87,6 +85,9 @@ void AttachRequestHandler::operator()(const llvm::json::Object &request) const {
8785
GetBoolean(arguments, "displayExtendedBacktrace").value_or(false);
8886
dap.configuration.commandEscapePrefix =
8987
GetString(arguments, "commandEscapePrefix").value_or("`");
88+
dap.configuration.program = GetString(arguments, "program");
89+
dap.configuration.targetTriple = GetString(arguments, "targetTriple");
90+
dap.configuration.platformName = GetString(arguments, "platformName");
9091
dap.SetFrameFormat(GetString(arguments, "customFrameFormat").value_or(""));
9192
dap.SetThreadFormat(GetString(arguments, "customThreadFormat").value_or(""));
9293

@@ -110,7 +111,7 @@ void AttachRequestHandler::operator()(const llvm::json::Object &request) const {
110111
SetSourceMapFromArguments(*arguments);
111112

112113
lldb::SBError status;
113-
dap.SetTarget(dap.CreateTargetFromArguments(*arguments, status));
114+
dap.SetTarget(dap.CreateTarget(status));
114115
if (status.Fail()) {
115116
response["success"] = llvm::json::Value(false);
116117
EmplaceSafeString(response, "message", status.GetCString());
@@ -180,7 +181,7 @@ void AttachRequestHandler::operator()(const llvm::json::Object &request) const {
180181

181182
// Make sure the process is attached and stopped before proceeding as the
182183
// the launch commands are not run using the synchronous mode.
183-
error = dap.WaitForProcessToStop(timeout_seconds);
184+
error = dap.WaitForProcessToStop(std::chrono::seconds(timeout_seconds));
184185
}
185186

186187
if (error.Success() && core_file.empty()) {

0 commit comments

Comments
 (0)