Skip to content

Commit a43b90d

Browse files
committed
[lldb-dap] Migrate attach to typed RequestHandler.
This updates the `attach` request to the typed `RequestHandler<protocol::AttachRequestArguments, protocol::AttachResponse>`. Added a few more overlapping configurations to `lldb_dap::protocol::Configuration` that are shared between launching and attaching. There may be some additional code we could clean-up that is no longer referenced now that this has migrated to use well defined types.
1 parent 7e71466 commit a43b90d

File tree

10 files changed

+204
-265
lines changed

10 files changed

+204
-265
lines changed

lldb/tools/lldb-dap/DAP.cpp

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -675,12 +675,11 @@ lldb::SBTarget DAP::CreateTarget(lldb::SBError &error) {
675675
// enough information to determine correct arch and platform (or ELF can be
676676
// omitted at all), so it is good to leave the user an opportunity to specify
677677
// those. Any of those three can be left empty.
678-
auto target = this->debugger.CreateTarget(
679-
configuration.program.value_or("").data(),
680-
configuration.targetTriple.value_or("").data(),
681-
configuration.platformName.value_or("").data(),
682-
true, // Add dependent modules.
683-
error);
678+
auto target = this->debugger.CreateTarget(configuration.program.data(),
679+
configuration.targetTriple.data(),
680+
configuration.platformName.data(),
681+
true, // Add dependent modules.
682+
error);
684683

685684
return target;
686685
}
@@ -1192,7 +1191,7 @@ bool SendEventRequestHandler::DoExecute(lldb::SBDebugger debugger,
11921191
}
11931192

