Coverage Report

Created: 2022-01-18 06:27

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