1//===-- lldb-dap.cpp -----------------------------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "DAP.h"
10#include "Watchpoint.h"
11#include "lldb/API/SBMemoryRegionInfo.h"
12
13#include <cassert>
14#include <climits>
15#include <cstdarg>
16#include <cstdio>
17#include <cstdlib>
18#include <cstring>
19#include <sys/stat.h>
20#include <sys/types.h>
21#if defined(_WIN32)
22// We need to #define NOMINMAX in order to skip `min()` and `max()` macro
23// definitions that conflict with other system headers.
24// We also need to #undef GetObject (which is defined to GetObjectW) because
25// the JSON code we use also has methods named `GetObject()` and we conflict
26// against these.
27#define NOMINMAX
28#include <windows.h>
29#undef GetObject
30#include <io.h>
31#else
32#include <netinet/in.h>
33#include <sys/socket.h>
34#include <unistd.h>
35#endif
36
37#if defined(__linux__)
38#include <sys/prctl.h>
39#endif
40
41#include <algorithm>
42#include <array>
43#include <chrono>
44#include <fstream>
45#include <map>
46#include <memory>
47#include <mutex>
48#include <set>
49#include <sstream>
50#include <thread>
51#include <vector>
52
53#include "lldb/Host/Config.h"
54#include "llvm/ADT/ArrayRef.h"
55#include "llvm/ADT/DenseMap.h"
56#include "llvm/ADT/ScopeExit.h"
57#include "llvm/ADT/StringExtras.h"
58#include "llvm/Option/Arg.h"
59#include "llvm/Option/ArgList.h"
60#include "llvm/Option/OptTable.h"
61#include "llvm/Option/Option.h"
62#include "llvm/Support/Errno.h"
63#include "llvm/Support/FileSystem.h"
64#include "llvm/Support/InitLLVM.h"
65#include "llvm/Support/Path.h"
66#include "llvm/Support/PrettyStackTrace.h"
67#include "llvm/Support/raw_ostream.h"
68
69#include "JSONUtils.h"
70#include "LLDBUtils.h"
71#include "OutputRedirector.h"
72
73#if defined(_WIN32)
74#ifndef PATH_MAX
75#define PATH_MAX MAX_PATH
76#endif
77typedef int socklen_t;
78#endif
79
80using namespace lldb_dap;
81
82namespace {
83using namespace llvm::opt;
84
85enum ID {
86 OPT_INVALID = 0, // This is not an option ID.
87#define OPTION(...) LLVM_MAKE_OPT_ID(__VA_ARGS__),
88#include "Options.inc"
89#undef OPTION
90};
91
92#define PREFIX(NAME, VALUE) \
93 static constexpr llvm::StringLiteral NAME##_init[] = VALUE; \
94 static constexpr llvm::ArrayRef<llvm::StringLiteral> NAME( \
95 NAME##_init, std::size(NAME##_init) - 1);
96#include "Options.inc"
97#undef PREFIX
98
99static constexpr llvm::opt::OptTable::Info InfoTable[] = {
100#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
101#include "Options.inc"
102#undef OPTION
103};
104class LLDBDAPOptTable : public llvm::opt::GenericOptTable {
105public:
106 LLDBDAPOptTable() : llvm::opt::GenericOptTable(InfoTable, true) {}
107};
108
109typedef void (*RequestCallback)(const llvm::json::Object &command);
110
111enum LaunchMethod { Launch, Attach, AttachForSuspendedLaunch };
112
113/// Prints a welcome message on the editor if the preprocessor variable
114/// LLDB_DAP_WELCOME_MESSAGE is defined.
115static void PrintWelcomeMessage() {
116#ifdef LLDB_DAP_WELCOME_MESSAGE
117 g_dap.SendOutput(OutputType::Console, LLDB_DAP_WELCOME_MESSAGE);
118#endif
119}
120
121lldb::SBValueList *GetTopLevelScope(int64_t variablesReference) {
122 switch (variablesReference) {
123 case VARREF_LOCALS:
124 return &g_dap.variables.locals;
125 case VARREF_GLOBALS:
126 return &g_dap.variables.globals;
127 case VARREF_REGS:
128 return &g_dap.variables.registers;
129 default:
130 return nullptr;
131 }
132}
133
134SOCKET AcceptConnection(int portno) {
135 // Accept a socket connection from any host on "portno".
136 SOCKET newsockfd = -1;
137 struct sockaddr_in serv_addr, cli_addr;
138 SOCKET sockfd = socket(AF_INET, SOCK_STREAM, protocol: 0);
139 if (sockfd < 0) {
140 if (g_dap.log)
141 *g_dap.log << "error: opening socket (" << strerror(errno) << ")"
142 << std::endl;
143 } else {
144 memset(s: (char *)&serv_addr, c: 0, n: sizeof(serv_addr));
145 serv_addr.sin_family = AF_INET;
146 // serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
147 serv_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
148 serv_addr.sin_port = htons(hostshort: portno);
149 if (bind(fd: sockfd, addr: (struct sockaddr *)&serv_addr, len: sizeof(serv_addr)) < 0) {
150 if (g_dap.log)
151 *g_dap.log << "error: binding socket (" << strerror(errno) << ")"
152 << std::endl;
153 } else {
154 listen(fd: sockfd, n: 5);
155 socklen_t clilen = sizeof(cli_addr);
156 newsockfd =
157 llvm::sys::RetryAfterSignal(static_cast<SOCKET>(-1), accept, sockfd,
158 (struct sockaddr *)&cli_addr, &clilen);
159 if (newsockfd < 0)
160 if (g_dap.log)
161 *g_dap.log << "error: accept (" << strerror(errno) << ")"
162 << std::endl;
163 }
164#if defined(_WIN32)
165 closesocket(sockfd);
166#else
167 close(fd: sockfd);
168#endif
169 }
170 return newsockfd;
171}
172
173std::vector<const char *> MakeArgv(const llvm::ArrayRef<std::string> &strs) {
174 // Create and return an array of "const char *", one for each C string in
175 // "strs" and terminate the list with a NULL. This can be used for argument
176 // vectors (argv) or environment vectors (envp) like those passed to the
177 // "main" function in C programs.
178 std::vector<const char *> argv;
179 for (const auto &s : strs)
180 argv.push_back(s.c_str());
181 argv.push_back(nullptr);
182 return argv;
183}
184
185// Send a "exited" event to indicate the process has exited.
186void SendProcessExitedEvent(lldb::SBProcess &process) {
187 llvm::json::Object event(CreateEventObject(event_name: "exited"));
188 llvm::json::Object body;
189 body.try_emplace("exitCode", (int64_t)process.GetExitStatus());
190 event.try_emplace("body", std::move(body));
191 g_dap.SendJSON(json: llvm::json::Value(std::move(event)));
192}
193
194void SendThreadExitedEvent(lldb::tid_t tid) {
195 llvm::json::Object event(CreateEventObject(event_name: "thread"));
196 llvm::json::Object body;
197 body.try_emplace("reason", "exited");
198 body.try_emplace("threadId", (int64_t)tid);
199 event.try_emplace("body", std::move(body));
200 g_dap.SendJSON(json: llvm::json::Value(std::move(event)));
201}
202
203// Send a "continued" event to indicate the process is in the running state.
204void SendContinuedEvent() {
205 lldb::SBProcess process = g_dap.target.GetProcess();
206 if (!process.IsValid()) {
207 return;
208 }
209
210 // If the focus thread is not set then we haven't reported any thread status
211 // to the client, so nothing to report.
212 if (!g_dap.configuration_done_sent ||
213 g_dap.focus_tid == LLDB_INVALID_THREAD_ID) {
214 return;
215 }
216
217 llvm::json::Object event(CreateEventObject(event_name: "continued"));
218 llvm::json::Object body;
219 body.try_emplace("threadId", (int64_t)g_dap.focus_tid);
220 body.try_emplace("allThreadsContinued", true);
221 event.try_emplace("body", std::move(body));
222 g_dap.SendJSON(json: llvm::json::Value(std::move(event)));
223}
224
225// Send a "terminated" event to indicate the process is done being
226// debugged.
227void SendTerminatedEvent() {
228 // If an inferior exits prior to the processing of a disconnect request, then
229 // the threads executing EventThreadFunction and request_discontinue
230 // respectively may call SendTerminatedEvent simultaneously. Without any
231 // synchronization, the thread executing EventThreadFunction may set
232 // g_dap.sent_terminated_event before the thread executing
233 // request_discontinue has had a chance to test it, in which case the latter
234 // would move ahead to issue a response to the disconnect request. Said
235 // response may get dispatched ahead of the terminated event compelling the
236 // client to terminate the debug session without consuming any console output
237 // that might've been generated by the execution of terminateCommands. So,
238 // synchronize simultaneous calls to SendTerminatedEvent.
239 static std::mutex mutex;
240 std::lock_guard<std::mutex> locker(mutex);
241 if (!g_dap.sent_terminated_event) {
242 g_dap.sent_terminated_event = true;
243 g_dap.RunTerminateCommands();
244 // Send a "terminated" event
245 llvm::json::Object event(CreateTerminatedEventObject());
246 g_dap.SendJSON(json: llvm::json::Value(std::move(event)));
247 }
248}
249
250// Send a thread stopped event for all threads as long as the process
251// is stopped.
252void SendThreadStoppedEvent() {
253 lldb::SBProcess process = g_dap.target.GetProcess();
254 if (process.IsValid()) {
255 auto state = process.GetState();
256 if (state == lldb::eStateStopped) {
257 llvm::DenseSet<lldb::tid_t> old_thread_ids;
258 old_thread_ids.swap(g_dap.thread_ids);
259 uint32_t stop_id = process.GetStopID();
260 const uint32_t num_threads = process.GetNumThreads();
261
262 // First make a pass through the threads to see if the focused thread
263 // has a stop reason. In case the focus thread doesn't have a stop
264 // reason, remember the first thread that has a stop reason so we can
265 // set it as the focus thread if below if needed.
266 lldb::tid_t first_tid_with_reason = LLDB_INVALID_THREAD_ID;
267 uint32_t num_threads_with_reason = 0;
268 bool focus_thread_exists = false;
269 for (uint32_t thread_idx = 0; thread_idx < num_threads; ++thread_idx) {
270 lldb::SBThread thread = process.GetThreadAtIndex(index: thread_idx);
271 const lldb::tid_t tid = thread.GetThreadID();
272 const bool has_reason = ThreadHasStopReason(thread);
273 // If the focus thread doesn't have a stop reason, clear the thread ID
274 if (tid == g_dap.focus_tid) {
275 focus_thread_exists = true;
276 if (!has_reason)
277 g_dap.focus_tid = LLDB_INVALID_THREAD_ID;
278 }
279 if (has_reason) {
280 ++num_threads_with_reason;
281 if (first_tid_with_reason == LLDB_INVALID_THREAD_ID)
282 first_tid_with_reason = tid;
283 }
284 }
285
286 // We will have cleared g_dap.focus_tid if the focus thread doesn't have
287 // a stop reason, so if it was cleared, or wasn't set, or doesn't exist,
288 // then set the focus thread to the first thread with a stop reason.
289 if (!focus_thread_exists || g_dap.focus_tid == LLDB_INVALID_THREAD_ID)
290 g_dap.focus_tid = first_tid_with_reason;
291
292 // If no threads stopped with a reason, then report the first one so
293 // we at least let the UI know we stopped.
294 if (num_threads_with_reason == 0) {
295 lldb::SBThread thread = process.GetThreadAtIndex(index: 0);
296 g_dap.focus_tid = thread.GetThreadID();
297 g_dap.SendJSON(json: CreateThreadStopped(thread, stop_id));
298 } else {
299 for (uint32_t thread_idx = 0; thread_idx < num_threads; ++thread_idx) {
300 lldb::SBThread thread = process.GetThreadAtIndex(index: thread_idx);
301 g_dap.thread_ids.insert(thread.GetThreadID());
302 if (ThreadHasStopReason(thread)) {
303 g_dap.SendJSON(json: CreateThreadStopped(thread, stop_id));
304 }
305 }
306 }
307
308 for (auto tid : old_thread_ids) {
309 auto end = g_dap.thread_ids.end();
310 auto pos = g_dap.thread_ids.find(tid);
311 if (pos == end)
312 SendThreadExitedEvent(tid);
313 }
314 } else {
315 if (g_dap.log)
316 *g_dap.log << "error: SendThreadStoppedEvent() when process"
317 " isn't stopped ("
318 << lldb::SBDebugger::StateAsCString(state) << ')'
319 << std::endl;
320 }
321 } else {
322 if (g_dap.log)
323 *g_dap.log << "error: SendThreadStoppedEvent() invalid process"
324 << std::endl;
325 }
326 g_dap.RunStopCommands();
327}
328
329// "ProcessEvent": {
330// "allOf": [
331// { "$ref": "#/definitions/Event" },
332// {
333// "type": "object",
334// "description": "Event message for 'process' event type. The event
335// indicates that the debugger has begun debugging a
336// new process. Either one that it has launched, or one
337// that it has attached to.",
338// "properties": {
339// "event": {
340// "type": "string",
341// "enum": [ "process" ]
342// },
343// "body": {
344// "type": "object",
345// "properties": {
346// "name": {
347// "type": "string",
348// "description": "The logical name of the process. This is
349// usually the full path to process's executable
350// file. Example: /home/myproj/program.js."
351// },
352// "systemProcessId": {
353// "type": "integer",
354// "description": "The system process id of the debugged process.
355// This property will be missing for non-system
356// processes."
357// },
358// "isLocalProcess": {
359// "type": "boolean",
360// "description": "If true, the process is running on the same
361// computer as the debug adapter."
362// },
363// "startMethod": {
364// "type": "string",
365// "enum": [ "launch", "attach", "attachForSuspendedLaunch" ],
366// "description": "Describes how the debug engine started
367// debugging this process.",
368// "enumDescriptions": [
369// "Process was launched under the debugger.",
370// "Debugger attached to an existing process.",
371// "A project launcher component has launched a new process in
372// a suspended state and then asked the debugger to attach."
373// ]
374// }
375// },
376// "required": [ "name" ]
377// }
378// },
379// "required": [ "event", "body" ]
380// }
381// ]
382// }
383void SendProcessEvent(LaunchMethod launch_method) {
384 lldb::SBFileSpec exe_fspec = g_dap.target.GetExecutable();
385 char exe_path[PATH_MAX];
386 exe_fspec.GetPath(dst_path: exe_path, dst_len: sizeof(exe_path));
387 llvm::json::Object event(CreateEventObject(event_name: "process"));
388 llvm::json::Object body;
389 EmplaceSafeString(obj&: body, key: "name", str: std::string(exe_path));
390 const auto pid = g_dap.target.GetProcess().GetProcessID();
391 body.try_emplace("systemProcessId", (int64_t)pid);
392 body.try_emplace("isLocalProcess", true);
393 const char *startMethod = nullptr;
394 switch (launch_method) {
395 case Launch:
396 startMethod = "launch";
397 break;
398 case Attach:
399 startMethod = "attach";
400 break;
401 case AttachForSuspendedLaunch:
402 startMethod = "attachForSuspendedLaunch";
403 break;
404 }
405 body.try_emplace("startMethod", startMethod);
406 event.try_emplace("body", std::move(body));
407 g_dap.SendJSON(json: llvm::json::Value(std::move(event)));
408}
409
410// Grab any STDOUT and STDERR from the process and send it up to VS Code
411// via an "output" event to the "stdout" and "stderr" categories.
412void SendStdOutStdErr(lldb::SBProcess &process) {
413 char buffer[1024];
414 size_t count;
415 while ((count = process.GetSTDOUT(dst: buffer, dst_len: sizeof(buffer))) > 0)
416 g_dap.SendOutput(o: OutputType::Stdout, output: llvm::StringRef(buffer, count));
417 while ((count = process.GetSTDERR(dst: buffer, dst_len: sizeof(buffer))) > 0)
418 g_dap.SendOutput(o: OutputType::Stderr, output: llvm::StringRef(buffer, count));
419}
420
421void ProgressEventThreadFunction() {
422 lldb::SBListener listener("lldb-dap.progress.listener");
423 g_dap.debugger.GetBroadcaster().AddListener(listener,
424 event_mask: lldb::eBroadcastBitProgress);
425 g_dap.broadcaster.AddListener(listener, event_mask: eBroadcastBitStopProgressThread);
426 lldb::SBEvent event;
427 bool done = false;
428 while (!done) {
429 if (listener.WaitForEvent(num_seconds: 1, event)) {
430 const auto event_mask = event.GetType();
431 if (event.BroadcasterMatchesRef(broadcaster: g_dap.broadcaster)) {
432 if (event_mask & eBroadcastBitStopProgressThread) {
433 done = true;
434 }
435 } else {
436 uint64_t progress_id = 0;
437 uint64_t completed = 0;
438 uint64_t total = 0;
439 bool is_debugger_specific = false;
440 const char *message = lldb::SBDebugger::GetProgressFromEvent(
441 event, progress_id, completed, total, is_debugger_specific);
442 if (message)
443 g_dap.SendProgressEvent(progress_id, message, completed, total);
444 }
445 }
446 }
447}
448
449// All events from the debugger, target, process, thread and frames are
450// received in this function that runs in its own thread. We are using a
451// "FILE *" to output packets back to VS Code and they have mutexes in them
452// them prevent multiple threads from writing simultaneously so no locking
453// is required.
454void EventThreadFunction() {
455 lldb::SBEvent event;
456 lldb::SBListener listener = g_dap.debugger.GetListener();
457 bool done = false;
458 while (!done) {
459 if (listener.WaitForEvent(num_seconds: 1, event)) {
460 const auto event_mask = event.GetType();
461 if (lldb::SBProcess::EventIsProcessEvent(event)) {
462 lldb::SBProcess process = lldb::SBProcess::GetProcessFromEvent(event);
463 if (event_mask & lldb::SBProcess::eBroadcastBitStateChanged) {
464 auto state = lldb::SBProcess::GetStateFromEvent(event);
465 switch (state) {
466 case lldb::eStateInvalid:
467 // Not a state event
468 break;
469 case lldb::eStateUnloaded:
470 break;
471 case lldb::eStateConnected:
472 break;
473 case lldb::eStateAttaching:
474 break;
475 case lldb::eStateLaunching:
476 break;
477 case lldb::eStateStepping:
478 break;
479 case lldb::eStateCrashed:
480 break;
481 case lldb::eStateDetached:
482 break;
483 case lldb::eStateSuspended:
484 break;
485 case lldb::eStateStopped:
486 // We launch and attach in synchronous mode then the first stop
487 // event will not be delivered. If we use "launchCommands" during a
488 // launch or "attachCommands" during an attach we might some process
489 // stop events which we do not want to send an event for. We will
490 // manually send a stopped event in request_configurationDone(...)
491 // so don't send any before then.
492 if (g_dap.configuration_done_sent) {
493 // Only report a stopped event if the process was not
494 // automatically restarted.
495 if (!lldb::SBProcess::GetRestartedFromEvent(event)) {
496 SendStdOutStdErr(process);
497 SendThreadStoppedEvent();
498 }
499 }
500 break;
501 case lldb::eStateRunning:
502 g_dap.WillContinue();
503 SendContinuedEvent();
504 break;
505 case lldb::eStateExited:
506 // When restarting, we can get an "exited" event for the process we
507 // just killed with the old PID, or even with no PID. In that case
508 // we don't have to terminate the session.
509 if (process.GetProcessID() == LLDB_INVALID_PROCESS_ID ||
510 process.GetProcessID() == g_dap.restarting_process_id) {
511 g_dap.restarting_process_id = LLDB_INVALID_PROCESS_ID;
512 } else {
513 // Run any exit LLDB commands the user specified in the
514 // launch.json
515 g_dap.RunExitCommands();
516 SendProcessExitedEvent(process);
517 SendTerminatedEvent();
518 done = true;
519 }
520 break;
521 }
522 } else if ((event_mask & lldb::SBProcess::eBroadcastBitSTDOUT) ||
523 (event_mask & lldb::SBProcess::eBroadcastBitSTDERR)) {
524 SendStdOutStdErr(process);
525 }
526 } else if (lldb::SBBreakpoint::EventIsBreakpointEvent(event)) {
527 if (event_mask & lldb::SBTarget::eBroadcastBitBreakpointChanged) {
528 auto event_type =
529 lldb::SBBreakpoint::GetBreakpointEventTypeFromEvent(event);
530 auto bp =
531 Breakpoint(lldb::SBBreakpoint::GetBreakpointFromEvent(event));
532 // If the breakpoint was originated from the IDE, it will have the
533 // BreakpointBase::GetBreakpointLabel() label attached. Regardless
534 // of wether the locations were added or removed, the breakpoint
535 // ins't going away, so we the reason is always "changed".
536 if ((event_type & lldb::eBreakpointEventTypeLocationsAdded ||
537 event_type & lldb::eBreakpointEventTypeLocationsRemoved) &&
538 bp.MatchesName(name: BreakpointBase::GetBreakpointLabel())) {
539 auto bp_event = CreateEventObject(event_name: "breakpoint");
540 llvm::json::Object body;
541 // As VSCode already knows the path of this breakpoint, we don't
542 // need to send it back as part of a "changed" event. This
543 // prevent us from sending to VSCode paths that should be source
544 // mapped. Note that CreateBreakpoint doesn't apply source mapping.
545 // Besides, the current implementation of VSCode ignores the
546 // "source" element of breakpoint events.
547 llvm::json::Value source_bp = CreateBreakpoint(bp: &bp);
548 source_bp.getAsObject()->erase(K: "source");
549
550 body.try_emplace("breakpoint", source_bp);
551 body.try_emplace("reason", "changed");
552 bp_event.try_emplace("body", std::move(body));
553 g_dap.SendJSON(json: llvm::json::Value(std::move(bp_event)));
554 }
555 }
556 } else if (event.BroadcasterMatchesRef(broadcaster: g_dap.broadcaster)) {
557 if (event_mask & eBroadcastBitStopEventThread) {
558 done = true;
559 }
560 }
561 }
562 }
563}
564
565lldb::SBValue FindVariable(uint64_t variablesReference, llvm::StringRef name) {
566 lldb::SBValue variable;
567 if (lldb::SBValueList *top_scope = GetTopLevelScope(variablesReference)) {
568 bool is_duplicated_variable_name = name.contains(Other: " @");
569 // variablesReference is one of our scopes, not an actual variable it is
570 // asking for a variable in locals or globals or registers
571 int64_t end_idx = top_scope->GetSize();
572 // Searching backward so that we choose the variable in closest scope
573 // among variables of the same name.
574 for (int64_t i = end_idx - 1; i >= 0; --i) {
575 lldb::SBValue curr_variable = top_scope->GetValueAtIndex(idx: i);
576 std::string variable_name = CreateUniqueVariableNameForDisplay(
577 v: curr_variable, is_name_duplicated: is_duplicated_variable_name);
578 if (variable_name == name) {
579 variable = curr_variable;
580 break;
581 }
582 }
583 } else {
584 // This is not under the globals or locals scope, so there are no duplicated
585 // names.
586
587 // We have a named item within an actual variable so we need to find it
588 // withing the container variable by name.
589 lldb::SBValue container = g_dap.variables.GetVariable(var_ref: variablesReference);
590 variable = container.GetChildMemberWithName(name: name.data());
591 if (!variable.IsValid()) {
592 if (name.starts_with(Prefix: "[")) {
593 llvm::StringRef index_str(name.drop_front(N: 1));
594 uint64_t index = 0;
595 if (!index_str.consumeInteger(0, index)) {
596 if (index_str == "]")
597 variable = container.GetChildAtIndex(idx: index);
598 }
599 }
600 }
601 }
602 return variable;
603}
604
605// Both attach and launch take a either a sourcePath or sourceMap
606// argument (or neither), from which we need to set the target.source-map.
607void SetSourceMapFromArguments(const llvm::json::Object &arguments) {
608 const char *sourceMapHelp =
609 "source must be be an array of two-element arrays, "
610 "each containing a source and replacement path string.\n";
611
612 std::string sourceMapCommand;
613 llvm::raw_string_ostream strm(sourceMapCommand);
614 strm << "settings set target.source-map ";
615 auto sourcePath = GetString(obj: arguments, key: "sourcePath");
616
617 // sourceMap is the new, more general form of sourcePath and overrides it.
618 auto sourceMap = arguments.getArray(K: "sourceMap");
619 if (sourceMap) {
620 for (const auto &value : *sourceMap) {
621 auto mapping = value.getAsArray();
622 if (mapping == nullptr || mapping->size() != 2 ||
623 (*mapping)[0].kind() != llvm::json::Value::String ||
624 (*mapping)[1].kind() != llvm::json::Value::String) {
625 g_dap.SendOutput(OutputType::Console, llvm::StringRef(sourceMapHelp));
626 return;
627 }
628 auto mapFrom = GetAsString((*mapping)[0]);
629 auto mapTo = GetAsString((*mapping)[1]);
630 strm << "\"" << mapFrom << "\" \"" << mapTo << "\" ";
631 }
632 } else {
633 if (ObjectContainsKey(obj: arguments, key: "sourceMap")) {
634 g_dap.SendOutput(o: OutputType::Console, output: llvm::StringRef(sourceMapHelp));
635 return;
636 }
637 if (sourcePath.empty())
638 return;
639 // Do any source remapping needed before we create our targets
640 strm << "\".\" \"" << sourcePath << "\"";
641 }
642 strm.flush();
643 if (!sourceMapCommand.empty()) {
644 g_dap.RunLLDBCommands("Setting source map:", {sourceMapCommand});
645 }
646}
647
648// "AttachRequest": {
649// "allOf": [ { "$ref": "#/definitions/Request" }, {
650// "type": "object",
651// "description": "Attach request; value of command field is 'attach'.",
652// "properties": {
653// "command": {
654// "type": "string",
655// "enum": [ "attach" ]
656// },
657// "arguments": {
658// "$ref": "#/definitions/AttachRequestArguments"
659// }
660// },
661// "required": [ "command", "arguments" ]
662// }]
663// },
664// "AttachRequestArguments": {
665// "type": "object",
666// "description": "Arguments for 'attach' request.\nThe attach request has no
667// standardized attributes."
668// },
669// "AttachResponse": {
670// "allOf": [ { "$ref": "#/definitions/Response" }, {
671// "type": "object",
672// "description": "Response to 'attach' request. This is just an
673// acknowledgement, so no body field is required."
674// }]
675// }
676void request_attach(const llvm::json::Object &request) {
677 g_dap.is_attach = true;
678 g_dap.last_launch_or_attach_request = request;
679 llvm::json::Object response;
680 lldb::SBError error;
681 FillResponse(request, response);
682 lldb::SBAttachInfo attach_info;
683 auto arguments = request.getObject(K: "arguments");
684 const lldb::pid_t pid =
685 GetUnsigned(obj: arguments, key: "pid", LLDB_INVALID_PROCESS_ID);
686 if (pid != LLDB_INVALID_PROCESS_ID)
687 attach_info.SetProcessID(pid);
688 const auto wait_for = GetBoolean(obj: arguments, key: "waitFor", fail_value: false);
689 attach_info.SetWaitForLaunch(b: wait_for, async: false /*async*/);
690 g_dap.init_commands = GetStrings(obj: arguments, key: "initCommands");
691 g_dap.pre_run_commands = GetStrings(obj: arguments, key: "preRunCommands");
692 g_dap.stop_commands = GetStrings(obj: arguments, key: "stopCommands");
693 g_dap.exit_commands = GetStrings(obj: arguments, key: "exitCommands");
694 g_dap.terminate_commands = GetStrings(obj: arguments, key: "terminateCommands");
695 auto attachCommands = GetStrings(obj: arguments, key: "attachCommands");
696 llvm::StringRef core_file = GetString(obj: arguments, key: "coreFile");
697 const uint64_t timeout_seconds = GetUnsigned(obj: arguments, key: "timeout", fail_value: 30);
698 g_dap.stop_at_entry =
699 core_file.empty() ? GetBoolean(obj: arguments, key: "stopOnEntry", fail_value: false) : true;
700 g_dap.post_run_commands = GetStrings(obj: arguments, key: "postRunCommands");
701 const llvm::StringRef debuggerRoot = GetString(obj: arguments, key: "debuggerRoot");
702 g_dap.enable_auto_variable_summaries =
703 GetBoolean(obj: arguments, key: "enableAutoVariableSummaries", fail_value: false);
704 g_dap.enable_synthetic_child_debugging =
705 GetBoolean(obj: arguments, key: "enableSyntheticChildDebugging", fail_value: false);
706 g_dap.command_escape_prefix =
707 GetString(obj: arguments, key: "commandEscapePrefix", defaultValue: "`");
708 g_dap.SetFrameFormat(GetString(obj: arguments, key: "customFrameFormat"));
709 g_dap.SetThreadFormat(GetString(obj: arguments, key: "customThreadFormat"));
710
711 PrintWelcomeMessage();
712
713 // This is a hack for loading DWARF in .o files on Mac where the .o files
714 // in the debug map of the main executable have relative paths which require
715 // the lldb-dap binary to have its working directory set to that relative
716 // root for the .o files in order to be able to load debug info.
717 if (!debuggerRoot.empty())
718 llvm::sys::fs::set_current_path(debuggerRoot);
719
720 // Run any initialize LLDB commands the user specified in the launch.json
721 if (llvm::Error err = g_dap.RunInitCommands()) {
722 response["success"] = false;
723 EmplaceSafeString(response, "message", llvm::toString(std::move(err)));
724 g_dap.SendJSON(json: llvm::json::Value(std::move(response)));
725 return;
726 }
727
728 SetSourceMapFromArguments(*arguments);
729
730 lldb::SBError status;
731 g_dap.SetTarget(g_dap.CreateTargetFromArguments(arguments: *arguments, error&: status));
732 if (status.Fail()) {
733 response["success"] = llvm::json::Value(false);
734 EmplaceSafeString(obj&: response, key: "message", str: status.GetCString());
735 g_dap.SendJSON(json: llvm::json::Value(std::move(response)));
736 return;
737 }
738
739 // Run any pre run LLDB commands the user specified in the launch.json
740 if (llvm::Error err = g_dap.RunPreRunCommands()) {
741 response["success"] = false;
742 EmplaceSafeString(response, "message", llvm::toString(std::move(err)));
743 g_dap.SendJSON(json: llvm::json::Value(std::move(response)));
744 return;
745 }
746
747 if (pid == LLDB_INVALID_PROCESS_ID && wait_for) {
748 char attach_msg[256];
749 auto attach_msg_len = snprintf(s: attach_msg, maxlen: sizeof(attach_msg),
750 format: "Waiting to attach to \"%s\"...",
751 g_dap.target.GetExecutable().GetFilename());
752 g_dap.SendOutput(o: OutputType::Console,
753 output: llvm::StringRef(attach_msg, attach_msg_len));
754 }
755 if (attachCommands.empty()) {
756 // No "attachCommands", just attach normally.
757 // Disable async events so the attach will be successful when we return from
758 // the launch call and the launch will happen synchronously
759 g_dap.debugger.SetAsync(false);
760 if (core_file.empty())
761 g_dap.target.Attach(attach_info, error);
762 else
763 g_dap.target.LoadCore(core_file: core_file.data(), error);
764 // Reenable async events
765 g_dap.debugger.SetAsync(true);
766 } else {
767 // We have "attachCommands" that are a set of commands that are expected
768 // to execute the commands after which a process should be created. If there
769 // is no valid process after running these commands, we have failed.
770 if (llvm::Error err = g_dap.RunAttachCommands(attachCommands)) {
771 response["success"] = false;
772 EmplaceSafeString(response, "message", llvm::toString(std::move(err)));
773 g_dap.SendJSON(json: llvm::json::Value(std::move(response)));
774 return;
775 }
776 // The custom commands might have created a new target so we should use the
777 // selected target after these commands are run.
778 g_dap.target = g_dap.debugger.GetSelectedTarget();
779
780 // Make sure the process is attached and stopped before proceeding as the
781 // the launch commands are not run using the synchronous mode.
782 error = g_dap.WaitForProcessToStop(seconds: timeout_seconds);
783 }
784
785 if (error.Success() && core_file.empty()) {
786 auto attached_pid = g_dap.target.GetProcess().GetProcessID();
787 if (attached_pid == LLDB_INVALID_PROCESS_ID) {
788 if (attachCommands.empty())
789 error.SetErrorString("failed to attach to a process");
790 else
791 error.SetErrorString("attachCommands failed to attach to a process");
792 }
793 }
794
795 if (error.Fail()) {
796 response["success"] = llvm::json::Value(false);
797 EmplaceSafeString(obj&: response, key: "message", str: std::string(error.GetCString()));
798 } else {
799 g_dap.RunPostRunCommands();
800 }
801
802 g_dap.SendJSON(json: llvm::json::Value(std::move(response)));
803 if (error.Success()) {
804 SendProcessEvent(launch_method: Attach);
805 g_dap.SendJSON(json: CreateEventObject(event_name: "initialized"));
806 }
807}
808
809// "ContinueRequest": {
810// "allOf": [ { "$ref": "#/definitions/Request" }, {
811// "type": "object",
812// "description": "Continue request; value of command field is 'continue'.
813// The request starts the debuggee to run again.",
814// "properties": {
815// "command": {
816// "type": "string",
817// "enum": [ "continue" ]
818// },
819// "arguments": {
820// "$ref": "#/definitions/ContinueArguments"
821// }
822// },
823// "required": [ "command", "arguments" ]
824// }]
825// },
826// "ContinueArguments": {
827// "type": "object",
828// "description": "Arguments for 'continue' request.",
829// "properties": {
830// "threadId": {
831// "type": "integer",
832// "description": "Continue execution for the specified thread (if
833// possible). If the backend cannot continue on a single
834// thread but will continue on all threads, it should
835// set the allThreadsContinued attribute in the response
836// to true."
837// }
838// },
839// "required": [ "threadId" ]
840// },
841// "ContinueResponse": {
842// "allOf": [ { "$ref": "#/definitions/Response" }, {
843// "type": "object",
844// "description": "Response to 'continue' request.",
845// "properties": {
846// "body": {
847// "type": "object",
848// "properties": {
849// "allThreadsContinued": {
850// "type": "boolean",
851// "description": "If true, the continue request has ignored the
852// specified thread and continued all threads
853// instead. If this attribute is missing a value
854// of 'true' is assumed for backward
855// compatibility."
856// }
857// }
858// }
859// },
860// "required": [ "body" ]
861// }]
862// }
863void request_continue(const llvm::json::Object &request) {
864 llvm::json::Object response;
865 FillResponse(request, response);
866 lldb::SBProcess process = g_dap.target.GetProcess();
867 lldb::SBError error = process.Continue();
868 llvm::json::Object body;
869 body.try_emplace("allThreadsContinued", true);
870 response.try_emplace("body", std::move(body));
871 g_dap.SendJSON(json: llvm::json::Value(std::move(response)));
872}
873
874// "ConfigurationDoneRequest": {
875// "allOf": [ { "$ref": "#/definitions/Request" }, {
876// "type": "object",
877// "description": "ConfigurationDone request; value of command field
878// is 'configurationDone'.\nThe client of the debug protocol must
879// send this request at the end of the sequence of configuration
880// requests (which was started by the InitializedEvent).",
881// "properties": {
882// "command": {
883// "type": "string",
884// "enum": [ "configurationDone" ]
885// },
886// "arguments": {
887// "$ref": "#/definitions/ConfigurationDoneArguments"
888// }
889// },
890// "required": [ "command" ]
891// }]
892// },
893// "ConfigurationDoneArguments": {
894// "type": "object",
895// "description": "Arguments for 'configurationDone' request.\nThe
896// configurationDone request has no standardized attributes."
897// },
898// "ConfigurationDoneResponse": {
899// "allOf": [ { "$ref": "#/definitions/Response" }, {
900// "type": "object",
901// "description": "Response to 'configurationDone' request. This is
902// just an acknowledgement, so no body field is required."
903// }]
904// },
905void request_configurationDone(const llvm::json::Object &request) {
906 llvm::json::Object response;
907 FillResponse(request, response);
908 g_dap.SendJSON(json: llvm::json::Value(std::move(response)));
909 g_dap.configuration_done_sent = true;
910 if (g_dap.stop_at_entry)
911 SendThreadStoppedEvent();
912 else
913 g_dap.target.GetProcess().Continue();
914}
915
916// "DisconnectRequest": {
917// "allOf": [ { "$ref": "#/definitions/Request" }, {
918// "type": "object",
919// "description": "Disconnect request; value of command field is
920// 'disconnect'.",
921// "properties": {
922// "command": {
923// "type": "string",
924// "enum": [ "disconnect" ]
925// },
926// "arguments": {
927// "$ref": "#/definitions/DisconnectArguments"
928// }
929// },
930// "required": [ "command" ]
931// }]
932// },
933// "DisconnectArguments": {
934// "type": "object",
935// "description": "Arguments for 'disconnect' request.",
936// "properties": {
937// "terminateDebuggee": {
938// "type": "boolean",
939// "description": "Indicates whether the debuggee should be terminated
940// when the debugger is disconnected. If unspecified,
941// the debug adapter is free to do whatever it thinks
942// is best. A client can only rely on this attribute
943// being properly honored if a debug adapter returns
944// true for the 'supportTerminateDebuggee' capability."
945// },
946// "restart": {
947// "type": "boolean",
948// "description": "Indicates whether the debuggee should be restart
949// the process."
950// }
951// }
952// },
953// "DisconnectResponse": {
954// "allOf": [ { "$ref": "#/definitions/Response" }, {
955// "type": "object",
956// "description": "Response to 'disconnect' request. This is just an
957// acknowledgement, so no body field is required."
958// }]
959// }
960void request_disconnect(const llvm::json::Object &request) {
961 llvm::json::Object response;
962 FillResponse(request, response);
963 auto arguments = request.getObject(K: "arguments");
964
965 bool defaultTerminateDebuggee = g_dap.is_attach ? false : true;
966 bool terminateDebuggee =
967 GetBoolean(obj: arguments, key: "terminateDebuggee", fail_value: defaultTerminateDebuggee);
968 lldb::SBProcess process = g_dap.target.GetProcess();
969 auto state = process.GetState();
970 switch (state) {
971 case lldb::eStateInvalid:
972 case lldb::eStateUnloaded:
973 case lldb::eStateDetached:
974 case lldb::eStateExited:
975 break;
976 case lldb::eStateConnected:
977 case lldb::eStateAttaching:
978 case lldb::eStateLaunching:
979 case lldb::eStateStepping:
980 case lldb::eStateCrashed:
981 case lldb::eStateSuspended:
982 case lldb::eStateStopped:
983 case lldb::eStateRunning:
984 g_dap.debugger.SetAsync(false);
985 lldb::SBError error = terminateDebuggee ? process.Kill() : process.Detach();
986 if (!error.Success())
987 response.try_emplace("error", error.GetCString());
988 g_dap.debugger.SetAsync(true);
989 break;
990 }
991 SendTerminatedEvent();
992 g_dap.SendJSON(json: llvm::json::Value(std::move(response)));
993 if (g_dap.event_thread.joinable()) {
994 g_dap.broadcaster.BroadcastEventByType(event_type: eBroadcastBitStopEventThread);
995 g_dap.event_thread.join();
996 }
997 if (g_dap.progress_event_thread.joinable()) {
998 g_dap.broadcaster.BroadcastEventByType(event_type: eBroadcastBitStopProgressThread);
999 g_dap.progress_event_thread.join();
1000 }
1001}
1002
1003void request_exceptionInfo(const llvm::json::Object &request) {
1004 llvm::json::Object response;
1005 FillResponse(request, response);
1006 auto arguments = request.getObject(K: "arguments");
1007 llvm::json::Object body;
1008 lldb::SBThread thread = g_dap.GetLLDBThread(arguments: *arguments);
1009 if (thread.IsValid()) {
1010 auto stopReason = thread.GetStopReason();
1011 if (stopReason == lldb::eStopReasonSignal)
1012 body.try_emplace("exceptionId", "signal");
1013 else if (stopReason == lldb::eStopReasonBreakpoint) {
1014 ExceptionBreakpoint *exc_bp = g_dap.GetExceptionBPFromStopReason(thread);
1015 if (exc_bp) {
1016 EmplaceSafeString(obj&: body, key: "exceptionId", str: exc_bp->filter);
1017 EmplaceSafeString(obj&: body, key: "description", str: exc_bp->label);
1018 } else {
1019 body.try_emplace("exceptionId", "exception");
1020 }
1021 } else {
1022 body.try_emplace("exceptionId", "exception");
1023 }
1024 if (!ObjectContainsKey(obj: body, key: "description")) {
1025 char description[1024];
1026 if (thread.GetStopDescription(dst_or_null: description, dst_len: sizeof(description))) {
1027 EmplaceSafeString(obj&: body, key: "description", str: std::string(description));
1028 }
1029 }
1030 body.try_emplace("breakMode", "always");
1031 // auto excInfoCount = thread.GetStopReasonDataCount();
1032 // for (auto i=0; i<excInfoCount; ++i) {
1033 // uint64_t exc_data = thread.GetStopReasonDataAtIndex(i);
1034 // }
1035 } else {
1036 response["success"] = llvm::json::Value(false);
1037 }
1038 response.try_emplace("body", std::move(body));
1039 g_dap.SendJSON(json: llvm::json::Value(std::move(response)));
1040}
1041
1042// "CompletionsRequest": {
1043// "allOf": [ { "$ref": "#/definitions/Request" }, {
1044// "type": "object",
1045// "description": "Returns a list of possible completions for a given caret
1046// position and text.\nThe CompletionsRequest may only be called if the
1047// 'supportsCompletionsRequest' capability exists and is true.",
1048// "properties": {
1049// "command": {
1050// "type": "string",
1051// "enum": [ "completions" ]
1052// },
1053// "arguments": {
1054// "$ref": "#/definitions/CompletionsArguments"
1055// }
1056// },
1057// "required": [ "command", "arguments" ]
1058// }]
1059// },
1060// "CompletionsArguments": {
1061// "type": "object",
1062// "description": "Arguments for 'completions' request.",
1063// "properties": {
1064// "frameId": {
1065// "type": "integer",
1066// "description": "Returns completions in the scope of this stack frame.
1067// If not specified, the completions are returned for the global scope."
1068// },
1069// "text": {
1070// "type": "string",
1071// "description": "One or more source lines. Typically this is the text a
1072// user has typed into the debug console before he asked for completion."
1073// },
1074// "column": {
1075// "type": "integer",
1076// "description": "The character position for which to determine the
1077// completion proposals."
1078// },
1079// "line": {
1080// "type": "integer",
1081// "description": "An optional line for which to determine the completion
1082// proposals. If missing the first line of the text is assumed."
1083// }
1084// },
1085// "required": [ "text", "column" ]
1086// },
1087// "CompletionsResponse": {
1088// "allOf": [ { "$ref": "#/definitions/Response" }, {
1089// "type": "object",
1090// "description": "Response to 'completions' request.",
1091// "properties": {
1092// "body": {
1093// "type": "object",
1094// "properties": {
1095// "targets": {
1096// "type": "array",
1097// "items": {
1098// "$ref": "#/definitions/CompletionItem"
1099// },
1100// "description": "The possible completions for ."
1101// }
1102// },
1103// "required": [ "targets" ]
1104// }
1105// },
1106// "required": [ "body" ]
1107// }]
1108// },
1109// "CompletionItem": {
1110// "type": "object",
1111// "description": "CompletionItems are the suggestions returned from the
1112// CompletionsRequest.", "properties": {
1113// "label": {
1114// "type": "string",
1115// "description": "The label of this completion item. By default this is
1116// also the text that is inserted when selecting this completion."
1117// },
1118// "text": {
1119// "type": "string",
1120// "description": "If text is not falsy then it is inserted instead of the
1121// label."
1122// },
1123// "sortText": {
1124// "type": "string",
1125// "description": "A string that should be used when comparing this item
1126// with other items. When `falsy` the label is used."
1127// },
1128// "type": {
1129// "$ref": "#/definitions/CompletionItemType",
1130// "description": "The item's type. Typically the client uses this
1131// information to render the item in the UI with an icon."
1132// },
1133// "start": {
1134// "type": "integer",
1135// "description": "This value determines the location (in the
1136// CompletionsRequest's 'text' attribute) where the completion text is
1137// added.\nIf missing the text is added at the location specified by the
1138// CompletionsRequest's 'column' attribute."
1139// },
1140// "length": {
1141// "type": "integer",
1142// "description": "This value determines how many characters are
1143// overwritten by the completion text.\nIf missing the value 0 is assumed
1144// which results in the completion text being inserted."
1145// }
1146// },
1147// "required": [ "label" ]
1148// },
1149// "CompletionItemType": {
1150// "type": "string",
1151// "description": "Some predefined types for the CompletionItem. Please note
1152// that not all clients have specific icons for all of them.", "enum": [
1153// "method", "function", "constructor", "field", "variable", "class",
1154// "interface", "module", "property", "unit", "value", "enum", "keyword",
1155// "snippet", "text", "color", "file", "reference", "customcolor" ]
1156// }
1157void request_completions(const llvm::json::Object &request) {
1158 llvm::json::Object response;
1159 FillResponse(request, response);
1160 llvm::json::Object body;
1161 auto arguments = request.getObject(K: "arguments");
1162
1163 // If we have a frame, try to set the context for variable completions.
1164 lldb::SBFrame frame = g_dap.GetLLDBFrame(arguments: *arguments);
1165 if (frame.IsValid()) {
1166 frame.GetThread().GetProcess().SetSelectedThread(frame.GetThread());
1167 frame.GetThread().SetSelectedFrame(frame.GetFrameID());
1168 }
1169
1170 std::string text = GetString(obj: arguments, key: "text").str();
1171 auto original_column = GetSigned(obj: arguments, key: "column", fail_value: text.size());
1172 auto original_line = GetSigned(obj: arguments, key: "line", fail_value: 1);
1173 auto offset = original_column - 1;
1174 if (original_line > 1) {
1175 llvm::SmallVector<::llvm::StringRef, 2> lines;
1176 llvm::StringRef(text).split(lines, '\n');
1177 for (int i = 0; i < original_line - 1; i++) {
1178 offset += lines[i].size();
1179 }
1180 }
1181 llvm::json::Array targets;
1182
1183 if (!text.empty() &&
1184 llvm::StringRef(text).starts_with(Prefix: g_dap.command_escape_prefix)) {
1185 text = text.substr(g_dap.command_escape_prefix.size());
1186 }
1187
1188 // While the user is typing then we likely have an incomplete input and cannot
1189 // reliably determine the precise intent (command vs variable), try completing
1190 // the text as both a command and variable expression, if applicable.
1191 const std::string expr_prefix = "expression -- ";
1192 std::array<std::tuple<ReplMode, std::string, uint64_t>, 2> exprs = {
1193 {std::make_tuple(ReplMode::Command, text, offset),
1194 std::make_tuple(ReplMode::Variable, expr_prefix + text,
1195 offset + expr_prefix.size())}};
1196 for (const auto &[mode, line, cursor] : exprs) {
1197 if (g_dap.repl_mode != ReplMode::Auto && g_dap.repl_mode != mode)
1198 continue;
1199
1200 lldb::SBStringList matches;
1201 lldb::SBStringList descriptions;
1202 if (!g_dap.debugger.GetCommandInterpreter()
1203 .HandleCompletionWithDescriptions(line.c_str(), cursor, 0, 100,
1204 matches, descriptions))
1205 continue;
1206
1207 // The first element is the common substring after the cursor position for
1208 // all the matches. The rest of the elements are the matches so ignore the
1209 // first result.
1210 for (size_t i = 1; i < matches.GetSize(); i++) {
1211 std::string match = matches.GetStringAtIndex(i);
1212 std::string description = descriptions.GetStringAtIndex(i);
1213
1214 llvm::json::Object item;
1215 llvm::StringRef match_ref = match;
1216 for (llvm::StringRef commit_point : {".", "->"}) {
1217 if (match_ref.contains(commit_point)) {
1218 match_ref = match_ref.rsplit(commit_point).second;
1219 }
1220 }
1221 EmplaceSafeString(item, "text", match_ref);
1222
1223 if (description.empty())
1224 EmplaceSafeString(item, "label", match);
1225 else
1226 EmplaceSafeString(item, "label", match + " -- " + description);
1227
1228 targets.emplace_back(std::move(item));
1229 }
1230 }
1231
1232 body.try_emplace("targets", std::move(targets));
1233 response.try_emplace("body", std::move(body));
1234 g_dap.SendJSON(json: llvm::json::Value(std::move(response)));
1235}
1236
1237// "EvaluateRequest": {
1238// "allOf": [ { "$ref": "#/definitions/Request" }, {
1239// "type": "object",
1240// "description": "Evaluate request; value of command field is 'evaluate'.
1241// Evaluates the given expression in the context of the
1242// top most stack frame. The expression has access to any
1243// variables and arguments that are in scope.",
1244// "properties": {
1245// "command": {
1246// "type": "string",
1247// "enum": [ "evaluate" ]
1248// },
1249// "arguments": {
1250// "$ref": "#/definitions/EvaluateArguments"
1251// }
1252// },
1253// "required": [ "command", "arguments" ]
1254// }]
1255// },
1256// "EvaluateArguments": {
1257// "type": "object",
1258// "description": "Arguments for 'evaluate' request.",
1259// "properties": {
1260// "expression": {
1261// "type": "string",
1262// "description": "The expression to evaluate."
1263// },
1264// "frameId": {
1265// "type": "integer",
1266// "description": "Evaluate the expression in the scope of this stack
1267// frame. If not specified, the expression is evaluated
1268// in the global scope."
1269// },
1270// "context": {
1271// "type": "string",
1272// "_enum": [ "watch", "repl", "hover" ],
1273// "enumDescriptions": [
1274// "evaluate is run in a watch.",
1275// "evaluate is run from REPL console.",
1276// "evaluate is run from a data hover."
1277// ],
1278// "description": "The context in which the evaluate request is run."
1279// },
1280// "format": {
1281// "$ref": "#/definitions/ValueFormat",
1282// "description": "Specifies details on how to format the Evaluate
1283// result."
1284// }
1285// },
1286// "required": [ "expression" ]
1287// },
1288// "EvaluateResponse": {
1289// "allOf": [ { "$ref": "#/definitions/Response" }, {
1290// "type": "object",
1291// "description": "Response to 'evaluate' request.",
1292// "properties": {
1293// "body": {
1294// "type": "object",
1295// "properties": {
1296// "result": {
1297// "type": "string",
1298// "description": "The result of the evaluate request."
1299// },
1300// "type": {
1301// "type": "string",
1302// "description": "The optional type of the evaluate result."
1303// },
1304// "presentationHint": {
1305// "$ref": "#/definitions/VariablePresentationHint",
1306// "description": "Properties of a evaluate result that can be
1307// used to determine how to render the result in
1308// the UI."
1309// },
1310// "variablesReference": {
1311// "type": "number",
1312// "description": "If variablesReference is > 0, the evaluate
1313// result is structured and its children can be
1314// retrieved by passing variablesReference to the
1315// VariablesRequest."
1316// },
1317// "namedVariables": {
1318// "type": "number",
1319// "description": "The number of named child variables. The
1320// client can use this optional information to
1321// present the variables in a paged UI and fetch
1322// them in chunks."
1323// },
1324// "indexedVariables": {
1325// "type": "number",
1326// "description": "The number of indexed child variables. The
1327// client can use this optional information to
1328// present the variables in a paged UI and fetch
1329// them in chunks."
1330// }
1331// },
1332// "required": [ "result", "variablesReference" ]
1333// }
1334// },
1335// "required": [ "body" ]
1336// }]
1337// }
1338void request_evaluate(const llvm::json::Object &request) {
1339 llvm::json::Object response;
1340 FillResponse(request, response);
1341 llvm::json::Object body;
1342 auto arguments = request.getObject(K: "arguments");
1343 lldb::SBFrame frame = g_dap.GetLLDBFrame(arguments: *arguments);
1344 std::string expression = GetString(obj: arguments, key: "expression").str();
1345 llvm::StringRef context = GetString(obj: arguments, key: "context");
1346
1347 if (context == "repl" && g_dap.DetectExpressionContext(frame, expression) ==
1348 ExpressionContext::Command) {
1349 // If we're evaluating a command relative to the current frame, set the
1350 // focus_tid to the current frame for any thread related events.
1351 if (frame.IsValid()) {
1352 g_dap.focus_tid = frame.GetThread().GetThreadID();
1353 }
1354 auto result =
1355 RunLLDBCommandsVerbatim(llvm::StringRef(), {std::string(expression)});
1356 EmplaceSafeString(body, "result", result);
1357 body.try_emplace("variablesReference", (int64_t)0);
1358 } else {
1359 // Always try to get the answer from the local variables if possible. If
1360 // this fails, then if the context is not "hover", actually evaluate an
1361 // expression using the expression parser.
1362 //
1363 // "frame variable" is more reliable than the expression parser in
1364 // many cases and it is faster.
1365 lldb::SBValue value = frame.GetValueForVariablePath(
1366 var_expr_cstr: expression.data(), use_dynamic: lldb::eDynamicDontRunTarget);
1367
1368 // Freeze dry the value in case users expand it later in the debug console
1369 if (value.GetError().Success() && context == "repl")
1370 value = value.Persist();
1371
1372 if (value.GetError().Fail() && context != "hover")
1373 value = frame.EvaluateExpression(expr: expression.data());
1374
1375 if (value.GetError().Fail()) {
1376 response["success"] = llvm::json::Value(false);
1377 // This error object must live until we're done with the pointer returned
1378 // by GetCString().
1379 lldb::SBError error = value.GetError();
1380 const char *error_cstr = error.GetCString();
1381 if (error_cstr && error_cstr[0])
1382 EmplaceSafeString(obj&: response, key: "message", str: std::string(error_cstr));
1383 else
1384 EmplaceSafeString(obj&: response, key: "message", str: "evaluate failed");
1385 } else {
1386 VariableDescription desc(value);
1387 EmplaceSafeString(obj&: body, key: "result", str: desc.GetResult(context));
1388 EmplaceSafeString(obj&: body, key: "type", str: desc.display_type_name);
1389 if (value.MightHaveChildren()) {
1390 auto variableReference = g_dap.variables.InsertExpandableVariable(
1391 variable: value, /*is_permanent=*/context == "repl");
1392 body.try_emplace("variablesReference", variableReference);
1393 } else {
1394 body.try_emplace("variablesReference", (int64_t)0);
1395 }
1396 }
1397 }
1398 response.try_emplace("body", std::move(body));
1399 g_dap.SendJSON(json: llvm::json::Value(std::move(response)));
1400}
1401
1402// "compileUnitsRequest": {
1403// "allOf": [ { "$ref": "#/definitions/Request" }, {
1404// "type": "object",
1405// "description": "Compile Unit request; value of command field is
1406// 'compileUnits'.",
1407// "properties": {
1408// "command": {
1409// "type": "string",
1410// "enum": [ "compileUnits" ]
1411// },
1412// "arguments": {
1413// "$ref": "#/definitions/compileUnitRequestArguments"
1414// }
1415// },
1416// "required": [ "command", "arguments" ]
1417// }]
1418// },
1419// "compileUnitsRequestArguments": {
1420// "type": "object",
1421// "description": "Arguments for 'compileUnits' request.",
1422// "properties": {
1423// "moduleId": {
1424// "type": "string",
1425// "description": "The ID of the module."
1426// }
1427// },
1428// "required": [ "moduleId" ]
1429// },
1430// "compileUnitsResponse": {
1431// "allOf": [ { "$ref": "#/definitions/Response" }, {
1432// "type": "object",
1433// "description": "Response to 'compileUnits' request.",
1434// "properties": {
1435// "body": {
1436// "description": "Response to 'compileUnits' request. Array of
1437// paths of compile units."
1438// }
1439// }
1440// }]
1441// }
1442void request_compileUnits(const llvm::json::Object &request) {
1443 llvm::json::Object response;
1444 FillResponse(request, response);
1445 llvm::json::Object body;
1446 llvm::json::Array units;
1447 auto arguments = request.getObject(K: "arguments");
1448 std::string module_id = std::string(GetString(obj: arguments, key: "moduleId"));
1449 int num_modules = g_dap.target.GetNumModules();
1450 for (int i = 0; i < num_modules; i++) {
1451 auto curr_module = g_dap.target.GetModuleAtIndex(idx: i);
1452 if (module_id == curr_module.GetUUIDString()) {
1453 int num_units = curr_module.GetNumCompileUnits();
1454 for (int j = 0; j < num_units; j++) {
1455 auto curr_unit = curr_module.GetCompileUnitAtIndex(j);
1456 units.emplace_back(CreateCompileUnit(unit: curr_unit));
1457 }
1458 body.try_emplace("compileUnits", std::move(units));
1459 break;
1460 }
1461 }
1462 response.try_emplace("body", std::move(body));
1463 g_dap.SendJSON(json: llvm::json::Value(std::move(response)));
1464}
1465
1466// "modulesRequest": {
1467// "allOf": [ { "$ref": "#/definitions/Request" }, {
1468// "type": "object",
1469// "description": "Modules request; value of command field is
1470// 'modules'.",
1471// "properties": {
1472// "command": {
1473// "type": "string",
1474// "enum": [ "modules" ]
1475// },
1476// },
1477// "required": [ "command" ]
1478// }]
1479// },
1480// "modulesResponse": {
1481// "allOf": [ { "$ref": "#/definitions/Response" }, {
1482// "type": "object",
1483// "description": "Response to 'modules' request.",
1484// "properties": {
1485// "body": {
1486// "description": "Response to 'modules' request. Array of
1487// module objects."
1488// }
1489// }
1490// }]
1491// }
1492void request_modules(const llvm::json::Object &request) {
1493 llvm::json::Object response;
1494 FillResponse(request, response);
1495
1496 llvm::json::Array modules;
1497 for (size_t i = 0; i < g_dap.target.GetNumModules(); i++) {
1498 lldb::SBModule module = g_dap.target.GetModuleAtIndex(idx: i);
1499 modules.emplace_back(CreateModule(module));
1500 }
1501
1502 llvm::json::Object body;
1503 body.try_emplace("modules", std::move(modules));
1504 response.try_emplace("body", std::move(body));
1505 g_dap.SendJSON(json: llvm::json::Value(std::move(response)));
1506}
1507
1508// "InitializeRequest": {
1509// "allOf": [ { "$ref": "#/definitions/Request" }, {
1510// "type": "object",
1511// "description": "Initialize request; value of command field is
1512// 'initialize'.",
1513// "properties": {
1514// "command": {
1515// "type": "string",
1516// "enum": [ "initialize" ]
1517// },
1518// "arguments": {
1519// "$ref": "#/definitions/InitializeRequestArguments"
1520// }
1521// },
1522// "required": [ "command", "arguments" ]
1523// }]
1524// },
1525// "InitializeRequestArguments": {
1526// "type": "object",
1527// "description": "Arguments for 'initialize' request.",
1528// "properties": {
1529// "clientID": {
1530// "type": "string",
1531// "description": "The ID of the (frontend) client using this adapter."
1532// },
1533// "adapterID": {
1534// "type": "string",
1535// "description": "The ID of the debug adapter."
1536// },
1537// "locale": {
1538// "type": "string",
1539// "description": "The ISO-639 locale of the (frontend) client using
1540// this adapter, e.g. en-US or de-CH."
1541// },
1542// "linesStartAt1": {
1543// "type": "boolean",
1544// "description": "If true all line numbers are 1-based (default)."
1545// },
1546// "columnsStartAt1": {
1547// "type": "boolean",
1548// "description": "If true all column numbers are 1-based (default)."
1549// },
1550// "pathFormat": {
1551// "type": "string",
1552// "_enum": [ "path", "uri" ],
1553// "description": "Determines in what format paths are specified. The
1554// default is 'path', which is the native format."
1555// },
1556// "supportsVariableType": {
1557// "type": "boolean",
1558// "description": "Client supports the optional type attribute for
1559// variables."
1560// },
1561// "supportsVariablePaging": {
1562// "type": "boolean",
1563// "description": "Client supports the paging of variables."
1564// },
1565// "supportsRunInTerminalRequest": {
1566// "type": "boolean",
1567// "description": "Client supports the runInTerminal request."
1568// }
1569// },
1570// "required": [ "adapterID" ]
1571// },
1572// "InitializeResponse": {
1573// "allOf": [ { "$ref": "#/definitions/Response" }, {
1574// "type": "object",
1575// "description": "Response to 'initialize' request.",
1576// "properties": {
1577// "body": {
1578// "$ref": "#/definitions/Capabilities",
1579// "description": "The capabilities of this debug adapter."
1580// }
1581// }
1582// }]
1583// }
1584void request_initialize(const llvm::json::Object &request) {
1585 auto log_cb = [](const char *buf, void *baton) -> void {
1586 g_dap.SendOutput(o: OutputType::Console, output: llvm::StringRef{buf});
1587 };
1588
1589 auto arguments = request.getObject(K: "arguments");
1590 // sourceInitFile option is not from formal DAP specification. It is only
1591 // used by unit tests to prevent sourcing .lldbinit files from environment
1592 // which may affect the outcome of tests.
1593 bool source_init_file = GetBoolean(obj: arguments, key: "sourceInitFile", fail_value: true);
1594
1595 g_dap.debugger = lldb::SBDebugger::Create(source_init_files: source_init_file, log_callback: log_cb, baton: nullptr);
1596 auto cmd = g_dap.debugger.GetCommandInterpreter().AddMultiwordCommand(
1597 name: "lldb-dap", help: "Commands for managing lldb-dap.");
1598 if (GetBoolean(obj: arguments, key: "supportsStartDebuggingRequest", fail_value: false)) {
1599 cmd.AddCommand(
1600 name: "startDebugging", impl: &g_dap.start_debugging_request_handler,
1601 help: "Sends a startDebugging request from the debug adapter to the client "
1602 "to start a child debug session of the same type as the caller.");
1603 }
1604 cmd.AddCommand(
1605 name: "repl-mode", impl: &g_dap.repl_mode_request_handler,
1606 help: "Get or set the repl behavior of lldb-dap evaluation requests.");
1607
1608 g_dap.progress_event_thread = std::thread(ProgressEventThreadFunction);
1609
1610 // Start our event thread so we can receive events from the debugger, target,
1611 // process and more.
1612 g_dap.event_thread = std::thread(EventThreadFunction);
1613
1614 llvm::json::Object response;
1615 FillResponse(request, response);
1616 llvm::json::Object body;
1617 // The debug adapter supports the configurationDoneRequest.
1618 body.try_emplace("supportsConfigurationDoneRequest", true);
1619 // The debug adapter supports function breakpoints.
1620 body.try_emplace("supportsFunctionBreakpoints", true);
1621 // The debug adapter supports conditional breakpoints.
1622 body.try_emplace("supportsConditionalBreakpoints", true);
1623 // The debug adapter supports breakpoints that break execution after a
1624 // specified number of hits.
1625 body.try_emplace("supportsHitConditionalBreakpoints", true);
1626 // The debug adapter supports a (side effect free) evaluate request for
1627 // data hovers.
1628 body.try_emplace("supportsEvaluateForHovers", true);
1629 // Available filters or options for the setExceptionBreakpoints request.
1630 llvm::json::Array filters;
1631 for (const auto &exc_bp : g_dap.exception_breakpoints) {
1632 filters.emplace_back(CreateExceptionBreakpointFilter(exc_bp));
1633 }
1634 body.try_emplace("exceptionBreakpointFilters", std::move(filters));
1635 // The debug adapter supports launching a debugee in intergrated VSCode
1636 // terminal.
1637 body.try_emplace("supportsRunInTerminalRequest", true);
1638 // The debug adapter supports stepping back via the stepBack and
1639 // reverseContinue requests.
1640 body.try_emplace("supportsStepBack", false);
1641 // The debug adapter supports setting a variable to a value.
1642 body.try_emplace("supportsSetVariable", true);
1643 // The debug adapter supports restarting a frame.
1644 body.try_emplace("supportsRestartFrame", false);
1645 // The debug adapter supports the gotoTargetsRequest.
1646 body.try_emplace("supportsGotoTargetsRequest", false);
1647 // The debug adapter supports the stepInTargetsRequest.
1648 body.try_emplace("supportsStepInTargetsRequest", false);
1649 // The debug adapter supports the completions request.
1650 body.try_emplace("supportsCompletionsRequest", true);
1651 // The debug adapter supports the disassembly request.
1652 body.try_emplace("supportsDisassembleRequest", true);
1653
1654 llvm::json::Array completion_characters;
1655 completion_characters.emplace_back(".");
1656 completion_characters.emplace_back(" ");
1657 completion_characters.emplace_back("\t");
1658 body.try_emplace("completionTriggerCharacters",
1659 std::move(completion_characters));
1660
1661 // The debug adapter supports the modules request.
1662 body.try_emplace("supportsModulesRequest", true);
1663 // The set of additional module information exposed by the debug adapter.
1664 // body.try_emplace("additionalModuleColumns"] = ColumnDescriptor
1665 // Checksum algorithms supported by the debug adapter.
1666 // body.try_emplace("supportedChecksumAlgorithms"] = ChecksumAlgorithm
1667 // The debug adapter supports the RestartRequest. In this case a client
1668 // should not implement 'restart' by terminating and relaunching the adapter
1669 // but by calling the RestartRequest.
1670 body.try_emplace("supportsRestartRequest", true);
1671 // The debug adapter supports 'exceptionOptions' on the
1672 // setExceptionBreakpoints request.
1673 body.try_emplace("supportsExceptionOptions", true);
1674 // The debug adapter supports a 'format' attribute on the stackTraceRequest,
1675 // variablesRequest, and evaluateRequest.
1676 body.try_emplace("supportsValueFormattingOptions", true);
1677 // The debug adapter supports the exceptionInfo request.
1678 body.try_emplace("supportsExceptionInfoRequest", true);
1679 // The debug adapter supports the 'terminateDebuggee' attribute on the
1680 // 'disconnect' request.
1681 body.try_emplace("supportTerminateDebuggee", true);
1682 // The debug adapter supports the delayed loading of parts of the stack,
1683 // which requires that both the 'startFrame' and 'levels' arguments and the
1684 // 'totalFrames' result of the 'StackTrace' request are supported.
1685 body.try_emplace("supportsDelayedStackTraceLoading", true);
1686 // The debug adapter supports the 'loadedSources' request.
1687 body.try_emplace("supportsLoadedSourcesRequest", false);
1688 // The debug adapter supports sending progress reporting events.
1689 body.try_emplace("supportsProgressReporting", true);
1690 // The debug adapter supports 'logMessage' in breakpoint.
1691 body.try_emplace("supportsLogPoints", true);
1692 // The debug adapter supports data watchpoints.
1693 body.try_emplace("supportsDataBreakpoints", true);
1694
1695 response.try_emplace("body", std::move(body));
1696 g_dap.SendJSON(json: llvm::json::Value(std::move(response)));
1697}
1698
1699llvm::Error request_runInTerminal(const llvm::json::Object &launch_request,
1700 const uint64_t timeout_seconds) {
1701 g_dap.is_attach = true;
1702 lldb::SBAttachInfo attach_info;
1703
1704 llvm::Expected<std::shared_ptr<FifoFile>> comm_file_or_err =
1705 CreateRunInTerminalCommFile();
1706 if (!comm_file_or_err)
1707 return comm_file_or_err.takeError();
1708 FifoFile &comm_file = *comm_file_or_err.get();
1709
1710 RunInTerminalDebugAdapterCommChannel comm_channel(comm_file.m_path);
1711
1712 lldb::pid_t debugger_pid = LLDB_INVALID_PROCESS_ID;
1713#if !defined(_WIN32)
1714 debugger_pid = getpid();
1715#endif
1716 llvm::json::Object reverse_request = CreateRunInTerminalReverseRequest(
1717 launch_request, debug_adaptor_path: g_dap.debug_adaptor_path, comm_file: comm_file.m_path, debugger_pid);
1718 g_dap.SendReverseRequest(command: "runInTerminal", arguments: std::move(reverse_request),
1719 callback: [](llvm::Expected<llvm::json::Value> value) {
1720 if (!value) {
1721 llvm::Error err = value.takeError();
1722 llvm::errs()
1723 << "runInTerminal request failed: "
1724 << llvm::toString(std::move(err)) << "\n";
1725 }
1726 });
1727
1728 if (llvm::Expected<lldb::pid_t> pid = comm_channel.GetLauncherPid())
1729 attach_info.SetProcessID(*pid);
1730 else
1731 return pid.takeError();
1732
1733 g_dap.debugger.SetAsync(false);
1734 lldb::SBError error;
1735 g_dap.target.Attach(attach_info, error);
1736
1737 if (error.Fail())
1738 return llvm::createStringError(llvm::inconvertibleErrorCode(),
1739 "Failed to attach to the target process. %s",
1740 comm_channel.GetLauncherError().c_str());
1741 // This will notify the runInTerminal launcher that we attached.
1742 // We have to make this async, as the function won't return until the launcher
1743 // resumes and reads the data.
1744 std::future<lldb::SBError> did_attach_message_success =
1745 comm_channel.NotifyDidAttach();
1746
1747 // We just attached to the runInTerminal launcher, which was waiting to be
1748 // attached. We now resume it, so it can receive the didAttach notification
1749 // and then perform the exec. Upon continuing, the debugger will stop the
1750 // process right in the middle of the exec. To the user, what we are doing is
1751 // transparent, as they will only be able to see the process since the exec,
1752 // completely unaware of the preparatory work.
1753 g_dap.target.GetProcess().Continue();
1754
1755 // Now that the actual target is just starting (i.e. exec was just invoked),
1756 // we return the debugger to its async state.
1757 g_dap.debugger.SetAsync(true);
1758
1759 // If sending the notification failed, the launcher should be dead by now and
1760 // the async didAttach notification should have an error message, so we
1761 // return it. Otherwise, everything was a success.
1762 did_attach_message_success.wait();
1763 error = did_attach_message_success.get();
1764 if (error.Success())
1765 return llvm::Error::success();
1766 return llvm::createStringError(EC: llvm::inconvertibleErrorCode(),
1767 Msg: error.GetCString());
1768}
1769
1770// Takes a LaunchRequest object and launches the process, also handling
1771// runInTerminal if applicable. It doesn't do any of the additional
1772// initialization and bookkeeping stuff that is needed for `request_launch`.
1773// This way we can reuse the process launching logic for RestartRequest too.
1774lldb::SBError LaunchProcess(const llvm::json::Object &request) {
1775 lldb::SBError error;
1776 auto arguments = request.getObject(K: "arguments");
1777 auto launchCommands = GetStrings(obj: arguments, key: "launchCommands");
1778
1779 // Instantiate a launch info instance for the target.
1780 auto launch_info = g_dap.target.GetLaunchInfo();
1781
1782 // Grab the current working directory if there is one and set it in the
1783 // launch info.
1784 const auto cwd = GetString(obj: arguments, key: "cwd");
1785 if (!cwd.empty())
1786 launch_info.SetWorkingDirectory(cwd.data());
1787
1788 // Extract any extra arguments and append them to our program arguments for
1789 // when we launch
1790 auto args = GetStrings(obj: arguments, key: "args");
1791 if (!args.empty())
1792 launch_info.SetArguments(MakeArgv(args).data(), true);
1793
1794 // Pass any environment variables along that the user specified.
1795 auto envs = GetStrings(obj: arguments, key: "env");
1796 if (!envs.empty())
1797 launch_info.SetEnvironmentEntries(MakeArgv(envs).data(), true);
1798
1799 auto flags = launch_info.GetLaunchFlags();
1800
1801 if (GetBoolean(obj: arguments, key: "disableASLR", fail_value: true))
1802 flags |= lldb::eLaunchFlagDisableASLR;
1803 if (GetBoolean(obj: arguments, key: "disableSTDIO", fail_value: false))
1804 flags |= lldb::eLaunchFlagDisableSTDIO;
1805 if (GetBoolean(obj: arguments, key: "shellExpandArguments", fail_value: false))
1806 flags |= lldb::eLaunchFlagShellExpandArguments;
1807 const bool detachOnError = GetBoolean(obj: arguments, key: "detachOnError", fail_value: false);
1808 launch_info.SetDetachOnError(detachOnError);
1809 launch_info.SetLaunchFlags(flags | lldb::eLaunchFlagDebug |
1810 lldb::eLaunchFlagStopAtEntry);
1811 const uint64_t timeout_seconds = GetUnsigned(obj: arguments, key: "timeout", fail_value: 30);
1812
1813 if (GetBoolean(obj: arguments, key: "runInTerminal", fail_value: false)) {
1814 if (llvm::Error err = request_runInTerminal(launch_request: request, timeout_seconds))
1815 error.SetErrorString(llvm::toString(std::move(err)).c_str());
1816 } else if (launchCommands.empty()) {
1817 // Disable async events so the launch will be successful when we return from
1818 // the launch call and the launch will happen synchronously
1819 g_dap.debugger.SetAsync(false);
1820 g_dap.target.Launch(launch_info, error);
1821 g_dap.debugger.SetAsync(true);
1822 } else {
1823 // Set the launch info so that run commands can access the configured
1824 // launch details.
1825 g_dap.target.SetLaunchInfo(launch_info);
1826 if (llvm::Error err = g_dap.RunLaunchCommands(launchCommands)) {
1827 error.SetErrorString(llvm::toString(std::move(err)).c_str());
1828 return error;
1829 }
1830 // The custom commands might have created a new target so we should use the
1831 // selected target after these commands are run.
1832 g_dap.target = g_dap.debugger.GetSelectedTarget();
1833 // Make sure the process is launched and stopped at the entry point before
1834 // proceeding as the launch commands are not run using the synchronous
1835 // mode.
1836 error = g_dap.WaitForProcessToStop(seconds: timeout_seconds);
1837 }
1838 return error;
1839}
1840
1841// "LaunchRequest": {
1842// "allOf": [ { "$ref": "#/definitions/Request" }, {
1843// "type": "object",
1844// "description": "Launch request; value of command field is 'launch'.",
1845// "properties": {
1846// "command": {
1847// "type": "string",
1848// "enum": [ "launch" ]
1849// },
1850// "arguments": {
1851// "$ref": "#/definitions/LaunchRequestArguments"
1852// }
1853// },
1854// "required": [ "command", "arguments" ]
1855// }]
1856// },
1857// "LaunchRequestArguments": {
1858// "type": "object",
1859// "description": "Arguments for 'launch' request.",
1860// "properties": {
1861// "noDebug": {
1862// "type": "boolean",
1863// "description": "If noDebug is true the launch request should launch
1864// the program without enabling debugging."
1865// }
1866// }
1867// },
1868// "LaunchResponse": {
1869// "allOf": [ { "$ref": "#/definitions/Response" }, {
1870// "type": "object",
1871// "description": "Response to 'launch' request. This is just an
1872// acknowledgement, so no body field is required."
1873// }]
1874// }
1875void request_launch(const llvm::json::Object &request) {
1876 g_dap.is_attach = false;
1877 g_dap.last_launch_or_attach_request = request;
1878 llvm::json::Object response;
1879 FillResponse(request, response);
1880 auto arguments = request.getObject(K: "arguments");
1881 g_dap.init_commands = GetStrings(obj: arguments, key: "initCommands");
1882 g_dap.pre_run_commands = GetStrings(obj: arguments, key: "preRunCommands");
1883 g_dap.stop_commands = GetStrings(obj: arguments, key: "stopCommands");
1884 g_dap.exit_commands = GetStrings(obj: arguments, key: "exitCommands");
1885 g_dap.terminate_commands = GetStrings(obj: arguments, key: "terminateCommands");
1886 g_dap.post_run_commands = GetStrings(obj: arguments, key: "postRunCommands");
1887 g_dap.stop_at_entry = GetBoolean(obj: arguments, key: "stopOnEntry", fail_value: false);
1888 const llvm::StringRef debuggerRoot = GetString(obj: arguments, key: "debuggerRoot");
1889 g_dap.enable_auto_variable_summaries =
1890 GetBoolean(obj: arguments, key: "enableAutoVariableSummaries", fail_value: false);
1891 g_dap.enable_synthetic_child_debugging =
1892 GetBoolean(obj: arguments, key: "enableSyntheticChildDebugging", fail_value: false);
1893 g_dap.command_escape_prefix =
1894 GetString(obj: arguments, key: "commandEscapePrefix", defaultValue: "`");
1895 g_dap.SetFrameFormat(GetString(obj: arguments, key: "customFrameFormat"));
1896 g_dap.SetThreadFormat(GetString(obj: arguments, key: "customThreadFormat"));
1897
1898 PrintWelcomeMessage();
1899
1900 // This is a hack for loading DWARF in .o files on Mac where the .o files
1901 // in the debug map of the main executable have relative paths which
1902 // require the lldb-dap binary to have its working directory set to that
1903 // relative root for the .o files in order to be able to load debug info.
1904 if (!debuggerRoot.empty())
1905 llvm::sys::fs::set_current_path(debuggerRoot);
1906
1907 // Run any initialize LLDB commands the user specified in the launch.json.
1908 // This is run before target is created, so commands can't do anything with
1909 // the targets - preRunCommands are run with the target.
1910 if (llvm::Error err = g_dap.RunInitCommands()) {
1911 response["success"] = false;
1912 EmplaceSafeString(response, "message", llvm::toString(std::move(err)));
1913 g_dap.SendJSON(json: llvm::json::Value(std::move(response)));
1914 return;
1915 }
1916
1917 SetSourceMapFromArguments(*arguments);
1918
1919 lldb::SBError status;
1920 g_dap.SetTarget(g_dap.CreateTargetFromArguments(arguments: *arguments, error&: status));
1921 if (status.Fail()) {
1922 response["success"] = llvm::json::Value(false);
1923 EmplaceSafeString(obj&: response, key: "message", str: status.GetCString());
1924 g_dap.SendJSON(json: llvm::json::Value(std::move(response)));
1925 return;
1926 }
1927
1928 // Run any pre run LLDB commands the user specified in the launch.json
1929 if (llvm::Error err = g_dap.RunPreRunCommands()) {
1930 response["success"] = false;
1931 EmplaceSafeString(response, "message", llvm::toString(std::move(err)));
1932 g_dap.SendJSON(json: llvm::json::Value(std::move(response)));
1933 return;
1934 }
1935
1936 status = LaunchProcess(request);
1937
1938 if (status.Fail()) {
1939 response["success"] = llvm::json::Value(false);
1940 EmplaceSafeString(obj&: response, key: "message", str: std::string(status.GetCString()));
1941 } else {
1942 g_dap.RunPostRunCommands();
1943 }
1944
1945 g_dap.SendJSON(json: llvm::json::Value(std::move(response)));
1946
1947 if (!status.Fail()) {
1948 if (g_dap.is_attach)
1949 SendProcessEvent(launch_method: Attach); // this happens when doing runInTerminal
1950 else
1951 SendProcessEvent(launch_method: Launch);
1952 }
1953 g_dap.SendJSON(json: CreateEventObject(event_name: "initialized"));
1954}
1955
1956// "NextRequest": {
1957// "allOf": [ { "$ref": "#/definitions/Request" }, {
1958// "type": "object",
1959// "description": "Next request; value of command field is 'next'. The
1960// request starts the debuggee to run again for one step.
1961// The debug adapter first sends the NextResponse and then
1962// a StoppedEvent (event type 'step') after the step has
1963// completed.",
1964// "properties": {
1965// "command": {
1966// "type": "string",
1967// "enum": [ "next" ]
1968// },
1969// "arguments": {
1970// "$ref": "#/definitions/NextArguments"
1971// }
1972// },
1973// "required": [ "command", "arguments" ]
1974// }]
1975// },
1976// "NextArguments": {
1977// "type": "object",
1978// "description": "Arguments for 'next' request.",
1979// "properties": {
1980// "threadId": {
1981// "type": "integer",
1982// "description": "Execute 'next' for this thread."
1983// }
1984// },
1985// "required": [ "threadId" ]
1986// },
1987// "NextResponse": {
1988// "allOf": [ { "$ref": "#/definitions/Response" }, {
1989// "type": "object",
1990// "description": "Response to 'next' request. This is just an
1991// acknowledgement, so no body field is required."
1992// }]
1993// }
1994void request_next(const llvm::json::Object &request) {
1995 llvm::json::Object response;
1996 FillResponse(request, response);
1997 auto arguments = request.getObject(K: "arguments");
1998 lldb::SBThread thread = g_dap.GetLLDBThread(arguments: *arguments);
1999 if (thread.IsValid()) {
2000 // Remember the thread ID that caused the resume so we can set the
2001 // "threadCausedFocus" boolean value in the "stopped" events.
2002 g_dap.focus_tid = thread.GetThreadID();
2003 thread.StepOver();
2004 } else {
2005 response["success"] = llvm::json::Value(false);
2006 }
2007 g_dap.SendJSON(json: llvm::json::Value(std::move(response)));
2008}
2009
2010// "PauseRequest": {
2011// "allOf": [ { "$ref": "#/definitions/Request" }, {
2012// "type": "object",
2013// "description": "Pause request; value of command field is 'pause'. The
2014// request suspenses the debuggee. The debug adapter first sends the
2015// PauseResponse and then a StoppedEvent (event type 'pause') after the
2016// thread has been paused successfully.", "properties": {
2017// "command": {
2018// "type": "string",
2019// "enum": [ "pause" ]
2020// },
2021// "arguments": {
2022// "$ref": "#/definitions/PauseArguments"
2023// }
2024// },
2025// "required": [ "command", "arguments" ]
2026// }]
2027// },
2028// "PauseArguments": {
2029// "type": "object",
2030// "description": "Arguments for 'pause' request.",
2031// "properties": {
2032// "threadId": {
2033// "type": "integer",
2034// "description": "Pause execution for this thread."
2035// }
2036// },
2037// "required": [ "threadId" ]
2038// },
2039// "PauseResponse": {
2040// "allOf": [ { "$ref": "#/definitions/Response" }, {
2041// "type": "object",
2042// "description": "Response to 'pause' request. This is just an
2043// acknowledgement, so no body field is required."
2044// }]
2045// }
2046void request_pause(const llvm::json::Object &request) {
2047 llvm::json::Object response;
2048 FillResponse(request, response);
2049 lldb::SBProcess process = g_dap.target.GetProcess();
2050 lldb::SBError error = process.Stop();
2051 g_dap.SendJSON(json: llvm::json::Value(std::move(response)));
2052}
2053
2054// "RestartRequest": {
2055// "allOf": [ { "$ref": "#/definitions/Request" }, {
2056// "type": "object",
2057// "description": "Restarts a debug session. Clients should only call this
2058// request if the corresponding capability `supportsRestartRequest` is
2059// true.\nIf the capability is missing or has the value false, a typical
2060// client emulates `restart` by terminating the debug adapter first and then
2061// launching it anew.",
2062// "properties": {
2063// "command": {
2064// "type": "string",
2065// "enum": [ "restart" ]
2066// },
2067// "arguments": {
2068// "$ref": "#/definitions/RestartArguments"
2069// }
2070// },
2071// "required": [ "command" ]
2072// }]
2073// },
2074// "RestartArguments": {
2075// "type": "object",
2076// "description": "Arguments for `restart` request.",
2077// "properties": {
2078// "arguments": {
2079// "oneOf": [
2080// { "$ref": "#/definitions/LaunchRequestArguments" },
2081// { "$ref": "#/definitions/AttachRequestArguments" }
2082// ],
2083// "description": "The latest version of the `launch` or `attach`
2084// configuration."
2085// }
2086// }
2087// },
2088// "RestartResponse": {
2089// "allOf": [ { "$ref": "#/definitions/Response" }, {
2090// "type": "object",
2091// "description": "Response to `restart` request. This is just an
2092// acknowledgement, so no body field is required."
2093// }]
2094// },
2095void request_restart(const llvm::json::Object &request) {
2096 llvm::json::Object response;
2097 FillResponse(request, response);
2098 if (!g_dap.last_launch_or_attach_request) {
2099 response["success"] = llvm::json::Value(false);
2100 EmplaceSafeString(obj&: response, key: "message",
2101 str: "Restart request received but no process was launched.");
2102 g_dap.SendJSON(json: llvm::json::Value(std::move(response)));
2103 return;
2104 }
2105 // Check if we were in a "launch" session or an "attach" session.
2106 //
2107 // Restarting is not well defined when we started the session by attaching to
2108 // an existing process, because we don't know how the process was started, so
2109 // we don't support it.
2110 //
2111 // Note that when using runInTerminal we're technically attached, but it's an
2112 // implementation detail. The adapter *did* launch the process in response to
2113 // a "launch" command, so we can still stop it and re-run it. This is why we
2114 // don't just check `g_dap.is_attach`.
2115 if (GetString(obj: *g_dap.last_launch_or_attach_request, key: "command") == "attach") {
2116 response["success"] = llvm::json::Value(false);
2117 EmplaceSafeString(obj&: response, key: "message",
2118 str: "Restarting an \"attach\" session is not supported.");
2119 g_dap.SendJSON(json: llvm::json::Value(std::move(response)));
2120 return;
2121 }
2122
2123 // The optional `arguments` field in RestartRequest can contain an updated
2124 // version of the launch arguments. If there's one, use it.
2125 auto restart_arguments = request.getObject(K: "arguments");
2126 if (restart_arguments) {
2127 auto launch_request_arguments = restart_arguments->getObject(K: "arguments");
2128 if (launch_request_arguments) {
2129 (*g_dap.last_launch_or_attach_request)["arguments"] =
2130 llvm::json::Value(llvm::json::Object(*launch_request_arguments));
2131 }
2132 }
2133
2134 // Keep track of the old PID so when we get a "process exited" event from the
2135 // killed process we can detect it and not shut down the whole session.
2136 lldb::SBProcess process = g_dap.target.GetProcess();
2137 g_dap.restarting_process_id = process.GetProcessID();
2138
2139 // Stop the current process if necessary. The logic here is similar to
2140 // CommandObjectProcessLaunchOrAttach::StopProcessIfNecessary, except that
2141 // we don't ask the user for confirmation.
2142 g_dap.debugger.SetAsync(false);
2143 if (process.IsValid()) {
2144 lldb::StateType state = process.GetState();
2145 if (state != lldb::eStateConnected) {
2146 process.Kill();
2147 }
2148 // Clear the list of thread ids to avoid sending "thread exited" events
2149 // for threads of the process we are terminating.
2150 g_dap.thread_ids.clear();
2151 }
2152 g_dap.debugger.SetAsync(true);
2153 LaunchProcess(request: *g_dap.last_launch_or_attach_request);
2154
2155 // This is normally done after receiving a "configuration done" request.
2156 // Because we're restarting, configuration has already happened so we can
2157 // continue the process right away.
2158 if (g_dap.stop_at_entry) {
2159 SendThreadStoppedEvent();
2160 } else {
2161 g_dap.target.GetProcess().Continue();
2162 }
2163
2164 g_dap.SendJSON(json: llvm::json::Value(std::move(response)));
2165}
2166
2167// "ScopesRequest": {
2168// "allOf": [ { "$ref": "#/definitions/Request" }, {
2169// "type": "object",
2170// "description": "Scopes request; value of command field is 'scopes'. The
2171// request returns the variable scopes for a given stackframe ID.",
2172// "properties": {
2173// "command": {
2174// "type": "string",
2175// "enum": [ "scopes" ]
2176// },
2177// "arguments": {
2178// "$ref": "#/definitions/ScopesArguments"
2179// }
2180// },
2181// "required": [ "command", "arguments" ]
2182// }]
2183// },
2184// "ScopesArguments": {
2185// "type": "object",
2186// "description": "Arguments for 'scopes' request.",
2187// "properties": {
2188// "frameId": {
2189// "type": "integer",
2190// "description": "Retrieve the scopes for this stackframe."
2191// }
2192// },
2193// "required": [ "frameId" ]
2194// },
2195// "ScopesResponse": {
2196// "allOf": [ { "$ref": "#/definitions/Response" }, {
2197// "type": "object",
2198// "description": "Response to 'scopes' request.",
2199// "properties": {
2200// "body": {
2201// "type": "object",
2202// "properties": {
2203// "scopes": {
2204// "type": "array",
2205// "items": {
2206// "$ref": "#/definitions/Scope"
2207// },
2208// "description": "The scopes of the stackframe. If the array has
2209// length zero, there are no scopes available."
2210// }
2211// },
2212// "required": [ "scopes" ]
2213// }
2214// },
2215// "required": [ "body" ]
2216// }]
2217// }
2218void request_scopes(const llvm::json::Object &request) {
2219 llvm::json::Object response;
2220 FillResponse(request, response);
2221 llvm::json::Object body;
2222 auto arguments = request.getObject(K: "arguments");
2223 lldb::SBFrame frame = g_dap.GetLLDBFrame(arguments: *arguments);
2224 // As the user selects different stack frames in the GUI, a "scopes" request
2225 // will be sent to the DAP. This is the only way we know that the user has
2226 // selected a frame in a thread. There are no other notifications that are
2227 // sent and VS code doesn't allow multiple frames to show variables
2228 // concurrently. If we select the thread and frame as the "scopes" requests
2229 // are sent, this allows users to type commands in the debugger console
2230 // with a backtick character to run lldb commands and these lldb commands
2231 // will now have the right context selected as they are run. If the user
2232 // types "`bt" into the debugger console and we had another thread selected
2233 // in the LLDB library, we would show the wrong thing to the user. If the
2234 // users switches threads with a lldb command like "`thread select 14", the
2235 // GUI will not update as there are no "event" notification packets that
2236 // allow us to change the currently selected thread or frame in the GUI that
2237 // I am aware of.
2238 if (frame.IsValid()) {
2239 frame.GetThread().GetProcess().SetSelectedThread(frame.GetThread());
2240 frame.GetThread().SetSelectedFrame(frame.GetFrameID());
2241 }
2242
2243 g_dap.variables.locals = frame.GetVariables(/*arguments=*/true,
2244 /*locals=*/true,
2245 /*statics=*/false,
2246 /*in_scope_only=*/true);
2247 g_dap.variables.globals = frame.GetVariables(/*arguments=*/false,
2248 /*locals=*/false,
2249 /*statics=*/true,
2250 /*in_scope_only=*/true);
2251 g_dap.variables.registers = frame.GetRegisters();
2252 body.try_emplace("scopes", g_dap.CreateTopLevelScopes());
2253 response.try_emplace("body", std::move(body));
2254 g_dap.SendJSON(json: llvm::json::Value(std::move(response)));
2255}
2256
2257// "SetBreakpointsRequest": {
2258// "allOf": [ { "$ref": "#/definitions/Request" }, {
2259// "type": "object",
2260// "description": "SetBreakpoints request; value of command field is
2261// 'setBreakpoints'. Sets multiple breakpoints for a single source and
2262// clears all previous breakpoints in that source. To clear all breakpoint
2263// for a source, specify an empty array. When a breakpoint is hit, a
2264// StoppedEvent (event type 'breakpoint') is generated.", "properties": {
2265// "command": {
2266// "type": "string",
2267// "enum": [ "setBreakpoints" ]
2268// },
2269// "arguments": {
2270// "$ref": "#/definitions/SetBreakpointsArguments"
2271// }
2272// },
2273// "required": [ "command", "arguments" ]
2274// }]
2275// },
2276// "SetBreakpointsArguments": {
2277// "type": "object",
2278// "description": "Arguments for 'setBreakpoints' request.",
2279// "properties": {
2280// "source": {
2281// "$ref": "#/definitions/Source",
2282// "description": "The source location of the breakpoints; either
2283// source.path or source.reference must be specified."
2284// },
2285// "breakpoints": {
2286// "type": "array",
2287// "items": {
2288// "$ref": "#/definitions/SourceBreakpoint"
2289// },
2290// "description": "The code locations of the breakpoints."
2291// },
2292// "lines": {
2293// "type": "array",
2294// "items": {
2295// "type": "integer"
2296// },
2297// "description": "Deprecated: The code locations of the breakpoints."
2298// },
2299// "sourceModified": {
2300// "type": "boolean",
2301// "description": "A value of true indicates that the underlying source
2302// has been modified which results in new breakpoint locations."
2303// }
2304// },
2305// "required": [ "source" ]
2306// },
2307// "SetBreakpointsResponse": {
2308// "allOf": [ { "$ref": "#/definitions/Response" }, {
2309// "type": "object",
2310// "description": "Response to 'setBreakpoints' request. Returned is
2311// information about each breakpoint created by this request. This includes
2312// the actual code location and whether the breakpoint could be verified.
2313// The breakpoints returned are in the same order as the elements of the
2314// 'breakpoints' (or the deprecated 'lines') in the
2315// SetBreakpointsArguments.", "properties": {
2316// "body": {
2317// "type": "object",
2318// "properties": {
2319// "breakpoints": {
2320// "type": "array",
2321// "items": {
2322// "$ref": "#/definitions/Breakpoint"
2323// },
2324// "description": "Information about the breakpoints. The array
2325// elements are in the same order as the elements of the
2326// 'breakpoints' (or the deprecated 'lines') in the
2327// SetBreakpointsArguments."
2328// }
2329// },
2330// "required": [ "breakpoints" ]
2331// }
2332// },
2333// "required": [ "body" ]
2334// }]
2335// },
2336// "SourceBreakpoint": {
2337// "type": "object",
2338// "description": "Properties of a breakpoint or logpoint passed to the
2339// setBreakpoints request.", "properties": {
2340// "line": {
2341// "type": "integer",
2342// "description": "The source line of the breakpoint or logpoint."
2343// },
2344// "column": {
2345// "type": "integer",
2346// "description": "An optional source column of the breakpoint."
2347// },
2348// "condition": {
2349// "type": "string",
2350// "description": "An optional expression for conditional breakpoints."
2351// },
2352// "hitCondition": {
2353// "type": "string",
2354// "description": "An optional expression that controls how many hits of
2355// the breakpoint are ignored. The backend is expected to interpret the
2356// expression as needed."
2357// },
2358// "logMessage": {
2359// "type": "string",
2360// "description": "If this attribute exists and is non-empty, the backend
2361// must not 'break' (stop) but log the message instead. Expressions within
2362// {} are interpolated."
2363// }
2364// },
2365// "required": [ "line" ]
2366// }
2367void request_setBreakpoints(const llvm::json::Object &request) {
2368 llvm::json::Object response;
2369 lldb::SBError error;
2370 FillResponse(request, response);
2371 auto arguments = request.getObject(K: "arguments");
2372 auto source = arguments->getObject(K: "source");
2373 const auto path = GetString(obj: source, key: "path");
2374 auto breakpoints = arguments->getArray(K: "breakpoints");
2375 llvm::json::Array response_breakpoints;
2376
2377 // Decode the source breakpoint infos for this "setBreakpoints" request
2378 SourceBreakpointMap request_bps;
2379 // "breakpoints" may be unset, in which case we treat it the same as being set
2380 // to an empty array.
2381 if (breakpoints) {
2382 for (const auto &bp : *breakpoints) {
2383 auto bp_obj = bp.getAsObject();
2384 if (bp_obj) {
2385 SourceBreakpoint src_bp(*bp_obj);
2386 request_bps[src_bp.line] = src_bp;
2387
2388 // We check if this breakpoint already exists to update it
2389 auto existing_source_bps = g_dap.source_breakpoints.find(path);
2390 if (existing_source_bps != g_dap.source_breakpoints.end()) {
2391 const auto &existing_bp =
2392 existing_source_bps->second.find(src_bp.line);
2393 if (existing_bp != existing_source_bps->second.end()) {
2394 existing_bp->second.UpdateBreakpoint(src_bp);
2395 AppendBreakpoint(&existing_bp->second, response_breakpoints, path,
2396 src_bp.line);
2397 continue;
2398 }
2399 }
2400 // At this point the breakpoint is new
2401 g_dap.source_breakpoints[path][src_bp.line] = src_bp;
2402 SourceBreakpoint &new_bp = g_dap.source_breakpoints[path][src_bp.line];
2403 new_bp.SetBreakpoint(path.data());
2404 AppendBreakpoint(&new_bp, response_breakpoints, path, new_bp.line);
2405 }
2406 }
2407 }
2408
2409 // Delete any breakpoints in this source file that aren't in the
2410 // request_bps set. There is no call to remove breakpoints other than
2411 // calling this function with a smaller or empty "breakpoints" list.
2412 auto old_src_bp_pos = g_dap.source_breakpoints.find(path);
2413 if (old_src_bp_pos != g_dap.source_breakpoints.end()) {
2414 for (auto &old_bp : old_src_bp_pos->second) {
2415 auto request_pos = request_bps.find(old_bp.first);
2416 if (request_pos == request_bps.end()) {
2417 // This breakpoint no longer exists in this source file, delete it
2418 g_dap.target.BreakpointDelete(old_bp.second.bp.GetID());
2419 old_src_bp_pos->second.erase(old_bp.first);
2420 }
2421 }
2422 }
2423
2424 llvm::json::Object body;
2425 body.try_emplace("breakpoints", std::move(response_breakpoints));
2426 response.try_emplace("body", std::move(body));
2427 g_dap.SendJSON(json: llvm::json::Value(std::move(response)));
2428}
2429
2430// "SetExceptionBreakpointsRequest": {
2431// "allOf": [ { "$ref": "#/definitions/Request" }, {
2432// "type": "object",
2433// "description": "SetExceptionBreakpoints request; value of command field
2434// is 'setExceptionBreakpoints'. The request configures the debuggers
2435// response to thrown exceptions. If an exception is configured to break, a
2436// StoppedEvent is fired (event type 'exception').", "properties": {
2437// "command": {
2438// "type": "string",
2439// "enum": [ "setExceptionBreakpoints" ]
2440// },
2441// "arguments": {
2442// "$ref": "#/definitions/SetExceptionBreakpointsArguments"
2443// }
2444// },
2445// "required": [ "command", "arguments" ]
2446// }]
2447// },
2448// "SetExceptionBreakpointsArguments": {
2449// "type": "object",
2450// "description": "Arguments for 'setExceptionBreakpoints' request.",
2451// "properties": {
2452// "filters": {
2453// "type": "array",
2454// "items": {
2455// "type": "string"
2456// },
2457// "description": "IDs of checked exception options. The set of IDs is
2458// returned via the 'exceptionBreakpointFilters' capability."
2459// },
2460// "exceptionOptions": {
2461// "type": "array",
2462// "items": {
2463// "$ref": "#/definitions/ExceptionOptions"
2464// },
2465// "description": "Configuration options for selected exceptions."
2466// }
2467// },
2468// "required": [ "filters" ]
2469// },
2470// "SetExceptionBreakpointsResponse": {
2471// "allOf": [ { "$ref": "#/definitions/Response" }, {
2472// "type": "object",
2473// "description": "Response to 'setExceptionBreakpoints' request. This is
2474// just an acknowledgement, so no body field is required."
2475// }]
2476// }
2477void request_setExceptionBreakpoints(const llvm::json::Object &request) {
2478 llvm::json::Object response;
2479 lldb::SBError error;
2480 FillResponse(request, response);
2481 auto arguments = request.getObject(K: "arguments");
2482 auto filters = arguments->getArray(K: "filters");
2483 // Keep a list of any exception breakpoint filter names that weren't set
2484 // so we can clear any exception breakpoints if needed.
2485 std::set<std::string> unset_filters;
2486 for (const auto &bp : g_dap.exception_breakpoints)
2487 unset_filters.insert(bp.filter);
2488
2489 for (const auto &value : *filters) {
2490 const auto filter = GetAsString(value);
2491 auto exc_bp = g_dap.GetExceptionBreakpoint(std::string(filter));
2492 if (exc_bp) {
2493 exc_bp->SetBreakpoint();
2494 unset_filters.erase(std::string(filter));
2495 }
2496 }
2497 for (const auto &filter : unset_filters) {
2498 auto exc_bp = g_dap.GetExceptionBreakpoint(filter);
2499 if (exc_bp)
2500 exc_bp->ClearBreakpoint();
2501 }
2502 g_dap.SendJSON(json: llvm::json::Value(std::move(response)));
2503}
2504
2505// "SetFunctionBreakpointsRequest": {
2506// "allOf": [ { "$ref": "#/definitions/Request" }, {
2507// "type": "object",
2508// "description": "SetFunctionBreakpoints request; value of command field is
2509// 'setFunctionBreakpoints'. Sets multiple function breakpoints and clears
2510// all previous function breakpoints. To clear all function breakpoint,
2511// specify an empty array. When a function breakpoint is hit, a StoppedEvent
2512// (event type 'function breakpoint') is generated.", "properties": {
2513// "command": {
2514// "type": "string",
2515// "enum": [ "setFunctionBreakpoints" ]
2516// },
2517// "arguments": {
2518// "$ref": "#/definitions/SetFunctionBreakpointsArguments"
2519// }
2520// },
2521// "required": [ "command", "arguments" ]
2522// }]
2523// },
2524// "SetFunctionBreakpointsArguments": {
2525// "type": "object",
2526// "description": "Arguments for 'setFunctionBreakpoints' request.",
2527// "properties": {
2528// "breakpoints": {
2529// "type": "array",
2530// "items": {
2531// "$ref": "#/definitions/FunctionBreakpoint"
2532// },
2533// "description": "The function names of the breakpoints."
2534// }
2535// },
2536// "required": [ "breakpoints" ]
2537// },
2538// "FunctionBreakpoint": {
2539// "type": "object",
2540// "description": "Properties of a breakpoint passed to the
2541// setFunctionBreakpoints request.", "properties": {
2542// "name": {
2543// "type": "string",
2544// "description": "The name of the function."
2545// },
2546// "condition": {
2547// "type": "string",
2548// "description": "An optional expression for conditional breakpoints."
2549// },
2550// "hitCondition": {
2551// "type": "string",
2552// "description": "An optional expression that controls how many hits of
2553// the breakpoint are ignored. The backend is expected to interpret the
2554// expression as needed."
2555// }
2556// },
2557// "required": [ "name" ]
2558// },
2559// "SetFunctionBreakpointsResponse": {
2560// "allOf": [ { "$ref": "#/definitions/Response" }, {
2561// "type": "object",
2562// "description": "Response to 'setFunctionBreakpoints' request. Returned is
2563// information about each breakpoint created by this request.",
2564// "properties": {
2565// "body": {
2566// "type": "object",
2567// "properties": {
2568// "breakpoints": {
2569// "type": "array",
2570// "items": {
2571// "$ref": "#/definitions/Breakpoint"
2572// },
2573// "description": "Information about the breakpoints. The array
2574// elements correspond to the elements of the 'breakpoints' array."
2575// }
2576// },
2577// "required": [ "breakpoints" ]
2578// }
2579// },
2580// "required": [ "body" ]
2581// }]
2582// }
2583void request_setFunctionBreakpoints(const llvm::json::Object &request) {
2584 llvm::json::Object response;
2585 lldb::SBError error;
2586 FillResponse(request, response);
2587 auto arguments = request.getObject(K: "arguments");
2588 auto breakpoints = arguments->getArray(K: "breakpoints");
2589 FunctionBreakpointMap request_bps;
2590 llvm::json::Array response_breakpoints;
2591 for (const auto &value : *breakpoints) {
2592 auto bp_obj = value.getAsObject();
2593 if (bp_obj == nullptr)
2594 continue;
2595 FunctionBreakpoint func_bp(*bp_obj);
2596 request_bps[func_bp.functionName] = std::move(func_bp);
2597 }
2598
2599 std::vector<llvm::StringRef> remove_names;
2600 // Disable any function breakpoints that aren't in the request_bps.
2601 // There is no call to remove function breakpoints other than calling this
2602 // function with a smaller or empty "breakpoints" list.
2603 for (auto &pair : g_dap.function_breakpoints) {
2604 auto request_pos = request_bps.find(pair.first());
2605 if (request_pos == request_bps.end()) {
2606 // This function breakpoint no longer exists delete it from LLDB
2607 g_dap.target.BreakpointDelete(pair.second.bp.GetID());
2608 remove_names.push_back(pair.first());
2609 } else {
2610 // Update the existing breakpoint as any setting withing the function
2611 // breakpoint might have changed.
2612 pair.second.UpdateBreakpoint(request_pos->second);
2613 // Remove this breakpoint from the request breakpoints since we have
2614 // handled it here and we don't need to set a new breakpoint below.
2615 request_bps.erase(request_pos);
2616 // Add this breakpoint info to the response
2617 AppendBreakpoint(&pair.second, response_breakpoints);
2618 }
2619 }
2620 // Remove any breakpoints that are no longer in our list
2621 for (const auto &name : remove_names)
2622 g_dap.function_breakpoints.erase(name);
2623
2624 // Any breakpoints that are left in "request_bps" are breakpoints that
2625 // need to be set.
2626 for (auto &pair : request_bps) {
2627 // Add this breakpoint info to the response
2628 g_dap.function_breakpoints[pair.first()] = std::move(pair.second);
2629 FunctionBreakpoint &new_bp = g_dap.function_breakpoints[pair.first()];
2630 new_bp.SetBreakpoint();
2631 AppendBreakpoint(&new_bp, response_breakpoints);
2632 }
2633
2634 llvm::json::Object body;
2635 body.try_emplace("breakpoints", std::move(response_breakpoints));
2636 response.try_emplace("body", std::move(body));
2637 g_dap.SendJSON(json: llvm::json::Value(std::move(response)));
2638}
2639
2640// "DataBreakpointInfoRequest": {
2641// "allOf": [ { "$ref": "#/definitions/Request" }, {
2642// "type": "object",
2643// "description": "Obtains information on a possible data breakpoint that
2644// could be set on an expression or variable.\nClients should only call this
2645// request if the corresponding capability `supportsDataBreakpoints` is
2646// true.", "properties": {
2647// "command": {
2648// "type": "string",
2649// "enum": [ "dataBreakpointInfo" ]
2650// },
2651// "arguments": {
2652// "$ref": "#/definitions/DataBreakpointInfoArguments"
2653// }
2654// },
2655// "required": [ "command", "arguments" ]
2656// }]
2657// },
2658// "DataBreakpointInfoArguments": {
2659// "type": "object",
2660// "description": "Arguments for `dataBreakpointInfo` request.",
2661// "properties": {
2662// "variablesReference": {
2663// "type": "integer",
2664// "description": "Reference to the variable container if the data
2665// breakpoint is requested for a child of the container. The
2666// `variablesReference` must have been obtained in the current suspended
2667// state. See 'Lifetime of Object References' in the Overview section for
2668// details."
2669// },
2670// "name": {
2671// "type": "string",
2672// "description": "The name of the variable's child to obtain data
2673// breakpoint information for.\nIf `variablesReference` isn't specified,
2674// this can be an expression."
2675// },
2676// "frameId": {
2677// "type": "integer",
2678// "description": "When `name` is an expression, evaluate it in the scope
2679// of this stack frame. If not specified, the expression is evaluated in
2680// the global scope. When `variablesReference` is specified, this property
2681// has no effect."
2682// }
2683// },
2684// "required": [ "name" ]
2685// },
2686// "DataBreakpointInfoResponse": {
2687// "allOf": [ { "$ref": "#/definitions/Response" }, {
2688// "type": "object",
2689// "description": "Response to `dataBreakpointInfo` request.",
2690// "properties": {
2691// "body": {
2692// "type": "object",
2693// "properties": {
2694// "dataId": {
2695// "type": [ "string", "null" ],
2696// "description": "An identifier for the data on which a data
2697// breakpoint can be registered with the `setDataBreakpoints`
2698// request or null if no data breakpoint is available. If a
2699// `variablesReference` or `frameId` is passed, the `dataId` is
2700// valid in the current suspended state, otherwise it's valid
2701// indefinitely. See 'Lifetime of Object References' in the Overview
2702// section for details. Breakpoints set using the `dataId` in the
2703// `setDataBreakpoints` request may outlive the lifetime of the
2704// associated `dataId`."
2705// },
2706// "description": {
2707// "type": "string",
2708// "description": "UI string that describes on what data the
2709// breakpoint is set on or why a data breakpoint is not available."
2710// },
2711// "accessTypes": {
2712// "type": "array",
2713// "items": {
2714// "$ref": "#/definitions/DataBreakpointAccessType"
2715// },
2716// "description": "Attribute lists the available access types for a
2717// potential data breakpoint. A UI client could surface this
2718// information."
2719// },
2720// "canPersist": {
2721// "type": "boolean",
2722// "description": "Attribute indicates that a potential data
2723// breakpoint could be persisted across sessions."
2724// }
2725// },
2726// "required": [ "dataId", "description" ]
2727// }
2728// },
2729// "required": [ "body" ]
2730// }]
2731// }
2732void request_dataBreakpointInfo(const llvm::json::Object &request) {
2733 llvm::json::Object response;
2734 FillResponse(request, response);
2735 llvm::json::Object body;
2736 lldb::SBError error;
2737 llvm::json::Array accessTypes{"read", "write", "readWrite"};
2738 const auto *arguments = request.getObject(K: "arguments");
2739 const auto variablesReference =
2740 GetUnsigned(obj: arguments, key: "variablesReference", fail_value: 0);
2741 llvm::StringRef name = GetString(obj: arguments, key: "name");
2742 lldb::SBFrame frame = g_dap.GetLLDBFrame(arguments: *arguments);
2743 lldb::SBValue variable = FindVariable(variablesReference, name);
2744 std::string addr, size;
2745
2746 if (variable.IsValid()) {
2747 lldb::addr_t load_addr = variable.GetLoadAddress();
2748 size_t byte_size = variable.GetByteSize();
2749 if (load_addr == LLDB_INVALID_ADDRESS) {
2750 body.try_emplace("dataId", nullptr);
2751 body.try_emplace("description",
2752 "does not exist in memory, its location is " +
2753 std::string(variable.GetLocation()));
2754 } else if (byte_size == 0) {
2755 body.try_emplace("dataId", nullptr);
2756 body.try_emplace("description", "variable size is 0");
2757 } else {
2758 addr = llvm::utohexstr(X: load_addr);
2759 size = llvm::utostr(X: byte_size);
2760 }
2761 } else if (variablesReference == 0 && frame.IsValid()) {
2762 lldb::SBValue value = frame.EvaluateExpression(expr: name.data());
2763 if (value.GetError().Fail()) {
2764 lldb::SBError error = value.GetError();
2765 const char *error_cstr = error.GetCString();
2766 body.try_emplace("dataId", nullptr);
2767 body.try_emplace("description", error_cstr && error_cstr[0]
2768 ? std::string(error_cstr)
2769 : "evaluation failed");
2770 } else {
2771 uint64_t load_addr = value.GetValueAsUnsigned();
2772 addr = llvm::utohexstr(X: load_addr);
2773 lldb::SBMemoryRegionInfo region;
2774 lldb::SBError err =
2775 g_dap.target.GetProcess().GetMemoryRegionInfo(load_addr, region_info&: region);
2776 if (err.Success()) {
2777 if (!(region.IsReadable() || region.IsWritable())) {
2778 body.try_emplace("dataId", nullptr);
2779 body.try_emplace("description",
2780 "memory region for address " + addr +
2781 " has no read or write permissions");
2782 } else {
2783 lldb::SBData data = value.GetPointeeData();
2784 if (data.IsValid())
2785 size = llvm::utostr(X: data.GetByteSize());
2786 else {
2787 body.try_emplace("dataId", nullptr);
2788 body.try_emplace("description",
2789 "unable to get byte size for expression: " +
2790 name.str());
2791 }
2792 }
2793 } else {
2794 body.try_emplace("dataId", nullptr);
2795 body.try_emplace("description",
2796 "unable to get memory region info for address " +
2797 addr);
2798 }
2799 }
2800 } else {
2801 body.try_emplace("dataId", nullptr);
2802 body.try_emplace("description", "variable not found: " + name.str());
2803 }
2804
2805 if (!body.getObject(K: "dataId")) {
2806 body.try_emplace("dataId", addr + "/" + size);
2807 body.try_emplace("accessTypes", std::move(accessTypes));
2808 body.try_emplace("description",
2809 size + " bytes at " + addr + " " + name.str());
2810 }
2811 response.try_emplace("body", std::move(body));
2812 g_dap.SendJSON(json: llvm::json::Value(std::move(response)));
2813}
2814
2815// "SetDataBreakpointsRequest": {
2816// "allOf": [ { "$ref": "#/definitions/Request" }, {
2817// "type": "object",
2818// "description": "Replaces all existing data breakpoints with new data
2819// breakpoints.\nTo clear all data breakpoints, specify an empty
2820// array.\nWhen a data breakpoint is hit, a `stopped` event (with reason
2821// `data breakpoint`) is generated.\nClients should only call this request
2822// if the corresponding capability `supportsDataBreakpoints` is true.",
2823// "properties": {
2824// "command": {
2825// "type": "string",
2826// "enum": [ "setDataBreakpoints" ]
2827// },
2828// "arguments": {
2829// "$ref": "#/definitions/SetDataBreakpointsArguments"
2830// }
2831// },
2832// "required": [ "command", "arguments" ]
2833// }]
2834// },
2835// "SetDataBreakpointsArguments": {
2836// "type": "object",
2837// "description": "Arguments for `setDataBreakpoints` request.",
2838// "properties": {
2839// "breakpoints": {
2840// "type": "array",
2841// "items": {
2842// "$ref": "#/definitions/DataBreakpoint"
2843// },
2844// "description": "The contents of this array replaces all existing data
2845// breakpoints. An empty array clears all data breakpoints."
2846// }
2847// },
2848// "required": [ "breakpoints" ]
2849// },
2850// "SetDataBreakpointsResponse": {
2851// "allOf": [ { "$ref": "#/definitions/Response" }, {
2852// "type": "object",
2853// "description": "Response to `setDataBreakpoints` request.\nReturned is
2854// information about each breakpoint created by this request.",
2855// "properties": {
2856// "body": {
2857// "type": "object",
2858// "properties": {
2859// "breakpoints": {
2860// "type": "array",
2861// "items": {
2862// "$ref": "#/definitions/Breakpoint"
2863// },
2864// "description": "Information about the data breakpoints. The array
2865// elements correspond to the elements of the input argument
2866// `breakpoints` array."
2867// }
2868// },
2869// "required": [ "breakpoints" ]
2870// }
2871// },
2872// "required": [ "body" ]
2873// }]
2874// }
2875void request_setDataBreakpoints(const llvm::json::Object &request) {
2876 llvm::json::Object response;
2877 lldb::SBError error;
2878 FillResponse(request, response);
2879 const auto *arguments = request.getObject(K: "arguments");
2880 const auto *breakpoints = arguments->getArray(K: "breakpoints");
2881 llvm::json::Array response_breakpoints;
2882 g_dap.target.DeleteAllWatchpoints();
2883 std::vector<Watchpoint> watchpoints;
2884 if (breakpoints) {
2885 for (const auto &bp : *breakpoints) {
2886 const auto *bp_obj = bp.getAsObject();
2887 if (bp_obj) {
2888 Watchpoint wp(*bp_obj);
2889 watchpoints.push_back(wp);
2890 }
2891 }
2892 }
2893 // If two watchpoints start at the same address, the latter overwrite the
2894 // former. So, we only enable those at first-seen addresses when iterating
2895 // backward.
2896 std::set<lldb::addr_t> addresses;
2897 for (auto iter = watchpoints.rbegin(); iter != watchpoints.rend(); ++iter) {
2898 if (addresses.count(iter->addr) == 0) {
2899 iter->SetWatchpoint();
2900 addresses.insert(iter->addr);
2901 }
2902 }
2903 for (auto wp : watchpoints)
2904 AppendBreakpoint(&wp, response_breakpoints);
2905
2906 llvm::json::Object body;
2907 body.try_emplace("breakpoints", std::move(response_breakpoints));
2908 response.try_emplace("body", std::move(body));
2909 g_dap.SendJSON(json: llvm::json::Value(std::move(response)));
2910}
2911
2912// "SourceRequest": {
2913// "allOf": [ { "$ref": "#/definitions/Request" }, {
2914// "type": "object",
2915// "description": "Source request; value of command field is 'source'. The
2916// request retrieves the source code for a given source reference.",
2917// "properties": {
2918// "command": {
2919// "type": "string",
2920// "enum": [ "source" ]
2921// },
2922// "arguments": {
2923// "$ref": "#/definitions/SourceArguments"
2924// }
2925// },
2926// "required": [ "command", "arguments" ]
2927// }]
2928// },
2929// "SourceArguments": {
2930// "type": "object",
2931// "description": "Arguments for 'source' request.",
2932// "properties": {
2933// "source": {
2934// "$ref": "#/definitions/Source",
2935// "description": "Specifies the source content to load. Either
2936// source.path or source.sourceReference must be specified."
2937// },
2938// "sourceReference": {
2939// "type": "integer",
2940// "description": "The reference to the source. This is the same as
2941// source.sourceReference. This is provided for backward compatibility
2942// since old backends do not understand the 'source' attribute."
2943// }
2944// },
2945// "required": [ "sourceReference" ]
2946// },
2947// "SourceResponse": {
2948// "allOf": [ { "$ref": "#/definitions/Response" }, {
2949// "type": "object",
2950// "description": "Response to 'source' request.",
2951// "properties": {
2952// "body": {
2953// "type": "object",
2954// "properties": {
2955// "content": {
2956// "type": "string",
2957// "description": "Content of the source reference."
2958// },
2959// "mimeType": {
2960// "type": "string",
2961// "description": "Optional content type (mime type) of the source."
2962// }
2963// },
2964// "required": [ "content" ]
2965// }
2966// },
2967// "required": [ "body" ]
2968// }]
2969// }
2970void request_source(const llvm::json::Object &request) {
2971 llvm::json::Object response;
2972 FillResponse(request, response);
2973 llvm::json::Object body{{.K: "content", .V: ""}};
2974 response.try_emplace("body", std::move(body));
2975 g_dap.SendJSON(json: llvm::json::Value(std::move(response)));
2976}
2977
2978// "StackTraceRequest": {
2979// "allOf": [ { "$ref": "#/definitions/Request" }, {
2980// "type": "object",
2981// "description": "StackTrace request; value of command field is
2982// 'stackTrace'. The request returns a stacktrace from the current execution
2983// state.", "properties": {
2984// "command": {
2985// "type": "string",
2986// "enum": [ "stackTrace" ]
2987// },
2988// "arguments": {
2989// "$ref": "#/definitions/StackTraceArguments"
2990// }
2991// },
2992// "required": [ "command", "arguments" ]
2993// }]
2994// },
2995// "StackTraceArguments": {
2996// "type": "object",
2997// "description": "Arguments for 'stackTrace' request.",
2998// "properties": {
2999// "threadId": {
3000// "type": "integer",
3001// "description": "Retrieve the stacktrace for this thread."
3002// },
3003// "startFrame": {
3004// "type": "integer",
3005// "description": "The index of the first frame to return; if omitted
3006// frames start at 0."
3007// },
3008// "levels": {
3009// "type": "integer",
3010// "description": "The maximum number of frames to return. If levels is
3011// not specified or 0, all frames are returned."
3012// },
3013// "format": {
3014// "$ref": "#/definitions/StackFrameFormat",
3015// "description": "Specifies details on how to format the stack frames."
3016// }
3017// },
3018// "required": [ "threadId" ]
3019// },
3020// "StackTraceResponse": {
3021// "allOf": [ { "$ref": "#/definitions/Response" }, {
3022// "type": "object",
3023// "description": "Response to 'stackTrace' request.",
3024// "properties": {
3025// "body": {
3026// "type": "object",
3027// "properties": {
3028// "stackFrames": {
3029// "type": "array",
3030// "items": {
3031// "$ref": "#/definitions/StackFrame"
3032// },
3033// "description": "The frames of the stackframe. If the array has
3034// length zero, there are no stackframes available. This means that
3035// there is no location information available."
3036// },
3037// "totalFrames": {
3038// "type": "integer",
3039// "description": "The total number of frames available."
3040// }
3041// },
3042// "required": [ "stackFrames" ]
3043// }
3044// },
3045// "required": [ "body" ]
3046// }]
3047// }
3048void request_stackTrace(const llvm::json::Object &request) {
3049 llvm::json::Object response;
3050 FillResponse(request, response);
3051 lldb::SBError error;
3052 auto arguments = request.getObject(K: "arguments");
3053 lldb::SBThread thread = g_dap.GetLLDBThread(arguments: *arguments);
3054 llvm::json::Array stackFrames;
3055 llvm::json::Object body;
3056
3057 if (thread.IsValid()) {
3058 const auto startFrame = GetUnsigned(obj: arguments, key: "startFrame", fail_value: 0);
3059 const auto levels = GetUnsigned(obj: arguments, key: "levels", fail_value: 0);
3060 const auto endFrame = (levels == 0) ? INT64_MAX : (startFrame + levels);
3061 auto totalFrames = thread.GetNumFrames();
3062
3063 // This will always return an invalid thread when
3064 // libBacktraceRecording.dylib is not loaded or if there is no extended
3065 // backtrace.
3066 lldb::SBThread queue_backtrace_thread =
3067 thread.GetExtendedBacktraceThread(type: "libdispatch");
3068 if (queue_backtrace_thread.IsValid()) {
3069 // One extra frame as a label to mark the enqueued thread.
3070 totalFrames += queue_backtrace_thread.GetNumFrames() + 1;
3071 }
3072
3073 // This will always return an invalid thread when there is no exception in
3074 // the current thread.
3075 lldb::SBThread exception_backtrace_thread =
3076 thread.GetCurrentExceptionBacktrace();
3077 if (exception_backtrace_thread.IsValid()) {
3078 // One extra frame as a label to mark the exception thread.
3079 totalFrames += exception_backtrace_thread.GetNumFrames() + 1;
3080 }
3081
3082 for (uint32_t i = startFrame; i < endFrame; ++i) {
3083 lldb::SBFrame frame;
3084 std::string prefix;
3085 if (i < thread.GetNumFrames()) {
3086 frame = thread.GetFrameAtIndex(idx: i);
3087 } else if (queue_backtrace_thread.IsValid() &&
3088 i < (thread.GetNumFrames() +
3089 queue_backtrace_thread.GetNumFrames() + 1)) {
3090 if (i == thread.GetNumFrames()) {
3091 const uint32_t thread_idx =
3092 queue_backtrace_thread.GetExtendedBacktraceOriginatingIndexID();
3093 const char *queue_name = queue_backtrace_thread.GetQueueName();
3094 auto name = llvm::formatv("Enqueued from {0} (Thread {1})",
3095 queue_name, thread_idx);
3096 stackFrames.emplace_back(
3097 llvm::json::Object{{"id", thread.GetThreadID() + 1},
3098 {"name", name},
3099 {"presentationHint", "label"}});
3100 continue;
3101 }
3102 frame = queue_backtrace_thread.GetFrameAtIndex(
3103 idx: i - thread.GetNumFrames() - 1);
3104 } else if (exception_backtrace_thread.IsValid()) {
3105 if (i == thread.GetNumFrames() +
3106 (queue_backtrace_thread.IsValid()
3107 ? queue_backtrace_thread.GetNumFrames() + 1
3108 : 0)) {
3109 stackFrames.emplace_back(
3110 llvm::json::Object{{"id", thread.GetThreadID() + 2},
3111 {"name", "Original Exception Backtrace"},
3112 {"presentationHint", "label"}});
3113 continue;
3114 }
3115
3116 frame = exception_backtrace_thread.GetFrameAtIndex(
3117 idx: i - thread.GetNumFrames() -
3118 (queue_backtrace_thread.IsValid()
3119 ? queue_backtrace_thread.GetNumFrames() + 1
3120 : 0));
3121 }
3122 if (!frame.IsValid())
3123 break;
3124 stackFrames.emplace_back(CreateStackFrame(frame));
3125 }
3126
3127 body.try_emplace("totalFrames", totalFrames);
3128 }
3129 body.try_emplace("stackFrames", std::move(stackFrames));
3130 response.try_emplace("body", std::move(body));
3131 g_dap.SendJSON(json: llvm::json::Value(std::move(response)));
3132}
3133
3134// "StepInRequest": {
3135// "allOf": [ { "$ref": "#/definitions/Request" }, {
3136// "type": "object",
3137// "description": "StepIn request; value of command field is 'stepIn'. The
3138// request starts the debuggee to step into a function/method if possible.
3139// If it cannot step into a target, 'stepIn' behaves like 'next'. The debug
3140// adapter first sends the StepInResponse and then a StoppedEvent (event
3141// type 'step') after the step has completed. If there are multiple
3142// function/method calls (or other targets) on the source line, the optional
3143// argument 'targetId' can be used to control into which target the 'stepIn'
3144// should occur. The list of possible targets for a given source line can be
3145// retrieved via the 'stepInTargets' request.", "properties": {
3146// "command": {
3147// "type": "string",
3148// "enum": [ "stepIn" ]
3149// },
3150// "arguments": {
3151// "$ref": "#/definitions/StepInArguments"
3152// }
3153// },
3154// "required": [ "command", "arguments" ]
3155// }]
3156// },
3157// "StepInArguments": {
3158// "type": "object",
3159// "description": "Arguments for 'stepIn' request.",
3160// "properties": {
3161// "threadId": {
3162// "type": "integer",
3163// "description": "Execute 'stepIn' for this thread."
3164// },
3165// "targetId": {
3166// "type": "integer",
3167// "description": "Optional id of the target to step into."
3168// }
3169// },
3170// "required": [ "threadId" ]
3171// },
3172// "StepInResponse": {
3173// "allOf": [ { "$ref": "#/definitions/Response" }, {
3174// "type": "object",
3175// "description": "Response to 'stepIn' request. This is just an
3176// acknowledgement, so no body field is required."
3177// }]
3178// }
3179void request_stepIn(const llvm::json::Object &request) {
3180 llvm::json::Object response;
3181 FillResponse(request, response);
3182 auto arguments = request.getObject(K: "arguments");
3183 lldb::SBThread thread = g_dap.GetLLDBThread(arguments: *arguments);
3184 if (thread.IsValid()) {
3185 // Remember the thread ID that caused the resume so we can set the
3186 // "threadCausedFocus" boolean value in the "stopped" events.
3187 g_dap.focus_tid = thread.GetThreadID();
3188 thread.StepInto();
3189 } else {
3190 response["success"] = llvm::json::Value(false);
3191 }
3192 g_dap.SendJSON(json: llvm::json::Value(std::move(response)));
3193}
3194
3195// "StepOutRequest": {
3196// "allOf": [ { "$ref": "#/definitions/Request" }, {
3197// "type": "object",
3198// "description": "StepOut request; value of command field is 'stepOut'. The
3199// request starts the debuggee to run again for one step. The debug adapter
3200// first sends the StepOutResponse and then a StoppedEvent (event type
3201// 'step') after the step has completed.", "properties": {
3202// "command": {
3203// "type": "string",
3204// "enum": [ "stepOut" ]
3205// },
3206// "arguments": {
3207// "$ref": "#/definitions/StepOutArguments"
3208// }
3209// },
3210// "required": [ "command", "arguments" ]
3211// }]
3212// },
3213// "StepOutArguments": {
3214// "type": "object",
3215// "description": "Arguments for 'stepOut' request.",
3216// "properties": {
3217// "threadId": {
3218// "type": "integer",
3219// "description": "Execute 'stepOut' for this thread."
3220// }
3221// },
3222// "required": [ "threadId" ]
3223// },
3224// "StepOutResponse": {
3225// "allOf": [ { "$ref": "#/definitions/Response" }, {
3226// "type": "object",
3227// "description": "Response to 'stepOut' request. This is just an
3228// acknowledgement, so no body field is required."
3229// }]
3230// }
3231void request_stepOut(const llvm::json::Object &request) {
3232 llvm::json::Object response;
3233 FillResponse(request, response);
3234 auto arguments = request.getObject(K: "arguments");
3235 lldb::SBThread thread = g_dap.GetLLDBThread(arguments: *arguments);
3236 if (thread.IsValid()) {
3237 // Remember the thread ID that caused the resume so we can set the
3238 // "threadCausedFocus" boolean value in the "stopped" events.
3239 g_dap.focus_tid = thread.GetThreadID();
3240 thread.StepOut();
3241 } else {
3242 response["success"] = llvm::json::Value(false);
3243 }
3244 g_dap.SendJSON(json: llvm::json::Value(std::move(response)));
3245}
3246
3247// "ThreadsRequest": {
3248// "allOf": [ { "$ref": "#/definitions/Request" }, {
3249// "type": "object",
3250// "description": "Thread request; value of command field is 'threads'. The
3251// request retrieves a list of all threads.", "properties": {
3252// "command": {
3253// "type": "string",
3254// "enum": [ "threads" ]
3255// }
3256// },
3257// "required": [ "command" ]
3258// }]
3259// },
3260// "ThreadsResponse": {
3261// "allOf": [ { "$ref": "#/definitions/Response" }, {
3262// "type": "object",
3263// "description": "Response to 'threads' request.",
3264// "properties": {
3265// "body": {
3266// "type": "object",
3267// "properties": {
3268// "threads": {
3269// "type": "array",
3270// "items": {
3271// "$ref": "#/definitions/Thread"
3272// },
3273// "description": "All threads."
3274// }
3275// },
3276// "required": [ "threads" ]
3277// }
3278// },
3279// "required": [ "body" ]
3280// }]
3281// }
3282void request_threads(const llvm::json::Object &request) {
3283
3284 lldb::SBProcess process = g_dap.target.GetProcess();
3285 llvm::json::Object response;
3286 FillResponse(request, response);
3287
3288 const uint32_t num_threads = process.GetNumThreads();
3289 llvm::json::Array threads;
3290 for (uint32_t thread_idx = 0; thread_idx < num_threads; ++thread_idx) {
3291 lldb::SBThread thread = process.GetThreadAtIndex(index: thread_idx);
3292 threads.emplace_back(CreateThread(thread));
3293 }
3294 if (threads.size() == 0) {
3295 response["success"] = llvm::json::Value(false);
3296 }
3297 llvm::json::Object body;
3298 body.try_emplace("threads", std::move(threads));
3299 response.try_emplace("body", std::move(body));
3300 g_dap.SendJSON(json: llvm::json::Value(std::move(response)));
3301}
3302
3303// "SetVariableRequest": {
3304// "allOf": [ { "$ref": "#/definitions/Request" }, {
3305// "type": "object",
3306// "description": "setVariable request; value of command field is
3307// 'setVariable'. Set the variable with the given name in the variable
3308// container to a new value.", "properties": {
3309// "command": {
3310// "type": "string",
3311// "enum": [ "setVariable" ]
3312// },
3313// "arguments": {
3314// "$ref": "#/definitions/SetVariableArguments"
3315// }
3316// },
3317// "required": [ "command", "arguments" ]
3318// }]
3319// },
3320// "SetVariableArguments": {
3321// "type": "object",
3322// "description": "Arguments for 'setVariable' request.",
3323// "properties": {
3324// "variablesReference": {
3325// "type": "integer",
3326// "description": "The reference of the variable container."
3327// },
3328// "name": {
3329// "type": "string",
3330// "description": "The name of the variable."
3331// },
3332// "value": {
3333// "type": "string",
3334// "description": "The value of the variable."
3335// },
3336// "format": {
3337// "$ref": "#/definitions/ValueFormat",
3338// "description": "Specifies details on how to format the response value."
3339// }
3340// },
3341// "required": [ "variablesReference", "name", "value" ]
3342// },
3343// "SetVariableResponse": {
3344// "allOf": [ { "$ref": "#/definitions/Response" }, {
3345// "type": "object",
3346// "description": "Response to 'setVariable' request.",
3347// "properties": {
3348// "body": {
3349// "type": "object",
3350// "properties": {
3351// "value": {
3352// "type": "string",
3353// "description": "The new value of the variable."
3354// },
3355// "type": {
3356// "type": "string",
3357// "description": "The type of the new value. Typically shown in the
3358// UI when hovering over the value."
3359// },
3360// "variablesReference": {
3361// "type": "number",
3362// "description": "If variablesReference is > 0, the new value is
3363// structured and its children can be retrieved by passing
3364// variablesReference to the VariablesRequest."
3365// },
3366// "namedVariables": {
3367// "type": "number",
3368// "description": "The number of named child variables. The client
3369// can use this optional information to present the variables in a
3370// paged UI and fetch them in chunks."
3371// },
3372// "indexedVariables": {
3373// "type": "number",
3374// "description": "The number of indexed child variables. The client
3375// can use this optional information to present the variables in a
3376// paged UI and fetch them in chunks."
3377// }
3378// },
3379// "required": [ "value" ]
3380// }
3381// },
3382// "required": [ "body" ]
3383// }]
3384// }
3385void request_setVariable(const llvm::json::Object &request) {
3386 llvm::json::Object response;
3387 FillResponse(request, response);
3388 llvm::json::Array variables;
3389 llvm::json::Object body;
3390 auto arguments = request.getObject(K: "arguments");
3391 // This is a reference to the containing variable/scope
3392 const auto variablesReference =
3393 GetUnsigned(obj: arguments, key: "variablesReference", fail_value: 0);
3394 llvm::StringRef name = GetString(obj: arguments, key: "name");
3395
3396 const auto value = GetString(obj: arguments, key: "value");
3397 // Set success to false just in case we don't find the variable by name
3398 response.try_emplace("success", false);
3399
3400 lldb::SBValue variable;
3401 int64_t newVariablesReference = 0;
3402
3403 // The "id" is the unique integer ID that is unique within the enclosing
3404 // variablesReference. It is optionally added to any "interface Variable"
3405 // objects to uniquely identify a variable within an enclosing
3406 // variablesReference. It helps to disambiguate between two variables that
3407 // have the same name within the same scope since the "setVariables" request
3408 // only specifies the variable reference of the enclosing scope/variable, and
3409 // the name of the variable. We could have two shadowed variables with the
3410 // same name in "Locals" or "Globals". In our case the "id" absolute index
3411 // of the variable within the g_dap.variables list.
3412 const auto id_value = GetUnsigned(obj: arguments, key: "id", UINT64_MAX);
3413 if (id_value != UINT64_MAX) {
3414 variable = g_dap.variables.GetVariable(var_ref: id_value);
3415 } else {
3416 variable = FindVariable(variablesReference, name);
3417 }
3418
3419 if (variable.IsValid()) {
3420 lldb::SBError error;
3421 bool success = variable.SetValueFromCString(value_str: value.data(), error);
3422 if (success) {
3423 VariableDescription desc(variable);
3424 EmplaceSafeString(obj&: body, key: "result", str: desc.display_value);
3425 EmplaceSafeString(obj&: body, key: "type", str: desc.display_type_name);
3426
3427 // We don't know the index of the variable in our g_dap.variables
3428 // so always insert a new one to get its variablesReference.
3429 // is_permanent is false because debug console does not support
3430 // setVariable request.
3431 if (variable.MightHaveChildren())
3432 newVariablesReference = g_dap.variables.InsertExpandableVariable(
3433 variable, /*is_permanent=*/false);
3434
3435 body.try_emplace("variablesReference", newVariablesReference);
3436 } else {
3437 EmplaceSafeString(obj&: body, key: "message", str: std::string(error.GetCString()));
3438 }
3439 response["success"] = llvm::json::Value(success);
3440 } else {
3441 response["success"] = llvm::json::Value(false);
3442 }
3443
3444 response.try_emplace("body", std::move(body));
3445 g_dap.SendJSON(json: llvm::json::Value(std::move(response)));
3446}
3447
3448// "VariablesRequest": {
3449// "allOf": [ { "$ref": "#/definitions/Request" }, {
3450// "type": "object",
3451// "description": "Variables request; value of command field is 'variables'.
3452// Retrieves all child variables for the given variable reference. An
3453// optional filter can be used to limit the fetched children to either named
3454// or indexed children.", "properties": {
3455// "command": {
3456// "type": "string",
3457// "enum": [ "variables" ]
3458// },
3459// "arguments": {
3460// "$ref": "#/definitions/VariablesArguments"
3461// }
3462// },
3463// "required": [ "command", "arguments" ]
3464// }]
3465// },
3466// "VariablesArguments": {
3467// "type": "object",
3468// "description": "Arguments for 'variables' request.",
3469// "properties": {
3470// "variablesReference": {
3471// "type": "integer",
3472// "description": "The Variable reference."
3473// },
3474// "filter": {
3475// "type": "string",
3476// "enum": [ "indexed", "named" ],
3477// "description": "Optional filter to limit the child variables to either
3478// named or indexed. If ommited, both types are fetched."
3479// },
3480// "start": {
3481// "type": "integer",
3482// "description": "The index of the first variable to return; if omitted
3483// children start at 0."
3484// },
3485// "count": {
3486// "type": "integer",
3487// "description": "The number of variables to return. If count is missing
3488// or 0, all variables are returned."
3489// },
3490// "format": {
3491// "$ref": "#/definitions/ValueFormat",
3492// "description": "Specifies details on how to format the Variable
3493// values."
3494// }
3495// },
3496// "required": [ "variablesReference" ]
3497// },
3498// "VariablesResponse": {
3499// "allOf": [ { "$ref": "#/definitions/Response" }, {
3500// "type": "object",
3501// "description": "Response to 'variables' request.",
3502// "properties": {
3503// "body": {
3504// "type": "object",
3505// "properties": {
3506// "variables": {
3507// "type": "array",
3508// "items": {
3509// "$ref": "#/definitions/Variable"
3510// },
3511// "description": "All (or a range) of variables for the given
3512// variable reference."
3513// }
3514// },
3515// "required": [ "variables" ]
3516// }
3517// },
3518// "required": [ "body" ]
3519// }]
3520// }
3521void request_variables(const llvm::json::Object &request) {
3522 llvm::json::Object response;
3523 FillResponse(request, response);
3524 llvm::json::Array variables;
3525 auto arguments = request.getObject(K: "arguments");
3526 const auto variablesReference =
3527 GetUnsigned(obj: arguments, key: "variablesReference", fail_value: 0);
3528 const int64_t start = GetSigned(obj: arguments, key: "start", fail_value: 0);
3529 const int64_t count = GetSigned(obj: arguments, key: "count", fail_value: 0);
3530 bool hex = false;
3531 auto format = arguments->getObject(K: "format");
3532 if (format)
3533 hex = GetBoolean(obj: format, key: "hex", fail_value: false);
3534
3535 if (lldb::SBValueList *top_scope = GetTopLevelScope(variablesReference)) {
3536 // variablesReference is one of our scopes, not an actual variable it is
3537 // asking for the list of args, locals or globals.
3538 int64_t start_idx = 0;
3539 int64_t num_children = 0;
3540
3541 if (variablesReference == VARREF_REGS) {
3542 // Change the default format of any pointer sized registers in the first
3543 // register set to be the lldb::eFormatAddressInfo so we show the pointer
3544 // and resolve what the pointer resolves to. Only change the format if the
3545 // format was set to the default format or if it was hex as some registers
3546 // have formats set for them.
3547 const uint32_t addr_size = g_dap.target.GetProcess().GetAddressByteSize();
3548 lldb::SBValue reg_set = g_dap.variables.registers.GetValueAtIndex(idx: 0);
3549 const uint32_t num_regs = reg_set.GetNumChildren();
3550 for (uint32_t reg_idx = 0; reg_idx < num_regs; ++reg_idx) {
3551 lldb::SBValue reg = reg_set.GetChildAtIndex(idx: reg_idx);
3552 const lldb::Format format = reg.GetFormat();
3553 if (format == lldb::eFormatDefault || format == lldb::eFormatHex) {
3554 if (reg.GetByteSize() == addr_size)
3555 reg.SetFormat(lldb::eFormatAddressInfo);
3556 }
3557 }
3558 }
3559
3560 num_children = top_scope->GetSize();
3561 if (num_children == 0 && variablesReference == VARREF_LOCALS) {
3562 // Check for an error in the SBValueList that might explain why we don't
3563 // have locals. If we have an error display it as the sole value in the
3564 // the locals.
3565
3566 // "error" owns the error string so we must keep it alive as long as we
3567 // want to use the returns "const char *"
3568 lldb::SBError error = top_scope->GetError();
3569 const char *var_err = error.GetCString();
3570 if (var_err) {
3571 // Create a fake variable named "error" to explain why variables were
3572 // not available. This new error will help let users know when there was
3573 // a problem that kept variables from being available for display and
3574 // allow users to fix this issue instead of seeing no variables. The
3575 // errors are only set when there is a problem that the user could
3576 // fix, so no error will show up when you have no debug info, only when
3577 // we do have debug info and something that is fixable can be done.
3578 llvm::json::Object object;
3579 EmplaceSafeString(obj&: object, key: "name", str: "<error>");
3580 EmplaceSafeString(obj&: object, key: "type", str: "const char *");
3581 EmplaceSafeString(obj&: object, key: "value", str: var_err);
3582 object.try_emplace("variablesReference", (int64_t)0);
3583 variables.emplace_back(std::move(object));
3584 }
3585 }
3586 const int64_t end_idx = start_idx + ((count == 0) ? num_children : count);
3587
3588 // We first find out which variable names are duplicated
3589 std::map<std::string, int> variable_name_counts;
3590 for (auto i = start_idx; i < end_idx; ++i) {
3591 lldb::SBValue variable = top_scope->GetValueAtIndex(idx: i);
3592 if (!variable.IsValid())
3593 break;
3594 variable_name_counts[GetNonNullVariableName(value: variable)]++;
3595 }
3596
3597 // Now we construct the result with unique display variable names
3598 for (auto i = start_idx; i < end_idx; ++i) {
3599 lldb::SBValue variable = top_scope->GetValueAtIndex(idx: i);
3600
3601 if (!variable.IsValid())
3602 break;
3603
3604 int64_t var_ref = 0;
3605 if (variable.MightHaveChildren() || variable.IsSynthetic()) {
3606 var_ref = g_dap.variables.InsertExpandableVariable(
3607 variable, /*is_permanent=*/false);
3608 }
3609 variables.emplace_back(CreateVariable(
3610 variable, var_ref, var_ref != 0 ? var_ref : UINT64_MAX, hex,
3611 variable_name_counts[GetNonNullVariableName(value: variable)] > 1));
3612 }
3613 } else {
3614 // We are expanding a variable that has children, so we will return its
3615 // children.
3616 lldb::SBValue variable = g_dap.variables.GetVariable(var_ref: variablesReference);
3617 if (variable.IsValid()) {
3618 auto addChild = [&](lldb::SBValue child,
3619 std::optional<std::string> custom_name = {}) {
3620 if (!child.IsValid())
3621 return;
3622 if (child.MightHaveChildren()) {
3623 auto is_permanent =
3624 g_dap.variables.IsPermanentVariableReference(var_ref: variablesReference);
3625 auto childVariablesReferences =
3626 g_dap.variables.InsertExpandableVariable(variable: child, is_permanent);
3627 variables.emplace_back(CreateVariable(
3628 v: child, variablesReference: childVariablesReferences, varID: childVariablesReferences, format_hex: hex,
3629 /*is_name_duplicated=*/false, custom_name));
3630 } else {
3631 variables.emplace_back(CreateVariable(v: child, variablesReference: 0, INT64_MAX, format_hex: hex,
3632 /*is_name_duplicated=*/false,
3633 custom_name));
3634 }
3635 };
3636 const int64_t num_children = variable.GetNumChildren();
3637 int64_t end_idx = start + ((count == 0) ? num_children : count);
3638 int64_t i = start;
3639 for (; i < end_idx && i < num_children; ++i)
3640 addChild(variable.GetChildAtIndex(idx: i));
3641
3642 // If we haven't filled the count quota from the request, we insert a new
3643 // "[raw]" child that can be used to inspect the raw version of a
3644 // synthetic member. That eliminates the need for the user to go to the
3645 // debug console and type `frame var <variable> to get these values.
3646 if (g_dap.enable_synthetic_child_debugging && variable.IsSynthetic() &&
3647 i == num_children)
3648 addChild(variable.GetNonSyntheticValue(), "[raw]");
3649 }
3650 }
3651 llvm::json::Object body;
3652 body.try_emplace("variables", std::move(variables));
3653 response.try_emplace("body", std::move(body));
3654 g_dap.SendJSON(json: llvm::json::Value(std::move(response)));
3655}
3656
3657// "DisassembleRequest": {
3658// "allOf": [ { "$ref": "#/definitions/Request" }, {
3659// "type": "object",
3660// "description": "Disassembles code stored at the provided
3661// location.\nClients should only call this request if the corresponding
3662// capability `supportsDisassembleRequest` is true.", "properties": {
3663// "command": {
3664// "type": "string",
3665// "enum": [ "disassemble" ]
3666// },
3667// "arguments": {
3668// "$ref": "#/definitions/DisassembleArguments"
3669// }
3670// },
3671// "required": [ "command", "arguments" ]
3672// }]
3673// },
3674// "DisassembleArguments": {
3675// "type": "object",
3676// "description": "Arguments for `disassemble` request.",
3677// "properties": {
3678// "memoryReference": {
3679// "type": "string",
3680// "description": "Memory reference to the base location containing the
3681// instructions to disassemble."
3682// },
3683// "offset": {
3684// "type": "integer",
3685// "description": "Offset (in bytes) to be applied to the reference
3686// location before disassembling. Can be negative."
3687// },
3688// "instructionOffset": {
3689// "type": "integer",
3690// "description": "Offset (in instructions) to be applied after the byte
3691// offset (if any) before disassembling. Can be negative."
3692// },
3693// "instructionCount": {
3694// "type": "integer",
3695// "description": "Number of instructions to disassemble starting at the
3696// specified location and offset.\nAn adapter must return exactly this
3697// number of instructions - any unavailable instructions should be
3698// replaced with an implementation-defined 'invalid instruction' value."
3699// },
3700// "resolveSymbols": {
3701// "type": "boolean",
3702// "description": "If true, the adapter should attempt to resolve memory
3703// addresses and other values to symbolic names."
3704// }
3705// },
3706// "required": [ "memoryReference", "instructionCount" ]
3707// },
3708// "DisassembleResponse": {
3709// "allOf": [ { "$ref": "#/definitions/Response" }, {
3710// "type": "object",
3711// "description": "Response to `disassemble` request.",
3712// "properties": {
3713// "body": {
3714// "type": "object",
3715// "properties": {
3716// "instructions": {
3717// "type": "array",
3718// "items": {
3719// "$ref": "#/definitions/DisassembledInstruction"
3720// },
3721// "description": "The list of disassembled instructions."
3722// }
3723// },
3724// "required": [ "instructions" ]
3725// }
3726// }
3727// }]
3728// }
3729void request_disassemble(const llvm::json::Object &request) {
3730 llvm::json::Object response;
3731 FillResponse(request, response);
3732 auto arguments = request.getObject(K: "arguments");
3733
3734 auto memoryReference = GetString(obj: arguments, key: "memoryReference");
3735 lldb::addr_t addr_ptr;
3736 if (memoryReference.consumeInteger(0, addr_ptr)) {
3737 response["success"] = false;
3738 response["message"] =
3739 "Malformed memory reference: " + memoryReference.str();
3740 g_dap.SendJSON(json: llvm::json::Value(std::move(response)));
3741 return;
3742 }
3743
3744 addr_ptr += GetSigned(obj: arguments, key: "instructionOffset", fail_value: 0);
3745 lldb::SBAddress addr(addr_ptr, g_dap.target);
3746 if (!addr.IsValid()) {
3747 response["success"] = false;
3748 response["message"] = "Memory reference not found in the current binary.";
3749 g_dap.SendJSON(json: llvm::json::Value(std::move(response)));
3750 return;
3751 }
3752
3753 const auto inst_count = GetUnsigned(obj: arguments, key: "instructionCount", fail_value: 0);
3754 lldb::SBInstructionList insts =
3755 g_dap.target.ReadInstructions(base_addr: addr, count: inst_count);
3756
3757 if (!insts.IsValid()) {
3758 response["success"] = false;
3759 response["message"] = "Failed to find instructions for memory address.";
3760 g_dap.SendJSON(json: llvm::json::Value(std::move(response)));
3761 return;
3762 }
3763
3764 const bool resolveSymbols = GetBoolean(obj: arguments, key: "resolveSymbols", fail_value: false);
3765 llvm::json::Array instructions;
3766 const auto num_insts = insts.GetSize();
3767 for (size_t i = 0; i < num_insts; ++i) {
3768 lldb::SBInstruction inst = insts.GetInstructionAtIndex(idx: i);
3769 auto addr = inst.GetAddress();
3770 const auto inst_addr = addr.GetLoadAddress(target: g_dap.target);
3771 const char *m = inst.GetMnemonic(target: g_dap.target);
3772 const char *o = inst.GetOperands(target: g_dap.target);
3773 const char *c = inst.GetComment(target: g_dap.target);
3774 auto d = inst.GetData(target: g_dap.target);
3775
3776 std::string bytes;
3777 llvm::raw_string_ostream sb(bytes);
3778 for (unsigned i = 0; i < inst.GetByteSize(); i++) {
3779 lldb::SBError error;
3780 uint8_t b = d.GetUnsignedInt8(error, offset: i);
3781 if (error.Success()) {
3782 sb << llvm::format("%2.2x ", b);
3783 }
3784 }
3785 sb.flush();
3786
3787 llvm::json::Object disassembled_inst{
3788 {"address", "0x" + llvm::utohexstr(X: inst_addr)},
3789 {"instructionBytes",
3790 bytes.size() > 0 ? bytes.substr(pos: 0, n: bytes.size() - 1) : ""},
3791 };
3792
3793 std::string instruction;
3794 llvm::raw_string_ostream si(instruction);
3795
3796 lldb::SBSymbol symbol = addr.GetSymbol();
3797 // Only add the symbol on the first line of the function.
3798 if (symbol.IsValid() && symbol.GetStartAddress() == addr) {
3799 // If we have a valid symbol, append it as a label prefix for the first
3800 // instruction. This is so you can see the start of a function/callsite
3801 // in the assembly, at the moment VS Code (1.80) does not visualize the
3802 // symbol associated with the assembly instruction.
3803 si << (symbol.GetMangledName() != nullptr ? symbol.GetMangledName()
3804 : symbol.GetName())
3805 << ": ";
3806
3807 if (resolveSymbols) {
3808 disassembled_inst.try_emplace("symbol", symbol.GetDisplayName());
3809 }
3810 }
3811
3812 si << llvm::formatv("{0,7} {1,12}", m, o);
3813 if (c && c[0]) {
3814 si << " ; " << c;
3815 }
3816 si.flush();
3817
3818 disassembled_inst.try_emplace("instruction", instruction);
3819
3820 auto line_entry = addr.GetLineEntry();
3821 // If the line number is 0 then the entry represents a compiler generated
3822 // location.
3823 if (line_entry.GetStartAddress() == addr && line_entry.IsValid() &&
3824 line_entry.GetFileSpec().IsValid() && line_entry.GetLine() != 0) {
3825 auto source = CreateSource(line_entry);
3826 disassembled_inst.try_emplace("location", source);
3827
3828 const auto line = line_entry.GetLine();
3829 if (line && line != LLDB_INVALID_LINE_NUMBER) {
3830 disassembled_inst.try_emplace("line", line);
3831 }
3832 const auto column = line_entry.GetColumn();
3833 if (column && column != LLDB_INVALID_COLUMN_NUMBER) {
3834 disassembled_inst.try_emplace("column", column);
3835 }
3836
3837 auto end_line_entry = line_entry.GetEndAddress().GetLineEntry();
3838 if (end_line_entry.IsValid() &&
3839 end_line_entry.GetFileSpec() == line_entry.GetFileSpec()) {
3840 const auto end_line = end_line_entry.GetLine();
3841 if (end_line && end_line != LLDB_INVALID_LINE_NUMBER &&
3842 end_line != line) {
3843 disassembled_inst.try_emplace("endLine", end_line);
3844
3845 const auto end_column = end_line_entry.GetColumn();
3846 if (end_column && end_column != LLDB_INVALID_COLUMN_NUMBER &&
3847 end_column != column) {
3848 disassembled_inst.try_emplace("endColumn", end_column - 1);
3849 }
3850 }
3851 }
3852 }
3853
3854 instructions.emplace_back(std::move(disassembled_inst));
3855 }
3856
3857 llvm::json::Object body;
3858 body.try_emplace("instructions", std::move(instructions));
3859 response.try_emplace("body", std::move(body));
3860 g_dap.SendJSON(json: llvm::json::Value(std::move(response)));
3861}
3862// A request used in testing to get the details on all breakpoints that are
3863// currently set in the target. This helps us to test "setBreakpoints" and
3864// "setFunctionBreakpoints" requests to verify we have the correct set of
3865// breakpoints currently set in LLDB.
3866void request__testGetTargetBreakpoints(const llvm::json::Object &request) {
3867 llvm::json::Object response;
3868 FillResponse(request, response);
3869 llvm::json::Array response_breakpoints;
3870 for (uint32_t i = 0; g_dap.target.GetBreakpointAtIndex(idx: i).IsValid(); ++i) {
3871 auto bp = Breakpoint(g_dap.target.GetBreakpointAtIndex(idx: i));
3872 AppendBreakpoint(bp: &bp, breakpoints&: response_breakpoints);
3873 }
3874 llvm::json::Object body;
3875 body.try_emplace("breakpoints", std::move(response_breakpoints));
3876 response.try_emplace("body", std::move(body));
3877 g_dap.SendJSON(json: llvm::json::Value(std::move(response)));
3878}
3879
3880void RegisterRequestCallbacks() {
3881 g_dap.RegisterRequestCallback("attach", request_attach);
3882 g_dap.RegisterRequestCallback("completions", request_completions);
3883 g_dap.RegisterRequestCallback("continue", request_continue);
3884 g_dap.RegisterRequestCallback("configurationDone", request_configurationDone);
3885 g_dap.RegisterRequestCallback("disconnect", request_disconnect);
3886 g_dap.RegisterRequestCallback("evaluate", request_evaluate);
3887 g_dap.RegisterRequestCallback("exceptionInfo", request_exceptionInfo);
3888 g_dap.RegisterRequestCallback("initialize", request_initialize);
3889 g_dap.RegisterRequestCallback("launch", request_launch);
3890 g_dap.RegisterRequestCallback("next", request_next);
3891 g_dap.RegisterRequestCallback("pause", request_pause);
3892 g_dap.RegisterRequestCallback("restart", request_restart);
3893 g_dap.RegisterRequestCallback("scopes", request_scopes);
3894 g_dap.RegisterRequestCallback("setBreakpoints", request_setBreakpoints);
3895 g_dap.RegisterRequestCallback("setExceptionBreakpoints",
3896 request_setExceptionBreakpoints);
3897 g_dap.RegisterRequestCallback("setFunctionBreakpoints",
3898 request_setFunctionBreakpoints);
3899 g_dap.RegisterRequestCallback("dataBreakpointInfo",
3900 request_dataBreakpointInfo);
3901 g_dap.RegisterRequestCallback("setDataBreakpoints",
3902 request_setDataBreakpoints);
3903 g_dap.RegisterRequestCallback("setVariable", request_setVariable);
3904 g_dap.RegisterRequestCallback("source", request_source);
3905 g_dap.RegisterRequestCallback("stackTrace", request_stackTrace);
3906 g_dap.RegisterRequestCallback("stepIn", request_stepIn);
3907 g_dap.RegisterRequestCallback("stepOut", request_stepOut);
3908 g_dap.RegisterRequestCallback("threads", request_threads);
3909 g_dap.RegisterRequestCallback("variables", request_variables);
3910 g_dap.RegisterRequestCallback("disassemble", request_disassemble);
3911 // Custom requests
3912 g_dap.RegisterRequestCallback("compileUnits", request_compileUnits);
3913 g_dap.RegisterRequestCallback("modules", request_modules);
3914 // Testing requests
3915 g_dap.RegisterRequestCallback("_testGetTargetBreakpoints",
3916 request__testGetTargetBreakpoints);
3917}
3918
3919} // anonymous namespace
3920
3921static void printHelp(LLDBDAPOptTable &table, llvm::StringRef tool_name) {
3922 std::string usage_str = tool_name.str() + " options";
3923 table.printHelp(OS&: llvm::outs(), Usage: usage_str.c_str(), Title: "LLDB DAP", ShowHidden: false);
3924
3925 std::string examples = R"___(
3926EXAMPLES:
3927 The debug adapter can be started in two modes.
3928
3929 Running lldb-dap without any arguments will start communicating with the
3930 parent over stdio. Passing a port number causes lldb-dap to start listening
3931 for connections on that port.
3932
3933 lldb-dap -p <port>
3934
3935 Passing --wait-for-debugger will pause the process at startup and wait for a
3936 debugger to attach to the process.
3937
3938 lldb-dap -g
3939)___";
3940 llvm::outs() << examples;
3941}
3942
3943// If --launch-target is provided, this instance of lldb-dap becomes a
3944// runInTerminal launcher. It will ultimately launch the program specified in
3945// the --launch-target argument, which is the original program the user wanted
3946// to debug. This is done in such a way that the actual debug adaptor can
3947// place breakpoints at the beginning of the program.
3948//
3949// The launcher will communicate with the debug adaptor using a fifo file in the
3950// directory specified in the --comm-file argument.
3951//
3952// Regarding the actual flow, this launcher will first notify the debug adaptor
3953// of its pid. Then, the launcher will be in a pending state waiting to be
3954// attached by the adaptor.
3955//
3956// Once attached and resumed, the launcher will exec and become the program
3957// specified by --launch-target, which is the original target the
3958// user wanted to run.
3959//
3960// In case of errors launching the target, a suitable error message will be
3961// emitted to the debug adaptor.
3962void LaunchRunInTerminalTarget(llvm::opt::Arg &target_arg,
3963 llvm::StringRef comm_file,
3964 lldb::pid_t debugger_pid, char *argv[]) {
3965#if defined(_WIN32)
3966 llvm::errs() << "runInTerminal is only supported on POSIX systems\n";
3967 exit(EXIT_FAILURE);
3968#else
3969
3970 // On Linux with the Yama security module enabled, a process can only attach
3971 // to its descendants by default. In the runInTerminal case the target
3972 // process is launched by the client so we need to allow tracing explicitly.
3973#if defined(__linux__)
3974 if (debugger_pid != LLDB_INVALID_PROCESS_ID)
3975 (void)prctl(PR_SET_PTRACER, debugger_pid, 0, 0, 0);
3976#endif
3977
3978 RunInTerminalLauncherCommChannel comm_channel(comm_file);
3979 if (llvm::Error err = comm_channel.NotifyPid()) {
3980 llvm::errs() << llvm::toString(E: std::move(err)) << "\n";
3981 exit(EXIT_FAILURE);
3982 }
3983
3984 // We will wait to be attached with a timeout. We don't wait indefinitely
3985 // using a signal to prevent being paused forever.
3986
3987 // This env var should be used only for tests.
3988 const char *timeout_env_var = getenv(name: "LLDB_DAP_RIT_TIMEOUT_IN_MS");
3989 int timeout_in_ms =
3990 timeout_env_var != nullptr ? atoi(nptr: timeout_env_var) : 20000;
3991 if (llvm::Error err = comm_channel.WaitUntilDebugAdaptorAttaches(
3992 timeout: std::chrono::milliseconds(timeout_in_ms))) {
3993 llvm::errs() << llvm::toString(E: std::move(err)) << "\n";
3994 exit(EXIT_FAILURE);
3995 }
3996
3997 const char *target = target_arg.getValue();
3998 execvp(file: target, argv: argv);
3999
4000 std::string error = std::strerror(errno);
4001 comm_channel.NotifyError(error);
4002 llvm::errs() << error << "\n";
4003 exit(EXIT_FAILURE);
4004#endif
4005}
4006
4007/// used only by TestVSCode_redirection_to_console.py
4008void redirection_test() {
4009 printf(format: "stdout message\n");
4010 fprintf(stderr, format: "stderr message\n");
4011 fflush(stdout);
4012 fflush(stderr);
4013}
4014
4015/// Redirect stdout and stderr fo the IDE's console output.
4016///
4017/// Errors in this operation will be printed to the log file and the IDE's
4018/// console output as well.
4019///
4020/// \return
4021/// A fd pointing to the original stdout.
4022int SetupStdoutStderrRedirection() {
4023 int stdoutfd = fileno(stdout);
4024 int new_stdout_fd = dup(fd: stdoutfd);
4025 auto output_callback_stderr = [](llvm::StringRef data) {
4026 g_dap.SendOutput(o: OutputType::Stderr, output: data);
4027 };
4028 auto output_callback_stdout = [](llvm::StringRef data) {
4029 g_dap.SendOutput(o: OutputType::Stdout, output: data);
4030 };
4031 if (llvm::Error err = RedirectFd(fd: stdoutfd, callback: output_callback_stdout)) {
4032 std::string error_message = llvm::toString(E: std::move(err));
4033 if (g_dap.log)
4034 *g_dap.log << error_message << std::endl;
4035 output_callback_stderr(error_message);
4036 }
4037 if (llvm::Error err = RedirectFd(fd: fileno(stderr), callback: output_callback_stderr)) {
4038 std::string error_message = llvm::toString(E: std::move(err));
4039 if (g_dap.log)
4040 *g_dap.log << error_message << std::endl;
4041 output_callback_stderr(error_message);
4042 }
4043
4044 /// used only by TestVSCode_redirection_to_console.py
4045 if (getenv(name: "LLDB_DAP_TEST_STDOUT_STDERR_REDIRECTION") != nullptr)
4046 redirection_test();
4047 return new_stdout_fd;
4048}
4049
4050int main(int argc, char *argv[]) {
4051 llvm::InitLLVM IL(argc, argv, /*InstallPipeSignalExitHandler=*/false);
4052 llvm::setBugReportMsg("PLEASE submit a bug report to " LLDB_BUG_REPORT_URL
4053 " and include the crash backtrace.\n");
4054
4055 llvm::SmallString<256> program_path(argv[0]);
4056 llvm::sys::fs::make_absolute(path&: program_path);
4057 g_dap.debug_adaptor_path = program_path.str().str();
4058
4059 LLDBDAPOptTable T;
4060 unsigned MAI, MAC;
4061 llvm::ArrayRef<const char *> ArgsArr = llvm::ArrayRef(argv + 1, argc);
4062 llvm::opt::InputArgList input_args = T.ParseArgs(Args: ArgsArr, MissingArgIndex&: MAI, MissingArgCount&: MAC);
4063
4064 if (input_args.hasArg(OPT_help)) {
4065 printHelp(table&: T, tool_name: llvm::sys::path::filename(path: argv[0]));
4066 return EXIT_SUCCESS;
4067 }
4068
4069 if (input_args.hasArg(OPT_repl_mode)) {
4070 llvm::opt::Arg *repl_mode = input_args.getLastArg(OPT_repl_mode);
4071 llvm::StringRef repl_mode_value = repl_mode->getValue();
4072 if (repl_mode_value == "auto") {
4073 g_dap.repl_mode = ReplMode::Auto;
4074 } else if (repl_mode_value == "variable") {
4075 g_dap.repl_mode = ReplMode::Variable;
4076 } else if (repl_mode_value == "command") {
4077 g_dap.repl_mode = ReplMode::Command;
4078 } else {
4079 llvm::errs()
4080 << "'" << repl_mode_value
4081 << "' is not a valid option, use 'variable', 'command' or 'auto'.\n";
4082 return EXIT_FAILURE;
4083 }
4084 }
4085
4086 if (llvm::opt::Arg *target_arg = input_args.getLastArg(OPT_launch_target)) {
4087 if (llvm::opt::Arg *comm_file = input_args.getLastArg(OPT_comm_file)) {
4088 lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
4089 llvm::opt::Arg *debugger_pid = input_args.getLastArg(OPT_debugger_pid);
4090 if (debugger_pid) {
4091 llvm::StringRef debugger_pid_value = debugger_pid->getValue();
4092 if (debugger_pid_value.getAsInteger(Radix: 10, Result&: pid)) {
4093 llvm::errs() << "'" << debugger_pid_value
4094 << "' is not a valid "
4095 "PID\n";
4096 return EXIT_FAILURE;
4097 }
4098 }
4099 int target_args_pos = argc;
4100 for (int i = 0; i < argc; i++)
4101 if (strcmp(s1: argv[i], s2: "--launch-target") == 0) {
4102 target_args_pos = i + 1;
4103 break;
4104 }
4105 LaunchRunInTerminalTarget(target_arg&: *target_arg, comm_file: comm_file->getValue(), debugger_pid: pid,
4106 argv: argv + target_args_pos);
4107 } else {
4108 llvm::errs() << "\"--launch-target\" requires \"--comm-file\" to be "
4109 "specified\n";
4110 return EXIT_FAILURE;
4111 }
4112 }
4113
4114 // stdout/stderr redirection to the IDE's console
4115 int new_stdout_fd = SetupStdoutStderrRedirection();
4116
4117 // Initialize LLDB first before we do anything.
4118 lldb::SBDebugger::Initialize();
4119
4120 // Terminate the debugger before the C++ destructor chain kicks in.
4121 auto terminate_debugger =
4122 llvm::make_scope_exit(F: [] { lldb::SBDebugger::Terminate(); });
4123
4124 RegisterRequestCallbacks();
4125
4126 int portno = -1;
4127
4128 if (auto *arg = input_args.getLastArg(OPT_port)) {
4129 auto optarg = arg->getValue();
4130 char *remainder;
4131 portno = strtol(optarg, &remainder, 0);
4132 if (remainder == optarg || *remainder != '\0') {
4133 fprintf(stderr, "'%s' is not a valid port number.\n", optarg);
4134 return EXIT_FAILURE;
4135 }
4136 }
4137
4138#if !defined(_WIN32)
4139 if (input_args.hasArg(OPT_wait_for_debugger)) {
4140 printf(format: "Paused waiting for debugger to attach (pid = %i)...\n", getpid());
4141 pause();
4142 }
4143#endif
4144 if (portno != -1) {
4145 printf(format: "Listening on port %i...\n", portno);
4146 SOCKET socket_fd = AcceptConnection(portno);
4147 if (socket_fd >= 0) {
4148 g_dap.input.descriptor = StreamDescriptor::from_socket(s: socket_fd, close: true);
4149 g_dap.output.descriptor = StreamDescriptor::from_socket(s: socket_fd, close: false);
4150 } else {
4151 return EXIT_FAILURE;
4152 }
4153 } else {
4154 g_dap.input.descriptor = StreamDescriptor::from_file(fd: fileno(stdin), close: false);
4155 g_dap.output.descriptor = StreamDescriptor::from_file(fd: new_stdout_fd, close: false);
4156 }
4157
4158 bool CleanExit = true;
4159 if (auto Err = g_dap.Loop()) {
4160 if (g_dap.log)
4161 *g_dap.log << "Transport Error: " << llvm::toString(E: std::move(Err))
4162 << "\n";
4163 CleanExit = false;
4164 }
4165
4166 return CleanExit ? EXIT_SUCCESS : EXIT_FAILURE;
4167}
4168

source code of lldb/tools/lldb-dap/lldb-dap.cpp