11941193
void DAP::ConfigureSourceMaps() {
1195-
if (configuration.sourceMap.empty() && !configuration.sourcePath)
1194+
if (configuration.sourceMap.empty() && configuration.sourcePath.empty())
11961195
return;
11971196

11981197
std::string sourceMapCommand;
@@ -1203,8 +1202,8 @@ void DAP::ConfigureSourceMaps() {
12031202
for (const auto &kv : configuration.sourceMap) {
12041203
strm << "\"" << kv.first << "\" \"" << kv.second << "\" ";
12051204
}
1206-
} else if (configuration.sourcePath) {
1207-
strm << "\".\" \"" << *configuration.sourcePath << "\"";
1205+
} else if (!configuration.sourcePath.empty()) {
1206+
strm << "\".\" \"" << configuration.sourcePath << "\"";
12081207
}
12091208

12101209
RunLLDBCommands("Setting source map:", {sourceMapCommand});
@@ -1213,12 +1212,13 @@ void DAP::ConfigureSourceMaps() {
12131212
void DAP::SetConfiguration(const protocol::Configuration &config,
12141213
bool is_attach) {
12151214
configuration = config;
1215+
stop_at_entry = config.stopOnEntry;
12161216
this->is_attach = is_attach;
12171217

1218-
if (configuration.customFrameFormat)
1219-
SetFrameFormat(*configuration.customFrameFormat);
1220-
if (configuration.customThreadFormat)
1221-
SetThreadFormat(*configuration.customThreadFormat);
1218+
if (!configuration.customFrameFormat.empty())
1219+
SetFrameFormat(configuration.customFrameFormat);
1220+
if (!configuration.customThreadFormat.empty())
1221+
SetThreadFormat(configuration.customThreadFormat);
12221222
}
12231223

12241224
void DAP::SetFrameFormat(llvm::StringRef format) {

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

Lines changed: 73 additions & 141 deletions
Original file line numberDiff line numberDiff line change
@@ -9,203 +9,135 @@
99
#include "DAP.h"
1010
#include "EventHelper.h"
1111
#include "JSONUtils.h"
12+
#include "LLDBUtils.h"
13+
#include "Protocol/ProtocolRequests.h"
1214
#include "RequestHandler.h"
1315
#include "lldb/API/SBListener.h"
16+
#include "lldb/lldb-defines.h"
17+
#include "llvm/Support/Error.h"
1418
#include "llvm/Support/FileSystem.h"
1519

20+
using namespace llvm;
21+
using namespace lldb_dap::protocol;
22+
1623
namespace lldb_dap {
1724

18-
// "AttachRequest": {
19-
// "allOf": [ { "$ref": "#/definitions/Request" }, {
20-
// "type": "object",
21-
// "description": "Attach request; value of command field is 'attach'.",
22-
// "properties": {
23-
// "command": {
24-
// "type": "string",
25-
// "enum": [ "attach" ]
26-
// },
27-
// "arguments": {
28-
// "$ref": "#/definitions/AttachRequestArguments"
29-
// }
30-
// },
31-
// "required": [ "command", "arguments" ]
32-
// }]
33-
// },
34-
// "AttachRequestArguments": {
35-
// "type": "object",
36-
// "description": "Arguments for 'attach' request.\nThe attach request has no
37-
// standardized attributes."
38-
// },
39-
// "AttachResponse": {
40-
// "allOf": [ { "$ref": "#/definitions/Response" }, {
41-
// "type": "object",
42-
// "description": "Response to 'attach' request. This is just an
43-
// acknowledgement, so no body field is required."
44-
// }]
45-
// }
46-
void AttachRequestHandler::operator()(const llvm::json::Object &request) const {
47-
dap.is_attach = true;
48-
llvm::json::Object response;
49-
lldb::SBError error;
50-
FillResponse(request, response);
51-
lldb::SBAttachInfo attach_info;
52-
const int invalid_port = 0;
53-
const auto *arguments = request.getObject("arguments");
54-
const lldb::pid_t pid =
55-
GetInteger<uint64_t>(arguments, "pid").value_or(LLDB_INVALID_PROCESS_ID);
56-
const auto gdb_remote_port =
57-
GetInteger<uint64_t>(arguments, "gdb-remote-port").value_or(invalid_port);
58-
const auto gdb_remote_hostname =
59-
GetString(arguments, "gdb-remote-hostname").value_or("localhost");
60-
if (pid != LLDB_INVALID_PROCESS_ID)
61-
attach_info.SetProcessID(pid);
62-
const auto wait_for = GetBoolean(arguments, "waitFor").value_or(false);
63-
attach_info.SetWaitForLaunch(wait_for, false /*async*/);
64-
dap.configuration.initCommands = GetStrings(arguments, "initCommands");
65-
dap.configuration.preRunCommands = GetStrings(arguments, "preRunCommands");
66-
dap.configuration.postRunCommands = GetStrings(arguments, "postRunCommands");
67-
dap.configuration.stopCommands = GetStrings(arguments, "stopCommands");
68-
dap.configuration.exitCommands = GetStrings(arguments, "exitCommands");
69-
dap.configuration.terminateCommands =
70-
GetStrings(arguments, "terminateCommands");
71-
auto attachCommands = GetStrings(arguments, "attachCommands");
72-
llvm::StringRef core_file = GetString(arguments, "coreFile").value_or("");
73-
const uint64_t timeout_seconds =
74-
GetInteger<uint64_t>(arguments, "timeout").value_or(30);
75-
dap.stop_at_entry = core_file.empty()
76-
? GetBoolean(arguments, "stopOnEntry").value_or(false)
77-
: true;
78-
const llvm::StringRef debuggerRoot =
79-
GetString(arguments, "debuggerRoot").value_or("");
80-
dap.configuration.enableAutoVariableSummaries =
81-
GetBoolean(arguments, "enableAutoVariableSummaries").value_or(false);
82-
dap.configuration.enableSyntheticChildDebugging =
83-
GetBoolean(arguments, "enableSyntheticChildDebugging").value_or(false);
84-
dap.configuration.displayExtendedBacktrace =
85-
GetBoolean(arguments, "displayExtendedBacktrace").value_or(false);
86-
dap.configuration.commandEscapePrefix =
87-
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");
91-
dap.SetFrameFormat(GetString(arguments, "customFrameFormat").value_or(""));
92-
dap.SetThreadFormat(GetString(arguments, "customThreadFormat").value_or(""));
25+
/// The `attach` request is sent from the client to the debug adapter to attach
26+
/// to a debuggee that is already running.
27+
///
28+
/// Since attaching is debugger/runtime specific, the arguments for this request
29+
/// are not part of this specification.
30+
Error AttachRequestHandler::Run(const AttachRequestArguments &args) const {
31+
dap.SetConfiguration(args.configuration, true);
32+
if (!args.coreFile.empty())
33+
dap.stop_at_entry = true;
34+
35+
// If both pid and port numbers are specified.
36+
if ((args.pid != LLDB_INVALID_PROCESS_ID) &&
37+
(args.gdbRemotePort != LLDB_DAP_INVALID_PORT))
38+
return make_error<DAPError>(
39+
"pid and gdb-remote-port are mutually exclusive");
9340

9441
PrintWelcomeMessage();
9542

9643
// This is a hack for loading DWARF in .o files on Mac where the .o files
97-
// in the debug map of the main executable have relative paths which require
98-
// the lldb-dap binary to have its working directory set to that relative
99-
// root for the .o files in order to be able to load debug info.
100-
if (!debuggerRoot.empty())
101-
llvm::sys::fs::set_current_path(debuggerRoot);
44+
// in the debug map of the main executable have relative paths which
45+
// require the lldb-dap binary to have its working directory set to that
46+
// relative root for the .o files in order to be able to load debug info.
47+
if (!dap.configuration.debuggerRoot.empty())
48+
sys::fs::set_current_path(dap.configuration.debuggerRoot);
10249

10350
// Run any initialize LLDB commands the user specified in the launch.json
104-
if (llvm::Error err = dap.RunInitCommands()) {
105-
response["success"] = false;
106-
EmplaceSafeString(response, "message", llvm::toString(std::move(err)));
107-
dap.SendJSON(llvm::json::Value(std::move(response)));
108-
return;
109-
}
51+
if (llvm::Error err = dap.RunInitCommands())
52+
return err;
11053

111-
SetSourceMapFromArguments(*arguments);
54+
dap.ConfigureSourceMaps();
11255

113-
lldb::SBError status;
114-
dap.SetTarget(dap.CreateTarget(status));
115-
if (status.Fail()) {
116-
response["success"] = llvm::json::Value(false);
117-
EmplaceSafeString(response, "message", status.GetCString());
118-
dap.SendJSON(llvm::json::Value(std::move(response)));
119-
return;
120-
}
56+
lldb::SBError error;
57+
lldb::SBTarget target = dap.CreateTarget(error);
58+
if (error.Fail())
59+
return ToError(error);
60+
61+
dap.SetTarget(target);
12162

12263
// Run any pre run LLDB commands the user specified in the launch.json
123-
if (llvm::Error err = dap.RunPreRunCommands()) {
124-
response["success"] = false;
125-
EmplaceSafeString(response, "message", llvm::toString(std::move(err)));
126-
dap.SendJSON(llvm::json::Value(std::move(response)));
127-
return;
128-
}
64+
if (Error err = dap.RunPreRunCommands())
65+
return err;
12966

130-
if ((pid == LLDB_INVALID_PROCESS_ID || gdb_remote_port == invalid_port) &&
131-
wait_for) {
67+
if ((args.pid == LLDB_INVALID_PROCESS_ID ||
68+
args.gdbRemotePort == LLDB_DAP_INVALID_PORT) &&
69+
args.waitFor) {
13270
char attach_msg[256];
13371
auto attach_msg_len = snprintf(attach_msg, sizeof(attach_msg),
13472
"Waiting to attach to \"%s\"...",
13573
dap.target.GetExecutable().GetFilename());
136-
dap.SendOutput(OutputType::Console,
137-
llvm::StringRef(attach_msg, attach_msg_len));
74+
dap.SendOutput(OutputType::Console, StringRef(attach_msg, attach_msg_len));
13875
}
139-
if (attachCommands.empty()) {
76+
77+
if (args.attachCommands.empty()) {
14078
// No "attachCommands", just attach normally.
14179
// Disable async events so the attach will be successful when we return from
14280
// the launch call and the launch will happen synchronously
14381
dap.debugger.SetAsync(false);
144-
if (core_file.empty()) {
145-
if ((pid != LLDB_INVALID_PROCESS_ID) &&
146-
(gdb_remote_port != invalid_port)) {
147-
// If both pid and port numbers are specified.
148-
error.SetErrorString("The user can't specify both pid and port");
149-
} else if (gdb_remote_port != invalid_port) {
82+
if (args.coreFile.empty()) {
83+
if (args.gdbRemotePort != LLDB_DAP_INVALID_PORT) {
15084
// If port is specified and pid is not.
15185
lldb::SBListener listener = dap.debugger.GetListener();
15286

15387
// If the user hasn't provided the hostname property, default localhost
15488
// being used.
15589
std::string connect_url =
156-
llvm::formatv("connect://{0}:", gdb_remote_hostname);
157-
connect_url += std::to_string(gdb_remote_port);
158-
dap.target.ConnectRemote(listener, connect_url.c_str(), "gdb-remote",
90+
llvm::formatv("connect://{0}:", args.gdbRemoteHostname);
91+
connect_url += std::to_string(args.gdbRemotePort);
92+
dap.target.ConnectRemote(listener, connect_url.data(), "gdb-remote",
15993
error);
16094
} else {
16195
// Attach by process name or id.
96+
lldb::SBAttachInfo attach_info;
97+
if (!args.configuration.program.empty())
98+
attach_info.SetExecutable(args.configuration.program.data());
99+
if (args.pid != LLDB_INVALID_PROCESS_ID)
100+
attach_info.SetProcessID(args.pid);
101+
attach_info.SetWaitForLaunch(args.waitFor, false /*async*/);
162102
dap.target.Attach(attach_info, error);
163103
}
164104
} else
165-
dap.target.LoadCore(core_file.data(), error);
105+
dap.target.LoadCore(args.coreFile.data(), error);
166106
// Reenable async events
167107
dap.debugger.SetAsync(true);
168108
} else {
169109
// We have "attachCommands" that are a set of commands that are expected
170110
// to execute the commands after which a process should be created. If there
171111
// is no valid process after running these commands, we have failed.
172-
if (llvm::Error err = dap.RunAttachCommands(attachCommands)) {
173-
response["success"] = false;
174-
EmplaceSafeString(response, "message", llvm::toString(std::move(err)));
175-
dap.SendJSON(llvm::json::Value(std::move(response)));
176-
return;
177-
}
112+
if (llvm::Error err = dap.RunAttachCommands(args.attachCommands))
113+
return err;
114+
178115
// The custom commands might have created a new target so we should use the
179116
// selected target after these commands are run.
180117
dap.target = dap.debugger.GetSelectedTarget();
181118

182119
// Make sure the process is attached and stopped before proceeding as the
183120
// the launch commands are not run using the synchronous mode.
184-
error = dap.WaitForProcessToStop(std::chrono::seconds(timeout_seconds));
121+
error = dap.WaitForProcessToStop(dap.configuration.timeout);
185122
}
186123

187-
if (error.Success() && core_file.empty()) {
188-
auto attached_pid = dap.target.GetProcess().GetProcessID();
189-
if (attached_pid == LLDB_INVALID_PROCESS_ID) {
190-
if (attachCommands.empty())
191-
error.SetErrorString("failed to attach to a process");
192-
else
193-
error.SetErrorString("attachCommands failed to attach to a process");
194-
}
195-
}
124+
if (error.Fail())
125+
return ToError(error);
196126

197-
if (error.Fail()) {
198-
response["success"] = llvm::json::Value(false);
199-
EmplaceSafeString(response, "message", std::string(error.GetCString()));
200-
} else {
201-
dap.RunPostRunCommands();
202-
}
127+
if (args.coreFile.empty() && !dap.target.GetProcess().IsValid())
128+
return make_error<DAPError>("failed to attach to process");
203129

204-
dap.SendJSON(llvm::json::Value(std::move(response)));
205-
if (error.Success()) {
130+
dap.RunPostRunCommands();
131+
132+
return Error::success();
133+
}
134+
135+
void AttachRequestHandler::PostRun() const {
136+
if (dap.target.GetProcess().IsValid()) {
206137
SendProcessEvent(dap, Attach);
207-
dap.SendJSON(CreateEventObject("initialized"));
208138
}
139+
140+
dap.SendJSON(CreateEventObject("initialized"));
209141
}
210142

211143
} // namespace lldb_dap

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,7 @@ static void EventThreadFunction(DAP &dap) {
277277
}
278278

279279
/// Initialize request; value of command field is 'initialize'.
280-
llvm::Expected<InitializeResponseBody> InitializeRequestHandler::Run(
280+
llvm::Expected<InitializeResponse> InitializeRequestHandler::Run(
281281
const InitializeRequestArguments &arguments) const {
282282
dap.clientFeatures = arguments.supportedFeatures;
283283

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

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ namespace lldb_dap {
2424
Error LaunchRequestHandler::Run(const LaunchRequestArguments &arguments) const {
2525
dap.SetConfiguration(arguments.configuration, /*is_attach=*/false);
2626
dap.last_launch_request = arguments;
27-
dap.stop_at_entry = arguments.stopOnEntry;
2827

2928
if (!arguments.launchCommands.empty() && arguments.runInTerminal)
3029
return make_error<DAPError>(
@@ -36,9 +35,8 @@ Error LaunchRequestHandler::Run(const LaunchRequestArguments &arguments) const {
3635
// in the debug map of the main executable have relative paths which
3736
// require the lldb-dap binary to have its working directory set to that
3837
// relative root for the .o files in order to be able to load debug info.
39-
const std::string debugger_root = dap.configuration.debuggerRoot.value_or("");
40-
if (!debugger_root.empty())
41-
sys::fs::set_current_path(debugger_root);
38+
if (!dap.configuration.debuggerRoot.empty())
39+
sys::fs::set_current_path(dap.configuration.debuggerRoot);
4240

4341
// Run any initialize LLDB commands the user specified in the launch.json.
4442
// This is run before target is created, so commands can't do anything with

0 commit comments

Comments
 (0)