Coverage Report

Created: 2023-09-12 09:32

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