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