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