1 //===-- lldb-vscode.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 "VSCode.h"
10 
11 #include <cassert>
12 #include <climits>
13 #include <cstdarg>
14 #include <cstdio>
15 #include <cstdlib>
16 #include <cstring>
17 #include <sys/stat.h>
18 #include <sys/types.h>
19 #if defined(_WIN32)
20 // We need to #define NOMINMAX in order to skip `min()` and `max()` macro
21 // definitions that conflict with other system headers.
22 // We also need to #undef GetObject (which is defined to GetObjectW) because
23 // the JSON code we use also has methods named `GetObject()` and we conflict
24 // against these.
25 #define NOMINMAX
26 #include <windows.h>
27 #undef GetObject
28 #include <io.h>
29 #else
30 #include <netinet/in.h>
31 #include <sys/socket.h>
32 #include <unistd.h>
33 #endif
34 
35 #include <algorithm>
36 #include <chrono>
37 #include <fstream>
38 #include <map>
39 #include <memory>
40 #include <mutex>
41 #include <set>
42 #include <sstream>
43 #include <thread>
44 #include <vector>
45 
46 #include "llvm/ADT/ArrayRef.h"
47 #include "llvm/ADT/DenseMap.h"
48 #include "llvm/ADT/ScopeExit.h"
49 #include "llvm/Option/Arg.h"
50 #include "llvm/Option/ArgList.h"
51 #include "llvm/Option/Option.h"
52 #include "llvm/Support/Errno.h"
53 #include "llvm/Support/FileSystem.h"
54 #include "llvm/Support/InitLLVM.h"
55 #include "llvm/Support/Path.h"
56 #include "llvm/Support/PrettyStackTrace.h"
57 #include "llvm/Support/raw_ostream.h"
58 
59 #include "JSONUtils.h"
60 #include "LLDBUtils.h"
61 #include "OutputRedirector.h"
62 
63 #if defined(_WIN32)
64 #ifndef PATH_MAX
65 #define PATH_MAX MAX_PATH
66 #endif
67 typedef int socklen_t;
68 #endif
69 
70 using namespace lldb_vscode;
71 
72 namespace {
73 enum ID {
74   OPT_INVALID = 0, // This is not an option ID.
75 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM,  \
76                HELPTEXT, METAVAR, VALUES)                                      \
77   OPT_##ID,
78 #include "Options.inc"
79 #undef OPTION
80 };
81 
82 #define PREFIX(NAME, VALUE)                                                    \
83   static constexpr llvm::StringLiteral NAME##_init[] = VALUE;                  \
84   static constexpr llvm::ArrayRef<llvm::StringLiteral> NAME(                   \
85       NAME##_init, std::size(NAME##_init) - 1);
86 #include "Options.inc"
87 #undef PREFIX
88 
89 static constexpr llvm::opt::OptTable::Info InfoTable[] = {
90 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM,  \
91                HELPTEXT, METAVAR, VALUES)                                      \
92   {PREFIX,      NAME,      HELPTEXT,                                           \
93    METAVAR,     OPT_##ID,  llvm::opt::Option::KIND##Class,                     \
94    PARAM,       FLAGS,     OPT_##GROUP,                                        \
95    OPT_##ALIAS, ALIASARGS, VALUES},
96 #include "Options.inc"
97 #undef OPTION
98 };
99 class LLDBVSCodeOptTable : public llvm::opt::GenericOptTable {
100 public:
LLDBVSCodeOptTable()101   LLDBVSCodeOptTable() : llvm::opt::GenericOptTable(InfoTable, true) {}
102 };
103 
104 typedef void (*RequestCallback)(const llvm::json::Object &command);
105 
106 enum LaunchMethod { Launch, Attach, AttachForSuspendedLaunch };
107 
GetTopLevelScope(int64_t variablesReference)108 lldb::SBValueList *GetTopLevelScope(int64_t variablesReference) {
109   switch (variablesReference) {
110   case VARREF_LOCALS:
111     return &g_vsc.variables.locals;
112   case VARREF_GLOBALS:
113     return &g_vsc.variables.globals;
114   case VARREF_REGS:
115     return &g_vsc.variables.registers;
116   default:
117     return nullptr;
118   }
119 }
120 
AcceptConnection(int portno)121 SOCKET AcceptConnection(int portno) {
122   // Accept a socket connection from any host on "portno".
123   SOCKET newsockfd = -1;
124   struct sockaddr_in serv_addr, cli_addr;
125   SOCKET sockfd = socket(AF_INET, SOCK_STREAM, 0);
126   if (sockfd < 0) {
127     if (g_vsc.log)
128       *g_vsc.log << "error: opening socket (" << strerror(errno) << ")"
129                  << std::endl;
130   } else {
131     memset((char *)&serv_addr, 0, sizeof(serv_addr));
132     serv_addr.sin_family = AF_INET;
133     // serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
134     serv_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
135     serv_addr.sin_port = htons(portno);
136     if (bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
137       if (g_vsc.log)
138         *g_vsc.log << "error: binding socket (" << strerror(errno) << ")"
139                    << std::endl;
140     } else {
141       listen(sockfd, 5);
142       socklen_t clilen = sizeof(cli_addr);
143       newsockfd =
144           llvm::sys::RetryAfterSignal(static_cast<SOCKET>(-1), accept, sockfd,
145                                       (struct sockaddr *)&cli_addr, &clilen);
146       if (newsockfd < 0)
147         if (g_vsc.log)
148           *g_vsc.log << "error: accept (" << strerror(errno) << ")"
149                      << std::endl;
150     }
151 #if defined(_WIN32)
152     closesocket(sockfd);
153 #else
154     close(sockfd);
155 #endif
156   }
157   return newsockfd;
158 }
159 
MakeArgv(const llvm::ArrayRef<std::string> & strs)160 std::vector<const char *> MakeArgv(const llvm::ArrayRef<std::string> &strs) {
161   // Create and return an array of "const char *", one for each C string in
162   // "strs" and terminate the list with a NULL. This can be used for argument
163   // vectors (argv) or environment vectors (envp) like those passed to the
164   // "main" function in C programs.
165   std::vector<const char *> argv;
166   for (const auto &s : strs)
167     argv.push_back(s.c_str());
168   argv.push_back(nullptr);
169   return argv;
170 }
171 
172 // Send a "exited" event to indicate the process has exited.
SendProcessExitedEvent(lldb::SBProcess & process)173 void SendProcessExitedEvent(lldb::SBProcess &process) {
174   llvm::json::Object event(CreateEventObject("exited"));
175   llvm::json::Object body;
176   body.try_emplace("exitCode", (int64_t)process.GetExitStatus());
177   event.try_emplace("body", std::move(body));
178   g_vsc.SendJSON(llvm::json::Value(std::move(event)));
179 }
180 
SendThreadExitedEvent(lldb::tid_t tid)181 void SendThreadExitedEvent(lldb::tid_t tid) {
182   llvm::json::Object event(CreateEventObject("thread"));
183   llvm::json::Object body;
184   body.try_emplace("reason", "exited");
185   body.try_emplace("threadId", (int64_t)tid);
186   event.try_emplace("body", std::move(body));
187   g_vsc.SendJSON(llvm::json::Value(std::move(event)));
188 }
189 
190 // Send a "terminated" event to indicate the process is done being
191 // debugged.
SendTerminatedEvent()192 void SendTerminatedEvent() {
193   // If an inferior exits prior to the processing of a disconnect request, then
194   // the threads executing EventThreadFunction and request_discontinue
195   // respectively may call SendTerminatedEvent simultaneously. Without any
196   // synchronization, the thread executing EventThreadFunction may set
197   // g_vsc.sent_terminated_event before the thread executing
198   // request_discontinue has had a chance to test it, in which case the latter
199   // would move ahead to issue a response to the disconnect request. Said
200   // response may get dispatched ahead of the terminated event compelling the
201   // client to terminate the debug session without consuming any console output
202   // that might've been generated by the execution of terminateCommands. So,
203   // synchronize simultaneous calls to SendTerminatedEvent.
204   static std::mutex mutex;
205   std::lock_guard<std::mutex> locker(mutex);
206   if (!g_vsc.sent_terminated_event) {
207     g_vsc.sent_terminated_event = true;
208     g_vsc.RunTerminateCommands();
209     // Send a "terminated" event
210     llvm::json::Object event(CreateTerminatedEventObject());
211     g_vsc.SendJSON(llvm::json::Value(std::move(event)));
212   }
213 }
214 
215 // Send a thread stopped event for all threads as long as the process
216 // is stopped.
SendThreadStoppedEvent()217 void SendThreadStoppedEvent() {
218   lldb::SBProcess process = g_vsc.target.GetProcess();
219   if (process.IsValid()) {
220     auto state = process.GetState();
221     if (state == lldb::eStateStopped) {
222       llvm::DenseSet<lldb::tid_t> old_thread_ids;
223       old_thread_ids.swap(g_vsc.thread_ids);
224       uint32_t stop_id = process.GetStopID();
225       const uint32_t num_threads = process.GetNumThreads();
226 
227       // First make a pass through the threads to see if the focused thread
228       // has a stop reason. In case the focus thread doesn't have a stop
229       // reason, remember the first thread that has a stop reason so we can
230       // set it as the focus thread if below if needed.
231       lldb::tid_t first_tid_with_reason = LLDB_INVALID_THREAD_ID;
232       uint32_t num_threads_with_reason = 0;
233       bool focus_thread_exists = false;
234       for (uint32_t thread_idx = 0; thread_idx < num_threads; ++thread_idx) {
235         lldb::SBThread thread = process.GetThreadAtIndex(thread_idx);
236         const lldb::tid_t tid = thread.GetThreadID();
237         const bool has_reason = ThreadHasStopReason(thread);
238         // If the focus thread doesn't have a stop reason, clear the thread ID
239         if (tid == g_vsc.focus_tid) {
240           focus_thread_exists = true;
241           if (!has_reason)
242             g_vsc.focus_tid = LLDB_INVALID_THREAD_ID;
243         }
244         if (has_reason) {
245           ++num_threads_with_reason;
246           if (first_tid_with_reason == LLDB_INVALID_THREAD_ID)
247             first_tid_with_reason = tid;
248         }
249       }
250 
251       // We will have cleared g_vsc.focus_tid if he focus thread doesn't have
252       // a stop reason, so if it was cleared, or wasn't set, or doesn't exist,
253       // then set the focus thread to the first thread with a stop reason.
254       if (!focus_thread_exists || g_vsc.focus_tid == LLDB_INVALID_THREAD_ID)
255         g_vsc.focus_tid = first_tid_with_reason;
256 
257       // If no threads stopped with a reason, then report the first one so
258       // we at least let the UI know we stopped.
259       if (num_threads_with_reason == 0) {
260         lldb::SBThread thread = process.GetThreadAtIndex(0);
261         g_vsc.SendJSON(CreateThreadStopped(thread, stop_id));
262       } else {
263         for (uint32_t thread_idx = 0; thread_idx < num_threads; ++thread_idx) {
264           lldb::SBThread thread = process.GetThreadAtIndex(thread_idx);
265           g_vsc.thread_ids.insert(thread.GetThreadID());
266           if (ThreadHasStopReason(thread)) {
267             g_vsc.SendJSON(CreateThreadStopped(thread, stop_id));
268           }
269         }
270       }
271 
272       for (auto tid : old_thread_ids) {
273         auto end = g_vsc.thread_ids.end();
274         auto pos = g_vsc.thread_ids.find(tid);
275         if (pos == end)
276           SendThreadExitedEvent(tid);
277       }
278     } else {
279       if (g_vsc.log)
280         *g_vsc.log << "error: SendThreadStoppedEvent() when process"
281                       " isn't stopped ("
282                    << lldb::SBDebugger::StateAsCString(state) << ')'
283                    << std::endl;
284     }
285   } else {
286     if (g_vsc.log)
287       *g_vsc.log << "error: SendThreadStoppedEvent() invalid process"
288                  << std::endl;
289   }
290   g_vsc.RunStopCommands();
291 }
292 
293 // "ProcessEvent": {
294 //   "allOf": [
295 //     { "$ref": "#/definitions/Event" },
296 //     {
297 //       "type": "object",
298 //       "description": "Event message for 'process' event type. The event
299 //                       indicates that the debugger has begun debugging a
300 //                       new process. Either one that it has launched, or one
301 //                       that it has attached to.",
302 //       "properties": {
303 //         "event": {
304 //           "type": "string",
305 //           "enum": [ "process" ]
306 //         },
307 //         "body": {
308 //           "type": "object",
309 //           "properties": {
310 //             "name": {
311 //               "type": "string",
312 //               "description": "The logical name of the process. This is
313 //                               usually the full path to process's executable
314 //                               file. Example: /home/myproj/program.js."
315 //             },
316 //             "systemProcessId": {
317 //               "type": "integer",
318 //               "description": "The system process id of the debugged process.
319 //                               This property will be missing for non-system
320 //                               processes."
321 //             },
322 //             "isLocalProcess": {
323 //               "type": "boolean",
324 //               "description": "If true, the process is running on the same
325 //                               computer as the debug adapter."
326 //             },
327 //             "startMethod": {
328 //               "type": "string",
329 //               "enum": [ "launch", "attach", "attachForSuspendedLaunch" ],
330 //               "description": "Describes how the debug engine started
331 //                               debugging this process.",
332 //               "enumDescriptions": [
333 //                 "Process was launched under the debugger.",
334 //                 "Debugger attached to an existing process.",
335 //                 "A project launcher component has launched a new process in
336 //                  a suspended state and then asked the debugger to attach."
337 //               ]
338 //             }
339 //           },
340 //           "required": [ "name" ]
341 //         }
342 //       },
343 //       "required": [ "event", "body" ]
344 //     }
345 //   ]
346 // }
SendProcessEvent(LaunchMethod launch_method)347 void SendProcessEvent(LaunchMethod launch_method) {
348   lldb::SBFileSpec exe_fspec = g_vsc.target.GetExecutable();
349   char exe_path[PATH_MAX];
350   exe_fspec.GetPath(exe_path, sizeof(exe_path));
351   llvm::json::Object event(CreateEventObject("process"));
352   llvm::json::Object body;
353   EmplaceSafeString(body, "name", std::string(exe_path));
354   const auto pid = g_vsc.target.GetProcess().GetProcessID();
355   body.try_emplace("systemProcessId", (int64_t)pid);
356   body.try_emplace("isLocalProcess", true);
357   const char *startMethod = nullptr;
358   switch (launch_method) {
359   case Launch:
360     startMethod = "launch";
361     break;
362   case Attach:
363     startMethod = "attach";
364     break;
365   case AttachForSuspendedLaunch:
366     startMethod = "attachForSuspendedLaunch";
367     break;
368   }
369   body.try_emplace("startMethod", startMethod);
370   event.try_emplace("body", std::move(body));
371   g_vsc.SendJSON(llvm::json::Value(std::move(event)));
372 }
373 
374 // Grab any STDOUT and STDERR from the process and send it up to VS Code
375 // via an "output" event to the "stdout" and "stderr" categories.
SendStdOutStdErr(lldb::SBProcess & process)376 void SendStdOutStdErr(lldb::SBProcess &process) {
377   char buffer[1024];
378   size_t count;
379   while ((count = process.GetSTDOUT(buffer, sizeof(buffer))) > 0)
380     g_vsc.SendOutput(OutputType::Stdout, llvm::StringRef(buffer, count));
381   while ((count = process.GetSTDERR(buffer, sizeof(buffer))) > 0)
382     g_vsc.SendOutput(OutputType::Stderr, llvm::StringRef(buffer, count));
383 }
384 
ProgressEventThreadFunction()385 void ProgressEventThreadFunction() {
386   lldb::SBListener listener("lldb-vscode.progress.listener");
387   g_vsc.debugger.GetBroadcaster().AddListener(
388       listener, lldb::SBDebugger::eBroadcastBitProgress);
389   g_vsc.broadcaster.AddListener(listener, eBroadcastBitStopProgressThread);
390   lldb::SBEvent event;
391   bool done = false;
392   while (!done) {
393     if (listener.WaitForEvent(1, event)) {
394       const auto event_mask = event.GetType();
395       if (event.BroadcasterMatchesRef(g_vsc.broadcaster)) {
396         if (event_mask & eBroadcastBitStopProgressThread) {
397           done = true;
398         }
399       } else {
400         uint64_t progress_id = 0;
401         uint64_t completed = 0;
402         uint64_t total = 0;
403         bool is_debugger_specific = false;
404         const char *message = lldb::SBDebugger::GetProgressFromEvent(
405             event, progress_id, completed, total, is_debugger_specific);
406         if (message)
407           g_vsc.SendProgressEvent(progress_id, message, completed, total);
408       }
409     }
410   }
411 }
412 
413 // All events from the debugger, target, process, thread and frames are
414 // received in this function that runs in its own thread. We are using a
415 // "FILE *" to output packets back to VS Code and they have mutexes in them
416 // them prevent multiple threads from writing simultaneously so no locking
417 // is required.
EventThreadFunction()418 void EventThreadFunction() {
419   lldb::SBEvent event;
420   lldb::SBListener listener = g_vsc.debugger.GetListener();
421   bool done = false;
422   while (!done) {
423     if (listener.WaitForEvent(1, event)) {
424       const auto event_mask = event.GetType();
425       if (lldb::SBProcess::EventIsProcessEvent(event)) {
426         lldb::SBProcess process = lldb::SBProcess::GetProcessFromEvent(event);
427         if (event_mask & lldb::SBProcess::eBroadcastBitStateChanged) {
428           auto state = lldb::SBProcess::GetStateFromEvent(event);
429           switch (state) {
430           case lldb::eStateInvalid:
431             // Not a state event
432             break;
433           case lldb::eStateUnloaded:
434             break;
435           case lldb::eStateConnected:
436             break;
437           case lldb::eStateAttaching:
438             break;
439           case lldb::eStateLaunching:
440             break;
441           case lldb::eStateStepping:
442             break;
443           case lldb::eStateCrashed:
444             break;
445           case lldb::eStateDetached:
446             break;
447           case lldb::eStateSuspended:
448             break;
449           case lldb::eStateStopped:
450             // We launch and attach in synchronous mode then the first stop
451             // event will not be delivered. If we use "launchCommands" during a
452             // launch or "attachCommands" during an attach we might some process
453             // stop events which we do not want to send an event for. We will
454             // manually send a stopped event in request_configurationDone(...)
455             // so don't send any before then.
456             if (g_vsc.configuration_done_sent) {
457               // Only report a stopped event if the process was not restarted.
458               if (!lldb::SBProcess::GetRestartedFromEvent(event)) {
459                 SendStdOutStdErr(process);
460                 SendThreadStoppedEvent();
461               }
462             }
463             break;
464           case lldb::eStateRunning:
465             g_vsc.WillContinue();
466             break;
467           case lldb::eStateExited: {
468             // Run any exit LLDB commands the user specified in the
469             // launch.json
470             g_vsc.RunExitCommands();
471             SendProcessExitedEvent(process);
472             SendTerminatedEvent();
473             done = true;
474           } break;
475           }
476         } else if ((event_mask & lldb::SBProcess::eBroadcastBitSTDOUT) ||
477                    (event_mask & lldb::SBProcess::eBroadcastBitSTDERR)) {
478           SendStdOutStdErr(process);
479         }
480       } else if (lldb::SBBreakpoint::EventIsBreakpointEvent(event)) {
481         if (event_mask & lldb::SBTarget::eBroadcastBitBreakpointChanged) {
482           auto event_type =
483               lldb::SBBreakpoint::GetBreakpointEventTypeFromEvent(event);
484           auto bp = lldb::SBBreakpoint::GetBreakpointFromEvent(event);
485           // If the breakpoint was originated from the IDE, it will have the
486           // BreakpointBase::GetBreakpointLabel() label attached. Regardless
487           // of wether the locations were added or removed, the breakpoint
488           // ins't going away, so we the reason is always "changed".
489           if ((event_type & lldb::eBreakpointEventTypeLocationsAdded ||
490                event_type & lldb::eBreakpointEventTypeLocationsRemoved) &&
491               bp.MatchesName(BreakpointBase::GetBreakpointLabel())) {
492             auto bp_event = CreateEventObject("breakpoint");
493             llvm::json::Object body;
494             // As VSCode already knows the path of this breakpoint, we don't
495             // need to send it back as part of a "changed" event. This
496             // prevent us from sending to VSCode paths that should be source
497             // mapped. Note that CreateBreakpoint doesn't apply source mapping.
498             // Besides, the current implementation of VSCode ignores the
499             // "source" element of breakpoint events.
500             llvm::json::Value source_bp = CreateBreakpoint(bp);
501             source_bp.getAsObject()->erase("source");
502 
503             body.try_emplace("breakpoint", source_bp);
504             body.try_emplace("reason", "changed");
505             bp_event.try_emplace("body", std::move(body));
506             g_vsc.SendJSON(llvm::json::Value(std::move(bp_event)));
507           }
508         }
509       } else if (event.BroadcasterMatchesRef(g_vsc.broadcaster)) {
510         if (event_mask & eBroadcastBitStopEventThread) {
511           done = true;
512         }
513       }
514     }
515   }
516 }
517 
518 // Both attach and launch take a either a sourcePath or sourceMap
519 // argument (or neither), from which we need to set the target.source-map.
SetSourceMapFromArguments(const llvm::json::Object & arguments)520 void SetSourceMapFromArguments(const llvm::json::Object &arguments) {
521   const char *sourceMapHelp =
522       "source must be be an array of two-element arrays, "
523       "each containing a source and replacement path string.\n";
524 
525   std::string sourceMapCommand;
526   llvm::raw_string_ostream strm(sourceMapCommand);
527   strm << "settings set target.source-map ";
528   auto sourcePath = GetString(arguments, "sourcePath");
529 
530   // sourceMap is the new, more general form of sourcePath and overrides it.
531   auto sourceMap = arguments.getArray("sourceMap");
532   if (sourceMap) {
533     for (const auto &value : *sourceMap) {
534       auto mapping = value.getAsArray();
535       if (mapping == nullptr || mapping->size() != 2 ||
536           (*mapping)[0].kind() != llvm::json::Value::String ||
537           (*mapping)[1].kind() != llvm::json::Value::String) {
538         g_vsc.SendOutput(OutputType::Console, llvm::StringRef(sourceMapHelp));
539         return;
540       }
541       auto mapFrom = GetAsString((*mapping)[0]);
542       auto mapTo = GetAsString((*mapping)[1]);
543       strm << "\"" << mapFrom << "\" \"" << mapTo << "\" ";
544     }
545   } else {
546     if (ObjectContainsKey(arguments, "sourceMap")) {
547       g_vsc.SendOutput(OutputType::Console, llvm::StringRef(sourceMapHelp));
548       return;
549     }
550     if (sourcePath.empty())
551       return;
552     // Do any source remapping needed before we create our targets
553     strm << "\".\" \"" << sourcePath << "\"";
554   }
555   strm.flush();
556   if (!sourceMapCommand.empty()) {
557     g_vsc.RunLLDBCommands("Setting source map:", {sourceMapCommand});
558   }
559 }
560 
561 // "AttachRequest": {
562 //   "allOf": [ { "$ref": "#/definitions/Request" }, {
563 //     "type": "object",
564 //     "description": "Attach request; value of command field is 'attach'.",
565 //     "properties": {
566 //       "command": {
567 //         "type": "string",
568 //         "enum": [ "attach" ]
569 //       },
570 //       "arguments": {
571 //         "$ref": "#/definitions/AttachRequestArguments"
572 //       }
573 //     },
574 //     "required": [ "command", "arguments" ]
575 //   }]
576 // },
577 // "AttachRequestArguments": {
578 //   "type": "object",
579 //   "description": "Arguments for 'attach' request.\nThe attach request has no
580 //   standardized attributes."
581 // },
582 // "AttachResponse": {
583 //   "allOf": [ { "$ref": "#/definitions/Response" }, {
584 //     "type": "object",
585 //     "description": "Response to 'attach' request. This is just an
586 //     acknowledgement, so no body field is required."
587 //   }]
588 // }
request_attach(const llvm::json::Object & request)589 void request_attach(const llvm::json::Object &request) {
590   g_vsc.is_attach = true;
591   llvm::json::Object response;
592   lldb::SBError error;
593   FillResponse(request, response);
594   lldb::SBAttachInfo attach_info;
595   auto arguments = request.getObject("arguments");
596   const lldb::pid_t pid =
597       GetUnsigned(arguments, "pid", LLDB_INVALID_PROCESS_ID);
598   if (pid != LLDB_INVALID_PROCESS_ID)
599     attach_info.SetProcessID(pid);
600   const auto wait_for = GetBoolean(arguments, "waitFor", false);
601   attach_info.SetWaitForLaunch(wait_for, false /*async*/);
602   g_vsc.init_commands = GetStrings(arguments, "initCommands");
603   g_vsc.pre_run_commands = GetStrings(arguments, "preRunCommands");
604   g_vsc.stop_commands = GetStrings(arguments, "stopCommands");
605   g_vsc.exit_commands = GetStrings(arguments, "exitCommands");
606   g_vsc.terminate_commands = GetStrings(arguments, "terminateCommands");
607   auto attachCommands = GetStrings(arguments, "attachCommands");
608   llvm::StringRef core_file = GetString(arguments, "coreFile");
609   const uint64_t timeout_seconds = GetUnsigned(arguments, "timeout", 30);
610   g_vsc.stop_at_entry =
611       core_file.empty() ? GetBoolean(arguments, "stopOnEntry", false) : true;
612   std::vector<std::string> postRunCommands =
613       GetStrings(arguments, "postRunCommands");
614   const llvm::StringRef debuggerRoot = GetString(arguments, "debuggerRoot");
615 
616   // This is a hack for loading DWARF in .o files on Mac where the .o files
617   // in the debug map of the main executable have relative paths which require
618   // the lldb-vscode binary to have its working directory set to that relative
619   // root for the .o files in order to be able to load debug info.
620   if (!debuggerRoot.empty())
621     llvm::sys::fs::set_current_path(debuggerRoot);
622 
623   // Run any initialize LLDB commands the user specified in the launch.json
624   g_vsc.RunInitCommands();
625 
626   SetSourceMapFromArguments(*arguments);
627 
628   lldb::SBError status;
629   g_vsc.SetTarget(g_vsc.CreateTargetFromArguments(*arguments, status));
630   if (status.Fail()) {
631     response["success"] = llvm::json::Value(false);
632     EmplaceSafeString(response, "message", status.GetCString());
633     g_vsc.SendJSON(llvm::json::Value(std::move(response)));
634     return;
635   }
636 
637   // Run any pre run LLDB commands the user specified in the launch.json
638   g_vsc.RunPreRunCommands();
639 
640   if (pid == LLDB_INVALID_PROCESS_ID && wait_for) {
641     char attach_msg[256];
642     auto attach_msg_len = snprintf(attach_msg, sizeof(attach_msg),
643                                    "Waiting to attach to \"%s\"...",
644                                    g_vsc.target.GetExecutable().GetFilename());
645     g_vsc.SendOutput(OutputType::Console,
646                      llvm::StringRef(attach_msg, attach_msg_len));
647   }
648   if (attachCommands.empty()) {
649     // No "attachCommands", just attach normally.
650     // Disable async events so the attach will be successful when we return from
651     // the launch call and the launch will happen synchronously
652     g_vsc.debugger.SetAsync(false);
653     if (core_file.empty())
654       g_vsc.target.Attach(attach_info, error);
655     else
656       g_vsc.target.LoadCore(core_file.data(), error);
657     // Reenable async events
658     g_vsc.debugger.SetAsync(true);
659   } else {
660     // We have "attachCommands" that are a set of commands that are expected
661     // to execute the commands after which a process should be created. If there
662     // is no valid process after running these commands, we have failed.
663     g_vsc.RunLLDBCommands("Running attachCommands:", attachCommands);
664     // The custom commands might have created a new target so we should use the
665     // selected target after these commands are run.
666     g_vsc.target = g_vsc.debugger.GetSelectedTarget();
667 
668     // Make sure the process is attached and stopped before proceeding as the
669     // the launch commands are not run using the synchronous mode.
670     error = g_vsc.WaitForProcessToStop(timeout_seconds);
671   }
672 
673   if (error.Success() && core_file.empty()) {
674     auto attached_pid = g_vsc.target.GetProcess().GetProcessID();
675     if (attached_pid == LLDB_INVALID_PROCESS_ID) {
676       if (attachCommands.empty())
677         error.SetErrorString("failed to attach to a process");
678       else
679         error.SetErrorString("attachCommands failed to attach to a process");
680     }
681   }
682 
683   if (error.Fail()) {
684     response["success"] = llvm::json::Value(false);
685     EmplaceSafeString(response, "message", std::string(error.GetCString()));
686   } else {
687     g_vsc.RunLLDBCommands("Running postRunCommands:", postRunCommands);
688   }
689 
690   g_vsc.SendJSON(llvm::json::Value(std::move(response)));
691   if (error.Success()) {
692     SendProcessEvent(Attach);
693     g_vsc.SendJSON(CreateEventObject("initialized"));
694   }
695 }
696 
697 // "ContinueRequest": {
698 //   "allOf": [ { "$ref": "#/definitions/Request" }, {
699 //     "type": "object",
700 //     "description": "Continue request; value of command field is 'continue'.
701 //                     The request starts the debuggee to run again.",
702 //     "properties": {
703 //       "command": {
704 //         "type": "string",
705 //         "enum": [ "continue" ]
706 //       },
707 //       "arguments": {
708 //         "$ref": "#/definitions/ContinueArguments"
709 //       }
710 //     },
711 //     "required": [ "command", "arguments"  ]
712 //   }]
713 // },
714 // "ContinueArguments": {
715 //   "type": "object",
716 //   "description": "Arguments for 'continue' request.",
717 //   "properties": {
718 //     "threadId": {
719 //       "type": "integer",
720 //       "description": "Continue execution for the specified thread (if
721 //                       possible). If the backend cannot continue on a single
722 //                       thread but will continue on all threads, it should
723 //                       set the allThreadsContinued attribute in the response
724 //                       to true."
725 //     }
726 //   },
727 //   "required": [ "threadId" ]
728 // },
729 // "ContinueResponse": {
730 //   "allOf": [ { "$ref": "#/definitions/Response" }, {
731 //     "type": "object",
732 //     "description": "Response to 'continue' request.",
733 //     "properties": {
734 //       "body": {
735 //         "type": "object",
736 //         "properties": {
737 //           "allThreadsContinued": {
738 //             "type": "boolean",
739 //             "description": "If true, the continue request has ignored the
740 //                             specified thread and continued all threads
741 //                             instead. If this attribute is missing a value
742 //                             of 'true' is assumed for backward
743 //                             compatibility."
744 //           }
745 //         }
746 //       }
747 //     },
748 //     "required": [ "body" ]
749 //   }]
750 // }
request_continue(const llvm::json::Object & request)751 void request_continue(const llvm::json::Object &request) {
752   llvm::json::Object response;
753   FillResponse(request, response);
754   lldb::SBProcess process = g_vsc.target.GetProcess();
755   auto arguments = request.getObject("arguments");
756   // Remember the thread ID that caused the resume so we can set the
757   // "threadCausedFocus" boolean value in the "stopped" events.
758   g_vsc.focus_tid = GetUnsigned(arguments, "threadId", LLDB_INVALID_THREAD_ID);
759   lldb::SBError error = process.Continue();
760   llvm::json::Object body;
761   body.try_emplace("allThreadsContinued", true);
762   response.try_emplace("body", std::move(body));
763   g_vsc.SendJSON(llvm::json::Value(std::move(response)));
764 }
765 
766 // "ConfigurationDoneRequest": {
767 //   "allOf": [ { "$ref": "#/definitions/Request" }, {
768 //             "type": "object",
769 //             "description": "ConfigurationDone request; value of command field
770 //             is 'configurationDone'.\nThe client of the debug protocol must
771 //             send this request at the end of the sequence of configuration
772 //             requests (which was started by the InitializedEvent).",
773 //             "properties": {
774 //             "command": {
775 //             "type": "string",
776 //             "enum": [ "configurationDone" ]
777 //             },
778 //             "arguments": {
779 //             "$ref": "#/definitions/ConfigurationDoneArguments"
780 //             }
781 //             },
782 //             "required": [ "command" ]
783 //             }]
784 // },
785 // "ConfigurationDoneArguments": {
786 //   "type": "object",
787 //   "description": "Arguments for 'configurationDone' request.\nThe
788 //   configurationDone request has no standardized attributes."
789 // },
790 // "ConfigurationDoneResponse": {
791 //   "allOf": [ { "$ref": "#/definitions/Response" }, {
792 //             "type": "object",
793 //             "description": "Response to 'configurationDone' request. This is
794 //             just an acknowledgement, so no body field is required."
795 //             }]
796 // },
request_configurationDone(const llvm::json::Object & request)797 void request_configurationDone(const llvm::json::Object &request) {
798   llvm::json::Object response;
799   FillResponse(request, response);
800   g_vsc.SendJSON(llvm::json::Value(std::move(response)));
801   g_vsc.configuration_done_sent = true;
802   if (g_vsc.stop_at_entry)
803     SendThreadStoppedEvent();
804   else
805     g_vsc.target.GetProcess().Continue();
806 }
807 
808 // "DisconnectRequest": {
809 //   "allOf": [ { "$ref": "#/definitions/Request" }, {
810 //     "type": "object",
811 //     "description": "Disconnect request; value of command field is
812 //                     'disconnect'.",
813 //     "properties": {
814 //       "command": {
815 //         "type": "string",
816 //         "enum": [ "disconnect" ]
817 //       },
818 //       "arguments": {
819 //         "$ref": "#/definitions/DisconnectArguments"
820 //       }
821 //     },
822 //     "required": [ "command" ]
823 //   }]
824 // },
825 // "DisconnectArguments": {
826 //   "type": "object",
827 //   "description": "Arguments for 'disconnect' request.",
828 //   "properties": {
829 //     "terminateDebuggee": {
830 //       "type": "boolean",
831 //       "description": "Indicates whether the debuggee should be terminated
832 //                       when the debugger is disconnected. If unspecified,
833 //                       the debug adapter is free to do whatever it thinks
834 //                       is best. A client can only rely on this attribute
835 //                       being properly honored if a debug adapter returns
836 //                       true for the 'supportTerminateDebuggee' capability."
837 //     },
838 //     "restart": {
839 //       "type": "boolean",
840 //       "description": "Indicates whether the debuggee should be restart
841 //                       the process."
842 //     }
843 //   }
844 // },
845 // "DisconnectResponse": {
846 //   "allOf": [ { "$ref": "#/definitions/Response" }, {
847 //     "type": "object",
848 //     "description": "Response to 'disconnect' request. This is just an
849 //                     acknowledgement, so no body field is required."
850 //   }]
851 // }
request_disconnect(const llvm::json::Object & request)852 void request_disconnect(const llvm::json::Object &request) {
853   llvm::json::Object response;
854   FillResponse(request, response);
855   auto arguments = request.getObject("arguments");
856 
857   bool defaultTerminateDebuggee = g_vsc.is_attach ? false : true;
858   bool terminateDebuggee =
859       GetBoolean(arguments, "terminateDebuggee", defaultTerminateDebuggee);
860   lldb::SBProcess process = g_vsc.target.GetProcess();
861   auto state = process.GetState();
862   switch (state) {
863   case lldb::eStateInvalid:
864   case lldb::eStateUnloaded:
865   case lldb::eStateDetached:
866   case lldb::eStateExited:
867     break;
868   case lldb::eStateConnected:
869   case lldb::eStateAttaching:
870   case lldb::eStateLaunching:
871   case lldb::eStateStepping:
872   case lldb::eStateCrashed:
873   case lldb::eStateSuspended:
874   case lldb::eStateStopped:
875   case lldb::eStateRunning:
876     g_vsc.debugger.SetAsync(false);
877     lldb::SBError error = terminateDebuggee ? process.Kill() : process.Detach();
878     if (!error.Success())
879       response.try_emplace("error", error.GetCString());
880     g_vsc.debugger.SetAsync(true);
881     break;
882   }
883   SendTerminatedEvent();
884   g_vsc.SendJSON(llvm::json::Value(std::move(response)));
885   if (g_vsc.event_thread.joinable()) {
886     g_vsc.broadcaster.BroadcastEventByType(eBroadcastBitStopEventThread);
887     g_vsc.event_thread.join();
888   }
889   if (g_vsc.progress_event_thread.joinable()) {
890     g_vsc.broadcaster.BroadcastEventByType(eBroadcastBitStopProgressThread);
891     g_vsc.progress_event_thread.join();
892   }
893 }
894 
request_exceptionInfo(const llvm::json::Object & request)895 void request_exceptionInfo(const llvm::json::Object &request) {
896   llvm::json::Object response;
897   FillResponse(request, response);
898   auto arguments = request.getObject("arguments");
899   llvm::json::Object body;
900   lldb::SBThread thread = g_vsc.GetLLDBThread(*arguments);
901   if (thread.IsValid()) {
902     auto stopReason = thread.GetStopReason();
903     if (stopReason == lldb::eStopReasonSignal)
904       body.try_emplace("exceptionId", "signal");
905     else if (stopReason == lldb::eStopReasonBreakpoint) {
906       ExceptionBreakpoint *exc_bp = g_vsc.GetExceptionBPFromStopReason(thread);
907       if (exc_bp) {
908         EmplaceSafeString(body, "exceptionId", exc_bp->filter);
909         EmplaceSafeString(body, "description", exc_bp->label);
910       } else {
911         body.try_emplace("exceptionId", "exception");
912       }
913     } else {
914       body.try_emplace("exceptionId", "exception");
915     }
916     if (!ObjectContainsKey(body, "description")) {
917       char description[1024];
918       if (thread.GetStopDescription(description, sizeof(description))) {
919         EmplaceSafeString(body, "description", std::string(description));
920       }
921     }
922     body.try_emplace("breakMode", "always");
923     // auto excInfoCount = thread.GetStopReasonDataCount();
924     // for (auto i=0; i<excInfoCount; ++i) {
925     //   uint64_t exc_data = thread.GetStopReasonDataAtIndex(i);
926     // }
927   } else {
928     response["success"] = llvm::json::Value(false);
929   }
930   response.try_emplace("body", std::move(body));
931   g_vsc.SendJSON(llvm::json::Value(std::move(response)));
932 }
933 
934 // "CompletionsRequest": {
935 //   "allOf": [ { "$ref": "#/definitions/Request" }, {
936 //     "type": "object",
937 //     "description": "Returns a list of possible completions for a given caret
938 //     position and text.\nThe CompletionsRequest may only be called if the
939 //     'supportsCompletionsRequest' capability exists and is true.",
940 //     "properties": {
941 //       "command": {
942 //         "type": "string",
943 //         "enum": [ "completions" ]
944 //       },
945 //       "arguments": {
946 //         "$ref": "#/definitions/CompletionsArguments"
947 //       }
948 //     },
949 //     "required": [ "command", "arguments"  ]
950 //   }]
951 // },
952 // "CompletionsArguments": {
953 //   "type": "object",
954 //   "description": "Arguments for 'completions' request.",
955 //   "properties": {
956 //     "frameId": {
957 //       "type": "integer",
958 //       "description": "Returns completions in the scope of this stack frame.
959 //       If not specified, the completions are returned for the global scope."
960 //     },
961 //     "text": {
962 //       "type": "string",
963 //       "description": "One or more source lines. Typically this is the text a
964 //       user has typed into the debug console before he asked for completion."
965 //     },
966 //     "column": {
967 //       "type": "integer",
968 //       "description": "The character position for which to determine the
969 //       completion proposals."
970 //     },
971 //     "line": {
972 //       "type": "integer",
973 //       "description": "An optional line for which to determine the completion
974 //       proposals. If missing the first line of the text is assumed."
975 //     }
976 //   },
977 //   "required": [ "text", "column" ]
978 // },
979 // "CompletionsResponse": {
980 //   "allOf": [ { "$ref": "#/definitions/Response" }, {
981 //     "type": "object",
982 //     "description": "Response to 'completions' request.",
983 //     "properties": {
984 //       "body": {
985 //         "type": "object",
986 //         "properties": {
987 //           "targets": {
988 //             "type": "array",
989 //             "items": {
990 //               "$ref": "#/definitions/CompletionItem"
991 //             },
992 //             "description": "The possible completions for ."
993 //           }
994 //         },
995 //         "required": [ "targets" ]
996 //       }
997 //     },
998 //     "required": [ "body" ]
999 //   }]
1000 // },
1001 // "CompletionItem": {
1002 //   "type": "object",
1003 //   "description": "CompletionItems are the suggestions returned from the
1004 //   CompletionsRequest.", "properties": {
1005 //     "label": {
1006 //       "type": "string",
1007 //       "description": "The label of this completion item. By default this is
1008 //       also the text that is inserted when selecting this completion."
1009 //     },
1010 //     "text": {
1011 //       "type": "string",
1012 //       "description": "If text is not falsy then it is inserted instead of the
1013 //       label."
1014 //     },
1015 //     "sortText": {
1016 //       "type": "string",
1017 //       "description": "A string that should be used when comparing this item
1018 //       with other items. When `falsy` the label is used."
1019 //     },
1020 //     "type": {
1021 //       "$ref": "#/definitions/CompletionItemType",
1022 //       "description": "The item's type. Typically the client uses this
1023 //       information to render the item in the UI with an icon."
1024 //     },
1025 //     "start": {
1026 //       "type": "integer",
1027 //       "description": "This value determines the location (in the
1028 //       CompletionsRequest's 'text' attribute) where the completion text is
1029 //       added.\nIf missing the text is added at the location specified by the
1030 //       CompletionsRequest's 'column' attribute."
1031 //     },
1032 //     "length": {
1033 //       "type": "integer",
1034 //       "description": "This value determines how many characters are
1035 //       overwritten by the completion text.\nIf missing the value 0 is assumed
1036 //       which results in the completion text being inserted."
1037 //     }
1038 //   },
1039 //   "required": [ "label" ]
1040 // },
1041 // "CompletionItemType": {
1042 //   "type": "string",
1043 //   "description": "Some predefined types for the CompletionItem. Please note
1044 //   that not all clients have specific icons for all of them.", "enum": [
1045 //   "method", "function", "constructor", "field", "variable", "class",
1046 //   "interface", "module", "property", "unit", "value", "enum", "keyword",
1047 //   "snippet", "text", "color", "file", "reference", "customcolor" ]
1048 // }
request_completions(const llvm::json::Object & request)1049 void request_completions(const llvm::json::Object &request) {
1050   llvm::json::Object response;
1051   FillResponse(request, response);
1052   llvm::json::Object body;
1053   auto arguments = request.getObject("arguments");
1054   std::string text = std::string(GetString(arguments, "text"));
1055   auto original_column = GetSigned(arguments, "column", text.size());
1056   auto actual_column = original_column - 1;
1057   llvm::json::Array targets;
1058   // NOTE: the 'line' argument is not needed, as multiline expressions
1059   // work well already
1060   // TODO: support frameID. Currently
1061   // g_vsc.debugger.GetCommandInterpreter().HandleCompletionWithDescriptions
1062   // is frame-unaware.
1063 
1064   if (!text.empty() && text[0] == '`') {
1065     text = text.substr(1);
1066     actual_column--;
1067   } else {
1068     text = "p " + text;
1069     actual_column += 2;
1070   }
1071   lldb::SBStringList matches;
1072   lldb::SBStringList descriptions;
1073   g_vsc.debugger.GetCommandInterpreter().HandleCompletionWithDescriptions(
1074       text.c_str(), actual_column, 0, -1, matches, descriptions);
1075   size_t count = std::min((uint32_t)100, matches.GetSize());
1076   targets.reserve(count);
1077   for (size_t i = 0; i < count; i++) {
1078     std::string match = matches.GetStringAtIndex(i);
1079     std::string description = descriptions.GetStringAtIndex(i);
1080 
1081     llvm::json::Object item;
1082 
1083     llvm::StringRef match_ref = match;
1084     for (llvm::StringRef commit_point : {".", "->"}) {
1085       if (match_ref.contains(commit_point)) {
1086         match_ref = match_ref.rsplit(commit_point).second;
1087       }
1088     }
1089     EmplaceSafeString(item, "text", match_ref);
1090 
1091     if (description.empty())
1092       EmplaceSafeString(item, "label", match);
1093     else
1094       EmplaceSafeString(item, "label", match + " -- " + description);
1095 
1096     targets.emplace_back(std::move(item));
1097   }
1098 
1099   body.try_emplace("targets", std::move(targets));
1100   response.try_emplace("body", std::move(body));
1101   g_vsc.SendJSON(llvm::json::Value(std::move(response)));
1102 }
1103 
1104 //  "EvaluateRequest": {
1105 //    "allOf": [ { "$ref": "#/definitions/Request" }, {
1106 //      "type": "object",
1107 //      "description": "Evaluate request; value of command field is 'evaluate'.
1108 //                      Evaluates the given expression in the context of the
1109 //                      top most stack frame. The expression has access to any
1110 //                      variables and arguments that are in scope.",
1111 //      "properties": {
1112 //        "command": {
1113 //          "type": "string",
1114 //          "enum": [ "evaluate" ]
1115 //        },
1116 //        "arguments": {
1117 //          "$ref": "#/definitions/EvaluateArguments"
1118 //        }
1119 //      },
1120 //      "required": [ "command", "arguments"  ]
1121 //    }]
1122 //  },
1123 //  "EvaluateArguments": {
1124 //    "type": "object",
1125 //    "description": "Arguments for 'evaluate' request.",
1126 //    "properties": {
1127 //      "expression": {
1128 //        "type": "string",
1129 //        "description": "The expression to evaluate."
1130 //      },
1131 //      "frameId": {
1132 //        "type": "integer",
1133 //        "description": "Evaluate the expression in the scope of this stack
1134 //                        frame. If not specified, the expression is evaluated
1135 //                        in the global scope."
1136 //      },
1137 //      "context": {
1138 //        "type": "string",
1139 //        "_enum": [ "watch", "repl", "hover" ],
1140 //        "enumDescriptions": [
1141 //          "evaluate is run in a watch.",
1142 //          "evaluate is run from REPL console.",
1143 //          "evaluate is run from a data hover."
1144 //        ],
1145 //        "description": "The context in which the evaluate request is run."
1146 //      },
1147 //      "format": {
1148 //        "$ref": "#/definitions/ValueFormat",
1149 //        "description": "Specifies details on how to format the Evaluate
1150 //                        result."
1151 //      }
1152 //    },
1153 //    "required": [ "expression" ]
1154 //  },
1155 //  "EvaluateResponse": {
1156 //    "allOf": [ { "$ref": "#/definitions/Response" }, {
1157 //      "type": "object",
1158 //      "description": "Response to 'evaluate' request.",
1159 //      "properties": {
1160 //        "body": {
1161 //          "type": "object",
1162 //          "properties": {
1163 //            "result": {
1164 //              "type": "string",
1165 //              "description": "The result of the evaluate request."
1166 //            },
1167 //            "type": {
1168 //              "type": "string",
1169 //              "description": "The optional type of the evaluate result."
1170 //            },
1171 //            "presentationHint": {
1172 //              "$ref": "#/definitions/VariablePresentationHint",
1173 //              "description": "Properties of a evaluate result that can be
1174 //                              used to determine how to render the result in
1175 //                              the UI."
1176 //            },
1177 //            "variablesReference": {
1178 //              "type": "number",
1179 //              "description": "If variablesReference is > 0, the evaluate
1180 //                              result is structured and its children can be
1181 //                              retrieved by passing variablesReference to the
1182 //                              VariablesRequest."
1183 //            },
1184 //            "namedVariables": {
1185 //              "type": "number",
1186 //              "description": "The number of named child variables. The
1187 //                              client can use this optional information to
1188 //                              present the variables in a paged UI and fetch
1189 //                              them in chunks."
1190 //            },
1191 //            "indexedVariables": {
1192 //              "type": "number",
1193 //              "description": "The number of indexed child variables. The
1194 //                              client can use this optional information to
1195 //                              present the variables in a paged UI and fetch
1196 //                              them in chunks."
1197 //            }
1198 //          },
1199 //          "required": [ "result", "variablesReference" ]
1200 //        }
1201 //      },
1202 //      "required": [ "body" ]
1203 //    }]
1204 //  }
request_evaluate(const llvm::json::Object & request)1205 void request_evaluate(const llvm::json::Object &request) {
1206   llvm::json::Object response;
1207   FillResponse(request, response);
1208   llvm::json::Object body;
1209   auto arguments = request.getObject("arguments");
1210   lldb::SBFrame frame = g_vsc.GetLLDBFrame(*arguments);
1211   const auto expression = GetString(arguments, "expression");
1212   llvm::StringRef context = GetString(arguments, "context");
1213 
1214   if (!expression.empty() && expression[0] == '`') {
1215     auto result =
1216         RunLLDBCommands(llvm::StringRef(), {std::string(expression.substr(1))});
1217     EmplaceSafeString(body, "result", result);
1218     body.try_emplace("variablesReference", (int64_t)0);
1219   } else {
1220     // Always try to get the answer from the local variables if possible. If
1221     // this fails, then if the context is not "hover", actually evaluate an
1222     // expression using the expression parser.
1223     //
1224     // "frame variable" is more reliable than the expression parser in
1225     // many cases and it is faster.
1226     lldb::SBValue value = frame.GetValueForVariablePath(
1227         expression.data(), lldb::eDynamicDontRunTarget);
1228 
1229     // Freeze dry the value in case users expand it later in the debug console
1230     if (value.GetError().Success() && context == "repl")
1231       value = value.Persist();
1232 
1233     if (value.GetError().Fail() && context != "hover")
1234       value = frame.EvaluateExpression(expression.data());
1235 
1236     if (value.GetError().Fail()) {
1237       response["success"] = llvm::json::Value(false);
1238       // This error object must live until we're done with the pointer returned
1239       // by GetCString().
1240       lldb::SBError error = value.GetError();
1241       const char *error_cstr = error.GetCString();
1242       if (error_cstr && error_cstr[0])
1243         EmplaceSafeString(response, "message", std::string(error_cstr));
1244       else
1245         EmplaceSafeString(response, "message", "evaluate failed");
1246     } else {
1247       SetValueForKey(value, body, "result");
1248       auto value_typename = value.GetType().GetDisplayTypeName();
1249       EmplaceSafeString(body, "type",
1250                         value_typename ? value_typename : NO_TYPENAME);
1251       if (value.MightHaveChildren()) {
1252         auto variableReference = g_vsc.variables.InsertExpandableVariable(
1253             value, /*is_permanent=*/context == "repl");
1254         body.try_emplace("variablesReference", variableReference);
1255       } else {
1256         body.try_emplace("variablesReference", (int64_t)0);
1257       }
1258     }
1259   }
1260   response.try_emplace("body", std::move(body));
1261   g_vsc.SendJSON(llvm::json::Value(std::move(response)));
1262 }
1263 
1264 // "compileUnitsRequest": {
1265 //   "allOf": [ { "$ref": "#/definitions/Request" }, {
1266 //     "type": "object",
1267 //     "description": "Compile Unit request; value of command field is
1268 //                     'compileUnits'.",
1269 //     "properties": {
1270 //       "command": {
1271 //         "type": "string",
1272 //         "enum": [ "compileUnits" ]
1273 //       },
1274 //       "arguments": {
1275 //         "$ref": "#/definitions/compileUnitRequestArguments"
1276 //       }
1277 //     },
1278 //     "required": [ "command", "arguments" ]
1279 //   }]
1280 // },
1281 // "compileUnitsRequestArguments": {
1282 //   "type": "object",
1283 //   "description": "Arguments for 'compileUnits' request.",
1284 //   "properties": {
1285 //     "moduleId": {
1286 //       "type": "string",
1287 //       "description": "The ID of the module."
1288 //     }
1289 //   },
1290 //   "required": [ "moduleId" ]
1291 // },
1292 // "compileUnitsResponse": {
1293 //   "allOf": [ { "$ref": "#/definitions/Response" }, {
1294 //     "type": "object",
1295 //     "description": "Response to 'compileUnits' request.",
1296 //     "properties": {
1297 //       "body": {
1298 //         "description": "Response to 'compileUnits' request. Array of
1299 //                         paths of compile units."
1300 //       }
1301 //     }
1302 //   }]
1303 // }
request_compileUnits(const llvm::json::Object & request)1304 void request_compileUnits(const llvm::json::Object &request) {
1305   llvm::json::Object response;
1306   FillResponse(request, response);
1307   llvm::json::Object body;
1308   llvm::json::Array units;
1309   auto arguments = request.getObject("arguments");
1310   std::string module_id = std::string(GetString(arguments, "moduleId"));
1311   int num_modules = g_vsc.target.GetNumModules();
1312   for (int i = 0; i < num_modules; i++) {
1313     auto curr_module = g_vsc.target.GetModuleAtIndex(i);
1314     if (module_id == curr_module.GetUUIDString()) {
1315       int num_units = curr_module.GetNumCompileUnits();
1316       for (int j = 0; j < num_units; j++) {
1317         auto curr_unit = curr_module.GetCompileUnitAtIndex(j);
1318         units.emplace_back(CreateCompileUnit(curr_unit));
1319       }
1320       body.try_emplace("compileUnits", std::move(units));
1321       break;
1322     }
1323   }
1324   response.try_emplace("body", std::move(body));
1325   g_vsc.SendJSON(llvm::json::Value(std::move(response)));
1326 }
1327 
1328 // "modulesRequest": {
1329 //   "allOf": [ { "$ref": "#/definitions/Request" }, {
1330 //     "type": "object",
1331 //     "description": "Modules request; value of command field is
1332 //                     'modules'.",
1333 //     "properties": {
1334 //       "command": {
1335 //         "type": "string",
1336 //         "enum": [ "modules" ]
1337 //       },
1338 //     },
1339 //     "required": [ "command" ]
1340 //   }]
1341 // },
1342 // "modulesResponse": {
1343 //   "allOf": [ { "$ref": "#/definitions/Response" }, {
1344 //     "type": "object",
1345 //     "description": "Response to 'modules' request.",
1346 //     "properties": {
1347 //       "body": {
1348 //         "description": "Response to 'modules' request. Array of
1349 //                         module objects."
1350 //       }
1351 //     }
1352 //   }]
1353 // }
request_modules(const llvm::json::Object & request)1354 void request_modules(const llvm::json::Object &request) {
1355   llvm::json::Object response;
1356   FillResponse(request, response);
1357 
1358   llvm::json::Array modules;
1359   for (size_t i = 0; i < g_vsc.target.GetNumModules(); i++) {
1360     lldb::SBModule module = g_vsc.target.GetModuleAtIndex(i);
1361     modules.emplace_back(CreateModule(module));
1362   }
1363 
1364   llvm::json::Object body;
1365   body.try_emplace("modules", std::move(modules));
1366   response.try_emplace("body", std::move(body));
1367   g_vsc.SendJSON(llvm::json::Value(std::move(response)));
1368 }
1369 
1370 // "InitializeRequest": {
1371 //   "allOf": [ { "$ref": "#/definitions/Request" }, {
1372 //     "type": "object",
1373 //     "description": "Initialize request; value of command field is
1374 //                     'initialize'.",
1375 //     "properties": {
1376 //       "command": {
1377 //         "type": "string",
1378 //         "enum": [ "initialize" ]
1379 //       },
1380 //       "arguments": {
1381 //         "$ref": "#/definitions/InitializeRequestArguments"
1382 //       }
1383 //     },
1384 //     "required": [ "command", "arguments" ]
1385 //   }]
1386 // },
1387 // "InitializeRequestArguments": {
1388 //   "type": "object",
1389 //   "description": "Arguments for 'initialize' request.",
1390 //   "properties": {
1391 //     "clientID": {
1392 //       "type": "string",
1393 //       "description": "The ID of the (frontend) client using this adapter."
1394 //     },
1395 //     "adapterID": {
1396 //       "type": "string",
1397 //       "description": "The ID of the debug adapter."
1398 //     },
1399 //     "locale": {
1400 //       "type": "string",
1401 //       "description": "The ISO-639 locale of the (frontend) client using
1402 //                       this adapter, e.g. en-US or de-CH."
1403 //     },
1404 //     "linesStartAt1": {
1405 //       "type": "boolean",
1406 //       "description": "If true all line numbers are 1-based (default)."
1407 //     },
1408 //     "columnsStartAt1": {
1409 //       "type": "boolean",
1410 //       "description": "If true all column numbers are 1-based (default)."
1411 //     },
1412 //     "pathFormat": {
1413 //       "type": "string",
1414 //       "_enum": [ "path", "uri" ],
1415 //       "description": "Determines in what format paths are specified. The
1416 //                       default is 'path', which is the native format."
1417 //     },
1418 //     "supportsVariableType": {
1419 //       "type": "boolean",
1420 //       "description": "Client supports the optional type attribute for
1421 //                       variables."
1422 //     },
1423 //     "supportsVariablePaging": {
1424 //       "type": "boolean",
1425 //       "description": "Client supports the paging of variables."
1426 //     },
1427 //     "supportsRunInTerminalRequest": {
1428 //       "type": "boolean",
1429 //       "description": "Client supports the runInTerminal request."
1430 //     }
1431 //   },
1432 //   "required": [ "adapterID" ]
1433 // },
1434 // "InitializeResponse": {
1435 //   "allOf": [ { "$ref": "#/definitions/Response" }, {
1436 //     "type": "object",
1437 //     "description": "Response to 'initialize' request.",
1438 //     "properties": {
1439 //       "body": {
1440 //         "$ref": "#/definitions/Capabilities",
1441 //         "description": "The capabilities of this debug adapter."
1442 //       }
1443 //     }
1444 //   }]
1445 // }
request_initialize(const llvm::json::Object & request)1446 void request_initialize(const llvm::json::Object &request) {
1447   auto log_cb = [](const char *buf, void *baton) -> void {
1448     g_vsc.SendOutput(OutputType::Console, llvm::StringRef{buf});
1449   };
1450 
1451   auto arguments = request.getObject("arguments");
1452   // sourceInitFile option is not from formal DAP specification. It is only
1453   // used by unit tests to prevent sourcing .lldbinit files from environment
1454   // which may affect the outcome of tests.
1455   bool source_init_file = GetBoolean(arguments, "sourceInitFile", true);
1456 
1457   g_vsc.debugger =
1458       lldb::SBDebugger::Create(source_init_file, log_cb, nullptr);
1459   g_vsc.progress_event_thread = std::thread(ProgressEventThreadFunction);
1460 
1461   // Start our event thread so we can receive events from the debugger, target,
1462   // process and more.
1463   g_vsc.event_thread = std::thread(EventThreadFunction);
1464 
1465   llvm::json::Object response;
1466   FillResponse(request, response);
1467   llvm::json::Object body;
1468   // The debug adapter supports the configurationDoneRequest.
1469   body.try_emplace("supportsConfigurationDoneRequest", true);
1470   // The debug adapter supports function breakpoints.
1471   body.try_emplace("supportsFunctionBreakpoints", true);
1472   // The debug adapter supports conditional breakpoints.
1473   body.try_emplace("supportsConditionalBreakpoints", true);
1474   // The debug adapter supports breakpoints that break execution after a
1475   // specified number of hits.
1476   body.try_emplace("supportsHitConditionalBreakpoints", true);
1477   // The debug adapter supports a (side effect free) evaluate request for
1478   // data hovers.
1479   body.try_emplace("supportsEvaluateForHovers", true);
1480   // Available filters or options for the setExceptionBreakpoints request.
1481   llvm::json::Array filters;
1482   for (const auto &exc_bp : g_vsc.exception_breakpoints) {
1483     filters.emplace_back(CreateExceptionBreakpointFilter(exc_bp));
1484   }
1485   body.try_emplace("exceptionBreakpointFilters", std::move(filters));
1486   // The debug adapter supports launching a debugee in intergrated VSCode
1487   // terminal.
1488   body.try_emplace("supportsRunInTerminalRequest", true);
1489   // The debug adapter supports stepping back via the stepBack and
1490   // reverseContinue requests.
1491   body.try_emplace("supportsStepBack", false);
1492   // The debug adapter supports setting a variable to a value.
1493   body.try_emplace("supportsSetVariable", true);
1494   // The debug adapter supports restarting a frame.
1495   body.try_emplace("supportsRestartFrame", false);
1496   // The debug adapter supports the gotoTargetsRequest.
1497   body.try_emplace("supportsGotoTargetsRequest", false);
1498   // The debug adapter supports the stepInTargetsRequest.
1499   body.try_emplace("supportsStepInTargetsRequest", false);
1500   // We need to improve the current implementation of completions in order to
1501   // enable it again. For some context, this is how VSCode works:
1502   // - VSCode sends a completion request whenever chars are added, the user
1503   //   triggers completion manually via CTRL-space or similar mechanisms, but
1504   //   not when there's a deletion. Besides, VSCode doesn't let us know which
1505   //   of these events we are handling. What is more, the use can paste or cut
1506   //   sections of the text arbitrarily.
1507   //   https://github.com/microsoft/vscode/issues/89531 tracks part of the
1508   //   issue just mentioned.
1509   // This behavior causes many problems with the current way completion is
1510   // implemented in lldb-vscode, as these requests could be really expensive,
1511   // blocking the debugger, and there could be many concurrent requests unless
1512   // the user types very slowly... We need to address this specific issue, or
1513   // at least trigger completion only when the user explicitly wants it, which
1514   // is the behavior of LLDB CLI, that expects a TAB.
1515   body.try_emplace("supportsCompletionsRequest", false);
1516   // The debug adapter supports the modules request.
1517   body.try_emplace("supportsModulesRequest", true);
1518   // The set of additional module information exposed by the debug adapter.
1519   //   body.try_emplace("additionalModuleColumns"] = ColumnDescriptor
1520   // Checksum algorithms supported by the debug adapter.
1521   //   body.try_emplace("supportedChecksumAlgorithms"] = ChecksumAlgorithm
1522   // The debug adapter supports the RestartRequest. In this case a client
1523   // should not implement 'restart' by terminating and relaunching the adapter
1524   // but by calling the RestartRequest.
1525   body.try_emplace("supportsRestartRequest", false);
1526   // The debug adapter supports 'exceptionOptions' on the
1527   // setExceptionBreakpoints request.
1528   body.try_emplace("supportsExceptionOptions", true);
1529   // The debug adapter supports a 'format' attribute on the stackTraceRequest,
1530   // variablesRequest, and evaluateRequest.
1531   body.try_emplace("supportsValueFormattingOptions", true);
1532   // The debug adapter supports the exceptionInfo request.
1533   body.try_emplace("supportsExceptionInfoRequest", true);
1534   // The debug adapter supports the 'terminateDebuggee' attribute on the
1535   // 'disconnect' request.
1536   body.try_emplace("supportTerminateDebuggee", true);
1537   // The debug adapter supports the delayed loading of parts of the stack,
1538   // which requires that both the 'startFrame' and 'levels' arguments and the
1539   // 'totalFrames' result of the 'StackTrace' request are supported.
1540   body.try_emplace("supportsDelayedStackTraceLoading", true);
1541   // The debug adapter supports the 'loadedSources' request.
1542   body.try_emplace("supportsLoadedSourcesRequest", false);
1543   // The debug adapter supports sending progress reporting events.
1544   body.try_emplace("supportsProgressReporting", true);
1545   // The debug adapter supports 'logMessage' in breakpoint.
1546   body.try_emplace("supportsLogPoints", true);
1547 
1548   response.try_emplace("body", std::move(body));
1549   g_vsc.SendJSON(llvm::json::Value(std::move(response)));
1550 }
1551 
request_runInTerminal(const llvm::json::Object & launch_request)1552 llvm::Error request_runInTerminal(const llvm::json::Object &launch_request) {
1553   g_vsc.is_attach = true;
1554   lldb::SBAttachInfo attach_info;
1555 
1556   llvm::Expected<std::shared_ptr<FifoFile>> comm_file_or_err =
1557       CreateRunInTerminalCommFile();
1558   if (!comm_file_or_err)
1559     return comm_file_or_err.takeError();
1560   FifoFile &comm_file = *comm_file_or_err.get();
1561 
1562   RunInTerminalDebugAdapterCommChannel comm_channel(comm_file.m_path);
1563 
1564   llvm::json::Object reverse_request = CreateRunInTerminalReverseRequest(
1565       launch_request, g_vsc.debug_adaptor_path, comm_file.m_path);
1566   llvm::json::Object reverse_response;
1567   lldb_vscode::PacketStatus status =
1568       g_vsc.SendReverseRequest(reverse_request, reverse_response);
1569   if (status != lldb_vscode::PacketStatus::Success)
1570     return llvm::createStringError(llvm::inconvertibleErrorCode(),
1571                                    "Process cannot be launched by the IDE. %s",
1572                                    comm_channel.GetLauncherError().c_str());
1573 
1574   if (llvm::Expected<lldb::pid_t> pid = comm_channel.GetLauncherPid())
1575     attach_info.SetProcessID(*pid);
1576   else
1577     return pid.takeError();
1578 
1579   g_vsc.debugger.SetAsync(false);
1580   lldb::SBError error;
1581   g_vsc.target.Attach(attach_info, error);
1582 
1583   if (error.Fail())
1584     return llvm::createStringError(llvm::inconvertibleErrorCode(),
1585                                    "Failed to attach to the target process. %s",
1586                                    comm_channel.GetLauncherError().c_str());
1587   // This will notify the runInTerminal launcher that we attached.
1588   // We have to make this async, as the function won't return until the launcher
1589   // resumes and reads the data.
1590   std::future<lldb::SBError> did_attach_message_success =
1591       comm_channel.NotifyDidAttach();
1592 
1593   // We just attached to the runInTerminal launcher, which was waiting to be
1594   // attached. We now resume it, so it can receive the didAttach notification
1595   // and then perform the exec. Upon continuing, the debugger will stop the
1596   // process right in the middle of the exec. To the user, what we are doing is
1597   // transparent, as they will only be able to see the process since the exec,
1598   // completely unaware of the preparatory work.
1599   g_vsc.target.GetProcess().Continue();
1600 
1601   // Now that the actual target is just starting (i.e. exec was just invoked),
1602   // we return the debugger to its async state.
1603   g_vsc.debugger.SetAsync(true);
1604 
1605   // If sending the notification failed, the launcher should be dead by now and
1606   // the async didAttach notification should have an error message, so we
1607   // return it. Otherwise, everything was a success.
1608   did_attach_message_success.wait();
1609   error = did_attach_message_success.get();
1610   if (error.Success())
1611     return llvm::Error::success();
1612   return llvm::createStringError(llvm::inconvertibleErrorCode(),
1613                                  error.GetCString());
1614 }
1615 
1616 // "LaunchRequest": {
1617 //   "allOf": [ { "$ref": "#/definitions/Request" }, {
1618 //     "type": "object",
1619 //     "description": "Launch request; value of command field is 'launch'.",
1620 //     "properties": {
1621 //       "command": {
1622 //         "type": "string",
1623 //         "enum": [ "launch" ]
1624 //       },
1625 //       "arguments": {
1626 //         "$ref": "#/definitions/LaunchRequestArguments"
1627 //       }
1628 //     },
1629 //     "required": [ "command", "arguments"  ]
1630 //   }]
1631 // },
1632 // "LaunchRequestArguments": {
1633 //   "type": "object",
1634 //   "description": "Arguments for 'launch' request.",
1635 //   "properties": {
1636 //     "noDebug": {
1637 //       "type": "boolean",
1638 //       "description": "If noDebug is true the launch request should launch
1639 //                       the program without enabling debugging."
1640 //     }
1641 //   }
1642 // },
1643 // "LaunchResponse": {
1644 //   "allOf": [ { "$ref": "#/definitions/Response" }, {
1645 //     "type": "object",
1646 //     "description": "Response to 'launch' request. This is just an
1647 //                     acknowledgement, so no body field is required."
1648 //   }]
1649 // }
request_launch(const llvm::json::Object & request)1650 void request_launch(const llvm::json::Object &request) {
1651   g_vsc.is_attach = false;
1652   llvm::json::Object response;
1653   lldb::SBError error;
1654   FillResponse(request, response);
1655   auto arguments = request.getObject("arguments");
1656   g_vsc.init_commands = GetStrings(arguments, "initCommands");
1657   g_vsc.pre_run_commands = GetStrings(arguments, "preRunCommands");
1658   g_vsc.stop_commands = GetStrings(arguments, "stopCommands");
1659   g_vsc.exit_commands = GetStrings(arguments, "exitCommands");
1660   g_vsc.terminate_commands = GetStrings(arguments, "terminateCommands");
1661   auto launchCommands = GetStrings(arguments, "launchCommands");
1662   std::vector<std::string> postRunCommands =
1663       GetStrings(arguments, "postRunCommands");
1664   g_vsc.stop_at_entry = GetBoolean(arguments, "stopOnEntry", false);
1665   const llvm::StringRef debuggerRoot = GetString(arguments, "debuggerRoot");
1666   const uint64_t timeout_seconds = GetUnsigned(arguments, "timeout", 30);
1667 
1668   // This is a hack for loading DWARF in .o files on Mac where the .o files
1669   // in the debug map of the main executable have relative paths which require
1670   // the lldb-vscode binary to have its working directory set to that relative
1671   // root for the .o files in order to be able to load debug info.
1672   if (!debuggerRoot.empty())
1673     llvm::sys::fs::set_current_path(debuggerRoot);
1674 
1675   // Run any initialize LLDB commands the user specified in the launch.json.
1676   // This is run before target is created, so commands can't do anything with
1677   // the targets - preRunCommands are run with the target.
1678   g_vsc.RunInitCommands();
1679 
1680   SetSourceMapFromArguments(*arguments);
1681 
1682   lldb::SBError status;
1683   g_vsc.SetTarget(g_vsc.CreateTargetFromArguments(*arguments, status));
1684   if (status.Fail()) {
1685     response["success"] = llvm::json::Value(false);
1686     EmplaceSafeString(response, "message", status.GetCString());
1687     g_vsc.SendJSON(llvm::json::Value(std::move(response)));
1688     return;
1689   }
1690 
1691   // Instantiate a launch info instance for the target.
1692   auto launch_info = g_vsc.target.GetLaunchInfo();
1693 
1694   // Grab the current working directory if there is one and set it in the
1695   // launch info.
1696   const auto cwd = GetString(arguments, "cwd");
1697   if (!cwd.empty())
1698     launch_info.SetWorkingDirectory(cwd.data());
1699 
1700   // Extract any extra arguments and append them to our program arguments for
1701   // when we launch
1702   auto args = GetStrings(arguments, "args");
1703   if (!args.empty())
1704     launch_info.SetArguments(MakeArgv(args).data(), true);
1705 
1706   // Pass any environment variables along that the user specified.
1707   auto envs = GetStrings(arguments, "env");
1708   if (!envs.empty())
1709     launch_info.SetEnvironmentEntries(MakeArgv(envs).data(), true);
1710 
1711   auto flags = launch_info.GetLaunchFlags();
1712 
1713   if (GetBoolean(arguments, "disableASLR", true))
1714     flags |= lldb::eLaunchFlagDisableASLR;
1715   if (GetBoolean(arguments, "disableSTDIO", false))
1716     flags |= lldb::eLaunchFlagDisableSTDIO;
1717   if (GetBoolean(arguments, "shellExpandArguments", false))
1718     flags |= lldb::eLaunchFlagShellExpandArguments;
1719   const bool detatchOnError = GetBoolean(arguments, "detachOnError", false);
1720   launch_info.SetDetachOnError(detatchOnError);
1721   launch_info.SetLaunchFlags(flags | lldb::eLaunchFlagDebug |
1722                              lldb::eLaunchFlagStopAtEntry);
1723 
1724   // Run any pre run LLDB commands the user specified in the launch.json
1725   g_vsc.RunPreRunCommands();
1726 
1727   if (GetBoolean(arguments, "runInTerminal", false)) {
1728     if (llvm::Error err = request_runInTerminal(request))
1729       error.SetErrorString(llvm::toString(std::move(err)).c_str());
1730   } else if (launchCommands.empty()) {
1731     // Disable async events so the launch will be successful when we return from
1732     // the launch call and the launch will happen synchronously
1733     g_vsc.debugger.SetAsync(false);
1734     g_vsc.target.Launch(launch_info, error);
1735     g_vsc.debugger.SetAsync(true);
1736   } else {
1737     g_vsc.RunLLDBCommands("Running launchCommands:", launchCommands);
1738     // The custom commands might have created a new target so we should use the
1739     // selected target after these commands are run.
1740     g_vsc.target = g_vsc.debugger.GetSelectedTarget();
1741     // Make sure the process is launched and stopped at the entry point before
1742     // proceeding as the the launch commands are not run using the synchronous
1743     // mode.
1744     error = g_vsc.WaitForProcessToStop(timeout_seconds);
1745   }
1746 
1747   if (error.Fail()) {
1748     response["success"] = llvm::json::Value(false);
1749     EmplaceSafeString(response, "message", std::string(error.GetCString()));
1750   } else {
1751     g_vsc.RunLLDBCommands("Running postRunCommands:", postRunCommands);
1752   }
1753 
1754   g_vsc.SendJSON(llvm::json::Value(std::move(response)));
1755 
1756   if (g_vsc.is_attach)
1757     SendProcessEvent(Attach); // this happens when doing runInTerminal
1758   else
1759     SendProcessEvent(Launch);
1760   g_vsc.SendJSON(llvm::json::Value(CreateEventObject("initialized")));
1761 }
1762 
1763 // "NextRequest": {
1764 //   "allOf": [ { "$ref": "#/definitions/Request" }, {
1765 //     "type": "object",
1766 //     "description": "Next request; value of command field is 'next'. The
1767 //                     request starts the debuggee to run again for one step.
1768 //                     The debug adapter first sends the NextResponse and then
1769 //                     a StoppedEvent (event type 'step') after the step has
1770 //                     completed.",
1771 //     "properties": {
1772 //       "command": {
1773 //         "type": "string",
1774 //         "enum": [ "next" ]
1775 //       },
1776 //       "arguments": {
1777 //         "$ref": "#/definitions/NextArguments"
1778 //       }
1779 //     },
1780 //     "required": [ "command", "arguments"  ]
1781 //   }]
1782 // },
1783 // "NextArguments": {
1784 //   "type": "object",
1785 //   "description": "Arguments for 'next' request.",
1786 //   "properties": {
1787 //     "threadId": {
1788 //       "type": "integer",
1789 //       "description": "Execute 'next' for this thread."
1790 //     }
1791 //   },
1792 //   "required": [ "threadId" ]
1793 // },
1794 // "NextResponse": {
1795 //   "allOf": [ { "$ref": "#/definitions/Response" }, {
1796 //     "type": "object",
1797 //     "description": "Response to 'next' request. This is just an
1798 //                     acknowledgement, so no body field is required."
1799 //   }]
1800 // }
request_next(const llvm::json::Object & request)1801 void request_next(const llvm::json::Object &request) {
1802   llvm::json::Object response;
1803   FillResponse(request, response);
1804   auto arguments = request.getObject("arguments");
1805   lldb::SBThread thread = g_vsc.GetLLDBThread(*arguments);
1806   if (thread.IsValid()) {
1807     // Remember the thread ID that caused the resume so we can set the
1808     // "threadCausedFocus" boolean value in the "stopped" events.
1809     g_vsc.focus_tid = thread.GetThreadID();
1810     thread.StepOver();
1811   } else {
1812     response["success"] = llvm::json::Value(false);
1813   }
1814   g_vsc.SendJSON(llvm::json::Value(std::move(response)));
1815 }
1816 
1817 // "PauseRequest": {
1818 //   "allOf": [ { "$ref": "#/definitions/Request" }, {
1819 //     "type": "object",
1820 //     "description": "Pause request; value of command field is 'pause'. The
1821 //     request suspenses the debuggee. The debug adapter first sends the
1822 //     PauseResponse and then a StoppedEvent (event type 'pause') after the
1823 //     thread has been paused successfully.", "properties": {
1824 //       "command": {
1825 //         "type": "string",
1826 //         "enum": [ "pause" ]
1827 //       },
1828 //       "arguments": {
1829 //         "$ref": "#/definitions/PauseArguments"
1830 //       }
1831 //     },
1832 //     "required": [ "command", "arguments"  ]
1833 //   }]
1834 // },
1835 // "PauseArguments": {
1836 //   "type": "object",
1837 //   "description": "Arguments for 'pause' request.",
1838 //   "properties": {
1839 //     "threadId": {
1840 //       "type": "integer",
1841 //       "description": "Pause execution for this thread."
1842 //     }
1843 //   },
1844 //   "required": [ "threadId" ]
1845 // },
1846 // "PauseResponse": {
1847 //   "allOf": [ { "$ref": "#/definitions/Response" }, {
1848 //     "type": "object",
1849 //     "description": "Response to 'pause' request. This is just an
1850 //     acknowledgement, so no body field is required."
1851 //   }]
1852 // }
request_pause(const llvm::json::Object & request)1853 void request_pause(const llvm::json::Object &request) {
1854   llvm::json::Object response;
1855   FillResponse(request, response);
1856   lldb::SBProcess process = g_vsc.target.GetProcess();
1857   lldb::SBError error = process.Stop();
1858   g_vsc.SendJSON(llvm::json::Value(std::move(response)));
1859 }
1860 
1861 // "ScopesRequest": {
1862 //   "allOf": [ { "$ref": "#/definitions/Request" }, {
1863 //     "type": "object",
1864 //     "description": "Scopes request; value of command field is 'scopes'. The
1865 //     request returns the variable scopes for a given stackframe ID.",
1866 //     "properties": {
1867 //       "command": {
1868 //         "type": "string",
1869 //         "enum": [ "scopes" ]
1870 //       },
1871 //       "arguments": {
1872 //         "$ref": "#/definitions/ScopesArguments"
1873 //       }
1874 //     },
1875 //     "required": [ "command", "arguments"  ]
1876 //   }]
1877 // },
1878 // "ScopesArguments": {
1879 //   "type": "object",
1880 //   "description": "Arguments for 'scopes' request.",
1881 //   "properties": {
1882 //     "frameId": {
1883 //       "type": "integer",
1884 //       "description": "Retrieve the scopes for this stackframe."
1885 //     }
1886 //   },
1887 //   "required": [ "frameId" ]
1888 // },
1889 // "ScopesResponse": {
1890 //   "allOf": [ { "$ref": "#/definitions/Response" }, {
1891 //     "type": "object",
1892 //     "description": "Response to 'scopes' request.",
1893 //     "properties": {
1894 //       "body": {
1895 //         "type": "object",
1896 //         "properties": {
1897 //           "scopes": {
1898 //             "type": "array",
1899 //             "items": {
1900 //               "$ref": "#/definitions/Scope"
1901 //             },
1902 //             "description": "The scopes of the stackframe. If the array has
1903 //             length zero, there are no scopes available."
1904 //           }
1905 //         },
1906 //         "required": [ "scopes" ]
1907 //       }
1908 //     },
1909 //     "required": [ "body" ]
1910 //   }]
1911 // }
request_scopes(const llvm::json::Object & request)1912 void request_scopes(const llvm::json::Object &request) {
1913   llvm::json::Object response;
1914   FillResponse(request, response);
1915   llvm::json::Object body;
1916   auto arguments = request.getObject("arguments");
1917   lldb::SBFrame frame = g_vsc.GetLLDBFrame(*arguments);
1918   // As the user selects different stack frames in the GUI, a "scopes" request
1919   // will be sent to the DAP. This is the only way we know that the user has
1920   // selected a frame in a thread. There are no other notifications that are
1921   // sent and VS code doesn't allow multiple frames to show variables
1922   // concurrently. If we select the thread and frame as the "scopes" requests
1923   // are sent, this allows users to type commands in the debugger console
1924   // with a backtick character to run lldb commands and these lldb commands
1925   // will now have the right context selected as they are run. If the user
1926   // types "`bt" into the debugger console and we had another thread selected
1927   // in the LLDB library, we would show the wrong thing to the user. If the
1928   // users switches threads with a lldb command like "`thread select 14", the
1929   // GUI will not update as there are no "event" notification packets that
1930   // allow us to change the currently selected thread or frame in the GUI that
1931   // I am aware of.
1932   if (frame.IsValid()) {
1933     frame.GetThread().GetProcess().SetSelectedThread(frame.GetThread());
1934     frame.GetThread().SetSelectedFrame(frame.GetFrameID());
1935   }
1936   g_vsc.variables.locals = frame.GetVariables(/*arguments=*/true,
1937                                               /*locals=*/true,
1938                                               /*statics=*/false,
1939                                               /*in_scope_only=*/true);
1940   g_vsc.variables.globals = frame.GetVariables(/*arguments=*/false,
1941                                                /*locals=*/false,
1942                                                /*statics=*/true,
1943                                                /*in_scope_only=*/true);
1944   g_vsc.variables.registers = frame.GetRegisters();
1945   body.try_emplace("scopes", g_vsc.CreateTopLevelScopes());
1946   response.try_emplace("body", std::move(body));
1947   g_vsc.SendJSON(llvm::json::Value(std::move(response)));
1948 }
1949 
1950 // "SetBreakpointsRequest": {
1951 //   "allOf": [ { "$ref": "#/definitions/Request" }, {
1952 //     "type": "object",
1953 //     "description": "SetBreakpoints request; value of command field is
1954 //     'setBreakpoints'. Sets multiple breakpoints for a single source and
1955 //     clears all previous breakpoints in that source. To clear all breakpoint
1956 //     for a source, specify an empty array. When a breakpoint is hit, a
1957 //     StoppedEvent (event type 'breakpoint') is generated.", "properties": {
1958 //       "command": {
1959 //         "type": "string",
1960 //         "enum": [ "setBreakpoints" ]
1961 //       },
1962 //       "arguments": {
1963 //         "$ref": "#/definitions/SetBreakpointsArguments"
1964 //       }
1965 //     },
1966 //     "required": [ "command", "arguments"  ]
1967 //   }]
1968 // },
1969 // "SetBreakpointsArguments": {
1970 //   "type": "object",
1971 //   "description": "Arguments for 'setBreakpoints' request.",
1972 //   "properties": {
1973 //     "source": {
1974 //       "$ref": "#/definitions/Source",
1975 //       "description": "The source location of the breakpoints; either
1976 //       source.path or source.reference must be specified."
1977 //     },
1978 //     "breakpoints": {
1979 //       "type": "array",
1980 //       "items": {
1981 //         "$ref": "#/definitions/SourceBreakpoint"
1982 //       },
1983 //       "description": "The code locations of the breakpoints."
1984 //     },
1985 //     "lines": {
1986 //       "type": "array",
1987 //       "items": {
1988 //         "type": "integer"
1989 //       },
1990 //       "description": "Deprecated: The code locations of the breakpoints."
1991 //     },
1992 //     "sourceModified": {
1993 //       "type": "boolean",
1994 //       "description": "A value of true indicates that the underlying source
1995 //       has been modified which results in new breakpoint locations."
1996 //     }
1997 //   },
1998 //   "required": [ "source" ]
1999 // },
2000 // "SetBreakpointsResponse": {
2001 //   "allOf": [ { "$ref": "#/definitions/Response" }, {
2002 //     "type": "object",
2003 //     "description": "Response to 'setBreakpoints' request. Returned is
2004 //     information about each breakpoint created by this request. This includes
2005 //     the actual code location and whether the breakpoint could be verified.
2006 //     The breakpoints returned are in the same order as the elements of the
2007 //     'breakpoints' (or the deprecated 'lines') in the
2008 //     SetBreakpointsArguments.", "properties": {
2009 //       "body": {
2010 //         "type": "object",
2011 //         "properties": {
2012 //           "breakpoints": {
2013 //             "type": "array",
2014 //             "items": {
2015 //               "$ref": "#/definitions/Breakpoint"
2016 //             },
2017 //             "description": "Information about the breakpoints. The array
2018 //             elements are in the same order as the elements of the
2019 //             'breakpoints' (or the deprecated 'lines') in the
2020 //             SetBreakpointsArguments."
2021 //           }
2022 //         },
2023 //         "required": [ "breakpoints" ]
2024 //       }
2025 //     },
2026 //     "required": [ "body" ]
2027 //   }]
2028 // },
2029 // "SourceBreakpoint": {
2030 //   "type": "object",
2031 //   "description": "Properties of a breakpoint or logpoint passed to the
2032 //   setBreakpoints request.", "properties": {
2033 //     "line": {
2034 //       "type": "integer",
2035 //       "description": "The source line of the breakpoint or logpoint."
2036 //     },
2037 //     "column": {
2038 //       "type": "integer",
2039 //       "description": "An optional source column of the breakpoint."
2040 //     },
2041 //     "condition": {
2042 //       "type": "string",
2043 //       "description": "An optional expression for conditional breakpoints."
2044 //     },
2045 //     "hitCondition": {
2046 //       "type": "string",
2047 //       "description": "An optional expression that controls how many hits of
2048 //       the breakpoint are ignored. The backend is expected to interpret the
2049 //       expression as needed."
2050 //     },
2051 //     "logMessage": {
2052 //       "type": "string",
2053 //       "description": "If this attribute exists and is non-empty, the backend
2054 //       must not 'break' (stop) but log the message instead. Expressions within
2055 //       {} are interpolated."
2056 //     }
2057 //   },
2058 //   "required": [ "line" ]
2059 // }
request_setBreakpoints(const llvm::json::Object & request)2060 void request_setBreakpoints(const llvm::json::Object &request) {
2061   llvm::json::Object response;
2062   lldb::SBError error;
2063   FillResponse(request, response);
2064   auto arguments = request.getObject("arguments");
2065   auto source = arguments->getObject("source");
2066   const auto path = GetString(source, "path");
2067   auto breakpoints = arguments->getArray("breakpoints");
2068   llvm::json::Array response_breakpoints;
2069 
2070   // Decode the source breakpoint infos for this "setBreakpoints" request
2071   SourceBreakpointMap request_bps;
2072   // "breakpoints" may be unset, in which case we treat it the same as being set
2073   // to an empty array.
2074   if (breakpoints) {
2075     for (const auto &bp : *breakpoints) {
2076       auto bp_obj = bp.getAsObject();
2077       if (bp_obj) {
2078         SourceBreakpoint src_bp(*bp_obj);
2079         request_bps[src_bp.line] = src_bp;
2080 
2081         // We check if this breakpoint already exists to update it
2082         auto existing_source_bps = g_vsc.source_breakpoints.find(path);
2083         if (existing_source_bps != g_vsc.source_breakpoints.end()) {
2084           const auto &existing_bp =
2085               existing_source_bps->second.find(src_bp.line);
2086           if (existing_bp != existing_source_bps->second.end()) {
2087             existing_bp->second.UpdateBreakpoint(src_bp);
2088             AppendBreakpoint(existing_bp->second.bp, response_breakpoints, path,
2089                              src_bp.line);
2090             continue;
2091           }
2092         }
2093         // At this point the breakpoint is new
2094         g_vsc.source_breakpoints[path][src_bp.line] = src_bp;
2095         SourceBreakpoint &new_bp = g_vsc.source_breakpoints[path][src_bp.line];
2096         new_bp.SetBreakpoint(path.data());
2097         AppendBreakpoint(new_bp.bp, response_breakpoints, path, new_bp.line);
2098       }
2099     }
2100   }
2101 
2102   // Delete any breakpoints in this source file that aren't in the
2103   // request_bps set. There is no call to remove breakpoints other than
2104   // calling this function with a smaller or empty "breakpoints" list.
2105   auto old_src_bp_pos = g_vsc.source_breakpoints.find(path);
2106   if (old_src_bp_pos != g_vsc.source_breakpoints.end()) {
2107     for (auto &old_bp : old_src_bp_pos->second) {
2108       auto request_pos = request_bps.find(old_bp.first);
2109       if (request_pos == request_bps.end()) {
2110         // This breakpoint no longer exists in this source file, delete it
2111         g_vsc.target.BreakpointDelete(old_bp.second.bp.GetID());
2112         old_src_bp_pos->second.erase(old_bp.first);
2113       }
2114     }
2115   }
2116 
2117   llvm::json::Object body;
2118   body.try_emplace("breakpoints", std::move(response_breakpoints));
2119   response.try_emplace("body", std::move(body));
2120   g_vsc.SendJSON(llvm::json::Value(std::move(response)));
2121 }
2122 
2123 // "SetExceptionBreakpointsRequest": {
2124 //   "allOf": [ { "$ref": "#/definitions/Request" }, {
2125 //     "type": "object",
2126 //     "description": "SetExceptionBreakpoints request; value of command field
2127 //     is 'setExceptionBreakpoints'. The request configures the debuggers
2128 //     response to thrown exceptions. If an exception is configured to break, a
2129 //     StoppedEvent is fired (event type 'exception').", "properties": {
2130 //       "command": {
2131 //         "type": "string",
2132 //         "enum": [ "setExceptionBreakpoints" ]
2133 //       },
2134 //       "arguments": {
2135 //         "$ref": "#/definitions/SetExceptionBreakpointsArguments"
2136 //       }
2137 //     },
2138 //     "required": [ "command", "arguments"  ]
2139 //   }]
2140 // },
2141 // "SetExceptionBreakpointsArguments": {
2142 //   "type": "object",
2143 //   "description": "Arguments for 'setExceptionBreakpoints' request.",
2144 //   "properties": {
2145 //     "filters": {
2146 //       "type": "array",
2147 //       "items": {
2148 //         "type": "string"
2149 //       },
2150 //       "description": "IDs of checked exception options. The set of IDs is
2151 //       returned via the 'exceptionBreakpointFilters' capability."
2152 //     },
2153 //     "exceptionOptions": {
2154 //       "type": "array",
2155 //       "items": {
2156 //         "$ref": "#/definitions/ExceptionOptions"
2157 //       },
2158 //       "description": "Configuration options for selected exceptions."
2159 //     }
2160 //   },
2161 //   "required": [ "filters" ]
2162 // },
2163 // "SetExceptionBreakpointsResponse": {
2164 //   "allOf": [ { "$ref": "#/definitions/Response" }, {
2165 //     "type": "object",
2166 //     "description": "Response to 'setExceptionBreakpoints' request. This is
2167 //     just an acknowledgement, so no body field is required."
2168 //   }]
2169 // }
request_setExceptionBreakpoints(const llvm::json::Object & request)2170 void request_setExceptionBreakpoints(const llvm::json::Object &request) {
2171   llvm::json::Object response;
2172   lldb::SBError error;
2173   FillResponse(request, response);
2174   auto arguments = request.getObject("arguments");
2175   auto filters = arguments->getArray("filters");
2176   // Keep a list of any exception breakpoint filter names that weren't set
2177   // so we can clear any exception breakpoints if needed.
2178   std::set<std::string> unset_filters;
2179   for (const auto &bp : g_vsc.exception_breakpoints)
2180     unset_filters.insert(bp.filter);
2181 
2182   for (const auto &value : *filters) {
2183     const auto filter = GetAsString(value);
2184     auto exc_bp = g_vsc.GetExceptionBreakpoint(std::string(filter));
2185     if (exc_bp) {
2186       exc_bp->SetBreakpoint();
2187       unset_filters.erase(std::string(filter));
2188     }
2189   }
2190   for (const auto &filter : unset_filters) {
2191     auto exc_bp = g_vsc.GetExceptionBreakpoint(filter);
2192     if (exc_bp)
2193       exc_bp->ClearBreakpoint();
2194   }
2195   g_vsc.SendJSON(llvm::json::Value(std::move(response)));
2196 }
2197 
2198 // "SetFunctionBreakpointsRequest": {
2199 //   "allOf": [ { "$ref": "#/definitions/Request" }, {
2200 //     "type": "object",
2201 //     "description": "SetFunctionBreakpoints request; value of command field is
2202 //     'setFunctionBreakpoints'. Sets multiple function breakpoints and clears
2203 //     all previous function breakpoints. To clear all function breakpoint,
2204 //     specify an empty array. When a function breakpoint is hit, a StoppedEvent
2205 //     (event type 'function breakpoint') is generated.", "properties": {
2206 //       "command": {
2207 //         "type": "string",
2208 //         "enum": [ "setFunctionBreakpoints" ]
2209 //       },
2210 //       "arguments": {
2211 //         "$ref": "#/definitions/SetFunctionBreakpointsArguments"
2212 //       }
2213 //     },
2214 //     "required": [ "command", "arguments"  ]
2215 //   }]
2216 // },
2217 // "SetFunctionBreakpointsArguments": {
2218 //   "type": "object",
2219 //   "description": "Arguments for 'setFunctionBreakpoints' request.",
2220 //   "properties": {
2221 //     "breakpoints": {
2222 //       "type": "array",
2223 //       "items": {
2224 //         "$ref": "#/definitions/FunctionBreakpoint"
2225 //       },
2226 //       "description": "The function names of the breakpoints."
2227 //     }
2228 //   },
2229 //   "required": [ "breakpoints" ]
2230 // },
2231 // "FunctionBreakpoint": {
2232 //   "type": "object",
2233 //   "description": "Properties of a breakpoint passed to the
2234 //   setFunctionBreakpoints request.", "properties": {
2235 //     "name": {
2236 //       "type": "string",
2237 //       "description": "The name of the function."
2238 //     },
2239 //     "condition": {
2240 //       "type": "string",
2241 //       "description": "An optional expression for conditional breakpoints."
2242 //     },
2243 //     "hitCondition": {
2244 //       "type": "string",
2245 //       "description": "An optional expression that controls how many hits of
2246 //       the breakpoint are ignored. The backend is expected to interpret the
2247 //       expression as needed."
2248 //     }
2249 //   },
2250 //   "required": [ "name" ]
2251 // },
2252 // "SetFunctionBreakpointsResponse": {
2253 //   "allOf": [ { "$ref": "#/definitions/Response" }, {
2254 //     "type": "object",
2255 //     "description": "Response to 'setFunctionBreakpoints' request. Returned is
2256 //     information about each breakpoint created by this request.",
2257 //     "properties": {
2258 //       "body": {
2259 //         "type": "object",
2260 //         "properties": {
2261 //           "breakpoints": {
2262 //             "type": "array",
2263 //             "items": {
2264 //               "$ref": "#/definitions/Breakpoint"
2265 //             },
2266 //             "description": "Information about the breakpoints. The array
2267 //             elements correspond to the elements of the 'breakpoints' array."
2268 //           }
2269 //         },
2270 //         "required": [ "breakpoints" ]
2271 //       }
2272 //     },
2273 //     "required": [ "body" ]
2274 //   }]
2275 // }
request_setFunctionBreakpoints(const llvm::json::Object & request)2276 void request_setFunctionBreakpoints(const llvm::json::Object &request) {
2277   llvm::json::Object response;
2278   lldb::SBError error;
2279   FillResponse(request, response);
2280   auto arguments = request.getObject("arguments");
2281   auto breakpoints = arguments->getArray("breakpoints");
2282   FunctionBreakpointMap request_bps;
2283   llvm::json::Array response_breakpoints;
2284   for (const auto &value : *breakpoints) {
2285     auto bp_obj = value.getAsObject();
2286     if (bp_obj == nullptr)
2287       continue;
2288     FunctionBreakpoint func_bp(*bp_obj);
2289     request_bps[func_bp.functionName] = std::move(func_bp);
2290   }
2291 
2292   std::vector<llvm::StringRef> remove_names;
2293   // Disable any function breakpoints that aren't in the request_bps.
2294   // There is no call to remove function breakpoints other than calling this
2295   // function with a smaller or empty "breakpoints" list.
2296   for (auto &pair : g_vsc.function_breakpoints) {
2297     auto request_pos = request_bps.find(pair.first());
2298     if (request_pos == request_bps.end()) {
2299       // This function breakpoint no longer exists delete it from LLDB
2300       g_vsc.target.BreakpointDelete(pair.second.bp.GetID());
2301       remove_names.push_back(pair.first());
2302     } else {
2303       // Update the existing breakpoint as any setting withing the function
2304       // breakpoint might have changed.
2305       pair.second.UpdateBreakpoint(request_pos->second);
2306       // Remove this breakpoint from the request breakpoints since we have
2307       // handled it here and we don't need to set a new breakpoint below.
2308       request_bps.erase(request_pos);
2309       // Add this breakpoint info to the response
2310       AppendBreakpoint(pair.second.bp, response_breakpoints);
2311     }
2312   }
2313   // Remove any breakpoints that are no longer in our list
2314   for (const auto &name : remove_names)
2315     g_vsc.function_breakpoints.erase(name);
2316 
2317   // Any breakpoints that are left in "request_bps" are breakpoints that
2318   // need to be set.
2319   for (auto &pair : request_bps) {
2320     // Add this breakpoint info to the response
2321     g_vsc.function_breakpoints[pair.first()] = std::move(pair.second);
2322     FunctionBreakpoint &new_bp = g_vsc.function_breakpoints[pair.first()];
2323     new_bp.SetBreakpoint();
2324     AppendBreakpoint(new_bp.bp, response_breakpoints);
2325   }
2326 
2327   llvm::json::Object body;
2328   body.try_emplace("breakpoints", std::move(response_breakpoints));
2329   response.try_emplace("body", std::move(body));
2330   g_vsc.SendJSON(llvm::json::Value(std::move(response)));
2331 }
2332 
2333 // "SourceRequest": {
2334 //   "allOf": [ { "$ref": "#/definitions/Request" }, {
2335 //     "type": "object",
2336 //     "description": "Source request; value of command field is 'source'. The
2337 //     request retrieves the source code for a given source reference.",
2338 //     "properties": {
2339 //       "command": {
2340 //         "type": "string",
2341 //         "enum": [ "source" ]
2342 //       },
2343 //       "arguments": {
2344 //         "$ref": "#/definitions/SourceArguments"
2345 //       }
2346 //     },
2347 //     "required": [ "command", "arguments"  ]
2348 //   }]
2349 // },
2350 // "SourceArguments": {
2351 //   "type": "object",
2352 //   "description": "Arguments for 'source' request.",
2353 //   "properties": {
2354 //     "source": {
2355 //       "$ref": "#/definitions/Source",
2356 //       "description": "Specifies the source content to load. Either
2357 //       source.path or source.sourceReference must be specified."
2358 //     },
2359 //     "sourceReference": {
2360 //       "type": "integer",
2361 //       "description": "The reference to the source. This is the same as
2362 //       source.sourceReference. This is provided for backward compatibility
2363 //       since old backends do not understand the 'source' attribute."
2364 //     }
2365 //   },
2366 //   "required": [ "sourceReference" ]
2367 // },
2368 // "SourceResponse": {
2369 //   "allOf": [ { "$ref": "#/definitions/Response" }, {
2370 //     "type": "object",
2371 //     "description": "Response to 'source' request.",
2372 //     "properties": {
2373 //       "body": {
2374 //         "type": "object",
2375 //         "properties": {
2376 //           "content": {
2377 //             "type": "string",
2378 //             "description": "Content of the source reference."
2379 //           },
2380 //           "mimeType": {
2381 //             "type": "string",
2382 //             "description": "Optional content type (mime type) of the source."
2383 //           }
2384 //         },
2385 //         "required": [ "content" ]
2386 //       }
2387 //     },
2388 //     "required": [ "body" ]
2389 //   }]
2390 // }
request_source(const llvm::json::Object & request)2391 void request_source(const llvm::json::Object &request) {
2392   llvm::json::Object response;
2393   FillResponse(request, response);
2394   llvm::json::Object body;
2395 
2396   auto arguments = request.getObject("arguments");
2397   auto source = arguments->getObject("source");
2398   auto sourceReference = GetSigned(source, "sourceReference", -1);
2399   auto pos = g_vsc.source_map.find((lldb::addr_t)sourceReference);
2400   if (pos != g_vsc.source_map.end()) {
2401     EmplaceSafeString(body, "content", pos->second.content);
2402   } else {
2403     response["success"] = llvm::json::Value(false);
2404   }
2405   EmplaceSafeString(body, "mimeType", "text/x-lldb.disassembly");
2406   response.try_emplace("body", std::move(body));
2407   g_vsc.SendJSON(llvm::json::Value(std::move(response)));
2408 }
2409 
2410 // "StackTraceRequest": {
2411 //   "allOf": [ { "$ref": "#/definitions/Request" }, {
2412 //     "type": "object",
2413 //     "description": "StackTrace request; value of command field is
2414 //     'stackTrace'. The request returns a stacktrace from the current execution
2415 //     state.", "properties": {
2416 //       "command": {
2417 //         "type": "string",
2418 //         "enum": [ "stackTrace" ]
2419 //       },
2420 //       "arguments": {
2421 //         "$ref": "#/definitions/StackTraceArguments"
2422 //       }
2423 //     },
2424 //     "required": [ "command", "arguments"  ]
2425 //   }]
2426 // },
2427 // "StackTraceArguments": {
2428 //   "type": "object",
2429 //   "description": "Arguments for 'stackTrace' request.",
2430 //   "properties": {
2431 //     "threadId": {
2432 //       "type": "integer",
2433 //       "description": "Retrieve the stacktrace for this thread."
2434 //     },
2435 //     "startFrame": {
2436 //       "type": "integer",
2437 //       "description": "The index of the first frame to return; if omitted
2438 //       frames start at 0."
2439 //     },
2440 //     "levels": {
2441 //       "type": "integer",
2442 //       "description": "The maximum number of frames to return. If levels is
2443 //       not specified or 0, all frames are returned."
2444 //     },
2445 //     "format": {
2446 //       "$ref": "#/definitions/StackFrameFormat",
2447 //       "description": "Specifies details on how to format the stack frames."
2448 //     }
2449 //  },
2450 //   "required": [ "threadId" ]
2451 // },
2452 // "StackTraceResponse": {
2453 //   "allOf": [ { "$ref": "#/definitions/Response" }, {
2454 //     "type": "object",
2455 //     "description": "Response to 'stackTrace' request.",
2456 //     "properties": {
2457 //       "body": {
2458 //         "type": "object",
2459 //         "properties": {
2460 //           "stackFrames": {
2461 //             "type": "array",
2462 //             "items": {
2463 //               "$ref": "#/definitions/StackFrame"
2464 //             },
2465 //             "description": "The frames of the stackframe. If the array has
2466 //             length zero, there are no stackframes available. This means that
2467 //             there is no location information available."
2468 //           },
2469 //           "totalFrames": {
2470 //             "type": "integer",
2471 //             "description": "The total number of frames available."
2472 //           }
2473 //         },
2474 //         "required": [ "stackFrames" ]
2475 //       }
2476 //     },
2477 //     "required": [ "body" ]
2478 //   }]
2479 // }
request_stackTrace(const llvm::json::Object & request)2480 void request_stackTrace(const llvm::json::Object &request) {
2481   llvm::json::Object response;
2482   FillResponse(request, response);
2483   lldb::SBError error;
2484   auto arguments = request.getObject("arguments");
2485   lldb::SBThread thread = g_vsc.GetLLDBThread(*arguments);
2486   llvm::json::Array stackFrames;
2487   llvm::json::Object body;
2488 
2489   if (thread.IsValid()) {
2490     const auto startFrame = GetUnsigned(arguments, "startFrame", 0);
2491     const auto levels = GetUnsigned(arguments, "levels", 0);
2492     const auto endFrame = (levels == 0) ? INT64_MAX : (startFrame + levels);
2493     for (uint32_t i = startFrame; i < endFrame; ++i) {
2494       auto frame = thread.GetFrameAtIndex(i);
2495       if (!frame.IsValid())
2496         break;
2497       stackFrames.emplace_back(CreateStackFrame(frame));
2498     }
2499     const auto totalFrames = thread.GetNumFrames();
2500     body.try_emplace("totalFrames", totalFrames);
2501   }
2502   body.try_emplace("stackFrames", std::move(stackFrames));
2503   response.try_emplace("body", std::move(body));
2504   g_vsc.SendJSON(llvm::json::Value(std::move(response)));
2505 }
2506 
2507 // "StepInRequest": {
2508 //   "allOf": [ { "$ref": "#/definitions/Request" }, {
2509 //     "type": "object",
2510 //     "description": "StepIn request; value of command field is 'stepIn'. The
2511 //     request starts the debuggee to step into a function/method if possible.
2512 //     If it cannot step into a target, 'stepIn' behaves like 'next'. The debug
2513 //     adapter first sends the StepInResponse and then a StoppedEvent (event
2514 //     type 'step') after the step has completed. If there are multiple
2515 //     function/method calls (or other targets) on the source line, the optional
2516 //     argument 'targetId' can be used to control into which target the 'stepIn'
2517 //     should occur. The list of possible targets for a given source line can be
2518 //     retrieved via the 'stepInTargets' request.", "properties": {
2519 //       "command": {
2520 //         "type": "string",
2521 //         "enum": [ "stepIn" ]
2522 //       },
2523 //       "arguments": {
2524 //         "$ref": "#/definitions/StepInArguments"
2525 //       }
2526 //     },
2527 //     "required": [ "command", "arguments"  ]
2528 //   }]
2529 // },
2530 // "StepInArguments": {
2531 //   "type": "object",
2532 //   "description": "Arguments for 'stepIn' request.",
2533 //   "properties": {
2534 //     "threadId": {
2535 //       "type": "integer",
2536 //       "description": "Execute 'stepIn' for this thread."
2537 //     },
2538 //     "targetId": {
2539 //       "type": "integer",
2540 //       "description": "Optional id of the target to step into."
2541 //     }
2542 //   },
2543 //   "required": [ "threadId" ]
2544 // },
2545 // "StepInResponse": {
2546 //   "allOf": [ { "$ref": "#/definitions/Response" }, {
2547 //     "type": "object",
2548 //     "description": "Response to 'stepIn' request. This is just an
2549 //     acknowledgement, so no body field is required."
2550 //   }]
2551 // }
request_stepIn(const llvm::json::Object & request)2552 void request_stepIn(const llvm::json::Object &request) {
2553   llvm::json::Object response;
2554   FillResponse(request, response);
2555   auto arguments = request.getObject("arguments");
2556   lldb::SBThread thread = g_vsc.GetLLDBThread(*arguments);
2557   if (thread.IsValid()) {
2558     // Remember the thread ID that caused the resume so we can set the
2559     // "threadCausedFocus" boolean value in the "stopped" events.
2560     g_vsc.focus_tid = thread.GetThreadID();
2561     thread.StepInto();
2562   } else {
2563     response["success"] = llvm::json::Value(false);
2564   }
2565   g_vsc.SendJSON(llvm::json::Value(std::move(response)));
2566 }
2567 
2568 // "StepOutRequest": {
2569 //   "allOf": [ { "$ref": "#/definitions/Request" }, {
2570 //     "type": "object",
2571 //     "description": "StepOut request; value of command field is 'stepOut'. The
2572 //     request starts the debuggee to run again for one step. The debug adapter
2573 //     first sends the StepOutResponse and then a StoppedEvent (event type
2574 //     'step') after the step has completed.", "properties": {
2575 //       "command": {
2576 //         "type": "string",
2577 //         "enum": [ "stepOut" ]
2578 //       },
2579 //       "arguments": {
2580 //         "$ref": "#/definitions/StepOutArguments"
2581 //       }
2582 //     },
2583 //     "required": [ "command", "arguments"  ]
2584 //   }]
2585 // },
2586 // "StepOutArguments": {
2587 //   "type": "object",
2588 //   "description": "Arguments for 'stepOut' request.",
2589 //   "properties": {
2590 //     "threadId": {
2591 //       "type": "integer",
2592 //       "description": "Execute 'stepOut' for this thread."
2593 //     }
2594 //   },
2595 //   "required": [ "threadId" ]
2596 // },
2597 // "StepOutResponse": {
2598 //   "allOf": [ { "$ref": "#/definitions/Response" }, {
2599 //     "type": "object",
2600 //     "description": "Response to 'stepOut' request. This is just an
2601 //     acknowledgement, so no body field is required."
2602 //   }]
2603 // }
request_stepOut(const llvm::json::Object & request)2604 void request_stepOut(const llvm::json::Object &request) {
2605   llvm::json::Object response;
2606   FillResponse(request, response);
2607   auto arguments = request.getObject("arguments");
2608   lldb::SBThread thread = g_vsc.GetLLDBThread(*arguments);
2609   if (thread.IsValid()) {
2610     // Remember the thread ID that caused the resume so we can set the
2611     // "threadCausedFocus" boolean value in the "stopped" events.
2612     g_vsc.focus_tid = thread.GetThreadID();
2613     thread.StepOut();
2614   } else {
2615     response["success"] = llvm::json::Value(false);
2616   }
2617   g_vsc.SendJSON(llvm::json::Value(std::move(response)));
2618 }
2619 
2620 // "ThreadsRequest": {
2621 //   "allOf": [ { "$ref": "#/definitions/Request" }, {
2622 //     "type": "object",
2623 //     "description": "Thread request; value of command field is 'threads'. The
2624 //     request retrieves a list of all threads.", "properties": {
2625 //       "command": {
2626 //         "type": "string",
2627 //         "enum": [ "threads" ]
2628 //       }
2629 //     },
2630 //     "required": [ "command" ]
2631 //   }]
2632 // },
2633 // "ThreadsResponse": {
2634 //   "allOf": [ { "$ref": "#/definitions/Response" }, {
2635 //     "type": "object",
2636 //     "description": "Response to 'threads' request.",
2637 //     "properties": {
2638 //       "body": {
2639 //         "type": "object",
2640 //         "properties": {
2641 //           "threads": {
2642 //             "type": "array",
2643 //             "items": {
2644 //               "$ref": "#/definitions/Thread"
2645 //             },
2646 //             "description": "All threads."
2647 //           }
2648 //         },
2649 //         "required": [ "threads" ]
2650 //       }
2651 //     },
2652 //     "required": [ "body" ]
2653 //   }]
2654 // }
request_threads(const llvm::json::Object & request)2655 void request_threads(const llvm::json::Object &request) {
2656 
2657   lldb::SBProcess process = g_vsc.target.GetProcess();
2658   llvm::json::Object response;
2659   FillResponse(request, response);
2660 
2661   const uint32_t num_threads = process.GetNumThreads();
2662   llvm::json::Array threads;
2663   for (uint32_t thread_idx = 0; thread_idx < num_threads; ++thread_idx) {
2664     lldb::SBThread thread = process.GetThreadAtIndex(thread_idx);
2665     threads.emplace_back(CreateThread(thread));
2666   }
2667   if (threads.size() == 0) {
2668     response["success"] = llvm::json::Value(false);
2669   }
2670   llvm::json::Object body;
2671   body.try_emplace("threads", std::move(threads));
2672   response.try_emplace("body", std::move(body));
2673   g_vsc.SendJSON(llvm::json::Value(std::move(response)));
2674 }
2675 
2676 // "SetVariableRequest": {
2677 //   "allOf": [ { "$ref": "#/definitions/Request" }, {
2678 //     "type": "object",
2679 //     "description": "setVariable request; value of command field is
2680 //     'setVariable'. Set the variable with the given name in the variable
2681 //     container to a new value.", "properties": {
2682 //       "command": {
2683 //         "type": "string",
2684 //         "enum": [ "setVariable" ]
2685 //       },
2686 //       "arguments": {
2687 //         "$ref": "#/definitions/SetVariableArguments"
2688 //       }
2689 //     },
2690 //     "required": [ "command", "arguments"  ]
2691 //   }]
2692 // },
2693 // "SetVariableArguments": {
2694 //   "type": "object",
2695 //   "description": "Arguments for 'setVariable' request.",
2696 //   "properties": {
2697 //     "variablesReference": {
2698 //       "type": "integer",
2699 //       "description": "The reference of the variable container."
2700 //     },
2701 //     "name": {
2702 //       "type": "string",
2703 //       "description": "The name of the variable."
2704 //     },
2705 //     "value": {
2706 //       "type": "string",
2707 //       "description": "The value of the variable."
2708 //     },
2709 //     "format": {
2710 //       "$ref": "#/definitions/ValueFormat",
2711 //       "description": "Specifies details on how to format the response value."
2712 //     }
2713 //   },
2714 //   "required": [ "variablesReference", "name", "value" ]
2715 // },
2716 // "SetVariableResponse": {
2717 //   "allOf": [ { "$ref": "#/definitions/Response" }, {
2718 //     "type": "object",
2719 //     "description": "Response to 'setVariable' request.",
2720 //     "properties": {
2721 //       "body": {
2722 //         "type": "object",
2723 //         "properties": {
2724 //           "value": {
2725 //             "type": "string",
2726 //             "description": "The new value of the variable."
2727 //           },
2728 //           "type": {
2729 //             "type": "string",
2730 //             "description": "The type of the new value. Typically shown in the
2731 //             UI when hovering over the value."
2732 //           },
2733 //           "variablesReference": {
2734 //             "type": "number",
2735 //             "description": "If variablesReference is > 0, the new value is
2736 //             structured and its children can be retrieved by passing
2737 //             variablesReference to the VariablesRequest."
2738 //           },
2739 //           "namedVariables": {
2740 //             "type": "number",
2741 //             "description": "The number of named child variables. The client
2742 //             can use this optional information to present the variables in a
2743 //             paged UI and fetch them in chunks."
2744 //           },
2745 //           "indexedVariables": {
2746 //             "type": "number",
2747 //             "description": "The number of indexed child variables. The client
2748 //             can use this optional information to present the variables in a
2749 //             paged UI and fetch them in chunks."
2750 //           }
2751 //         },
2752 //         "required": [ "value" ]
2753 //       }
2754 //     },
2755 //     "required": [ "body" ]
2756 //   }]
2757 // }
request_setVariable(const llvm::json::Object & request)2758 void request_setVariable(const llvm::json::Object &request) {
2759   llvm::json::Object response;
2760   FillResponse(request, response);
2761   llvm::json::Array variables;
2762   llvm::json::Object body;
2763   auto arguments = request.getObject("arguments");
2764   // This is a reference to the containing variable/scope
2765   const auto variablesReference =
2766       GetUnsigned(arguments, "variablesReference", 0);
2767   llvm::StringRef name = GetString(arguments, "name");
2768   bool is_duplicated_variable_name = name.contains(" @");
2769 
2770   const auto value = GetString(arguments, "value");
2771   // Set success to false just in case we don't find the variable by name
2772   response.try_emplace("success", false);
2773 
2774   lldb::SBValue variable;
2775   int64_t newVariablesReference = 0;
2776 
2777   // The "id" is the unique integer ID that is unique within the enclosing
2778   // variablesReference. It is optionally added to any "interface Variable"
2779   // objects to uniquely identify a variable within an enclosing
2780   // variablesReference. It helps to disambiguate between two variables that
2781   // have the same name within the same scope since the "setVariables" request
2782   // only specifies the variable reference of the enclosing scope/variable, and
2783   // the name of the variable. We could have two shadowed variables with the
2784   // same name in "Locals" or "Globals". In our case the "id" absolute index
2785   // of the variable within the g_vsc.variables list.
2786   const auto id_value = GetUnsigned(arguments, "id", UINT64_MAX);
2787   if (id_value != UINT64_MAX) {
2788     variable = g_vsc.variables.GetVariable(id_value);
2789   } else if (lldb::SBValueList *top_scope =
2790                  GetTopLevelScope(variablesReference)) {
2791     // variablesReference is one of our scopes, not an actual variable it is
2792     // asking for a variable in locals or globals or registers
2793     int64_t end_idx = top_scope->GetSize();
2794     // Searching backward so that we choose the variable in closest scope
2795     // among variables of the same name.
2796     for (int64_t i = end_idx - 1; i >= 0; --i) {
2797       lldb::SBValue curr_variable = top_scope->GetValueAtIndex(i);
2798       std::string variable_name = CreateUniqueVariableNameForDisplay(
2799           curr_variable, is_duplicated_variable_name);
2800       if (variable_name == name) {
2801         variable = curr_variable;
2802         break;
2803       }
2804     }
2805   } else {
2806     // This is not under the globals or locals scope, so there are no duplicated
2807     // names.
2808 
2809     // We have a named item within an actual variable so we need to find it
2810     // withing the container variable by name.
2811     lldb::SBValue container = g_vsc.variables.GetVariable(variablesReference);
2812     variable = container.GetChildMemberWithName(name.data());
2813     if (!variable.IsValid()) {
2814       if (name.startswith("[")) {
2815         llvm::StringRef index_str(name.drop_front(1));
2816         uint64_t index = 0;
2817         if (!index_str.consumeInteger(0, index)) {
2818           if (index_str == "]")
2819             variable = container.GetChildAtIndex(index);
2820         }
2821       }
2822     }
2823   }
2824 
2825   if (variable.IsValid()) {
2826     lldb::SBError error;
2827     bool success = variable.SetValueFromCString(value.data(), error);
2828     if (success) {
2829       SetValueForKey(variable, body, "value");
2830       EmplaceSafeString(body, "type", variable.GetType().GetDisplayTypeName());
2831 
2832       // We don't know the index of the variable in our g_vsc.variables
2833       // so always insert a new one to get its variablesReference.
2834       // is_permanent is false because debug console does not support
2835       // setVariable request.
2836       if (variable.MightHaveChildren())
2837         newVariablesReference = g_vsc.variables.InsertExpandableVariable(
2838             variable, /*is_permanent=*/false);
2839 
2840       body.try_emplace("variablesReference", newVariablesReference);
2841     } else {
2842       EmplaceSafeString(body, "message", std::string(error.GetCString()));
2843     }
2844     response["success"] = llvm::json::Value(success);
2845   } else {
2846     response["success"] = llvm::json::Value(false);
2847   }
2848 
2849   response.try_emplace("body", std::move(body));
2850   g_vsc.SendJSON(llvm::json::Value(std::move(response)));
2851 }
2852 
2853 // "VariablesRequest": {
2854 //   "allOf": [ { "$ref": "#/definitions/Request" }, {
2855 //     "type": "object",
2856 //     "description": "Variables request; value of command field is 'variables'.
2857 //     Retrieves all child variables for the given variable reference. An
2858 //     optional filter can be used to limit the fetched children to either named
2859 //     or indexed children.", "properties": {
2860 //       "command": {
2861 //         "type": "string",
2862 //         "enum": [ "variables" ]
2863 //       },
2864 //       "arguments": {
2865 //         "$ref": "#/definitions/VariablesArguments"
2866 //       }
2867 //     },
2868 //     "required": [ "command", "arguments"  ]
2869 //   }]
2870 // },
2871 // "VariablesArguments": {
2872 //   "type": "object",
2873 //   "description": "Arguments for 'variables' request.",
2874 //   "properties": {
2875 //     "variablesReference": {
2876 //       "type": "integer",
2877 //       "description": "The Variable reference."
2878 //     },
2879 //     "filter": {
2880 //       "type": "string",
2881 //       "enum": [ "indexed", "named" ],
2882 //       "description": "Optional filter to limit the child variables to either
2883 //       named or indexed. If ommited, both types are fetched."
2884 //     },
2885 //     "start": {
2886 //       "type": "integer",
2887 //       "description": "The index of the first variable to return; if omitted
2888 //       children start at 0."
2889 //     },
2890 //     "count": {
2891 //       "type": "integer",
2892 //       "description": "The number of variables to return. If count is missing
2893 //       or 0, all variables are returned."
2894 //     },
2895 //     "format": {
2896 //       "$ref": "#/definitions/ValueFormat",
2897 //       "description": "Specifies details on how to format the Variable
2898 //       values."
2899 //     }
2900 //   },
2901 //   "required": [ "variablesReference" ]
2902 // },
2903 // "VariablesResponse": {
2904 //   "allOf": [ { "$ref": "#/definitions/Response" }, {
2905 //     "type": "object",
2906 //     "description": "Response to 'variables' request.",
2907 //     "properties": {
2908 //       "body": {
2909 //         "type": "object",
2910 //         "properties": {
2911 //           "variables": {
2912 //             "type": "array",
2913 //             "items": {
2914 //               "$ref": "#/definitions/Variable"
2915 //             },
2916 //             "description": "All (or a range) of variables for the given
2917 //             variable reference."
2918 //           }
2919 //         },
2920 //         "required": [ "variables" ]
2921 //       }
2922 //     },
2923 //     "required": [ "body" ]
2924 //   }]
2925 // }
request_variables(const llvm::json::Object & request)2926 void request_variables(const llvm::json::Object &request) {
2927   llvm::json::Object response;
2928   FillResponse(request, response);
2929   llvm::json::Array variables;
2930   auto arguments = request.getObject("arguments");
2931   const auto variablesReference =
2932       GetUnsigned(arguments, "variablesReference", 0);
2933   const int64_t start = GetSigned(arguments, "start", 0);
2934   const int64_t count = GetSigned(arguments, "count", 0);
2935   bool hex = false;
2936   auto format = arguments->getObject("format");
2937   if (format)
2938     hex = GetBoolean(format, "hex", false);
2939 
2940   if (lldb::SBValueList *top_scope = GetTopLevelScope(variablesReference)) {
2941     // variablesReference is one of our scopes, not an actual variable it is
2942     // asking for the list of args, locals or globals.
2943     int64_t start_idx = 0;
2944     int64_t num_children = 0;
2945 
2946     if (variablesReference == VARREF_REGS) {
2947       // Change the default format of any pointer sized registers in the first
2948       // register set to be the lldb::eFormatAddressInfo so we show the pointer
2949       // and resolve what the pointer resolves to. Only change the format if the
2950       // format was set to the default format or if it was hex as some registers
2951       // have formats set for them.
2952       const uint32_t addr_size = g_vsc.target.GetProcess().GetAddressByteSize();
2953       lldb::SBValue reg_set = g_vsc.variables.registers.GetValueAtIndex(0);
2954       const uint32_t num_regs = reg_set.GetNumChildren();
2955       for (uint32_t reg_idx = 0; reg_idx < num_regs; ++reg_idx) {
2956         lldb::SBValue reg = reg_set.GetChildAtIndex(reg_idx);
2957         const lldb::Format format = reg.GetFormat();
2958         if (format == lldb::eFormatDefault || format == lldb::eFormatHex) {
2959           if (reg.GetByteSize() == addr_size)
2960             reg.SetFormat(lldb::eFormatAddressInfo);
2961         }
2962       }
2963     }
2964 
2965     num_children = top_scope->GetSize();
2966     if (num_children == 0 && variablesReference == VARREF_LOCALS) {
2967       // Check for an error in the SBValueList that might explain why we don't
2968       // have locals. If we have an error display it as the sole value in the
2969       // the locals.
2970 
2971       // "error" owns the error string so we must keep it alive as long as we
2972       // want to use the returns "const char *"
2973       lldb::SBError error = top_scope->GetError();
2974       const char *var_err = error.GetCString();
2975       if (var_err) {
2976         // Create a fake variable named "error" to explain why variables were
2977         // not available. This new error will help let users know when there was
2978         // a problem that kept variables from being available for display and
2979         // allow users to fix this issue instead of seeing no variables. The
2980         // errors are only set when there is a problem that the user could
2981         // fix, so no error will show up when you have no debug info, only when
2982         // we do have debug info and something that is fixable can be done.
2983         llvm::json::Object object;
2984         EmplaceSafeString(object, "name", "<error>");
2985         EmplaceSafeString(object, "type", "const char *");
2986         EmplaceSafeString(object, "value", var_err);
2987         object.try_emplace("variablesReference", (int64_t)0);
2988         variables.emplace_back(std::move(object));
2989       }
2990     }
2991     const int64_t end_idx = start_idx + ((count == 0) ? num_children : count);
2992 
2993     // We first find out which variable names are duplicated
2994     std::map<std::string, int> variable_name_counts;
2995     for (auto i = start_idx; i < end_idx; ++i) {
2996       lldb::SBValue variable = top_scope->GetValueAtIndex(i);
2997       if (!variable.IsValid())
2998         break;
2999       variable_name_counts[GetNonNullVariableName(variable)]++;
3000     }
3001 
3002     // Now we construct the result with unique display variable names
3003     for (auto i = start_idx; i < end_idx; ++i) {
3004       lldb::SBValue variable = top_scope->GetValueAtIndex(i);
3005 
3006       if (!variable.IsValid())
3007         break;
3008 
3009       int64_t var_ref = 0;
3010       if (variable.MightHaveChildren()) {
3011         var_ref = g_vsc.variables.InsertExpandableVariable(
3012             variable, /*is_permanent=*/false);
3013       }
3014       variables.emplace_back(CreateVariable(
3015           variable, var_ref, var_ref != 0 ? var_ref : UINT64_MAX, hex,
3016           variable_name_counts[GetNonNullVariableName(variable)] > 1));
3017     }
3018   } else {
3019     // We are expanding a variable that has children, so we will return its
3020     // children.
3021     lldb::SBValue variable = g_vsc.variables.GetVariable(variablesReference);
3022     if (variable.IsValid()) {
3023       const auto num_children = variable.GetNumChildren();
3024       const int64_t end_idx = start + ((count == 0) ? num_children : count);
3025       for (auto i = start; i < end_idx; ++i) {
3026         lldb::SBValue child = variable.GetChildAtIndex(i);
3027         if (!child.IsValid())
3028           break;
3029         if (child.MightHaveChildren()) {
3030           auto is_permanent =
3031               g_vsc.variables.IsPermanentVariableReference(variablesReference);
3032           auto childVariablesReferences =
3033               g_vsc.variables.InsertExpandableVariable(child, is_permanent);
3034           variables.emplace_back(CreateVariable(child, childVariablesReferences,
3035                                                 childVariablesReferences, hex));
3036         } else {
3037           variables.emplace_back(CreateVariable(child, 0, INT64_MAX, hex));
3038         }
3039       }
3040     }
3041   }
3042   llvm::json::Object body;
3043   body.try_emplace("variables", std::move(variables));
3044   response.try_emplace("body", std::move(body));
3045   g_vsc.SendJSON(llvm::json::Value(std::move(response)));
3046 }
3047 
3048 // A request used in testing to get the details on all breakpoints that are
3049 // currently set in the target. This helps us to test "setBreakpoints" and
3050 // "setFunctionBreakpoints" requests to verify we have the correct set of
3051 // breakpoints currently set in LLDB.
request__testGetTargetBreakpoints(const llvm::json::Object & request)3052 void request__testGetTargetBreakpoints(const llvm::json::Object &request) {
3053   llvm::json::Object response;
3054   FillResponse(request, response);
3055   llvm::json::Array response_breakpoints;
3056   for (uint32_t i = 0; g_vsc.target.GetBreakpointAtIndex(i).IsValid(); ++i) {
3057     auto bp = g_vsc.target.GetBreakpointAtIndex(i);
3058     AppendBreakpoint(bp, response_breakpoints);
3059   }
3060   llvm::json::Object body;
3061   body.try_emplace("breakpoints", std::move(response_breakpoints));
3062   response.try_emplace("body", std::move(body));
3063   g_vsc.SendJSON(llvm::json::Value(std::move(response)));
3064 }
3065 
RegisterRequestCallbacks()3066 void RegisterRequestCallbacks() {
3067   g_vsc.RegisterRequestCallback("attach", request_attach);
3068   g_vsc.RegisterRequestCallback("completions", request_completions);
3069   g_vsc.RegisterRequestCallback("continue", request_continue);
3070   g_vsc.RegisterRequestCallback("configurationDone", request_configurationDone);
3071   g_vsc.RegisterRequestCallback("disconnect", request_disconnect);
3072   g_vsc.RegisterRequestCallback("evaluate", request_evaluate);
3073   g_vsc.RegisterRequestCallback("exceptionInfo", request_exceptionInfo);
3074   g_vsc.RegisterRequestCallback("initialize", request_initialize);
3075   g_vsc.RegisterRequestCallback("launch", request_launch);
3076   g_vsc.RegisterRequestCallback("next", request_next);
3077   g_vsc.RegisterRequestCallback("pause", request_pause);
3078   g_vsc.RegisterRequestCallback("scopes", request_scopes);
3079   g_vsc.RegisterRequestCallback("setBreakpoints", request_setBreakpoints);
3080   g_vsc.RegisterRequestCallback("setExceptionBreakpoints",
3081                                 request_setExceptionBreakpoints);
3082   g_vsc.RegisterRequestCallback("setFunctionBreakpoints",
3083                                 request_setFunctionBreakpoints);
3084   g_vsc.RegisterRequestCallback("setVariable", request_setVariable);
3085   g_vsc.RegisterRequestCallback("source", request_source);
3086   g_vsc.RegisterRequestCallback("stackTrace", request_stackTrace);
3087   g_vsc.RegisterRequestCallback("stepIn", request_stepIn);
3088   g_vsc.RegisterRequestCallback("stepOut", request_stepOut);
3089   g_vsc.RegisterRequestCallback("threads", request_threads);
3090   g_vsc.RegisterRequestCallback("variables", request_variables);
3091   // Custom requests
3092   g_vsc.RegisterRequestCallback("compileUnits", request_compileUnits);
3093   g_vsc.RegisterRequestCallback("modules", request_modules);
3094   // Testing requests
3095   g_vsc.RegisterRequestCallback("_testGetTargetBreakpoints",
3096                                 request__testGetTargetBreakpoints);
3097 }
3098 
3099 } // anonymous namespace
3100 
printHelp(LLDBVSCodeOptTable & table,llvm::StringRef tool_name)3101 static void printHelp(LLDBVSCodeOptTable &table, llvm::StringRef tool_name) {
3102   std::string usage_str = tool_name.str() + " options";
3103   table.printHelp(llvm::outs(), usage_str.c_str(), "LLDB VSCode", false);
3104 
3105   std::string examples = R"___(
3106 EXAMPLES:
3107   The debug adapter can be started in two modes.
3108 
3109   Running lldb-vscode without any arguments will start communicating with the
3110   parent over stdio. Passing a port number causes lldb-vscode to start listening
3111   for connections on that port.
3112 
3113     lldb-vscode -p <port>
3114 
3115   Passing --wait-for-debugger will pause the process at startup and wait for a
3116   debugger to attach to the process.
3117 
3118     lldb-vscode -g
3119   )___";
3120   llvm::outs() << examples;
3121 }
3122 
3123 // If --launch-target is provided, this instance of lldb-vscode becomes a
3124 // runInTerminal launcher. It will ultimately launch the program specified in
3125 // the --launch-target argument, which is the original program the user wanted
3126 // to debug. This is done in such a way that the actual debug adaptor can
3127 // place breakpoints at the beginning of the program.
3128 //
3129 // The launcher will communicate with the debug adaptor using a fifo file in the
3130 // directory specified in the --comm-file argument.
3131 //
3132 // Regarding the actual flow, this launcher will first notify the debug adaptor
3133 // of its pid. Then, the launcher will be in a pending state waiting to be
3134 // attached by the adaptor.
3135 //
3136 // Once attached and resumed, the launcher will exec and become the program
3137 // specified by --launch-target, which is the original target the
3138 // user wanted to run.
3139 //
3140 // In case of errors launching the target, a suitable error message will be
3141 // emitted to the debug adaptor.
LaunchRunInTerminalTarget(llvm::opt::Arg & target_arg,llvm::StringRef comm_file,char * argv[])3142 void LaunchRunInTerminalTarget(llvm::opt::Arg &target_arg,
3143                                llvm::StringRef comm_file, char *argv[]) {
3144 #if defined(_WIN32)
3145   llvm::errs() << "runInTerminal is only supported on POSIX systems\n";
3146   exit(EXIT_FAILURE);
3147 #else
3148   RunInTerminalLauncherCommChannel comm_channel(comm_file);
3149   if (llvm::Error err = comm_channel.NotifyPid()) {
3150     llvm::errs() << llvm::toString(std::move(err)) << "\n";
3151     exit(EXIT_FAILURE);
3152   }
3153 
3154   // We will wait to be attached with a timeout. We don't wait indefinitely
3155   // using a signal to prevent being paused forever.
3156 
3157   // This env var should be used only for tests.
3158   const char *timeout_env_var = getenv("LLDB_VSCODE_RIT_TIMEOUT_IN_MS");
3159   int timeout_in_ms =
3160       timeout_env_var != nullptr ? atoi(timeout_env_var) : 20000;
3161   if (llvm::Error err = comm_channel.WaitUntilDebugAdaptorAttaches(
3162           std::chrono::milliseconds(timeout_in_ms))) {
3163     llvm::errs() << llvm::toString(std::move(err)) << "\n";
3164     exit(EXIT_FAILURE);
3165   }
3166 
3167   const char *target = target_arg.getValue();
3168   execvp(target, argv);
3169 
3170   std::string error = std::strerror(errno);
3171   comm_channel.NotifyError(error);
3172   llvm::errs() << error << "\n";
3173   exit(EXIT_FAILURE);
3174 #endif
3175 }
3176 
3177 /// used only by TestVSCode_redirection_to_console.py
redirection_test()3178 void redirection_test() {
3179   printf("stdout message\n");
3180   fprintf(stderr, "stderr message\n");
3181   fflush(stdout);
3182   fflush(stderr);
3183 }
3184 
3185 /// Redirect stdout and stderr fo the IDE's console output.
3186 ///
3187 /// Errors in this operation will be printed to the log file and the IDE's
3188 /// console output as well.
3189 ///
3190 /// \return
3191 ///     A fd pointing to the original stdout.
SetupStdoutStderrRedirection()3192 int SetupStdoutStderrRedirection() {
3193   int stdoutfd = fileno(stdout);
3194   int new_stdout_fd = dup(stdoutfd);
3195   auto output_callback_stderr = [](llvm::StringRef data) {
3196     g_vsc.SendOutput(OutputType::Stderr, data);
3197   };
3198   auto output_callback_stdout = [](llvm::StringRef data) {
3199     g_vsc.SendOutput(OutputType::Stdout, data);
3200   };
3201   if (llvm::Error err = RedirectFd(stdoutfd, output_callback_stdout)) {
3202     std::string error_message = llvm::toString(std::move(err));
3203     if (g_vsc.log)
3204       *g_vsc.log << error_message << std::endl;
3205     output_callback_stderr(error_message);
3206   }
3207   if (llvm::Error err = RedirectFd(fileno(stderr), output_callback_stderr)) {
3208     std::string error_message = llvm::toString(std::move(err));
3209     if (g_vsc.log)
3210       *g_vsc.log << error_message << std::endl;
3211     output_callback_stderr(error_message);
3212   }
3213 
3214   /// used only by TestVSCode_redirection_to_console.py
3215   if (getenv("LLDB_VSCODE_TEST_STDOUT_STDERR_REDIRECTION") != nullptr)
3216     redirection_test();
3217   return new_stdout_fd;
3218 }
3219 
main(int argc,char * argv[])3220 int main(int argc, char *argv[]) {
3221   llvm::InitLLVM IL(argc, argv, /*InstallPipeSignalExitHandler=*/false);
3222   llvm::PrettyStackTraceProgram X(argc, argv);
3223 
3224   llvm::SmallString<256> program_path(argv[0]);
3225   llvm::sys::fs::make_absolute(program_path);
3226   g_vsc.debug_adaptor_path = program_path.str().str();
3227 
3228   LLDBVSCodeOptTable T;
3229   unsigned MAI, MAC;
3230   llvm::ArrayRef<const char *> ArgsArr = llvm::ArrayRef(argv + 1, argc);
3231   llvm::opt::InputArgList input_args = T.ParseArgs(ArgsArr, MAI, MAC);
3232 
3233   if (input_args.hasArg(OPT_help)) {
3234     printHelp(T, llvm::sys::path::filename(argv[0]));
3235     return EXIT_SUCCESS;
3236   }
3237 
3238   if (llvm::opt::Arg *target_arg = input_args.getLastArg(OPT_launch_target)) {
3239     if (llvm::opt::Arg *comm_file = input_args.getLastArg(OPT_comm_file)) {
3240       int target_args_pos = argc;
3241       for (int i = 0; i < argc; i++)
3242         if (strcmp(argv[i], "--launch-target") == 0) {
3243           target_args_pos = i + 1;
3244           break;
3245         }
3246       LaunchRunInTerminalTarget(*target_arg, comm_file->getValue(),
3247                                 argv + target_args_pos);
3248     } else {
3249       llvm::errs() << "\"--launch-target\" requires \"--comm-file\" to be "
3250                       "specified\n";
3251       return EXIT_FAILURE;
3252     }
3253   }
3254 
3255   // stdout/stderr redirection to the IDE's console
3256   int new_stdout_fd = SetupStdoutStderrRedirection();
3257 
3258   // Initialize LLDB first before we do anything.
3259   lldb::SBDebugger::Initialize();
3260 
3261   // Terminate the debugger before the C++ destructor chain kicks in.
3262   auto terminate_debugger =
3263       llvm::make_scope_exit([] { lldb::SBDebugger::Terminate(); });
3264 
3265   RegisterRequestCallbacks();
3266 
3267   int portno = -1;
3268 
3269   if (auto *arg = input_args.getLastArg(OPT_port)) {
3270     auto optarg = arg->getValue();
3271     char *remainder;
3272     portno = strtol(optarg, &remainder, 0);
3273     if (remainder == optarg || *remainder != '\0') {
3274       fprintf(stderr, "'%s' is not a valid port number.\n", optarg);
3275       return EXIT_FAILURE;
3276     }
3277   }
3278 
3279 #if !defined(_WIN32)
3280   if (input_args.hasArg(OPT_wait_for_debugger)) {
3281     printf("Paused waiting for debugger to attach (pid = %i)...\n", getpid());
3282     pause();
3283   }
3284 #endif
3285   if (portno != -1) {
3286     printf("Listening on port %i...\n", portno);
3287     SOCKET socket_fd = AcceptConnection(portno);
3288     if (socket_fd >= 0) {
3289       g_vsc.input.descriptor = StreamDescriptor::from_socket(socket_fd, true);
3290       g_vsc.output.descriptor = StreamDescriptor::from_socket(socket_fd, false);
3291     } else {
3292       return EXIT_FAILURE;
3293     }
3294   } else {
3295     g_vsc.input.descriptor = StreamDescriptor::from_file(fileno(stdin), false);
3296     g_vsc.output.descriptor = StreamDescriptor::from_file(new_stdout_fd, false);
3297   }
3298 
3299   while (!g_vsc.sent_terminated_event) {
3300     llvm::json::Object object;
3301     lldb_vscode::PacketStatus status = g_vsc.GetNextObject(object);
3302     if (status == lldb_vscode::PacketStatus::EndOfFile)
3303       break;
3304     if (status != lldb_vscode::PacketStatus::Success)
3305       return 1; // Fatal error
3306 
3307     if (!g_vsc.HandleObject(object))
3308       return 1;
3309   }
3310 
3311   return EXIT_SUCCESS;
3312 }
3313