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 = 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 EmplaceSafeString(item, "text", match); 957 if (description.empty()) 958 EmplaceSafeString(item, "label", match); 959 else 960 EmplaceSafeString(item, "label", match + " -- " + description); 961 962 targets.emplace_back(std::move(item)); 963 } 964 965 body.try_emplace("targets", std::move(targets)); 966 response.try_emplace("body", std::move(body)); 967 g_vsc.SendJSON(llvm::json::Value(std::move(response))); 968 } 969 970 // "EvaluateRequest": { 971 // "allOf": [ { "$ref": "#/definitions/Request" }, { 972 // "type": "object", 973 // "description": "Evaluate request; value of command field is 'evaluate'. 974 // Evaluates the given expression in the context of the 975 // top most stack frame. The expression has access to any 976 // variables and arguments that are in scope.", 977 // "properties": { 978 // "command": { 979 // "type": "string", 980 // "enum": [ "evaluate" ] 981 // }, 982 // "arguments": { 983 // "$ref": "#/definitions/EvaluateArguments" 984 // } 985 // }, 986 // "required": [ "command", "arguments" ] 987 // }] 988 // }, 989 // "EvaluateArguments": { 990 // "type": "object", 991 // "description": "Arguments for 'evaluate' request.", 992 // "properties": { 993 // "expression": { 994 // "type": "string", 995 // "description": "The expression to evaluate." 996 // }, 997 // "frameId": { 998 // "type": "integer", 999 // "description": "Evaluate the expression in the scope of this stack 1000 // frame. If not specified, the expression is evaluated 1001 // in the global scope." 1002 // }, 1003 // "context": { 1004 // "type": "string", 1005 // "_enum": [ "watch", "repl", "hover" ], 1006 // "enumDescriptions": [ 1007 // "evaluate is run in a watch.", 1008 // "evaluate is run from REPL console.", 1009 // "evaluate is run from a data hover." 1010 // ], 1011 // "description": "The context in which the evaluate request is run." 1012 // }, 1013 // "format": { 1014 // "$ref": "#/definitions/ValueFormat", 1015 // "description": "Specifies details on how to format the Evaluate 1016 // result." 1017 // } 1018 // }, 1019 // "required": [ "expression" ] 1020 // }, 1021 // "EvaluateResponse": { 1022 // "allOf": [ { "$ref": "#/definitions/Response" }, { 1023 // "type": "object", 1024 // "description": "Response to 'evaluate' request.", 1025 // "properties": { 1026 // "body": { 1027 // "type": "object", 1028 // "properties": { 1029 // "result": { 1030 // "type": "string", 1031 // "description": "The result of the evaluate request." 1032 // }, 1033 // "type": { 1034 // "type": "string", 1035 // "description": "The optional type of the evaluate result." 1036 // }, 1037 // "presentationHint": { 1038 // "$ref": "#/definitions/VariablePresentationHint", 1039 // "description": "Properties of a evaluate result that can be 1040 // used to determine how to render the result in 1041 // the UI." 1042 // }, 1043 // "variablesReference": { 1044 // "type": "number", 1045 // "description": "If variablesReference is > 0, the evaluate 1046 // result is structured and its children can be 1047 // retrieved by passing variablesReference to the 1048 // VariablesRequest." 1049 // }, 1050 // "namedVariables": { 1051 // "type": "number", 1052 // "description": "The number of named child variables. The 1053 // client can use this optional information to 1054 // present the variables in a paged UI and fetch 1055 // them in chunks." 1056 // }, 1057 // "indexedVariables": { 1058 // "type": "number", 1059 // "description": "The number of indexed child variables. The 1060 // client can use this optional information to 1061 // present the variables in a paged UI and fetch 1062 // them in chunks." 1063 // } 1064 // }, 1065 // "required": [ "result", "variablesReference" ] 1066 // } 1067 // }, 1068 // "required": [ "body" ] 1069 // }] 1070 // } 1071 void request_evaluate(const llvm::json::Object &request) { 1072 llvm::json::Object response; 1073 FillResponse(request, response); 1074 llvm::json::Object body; 1075 auto arguments = request.getObject("arguments"); 1076 lldb::SBFrame frame = g_vsc.GetLLDBFrame(*arguments); 1077 const auto expression = GetString(arguments, "expression"); 1078 1079 if (!expression.empty() && expression[0] == '`') { 1080 auto result = RunLLDBCommands(llvm::StringRef(), 1081 {expression.substr(1)}); 1082 EmplaceSafeString(body, "result", result); 1083 body.try_emplace("variablesReference", (int64_t)0); 1084 } else { 1085 // Always try to get the answer from the local variables if possible. If 1086 // this fails, then actually evaluate an expression using the expression 1087 // parser. "frame variable" is more reliable than the expression parser in 1088 // many cases and it is faster. 1089 lldb::SBValue value = frame.GetValueForVariablePath( 1090 expression.data(), lldb::eDynamicDontRunTarget); 1091 if (value.GetError().Fail()) 1092 value = frame.EvaluateExpression(expression.data()); 1093 if (value.GetError().Fail()) { 1094 response["success"] = llvm::json::Value(false); 1095 // This error object must live until we're done with the pointer returned 1096 // by GetCString(). 1097 lldb::SBError error = value.GetError(); 1098 const char *error_cstr = error.GetCString(); 1099 if (error_cstr && error_cstr[0]) 1100 EmplaceSafeString(response, "message", std::string(error_cstr)); 1101 else 1102 EmplaceSafeString(response, "message", "evaluate failed"); 1103 } else { 1104 SetValueForKey(value, body, "result"); 1105 auto value_typename = value.GetType().GetDisplayTypeName(); 1106 EmplaceSafeString(body, "type", value_typename ? value_typename : NO_TYPENAME); 1107 if (value.MightHaveChildren()) { 1108 auto variablesReference = VARIDX_TO_VARREF(g_vsc.variables.GetSize()); 1109 g_vsc.variables.Append(value); 1110 body.try_emplace("variablesReference", variablesReference); 1111 } else { 1112 body.try_emplace("variablesReference", (int64_t)0); 1113 } 1114 } 1115 } 1116 response.try_emplace("body", std::move(body)); 1117 g_vsc.SendJSON(llvm::json::Value(std::move(response))); 1118 } 1119 1120 // "InitializeRequest": { 1121 // "allOf": [ { "$ref": "#/definitions/Request" }, { 1122 // "type": "object", 1123 // "description": "Initialize request; value of command field is 1124 // 'initialize'.", 1125 // "properties": { 1126 // "command": { 1127 // "type": "string", 1128 // "enum": [ "initialize" ] 1129 // }, 1130 // "arguments": { 1131 // "$ref": "#/definitions/InitializeRequestArguments" 1132 // } 1133 // }, 1134 // "required": [ "command", "arguments" ] 1135 // }] 1136 // }, 1137 // "InitializeRequestArguments": { 1138 // "type": "object", 1139 // "description": "Arguments for 'initialize' request.", 1140 // "properties": { 1141 // "clientID": { 1142 // "type": "string", 1143 // "description": "The ID of the (frontend) client using this adapter." 1144 // }, 1145 // "adapterID": { 1146 // "type": "string", 1147 // "description": "The ID of the debug adapter." 1148 // }, 1149 // "locale": { 1150 // "type": "string", 1151 // "description": "The ISO-639 locale of the (frontend) client using 1152 // this adapter, e.g. en-US or de-CH." 1153 // }, 1154 // "linesStartAt1": { 1155 // "type": "boolean", 1156 // "description": "If true all line numbers are 1-based (default)." 1157 // }, 1158 // "columnsStartAt1": { 1159 // "type": "boolean", 1160 // "description": "If true all column numbers are 1-based (default)." 1161 // }, 1162 // "pathFormat": { 1163 // "type": "string", 1164 // "_enum": [ "path", "uri" ], 1165 // "description": "Determines in what format paths are specified. The 1166 // default is 'path', which is the native format." 1167 // }, 1168 // "supportsVariableType": { 1169 // "type": "boolean", 1170 // "description": "Client supports the optional type attribute for 1171 // variables." 1172 // }, 1173 // "supportsVariablePaging": { 1174 // "type": "boolean", 1175 // "description": "Client supports the paging of variables." 1176 // }, 1177 // "supportsRunInTerminalRequest": { 1178 // "type": "boolean", 1179 // "description": "Client supports the runInTerminal request." 1180 // } 1181 // }, 1182 // "required": [ "adapterID" ] 1183 // }, 1184 // "InitializeResponse": { 1185 // "allOf": [ { "$ref": "#/definitions/Response" }, { 1186 // "type": "object", 1187 // "description": "Response to 'initialize' request.", 1188 // "properties": { 1189 // "body": { 1190 // "$ref": "#/definitions/Capabilities", 1191 // "description": "The capabilities of this debug adapter." 1192 // } 1193 // } 1194 // }] 1195 // } 1196 void request_initialize(const llvm::json::Object &request) { 1197 g_vsc.debugger = lldb::SBDebugger::Create(true /*source_init_files*/); 1198 // Create an empty target right away since we might get breakpoint requests 1199 // before we are given an executable to launch in a "launch" request, or a 1200 // executable when attaching to a process by process ID in a "attach" 1201 // request. 1202 FILE *out = llvm::sys::RetryAfterSignal(nullptr, fopen, dev_null_path, "w"); 1203 if (out) { 1204 // Set the output and error file handles to redirect into nothing otherwise 1205 // if any code in LLDB prints to the debugger file handles, the output and 1206 // error file handles are initialized to STDOUT and STDERR and any output 1207 // will kill our debug session. 1208 g_vsc.debugger.SetOutputFileHandle(out, true); 1209 g_vsc.debugger.SetErrorFileHandle(out, false); 1210 } 1211 1212 g_vsc.target = g_vsc.debugger.CreateTarget(nullptr); 1213 lldb::SBListener listener = g_vsc.debugger.GetListener(); 1214 listener.StartListeningForEvents( 1215 g_vsc.target.GetBroadcaster(), 1216 lldb::SBTarget::eBroadcastBitBreakpointChanged); 1217 listener.StartListeningForEvents(g_vsc.broadcaster, 1218 eBroadcastBitStopEventThread); 1219 // Start our event thread so we can receive events from the debugger, target, 1220 // process and more. 1221 g_vsc.event_thread = std::thread(EventThreadFunction); 1222 1223 llvm::json::Object response; 1224 FillResponse(request, response); 1225 llvm::json::Object body; 1226 // The debug adapter supports the configurationDoneRequest. 1227 body.try_emplace("supportsConfigurationDoneRequest", true); 1228 // The debug adapter supports function breakpoints. 1229 body.try_emplace("supportsFunctionBreakpoints", true); 1230 // The debug adapter supports conditional breakpoints. 1231 body.try_emplace("supportsConditionalBreakpoints", true); 1232 // The debug adapter supports breakpoints that break execution after a 1233 // specified number of hits. 1234 body.try_emplace("supportsHitConditionalBreakpoints", true); 1235 // The debug adapter supports a (side effect free) evaluate request for 1236 // data hovers. 1237 body.try_emplace("supportsEvaluateForHovers", true); 1238 // Available filters or options for the setExceptionBreakpoints request. 1239 llvm::json::Array filters; 1240 for (const auto &exc_bp : g_vsc.exception_breakpoints) { 1241 filters.emplace_back(CreateExceptionBreakpointFilter(exc_bp)); 1242 } 1243 body.try_emplace("exceptionBreakpointFilters", std::move(filters)); 1244 // The debug adapter supports stepping back via the stepBack and 1245 // reverseContinue requests. 1246 body.try_emplace("supportsStepBack", false); 1247 // The debug adapter supports setting a variable to a value. 1248 body.try_emplace("supportsSetVariable", true); 1249 // The debug adapter supports restarting a frame. 1250 body.try_emplace("supportsRestartFrame", false); 1251 // The debug adapter supports the gotoTargetsRequest. 1252 body.try_emplace("supportsGotoTargetsRequest", false); 1253 // The debug adapter supports the stepInTargetsRequest. 1254 body.try_emplace("supportsStepInTargetsRequest", false); 1255 // The debug adapter supports the completionsRequest. 1256 body.try_emplace("supportsCompletionsRequest", true); 1257 // The debug adapter supports the modules request. 1258 body.try_emplace("supportsModulesRequest", false); 1259 // The set of additional module information exposed by the debug adapter. 1260 // body.try_emplace("additionalModuleColumns"] = ColumnDescriptor 1261 // Checksum algorithms supported by the debug adapter. 1262 // body.try_emplace("supportedChecksumAlgorithms"] = ChecksumAlgorithm 1263 // The debug adapter supports the RestartRequest. In this case a client 1264 // should not implement 'restart' by terminating and relaunching the adapter 1265 // but by calling the RestartRequest. 1266 body.try_emplace("supportsRestartRequest", false); 1267 // The debug adapter supports 'exceptionOptions' on the 1268 // setExceptionBreakpoints request. 1269 body.try_emplace("supportsExceptionOptions", true); 1270 // The debug adapter supports a 'format' attribute on the stackTraceRequest, 1271 // variablesRequest, and evaluateRequest. 1272 body.try_emplace("supportsValueFormattingOptions", true); 1273 // The debug adapter supports the exceptionInfo request. 1274 body.try_emplace("supportsExceptionInfoRequest", true); 1275 // The debug adapter supports the 'terminateDebuggee' attribute on the 1276 // 'disconnect' request. 1277 body.try_emplace("supportTerminateDebuggee", true); 1278 // The debug adapter supports the delayed loading of parts of the stack, 1279 // which requires that both the 'startFrame' and 'levels' arguments and the 1280 // 'totalFrames' result of the 'StackTrace' request are supported. 1281 body.try_emplace("supportsDelayedStackTraceLoading", true); 1282 // The debug adapter supports the 'loadedSources' request. 1283 body.try_emplace("supportsLoadedSourcesRequest", false); 1284 1285 response.try_emplace("body", std::move(body)); 1286 g_vsc.SendJSON(llvm::json::Value(std::move(response))); 1287 } 1288 1289 // "LaunchRequest": { 1290 // "allOf": [ { "$ref": "#/definitions/Request" }, { 1291 // "type": "object", 1292 // "description": "Launch request; value of command field is 'launch'.", 1293 // "properties": { 1294 // "command": { 1295 // "type": "string", 1296 // "enum": [ "launch" ] 1297 // }, 1298 // "arguments": { 1299 // "$ref": "#/definitions/LaunchRequestArguments" 1300 // } 1301 // }, 1302 // "required": [ "command", "arguments" ] 1303 // }] 1304 // }, 1305 // "LaunchRequestArguments": { 1306 // "type": "object", 1307 // "description": "Arguments for 'launch' request.", 1308 // "properties": { 1309 // "noDebug": { 1310 // "type": "boolean", 1311 // "description": "If noDebug is true the launch request should launch 1312 // the program without enabling debugging." 1313 // } 1314 // } 1315 // }, 1316 // "LaunchResponse": { 1317 // "allOf": [ { "$ref": "#/definitions/Response" }, { 1318 // "type": "object", 1319 // "description": "Response to 'launch' request. This is just an 1320 // acknowledgement, so no body field is required." 1321 // }] 1322 // } 1323 void request_launch(const llvm::json::Object &request) { 1324 llvm::json::Object response; 1325 lldb::SBError error; 1326 FillResponse(request, response); 1327 auto arguments = request.getObject("arguments"); 1328 g_vsc.init_commands = GetStrings(arguments, "initCommands"); 1329 g_vsc.pre_run_commands = GetStrings(arguments, "preRunCommands"); 1330 g_vsc.stop_commands = GetStrings(arguments, "stopCommands"); 1331 g_vsc.exit_commands = GetStrings(arguments, "exitCommands"); 1332 auto launchCommands = GetStrings(arguments, "launchCommands"); 1333 g_vsc.stop_at_entry = GetBoolean(arguments, "stopOnEntry", false); 1334 const auto debuggerRoot = GetString(arguments, "debuggerRoot"); 1335 1336 // This is a hack for loading DWARF in .o files on Mac where the .o files 1337 // in the debug map of the main executable have relative paths which require 1338 // the lldb-vscode binary to have its working directory set to that relative 1339 // root for the .o files in order to be able to load debug info. 1340 if (!debuggerRoot.empty()) { 1341 llvm::sys::fs::set_current_path(debuggerRoot.data()); 1342 } 1343 1344 SetSourceMapFromArguments(*arguments); 1345 1346 // Run any initialize LLDB commands the user specified in the launch.json 1347 g_vsc.RunInitCommands(); 1348 1349 // Grab the current working directory if there is one and set it in the 1350 // launch info. 1351 const auto cwd = GetString(arguments, "cwd"); 1352 if (!cwd.empty()) 1353 g_vsc.launch_info.SetWorkingDirectory(cwd.data()); 1354 1355 // Grab the name of the program we need to debug and set it as the first 1356 // argument that will be passed to the program we will debug. 1357 llvm::StringRef program = GetString(arguments, "program"); 1358 if (!program.empty()) { 1359 lldb::SBFileSpec program_fspec(program.data(), true /*resolve_path*/); 1360 g_vsc.launch_info.SetExecutableFile(program_fspec, 1361 true /*add_as_first_arg*/); 1362 const char *target_triple = nullptr; 1363 const char *uuid_cstr = nullptr; 1364 // Stand alone debug info file if different from executable 1365 const char *symfile = nullptr; 1366 lldb::SBModule module = g_vsc.target.AddModule( 1367 program.data(), target_triple, uuid_cstr, symfile); 1368 if (!module.IsValid()) { 1369 response["success"] = llvm::json::Value(false); 1370 1371 EmplaceSafeString( 1372 response, "message", 1373 llvm::formatv("Could not load program '{0}'.", program).str()); 1374 g_vsc.SendJSON(llvm::json::Value(std::move(response))); 1375 return; 1376 } 1377 } 1378 1379 // Extract any extra arguments and append them to our program arguments for 1380 // when we launch 1381 auto args = GetStrings(arguments, "args"); 1382 if (!args.empty()) 1383 g_vsc.launch_info.SetArguments(MakeArgv(args).data(), true); 1384 1385 // Pass any environment variables along that the user specified. 1386 auto envs = GetStrings(arguments, "env"); 1387 if (!envs.empty()) 1388 g_vsc.launch_info.SetEnvironmentEntries(MakeArgv(envs).data(), true); 1389 1390 auto flags = g_vsc.launch_info.GetLaunchFlags(); 1391 1392 if (GetBoolean(arguments, "disableASLR", true)) 1393 flags |= lldb::eLaunchFlagDisableASLR; 1394 if (GetBoolean(arguments, "disableSTDIO", false)) 1395 flags |= lldb::eLaunchFlagDisableSTDIO; 1396 if (GetBoolean(arguments, "shellExpandArguments", false)) 1397 flags |= lldb::eLaunchFlagShellExpandArguments; 1398 const bool detatchOnError = GetBoolean(arguments, "detachOnError", false); 1399 g_vsc.launch_info.SetDetachOnError(detatchOnError); 1400 g_vsc.launch_info.SetLaunchFlags(flags | lldb::eLaunchFlagDebug | 1401 lldb::eLaunchFlagStopAtEntry); 1402 1403 // Run any pre run LLDB commands the user specified in the launch.json 1404 g_vsc.RunPreRunCommands(); 1405 if (launchCommands.empty()) { 1406 // Disable async events so the launch will be successful when we return from 1407 // the launch call and the launch will happen synchronously 1408 g_vsc.debugger.SetAsync(false); 1409 g_vsc.target.Launch(g_vsc.launch_info, error); 1410 g_vsc.debugger.SetAsync(true); 1411 } else { 1412 g_vsc.RunLLDBCommands("Running launchCommands:", launchCommands); 1413 // The custom commands might have created a new target so we should use the 1414 // selected target after these commands are run. 1415 g_vsc.target = g_vsc.debugger.GetSelectedTarget(); 1416 } 1417 1418 if (error.Fail()) { 1419 response["success"] = llvm::json::Value(false); 1420 EmplaceSafeString(response, "message", std::string(error.GetCString())); 1421 } 1422 g_vsc.SendJSON(llvm::json::Value(std::move(response))); 1423 1424 SendProcessEvent(Launch); 1425 g_vsc.SendJSON(llvm::json::Value(CreateEventObject("initialized"))); 1426 // Reenable async events and start the event thread to catch async events. 1427 // g_vsc.debugger.SetAsync(true); 1428 } 1429 1430 // "NextRequest": { 1431 // "allOf": [ { "$ref": "#/definitions/Request" }, { 1432 // "type": "object", 1433 // "description": "Next request; value of command field is 'next'. The 1434 // request starts the debuggee to run again for one step. 1435 // The debug adapter first sends the NextResponse and then 1436 // a StoppedEvent (event type 'step') after the step has 1437 // completed.", 1438 // "properties": { 1439 // "command": { 1440 // "type": "string", 1441 // "enum": [ "next" ] 1442 // }, 1443 // "arguments": { 1444 // "$ref": "#/definitions/NextArguments" 1445 // } 1446 // }, 1447 // "required": [ "command", "arguments" ] 1448 // }] 1449 // }, 1450 // "NextArguments": { 1451 // "type": "object", 1452 // "description": "Arguments for 'next' request.", 1453 // "properties": { 1454 // "threadId": { 1455 // "type": "integer", 1456 // "description": "Execute 'next' for this thread." 1457 // } 1458 // }, 1459 // "required": [ "threadId" ] 1460 // }, 1461 // "NextResponse": { 1462 // "allOf": [ { "$ref": "#/definitions/Response" }, { 1463 // "type": "object", 1464 // "description": "Response to 'next' request. This is just an 1465 // acknowledgement, so no body field is required." 1466 // }] 1467 // } 1468 void request_next(const llvm::json::Object &request) { 1469 llvm::json::Object response; 1470 FillResponse(request, response); 1471 auto arguments = request.getObject("arguments"); 1472 lldb::SBThread thread = g_vsc.GetLLDBThread(*arguments); 1473 if (thread.IsValid()) { 1474 // Remember the thread ID that caused the resume so we can set the 1475 // "threadCausedFocus" boolean value in the "stopped" events. 1476 g_vsc.focus_tid = thread.GetThreadID(); 1477 thread.StepOver(); 1478 } else { 1479 response["success"] = llvm::json::Value(false); 1480 } 1481 g_vsc.SendJSON(llvm::json::Value(std::move(response))); 1482 } 1483 1484 // "PauseRequest": { 1485 // "allOf": [ { "$ref": "#/definitions/Request" }, { 1486 // "type": "object", 1487 // "description": "Pause request; value of command field is 'pause'. The 1488 // request suspenses the debuggee. The debug adapter first sends the 1489 // PauseResponse and then a StoppedEvent (event type 'pause') after the 1490 // thread has been paused successfully.", "properties": { 1491 // "command": { 1492 // "type": "string", 1493 // "enum": [ "pause" ] 1494 // }, 1495 // "arguments": { 1496 // "$ref": "#/definitions/PauseArguments" 1497 // } 1498 // }, 1499 // "required": [ "command", "arguments" ] 1500 // }] 1501 // }, 1502 // "PauseArguments": { 1503 // "type": "object", 1504 // "description": "Arguments for 'pause' request.", 1505 // "properties": { 1506 // "threadId": { 1507 // "type": "integer", 1508 // "description": "Pause execution for this thread." 1509 // } 1510 // }, 1511 // "required": [ "threadId" ] 1512 // }, 1513 // "PauseResponse": { 1514 // "allOf": [ { "$ref": "#/definitions/Response" }, { 1515 // "type": "object", 1516 // "description": "Response to 'pause' request. This is just an 1517 // acknowledgement, so no body field is required." 1518 // }] 1519 // } 1520 void request_pause(const llvm::json::Object &request) { 1521 llvm::json::Object response; 1522 FillResponse(request, response); 1523 lldb::SBProcess process = g_vsc.target.GetProcess(); 1524 lldb::SBError error = process.Stop(); 1525 g_vsc.SendJSON(llvm::json::Value(std::move(response))); 1526 } 1527 1528 // "ScopesRequest": { 1529 // "allOf": [ { "$ref": "#/definitions/Request" }, { 1530 // "type": "object", 1531 // "description": "Scopes request; value of command field is 'scopes'. The 1532 // request returns the variable scopes for a given stackframe ID.", 1533 // "properties": { 1534 // "command": { 1535 // "type": "string", 1536 // "enum": [ "scopes" ] 1537 // }, 1538 // "arguments": { 1539 // "$ref": "#/definitions/ScopesArguments" 1540 // } 1541 // }, 1542 // "required": [ "command", "arguments" ] 1543 // }] 1544 // }, 1545 // "ScopesArguments": { 1546 // "type": "object", 1547 // "description": "Arguments for 'scopes' request.", 1548 // "properties": { 1549 // "frameId": { 1550 // "type": "integer", 1551 // "description": "Retrieve the scopes for this stackframe." 1552 // } 1553 // }, 1554 // "required": [ "frameId" ] 1555 // }, 1556 // "ScopesResponse": { 1557 // "allOf": [ { "$ref": "#/definitions/Response" }, { 1558 // "type": "object", 1559 // "description": "Response to 'scopes' request.", 1560 // "properties": { 1561 // "body": { 1562 // "type": "object", 1563 // "properties": { 1564 // "scopes": { 1565 // "type": "array", 1566 // "items": { 1567 // "$ref": "#/definitions/Scope" 1568 // }, 1569 // "description": "The scopes of the stackframe. If the array has 1570 // length zero, there are no scopes available." 1571 // } 1572 // }, 1573 // "required": [ "scopes" ] 1574 // } 1575 // }, 1576 // "required": [ "body" ] 1577 // }] 1578 // } 1579 void request_scopes(const llvm::json::Object &request) { 1580 llvm::json::Object response; 1581 FillResponse(request, response); 1582 llvm::json::Object body; 1583 auto arguments = request.getObject("arguments"); 1584 lldb::SBFrame frame = g_vsc.GetLLDBFrame(*arguments); 1585 g_vsc.variables.Clear(); 1586 g_vsc.variables.Append(frame.GetVariables(true, // arguments 1587 true, // locals 1588 false, // statics 1589 true)); // in_scope_only 1590 g_vsc.num_locals = g_vsc.variables.GetSize(); 1591 g_vsc.variables.Append(frame.GetVariables(false, // arguments 1592 false, // locals 1593 true, // statics 1594 true)); // in_scope_only 1595 g_vsc.num_globals = g_vsc.variables.GetSize() - (g_vsc.num_locals); 1596 g_vsc.variables.Append(frame.GetRegisters()); 1597 g_vsc.num_regs = 1598 g_vsc.variables.GetSize() - (g_vsc.num_locals + g_vsc.num_globals); 1599 body.try_emplace("scopes", g_vsc.CreateTopLevelScopes()); 1600 response.try_emplace("body", std::move(body)); 1601 g_vsc.SendJSON(llvm::json::Value(std::move(response))); 1602 } 1603 1604 // "SetBreakpointsRequest": { 1605 // "allOf": [ { "$ref": "#/definitions/Request" }, { 1606 // "type": "object", 1607 // "description": "SetBreakpoints request; value of command field is 1608 // 'setBreakpoints'. Sets multiple breakpoints for a single source and 1609 // clears all previous breakpoints in that source. To clear all breakpoint 1610 // for a source, specify an empty array. When a breakpoint is hit, a 1611 // StoppedEvent (event type 'breakpoint') is generated.", "properties": { 1612 // "command": { 1613 // "type": "string", 1614 // "enum": [ "setBreakpoints" ] 1615 // }, 1616 // "arguments": { 1617 // "$ref": "#/definitions/SetBreakpointsArguments" 1618 // } 1619 // }, 1620 // "required": [ "command", "arguments" ] 1621 // }] 1622 // }, 1623 // "SetBreakpointsArguments": { 1624 // "type": "object", 1625 // "description": "Arguments for 'setBreakpoints' request.", 1626 // "properties": { 1627 // "source": { 1628 // "$ref": "#/definitions/Source", 1629 // "description": "The source location of the breakpoints; either 1630 // source.path or source.reference must be specified." 1631 // }, 1632 // "breakpoints": { 1633 // "type": "array", 1634 // "items": { 1635 // "$ref": "#/definitions/SourceBreakpoint" 1636 // }, 1637 // "description": "The code locations of the breakpoints." 1638 // }, 1639 // "lines": { 1640 // "type": "array", 1641 // "items": { 1642 // "type": "integer" 1643 // }, 1644 // "description": "Deprecated: The code locations of the breakpoints." 1645 // }, 1646 // "sourceModified": { 1647 // "type": "boolean", 1648 // "description": "A value of true indicates that the underlying source 1649 // has been modified which results in new breakpoint locations." 1650 // } 1651 // }, 1652 // "required": [ "source" ] 1653 // }, 1654 // "SetBreakpointsResponse": { 1655 // "allOf": [ { "$ref": "#/definitions/Response" }, { 1656 // "type": "object", 1657 // "description": "Response to 'setBreakpoints' request. Returned is 1658 // information about each breakpoint created by this request. This includes 1659 // the actual code location and whether the breakpoint could be verified. 1660 // The breakpoints returned are in the same order as the elements of the 1661 // 'breakpoints' (or the deprecated 'lines') in the 1662 // SetBreakpointsArguments.", "properties": { 1663 // "body": { 1664 // "type": "object", 1665 // "properties": { 1666 // "breakpoints": { 1667 // "type": "array", 1668 // "items": { 1669 // "$ref": "#/definitions/Breakpoint" 1670 // }, 1671 // "description": "Information about the breakpoints. The array 1672 // elements are in the same order as the elements of the 1673 // 'breakpoints' (or the deprecated 'lines') in the 1674 // SetBreakpointsArguments." 1675 // } 1676 // }, 1677 // "required": [ "breakpoints" ] 1678 // } 1679 // }, 1680 // "required": [ "body" ] 1681 // }] 1682 // }, 1683 // "SourceBreakpoint": { 1684 // "type": "object", 1685 // "description": "Properties of a breakpoint or logpoint passed to the 1686 // setBreakpoints request.", "properties": { 1687 // "line": { 1688 // "type": "integer", 1689 // "description": "The source line of the breakpoint or logpoint." 1690 // }, 1691 // "column": { 1692 // "type": "integer", 1693 // "description": "An optional source column of the breakpoint." 1694 // }, 1695 // "condition": { 1696 // "type": "string", 1697 // "description": "An optional expression for conditional breakpoints." 1698 // }, 1699 // "hitCondition": { 1700 // "type": "string", 1701 // "description": "An optional expression that controls how many hits of 1702 // the breakpoint are ignored. The backend is expected to interpret the 1703 // expression as needed." 1704 // }, 1705 // "logMessage": { 1706 // "type": "string", 1707 // "description": "If this attribute exists and is non-empty, the backend 1708 // must not 'break' (stop) but log the message instead. Expressions within 1709 // {} are interpolated." 1710 // } 1711 // }, 1712 // "required": [ "line" ] 1713 // } 1714 void request_setBreakpoints(const llvm::json::Object &request) { 1715 llvm::json::Object response; 1716 lldb::SBError error; 1717 FillResponse(request, response); 1718 auto arguments = request.getObject("arguments"); 1719 auto source = arguments->getObject("source"); 1720 const auto path = GetString(source, "path"); 1721 auto breakpoints = arguments->getArray("breakpoints"); 1722 llvm::json::Array response_breakpoints; 1723 // Decode the source breakpoint infos for this "setBreakpoints" request 1724 SourceBreakpointMap request_bps; 1725 for (const auto &bp : *breakpoints) { 1726 auto bp_obj = bp.getAsObject(); 1727 if (bp_obj) { 1728 SourceBreakpoint src_bp(*bp_obj); 1729 request_bps[src_bp.line] = std::move(src_bp); 1730 } 1731 } 1732 1733 // See if we already have breakpoints set for this source file from a 1734 // previous "setBreakpoints" request 1735 auto old_src_bp_pos = g_vsc.source_breakpoints.find(path); 1736 if (old_src_bp_pos != g_vsc.source_breakpoints.end()) { 1737 1738 // We have already set breakpoints in this source file and they are giving 1739 // use a new list of lines to set breakpoints on. Some breakpoints might 1740 // already be set, and some might not. We need to remove any breakpoints 1741 // whose lines are not contained in the any breakpoints lines in in the 1742 // "breakpoints" array. 1743 1744 // Delete any breakpoints in this source file that aren't in the 1745 // request_bps set. There is no call to remove breakpoints other than 1746 // calling this function with a smaller or empty "breakpoints" list. 1747 std::vector<uint32_t> remove_lines; 1748 for (auto &pair: old_src_bp_pos->second) { 1749 auto request_pos = request_bps.find(pair.first); 1750 if (request_pos == request_bps.end()) { 1751 // This breakpoint no longer exists in this source file, delete it 1752 g_vsc.target.BreakpointDelete(pair.second.bp.GetID()); 1753 remove_lines.push_back(pair.first); 1754 } else { 1755 pair.second.UpdateBreakpoint(request_pos->second); 1756 // Remove this breakpoint from the request breakpoints since we have 1757 // handled it here and we don't need to set a new breakpoint below. 1758 request_bps.erase(request_pos); 1759 // Add this breakpoint info to the response 1760 AppendBreakpoint(pair.second.bp, response_breakpoints); 1761 } 1762 } 1763 // Remove any lines from this existing source breakpoint map 1764 for (auto line: remove_lines) 1765 old_src_bp_pos->second.erase(line); 1766 1767 // Now add any breakpoint infos left over in request_bps are the 1768 // breakpoints that weren't set in this source file yet. We need to update 1769 // thread source breakpoint info for the source file in the variable 1770 // "old_src_bp_pos->second" so the info for this source file is up to date. 1771 for (auto &pair : request_bps) { 1772 pair.second.SetBreakpoint(path.data()); 1773 // Add this breakpoint info to the response 1774 AppendBreakpoint(pair.second.bp, response_breakpoints); 1775 old_src_bp_pos->second[pair.first] = std::move(pair.second); 1776 } 1777 } else { 1778 // No breakpoints were set for this source file yet. Set all breakpoints 1779 // for each line and add them to the response and create an entry in 1780 // g_vsc.source_breakpoints for this source file. 1781 for (auto &pair : request_bps) { 1782 pair.second.SetBreakpoint(path.data()); 1783 // Add this breakpoint info to the response 1784 AppendBreakpoint(pair.second.bp, response_breakpoints); 1785 } 1786 g_vsc.source_breakpoints[path] = std::move(request_bps); 1787 } 1788 1789 llvm::json::Object body; 1790 body.try_emplace("breakpoints", std::move(response_breakpoints)); 1791 response.try_emplace("body", std::move(body)); 1792 g_vsc.SendJSON(llvm::json::Value(std::move(response))); 1793 } 1794 1795 // "SetExceptionBreakpointsRequest": { 1796 // "allOf": [ { "$ref": "#/definitions/Request" }, { 1797 // "type": "object", 1798 // "description": "SetExceptionBreakpoints request; value of command field 1799 // is 'setExceptionBreakpoints'. The request configures the debuggers 1800 // response to thrown exceptions. If an exception is configured to break, a 1801 // StoppedEvent is fired (event type 'exception').", "properties": { 1802 // "command": { 1803 // "type": "string", 1804 // "enum": [ "setExceptionBreakpoints" ] 1805 // }, 1806 // "arguments": { 1807 // "$ref": "#/definitions/SetExceptionBreakpointsArguments" 1808 // } 1809 // }, 1810 // "required": [ "command", "arguments" ] 1811 // }] 1812 // }, 1813 // "SetExceptionBreakpointsArguments": { 1814 // "type": "object", 1815 // "description": "Arguments for 'setExceptionBreakpoints' request.", 1816 // "properties": { 1817 // "filters": { 1818 // "type": "array", 1819 // "items": { 1820 // "type": "string" 1821 // }, 1822 // "description": "IDs of checked exception options. The set of IDs is 1823 // returned via the 'exceptionBreakpointFilters' capability." 1824 // }, 1825 // "exceptionOptions": { 1826 // "type": "array", 1827 // "items": { 1828 // "$ref": "#/definitions/ExceptionOptions" 1829 // }, 1830 // "description": "Configuration options for selected exceptions." 1831 // } 1832 // }, 1833 // "required": [ "filters" ] 1834 // }, 1835 // "SetExceptionBreakpointsResponse": { 1836 // "allOf": [ { "$ref": "#/definitions/Response" }, { 1837 // "type": "object", 1838 // "description": "Response to 'setExceptionBreakpoints' request. This is 1839 // just an acknowledgement, so no body field is required." 1840 // }] 1841 // } 1842 void request_setExceptionBreakpoints(const llvm::json::Object &request) { 1843 llvm::json::Object response; 1844 lldb::SBError error; 1845 FillResponse(request, response); 1846 auto arguments = request.getObject("arguments"); 1847 auto filters = arguments->getArray("filters"); 1848 // Keep a list of any exception breakpoint filter names that weren't set 1849 // so we can clear any exception breakpoints if needed. 1850 std::set<std::string> unset_filters; 1851 for (const auto &bp : g_vsc.exception_breakpoints) 1852 unset_filters.insert(bp.filter); 1853 1854 for (const auto &value : *filters) { 1855 const auto filter = GetAsString(value); 1856 auto exc_bp = g_vsc.GetExceptionBreakpoint(filter); 1857 if (exc_bp) { 1858 exc_bp->SetBreakpoint(); 1859 unset_filters.erase(filter); 1860 } 1861 } 1862 for (const auto &filter : unset_filters) { 1863 auto exc_bp = g_vsc.GetExceptionBreakpoint(filter); 1864 if (exc_bp) 1865 exc_bp->ClearBreakpoint(); 1866 } 1867 g_vsc.SendJSON(llvm::json::Value(std::move(response))); 1868 } 1869 1870 // "SetFunctionBreakpointsRequest": { 1871 // "allOf": [ { "$ref": "#/definitions/Request" }, { 1872 // "type": "object", 1873 // "description": "SetFunctionBreakpoints request; value of command field is 1874 // 'setFunctionBreakpoints'. Sets multiple function breakpoints and clears 1875 // all previous function breakpoints. To clear all function breakpoint, 1876 // specify an empty array. When a function breakpoint is hit, a StoppedEvent 1877 // (event type 'function breakpoint') is generated.", "properties": { 1878 // "command": { 1879 // "type": "string", 1880 // "enum": [ "setFunctionBreakpoints" ] 1881 // }, 1882 // "arguments": { 1883 // "$ref": "#/definitions/SetFunctionBreakpointsArguments" 1884 // } 1885 // }, 1886 // "required": [ "command", "arguments" ] 1887 // }] 1888 // }, 1889 // "SetFunctionBreakpointsArguments": { 1890 // "type": "object", 1891 // "description": "Arguments for 'setFunctionBreakpoints' request.", 1892 // "properties": { 1893 // "breakpoints": { 1894 // "type": "array", 1895 // "items": { 1896 // "$ref": "#/definitions/FunctionBreakpoint" 1897 // }, 1898 // "description": "The function names of the breakpoints." 1899 // } 1900 // }, 1901 // "required": [ "breakpoints" ] 1902 // }, 1903 // "FunctionBreakpoint": { 1904 // "type": "object", 1905 // "description": "Properties of a breakpoint passed to the 1906 // setFunctionBreakpoints request.", "properties": { 1907 // "name": { 1908 // "type": "string", 1909 // "description": "The name of the function." 1910 // }, 1911 // "condition": { 1912 // "type": "string", 1913 // "description": "An optional expression for conditional breakpoints." 1914 // }, 1915 // "hitCondition": { 1916 // "type": "string", 1917 // "description": "An optional expression that controls how many hits of 1918 // the breakpoint are ignored. The backend is expected to interpret the 1919 // expression as needed." 1920 // } 1921 // }, 1922 // "required": [ "name" ] 1923 // }, 1924 // "SetFunctionBreakpointsResponse": { 1925 // "allOf": [ { "$ref": "#/definitions/Response" }, { 1926 // "type": "object", 1927 // "description": "Response to 'setFunctionBreakpoints' request. Returned is 1928 // information about each breakpoint created by this request.", 1929 // "properties": { 1930 // "body": { 1931 // "type": "object", 1932 // "properties": { 1933 // "breakpoints": { 1934 // "type": "array", 1935 // "items": { 1936 // "$ref": "#/definitions/Breakpoint" 1937 // }, 1938 // "description": "Information about the breakpoints. The array 1939 // elements correspond to the elements of the 'breakpoints' array." 1940 // } 1941 // }, 1942 // "required": [ "breakpoints" ] 1943 // } 1944 // }, 1945 // "required": [ "body" ] 1946 // }] 1947 // } 1948 void request_setFunctionBreakpoints(const llvm::json::Object &request) { 1949 llvm::json::Object response; 1950 lldb::SBError error; 1951 FillResponse(request, response); 1952 auto arguments = request.getObject("arguments"); 1953 auto breakpoints = arguments->getArray("breakpoints"); 1954 FunctionBreakpointMap request_bps; 1955 llvm::json::Array response_breakpoints; 1956 for (const auto &value : *breakpoints) { 1957 auto bp_obj = value.getAsObject(); 1958 if (bp_obj == nullptr) 1959 continue; 1960 FunctionBreakpoint func_bp(*bp_obj); 1961 request_bps[func_bp.functionName] = std::move(func_bp); 1962 } 1963 1964 std::vector<llvm::StringRef> remove_names; 1965 // Disable any function breakpoints that aren't in the request_bps. 1966 // There is no call to remove function breakpoints other than calling this 1967 // function with a smaller or empty "breakpoints" list. 1968 for (auto &pair: g_vsc.function_breakpoints) { 1969 auto request_pos = request_bps.find(pair.first()); 1970 if (request_pos == request_bps.end()) { 1971 // This function breakpoint no longer exists delete it from LLDB 1972 g_vsc.target.BreakpointDelete(pair.second.bp.GetID()); 1973 remove_names.push_back(pair.first()); 1974 } else { 1975 // Update the existing breakpoint as any setting withing the function 1976 // breakpoint might have changed. 1977 pair.second.UpdateBreakpoint(request_pos->second); 1978 // Remove this breakpoint from the request breakpoints since we have 1979 // handled it here and we don't need to set a new breakpoint below. 1980 request_bps.erase(request_pos); 1981 // Add this breakpoint info to the response 1982 AppendBreakpoint(pair.second.bp, response_breakpoints); 1983 } 1984 } 1985 // Remove any breakpoints that are no longer in our list 1986 for (const auto &name: remove_names) 1987 g_vsc.function_breakpoints.erase(name); 1988 1989 // Any breakpoints that are left in "request_bps" are breakpoints that 1990 // need to be set. 1991 for (auto &pair : request_bps) { 1992 pair.second.SetBreakpoint(); 1993 // Add this breakpoint info to the response 1994 AppendBreakpoint(pair.second.bp, response_breakpoints); 1995 g_vsc.function_breakpoints[pair.first()] = std::move(pair.second); 1996 } 1997 1998 llvm::json::Object body; 1999 body.try_emplace("breakpoints", std::move(response_breakpoints)); 2000 response.try_emplace("body", std::move(body)); 2001 g_vsc.SendJSON(llvm::json::Value(std::move(response))); 2002 } 2003 2004 // "SourceRequest": { 2005 // "allOf": [ { "$ref": "#/definitions/Request" }, { 2006 // "type": "object", 2007 // "description": "Source request; value of command field is 'source'. The 2008 // request retrieves the source code for a given source reference.", 2009 // "properties": { 2010 // "command": { 2011 // "type": "string", 2012 // "enum": [ "source" ] 2013 // }, 2014 // "arguments": { 2015 // "$ref": "#/definitions/SourceArguments" 2016 // } 2017 // }, 2018 // "required": [ "command", "arguments" ] 2019 // }] 2020 // }, 2021 // "SourceArguments": { 2022 // "type": "object", 2023 // "description": "Arguments for 'source' request.", 2024 // "properties": { 2025 // "source": { 2026 // "$ref": "#/definitions/Source", 2027 // "description": "Specifies the source content to load. Either 2028 // source.path or source.sourceReference must be specified." 2029 // }, 2030 // "sourceReference": { 2031 // "type": "integer", 2032 // "description": "The reference to the source. This is the same as 2033 // source.sourceReference. This is provided for backward compatibility 2034 // since old backends do not understand the 'source' attribute." 2035 // } 2036 // }, 2037 // "required": [ "sourceReference" ] 2038 // }, 2039 // "SourceResponse": { 2040 // "allOf": [ { "$ref": "#/definitions/Response" }, { 2041 // "type": "object", 2042 // "description": "Response to 'source' request.", 2043 // "properties": { 2044 // "body": { 2045 // "type": "object", 2046 // "properties": { 2047 // "content": { 2048 // "type": "string", 2049 // "description": "Content of the source reference." 2050 // }, 2051 // "mimeType": { 2052 // "type": "string", 2053 // "description": "Optional content type (mime type) of the source." 2054 // } 2055 // }, 2056 // "required": [ "content" ] 2057 // } 2058 // }, 2059 // "required": [ "body" ] 2060 // }] 2061 // } 2062 void request_source(const llvm::json::Object &request) { 2063 llvm::json::Object response; 2064 FillResponse(request, response); 2065 llvm::json::Object body; 2066 2067 auto arguments = request.getObject("arguments"); 2068 auto source = arguments->getObject("source"); 2069 auto sourceReference = GetSigned(source, "sourceReference", -1); 2070 auto pos = g_vsc.source_map.find((lldb::addr_t)sourceReference); 2071 if (pos != g_vsc.source_map.end()) { 2072 EmplaceSafeString(body, "content", pos->second.content); 2073 } else { 2074 response["success"] = llvm::json::Value(false); 2075 } 2076 response.try_emplace("body", std::move(body)); 2077 g_vsc.SendJSON(llvm::json::Value(std::move(response))); 2078 } 2079 2080 // "StackTraceRequest": { 2081 // "allOf": [ { "$ref": "#/definitions/Request" }, { 2082 // "type": "object", 2083 // "description": "StackTrace request; value of command field is 2084 // 'stackTrace'. The request returns a stacktrace from the current execution 2085 // state.", "properties": { 2086 // "command": { 2087 // "type": "string", 2088 // "enum": [ "stackTrace" ] 2089 // }, 2090 // "arguments": { 2091 // "$ref": "#/definitions/StackTraceArguments" 2092 // } 2093 // }, 2094 // "required": [ "command", "arguments" ] 2095 // }] 2096 // }, 2097 // "StackTraceArguments": { 2098 // "type": "object", 2099 // "description": "Arguments for 'stackTrace' request.", 2100 // "properties": { 2101 // "threadId": { 2102 // "type": "integer", 2103 // "description": "Retrieve the stacktrace for this thread." 2104 // }, 2105 // "startFrame": { 2106 // "type": "integer", 2107 // "description": "The index of the first frame to return; if omitted 2108 // frames start at 0." 2109 // }, 2110 // "levels": { 2111 // "type": "integer", 2112 // "description": "The maximum number of frames to return. If levels is 2113 // not specified or 0, all frames are returned." 2114 // }, 2115 // "format": { 2116 // "$ref": "#/definitions/StackFrameFormat", 2117 // "description": "Specifies details on how to format the stack frames." 2118 // } 2119 // }, 2120 // "required": [ "threadId" ] 2121 // }, 2122 // "StackTraceResponse": { 2123 // "allOf": [ { "$ref": "#/definitions/Response" }, { 2124 // "type": "object", 2125 // "description": "Response to 'stackTrace' request.", 2126 // "properties": { 2127 // "body": { 2128 // "type": "object", 2129 // "properties": { 2130 // "stackFrames": { 2131 // "type": "array", 2132 // "items": { 2133 // "$ref": "#/definitions/StackFrame" 2134 // }, 2135 // "description": "The frames of the stackframe. If the array has 2136 // length zero, there are no stackframes available. This means that 2137 // there is no location information available." 2138 // }, 2139 // "totalFrames": { 2140 // "type": "integer", 2141 // "description": "The total number of frames available." 2142 // } 2143 // }, 2144 // "required": [ "stackFrames" ] 2145 // } 2146 // }, 2147 // "required": [ "body" ] 2148 // }] 2149 // } 2150 void request_stackTrace(const llvm::json::Object &request) { 2151 llvm::json::Object response; 2152 FillResponse(request, response); 2153 lldb::SBError error; 2154 auto arguments = request.getObject("arguments"); 2155 lldb::SBThread thread = g_vsc.GetLLDBThread(*arguments); 2156 llvm::json::Array stackFrames; 2157 llvm::json::Object body; 2158 2159 if (thread.IsValid()) { 2160 const auto startFrame = GetUnsigned(arguments, "startFrame", 0); 2161 const auto levels = GetUnsigned(arguments, "levels", 0); 2162 const auto endFrame = (levels == 0) ? INT64_MAX : (startFrame + levels); 2163 for (uint32_t i = startFrame; i < endFrame; ++i) { 2164 auto frame = thread.GetFrameAtIndex(i); 2165 if (!frame.IsValid()) 2166 break; 2167 stackFrames.emplace_back(CreateStackFrame(frame)); 2168 } 2169 const auto totalFrames = thread.GetNumFrames(); 2170 body.try_emplace("totalFrames", totalFrames); 2171 } 2172 body.try_emplace("stackFrames", std::move(stackFrames)); 2173 response.try_emplace("body", std::move(body)); 2174 g_vsc.SendJSON(llvm::json::Value(std::move(response))); 2175 } 2176 2177 // "StepInRequest": { 2178 // "allOf": [ { "$ref": "#/definitions/Request" }, { 2179 // "type": "object", 2180 // "description": "StepIn request; value of command field is 'stepIn'. The 2181 // request starts the debuggee to step into a function/method if possible. 2182 // If it cannot step into a target, 'stepIn' behaves like 'next'. The debug 2183 // adapter first sends the StepInResponse and then a StoppedEvent (event 2184 // type 'step') after the step has completed. If there are multiple 2185 // function/method calls (or other targets) on the source line, the optional 2186 // argument 'targetId' can be used to control into which target the 'stepIn' 2187 // should occur. The list of possible targets for a given source line can be 2188 // retrieved via the 'stepInTargets' request.", "properties": { 2189 // "command": { 2190 // "type": "string", 2191 // "enum": [ "stepIn" ] 2192 // }, 2193 // "arguments": { 2194 // "$ref": "#/definitions/StepInArguments" 2195 // } 2196 // }, 2197 // "required": [ "command", "arguments" ] 2198 // }] 2199 // }, 2200 // "StepInArguments": { 2201 // "type": "object", 2202 // "description": "Arguments for 'stepIn' request.", 2203 // "properties": { 2204 // "threadId": { 2205 // "type": "integer", 2206 // "description": "Execute 'stepIn' for this thread." 2207 // }, 2208 // "targetId": { 2209 // "type": "integer", 2210 // "description": "Optional id of the target to step into." 2211 // } 2212 // }, 2213 // "required": [ "threadId" ] 2214 // }, 2215 // "StepInResponse": { 2216 // "allOf": [ { "$ref": "#/definitions/Response" }, { 2217 // "type": "object", 2218 // "description": "Response to 'stepIn' request. This is just an 2219 // acknowledgement, so no body field is required." 2220 // }] 2221 // } 2222 void request_stepIn(const llvm::json::Object &request) { 2223 llvm::json::Object response; 2224 FillResponse(request, response); 2225 auto arguments = request.getObject("arguments"); 2226 lldb::SBThread thread = g_vsc.GetLLDBThread(*arguments); 2227 if (thread.IsValid()) { 2228 // Remember the thread ID that caused the resume so we can set the 2229 // "threadCausedFocus" boolean value in the "stopped" events. 2230 g_vsc.focus_tid = thread.GetThreadID(); 2231 thread.StepInto(); 2232 } else { 2233 response["success"] = llvm::json::Value(false); 2234 } 2235 g_vsc.SendJSON(llvm::json::Value(std::move(response))); 2236 } 2237 2238 // "StepOutRequest": { 2239 // "allOf": [ { "$ref": "#/definitions/Request" }, { 2240 // "type": "object", 2241 // "description": "StepOut request; value of command field is 'stepOut'. The 2242 // request starts the debuggee to run again for one step. The debug adapter 2243 // first sends the StepOutResponse and then a StoppedEvent (event type 2244 // 'step') after the step has completed.", "properties": { 2245 // "command": { 2246 // "type": "string", 2247 // "enum": [ "stepOut" ] 2248 // }, 2249 // "arguments": { 2250 // "$ref": "#/definitions/StepOutArguments" 2251 // } 2252 // }, 2253 // "required": [ "command", "arguments" ] 2254 // }] 2255 // }, 2256 // "StepOutArguments": { 2257 // "type": "object", 2258 // "description": "Arguments for 'stepOut' request.", 2259 // "properties": { 2260 // "threadId": { 2261 // "type": "integer", 2262 // "description": "Execute 'stepOut' for this thread." 2263 // } 2264 // }, 2265 // "required": [ "threadId" ] 2266 // }, 2267 // "StepOutResponse": { 2268 // "allOf": [ { "$ref": "#/definitions/Response" }, { 2269 // "type": "object", 2270 // "description": "Response to 'stepOut' request. This is just an 2271 // acknowledgement, so no body field is required." 2272 // }] 2273 // } 2274 void request_stepOut(const llvm::json::Object &request) { 2275 llvm::json::Object response; 2276 FillResponse(request, response); 2277 auto arguments = request.getObject("arguments"); 2278 lldb::SBThread thread = g_vsc.GetLLDBThread(*arguments); 2279 if (thread.IsValid()) { 2280 // Remember the thread ID that caused the resume so we can set the 2281 // "threadCausedFocus" boolean value in the "stopped" events. 2282 g_vsc.focus_tid = thread.GetThreadID(); 2283 thread.StepOut(); 2284 } else { 2285 response["success"] = llvm::json::Value(false); 2286 } 2287 g_vsc.SendJSON(llvm::json::Value(std::move(response))); 2288 } 2289 2290 // "ThreadsRequest": { 2291 // "allOf": [ { "$ref": "#/definitions/Request" }, { 2292 // "type": "object", 2293 // "description": "Thread request; value of command field is 'threads'. The 2294 // request retrieves a list of all threads.", "properties": { 2295 // "command": { 2296 // "type": "string", 2297 // "enum": [ "threads" ] 2298 // } 2299 // }, 2300 // "required": [ "command" ] 2301 // }] 2302 // }, 2303 // "ThreadsResponse": { 2304 // "allOf": [ { "$ref": "#/definitions/Response" }, { 2305 // "type": "object", 2306 // "description": "Response to 'threads' request.", 2307 // "properties": { 2308 // "body": { 2309 // "type": "object", 2310 // "properties": { 2311 // "threads": { 2312 // "type": "array", 2313 // "items": { 2314 // "$ref": "#/definitions/Thread" 2315 // }, 2316 // "description": "All threads." 2317 // } 2318 // }, 2319 // "required": [ "threads" ] 2320 // } 2321 // }, 2322 // "required": [ "body" ] 2323 // }] 2324 // } 2325 void request_threads(const llvm::json::Object &request) { 2326 2327 lldb::SBProcess process = g_vsc.target.GetProcess(); 2328 llvm::json::Object response; 2329 FillResponse(request, response); 2330 2331 const uint32_t num_threads = process.GetNumThreads(); 2332 llvm::json::Array threads; 2333 for (uint32_t thread_idx = 0; thread_idx < num_threads; ++thread_idx) { 2334 lldb::SBThread thread = process.GetThreadAtIndex(thread_idx); 2335 threads.emplace_back(CreateThread(thread)); 2336 } 2337 if (threads.size() == 0) { 2338 response["success"] = llvm::json::Value(false); 2339 } 2340 llvm::json::Object body; 2341 body.try_emplace("threads", std::move(threads)); 2342 response.try_emplace("body", std::move(body)); 2343 g_vsc.SendJSON(llvm::json::Value(std::move(response))); 2344 } 2345 2346 // "SetVariableRequest": { 2347 // "allOf": [ { "$ref": "#/definitions/Request" }, { 2348 // "type": "object", 2349 // "description": "setVariable request; value of command field is 2350 // 'setVariable'. Set the variable with the given name in the variable 2351 // container to a new value.", "properties": { 2352 // "command": { 2353 // "type": "string", 2354 // "enum": [ "setVariable" ] 2355 // }, 2356 // "arguments": { 2357 // "$ref": "#/definitions/SetVariableArguments" 2358 // } 2359 // }, 2360 // "required": [ "command", "arguments" ] 2361 // }] 2362 // }, 2363 // "SetVariableArguments": { 2364 // "type": "object", 2365 // "description": "Arguments for 'setVariable' request.", 2366 // "properties": { 2367 // "variablesReference": { 2368 // "type": "integer", 2369 // "description": "The reference of the variable container." 2370 // }, 2371 // "name": { 2372 // "type": "string", 2373 // "description": "The name of the variable." 2374 // }, 2375 // "value": { 2376 // "type": "string", 2377 // "description": "The value of the variable." 2378 // }, 2379 // "format": { 2380 // "$ref": "#/definitions/ValueFormat", 2381 // "description": "Specifies details on how to format the response value." 2382 // } 2383 // }, 2384 // "required": [ "variablesReference", "name", "value" ] 2385 // }, 2386 // "SetVariableResponse": { 2387 // "allOf": [ { "$ref": "#/definitions/Response" }, { 2388 // "type": "object", 2389 // "description": "Response to 'setVariable' request.", 2390 // "properties": { 2391 // "body": { 2392 // "type": "object", 2393 // "properties": { 2394 // "value": { 2395 // "type": "string", 2396 // "description": "The new value of the variable." 2397 // }, 2398 // "type": { 2399 // "type": "string", 2400 // "description": "The type of the new value. Typically shown in the 2401 // UI when hovering over the value." 2402 // }, 2403 // "variablesReference": { 2404 // "type": "number", 2405 // "description": "If variablesReference is > 0, the new value is 2406 // structured and its children can be retrieved by passing 2407 // variablesReference to the VariablesRequest." 2408 // }, 2409 // "namedVariables": { 2410 // "type": "number", 2411 // "description": "The number of named child variables. The client 2412 // can use this optional information to present the variables in a 2413 // paged UI and fetch them in chunks." 2414 // }, 2415 // "indexedVariables": { 2416 // "type": "number", 2417 // "description": "The number of indexed child variables. The client 2418 // can use this optional information to present the variables in a 2419 // paged UI and fetch them in chunks." 2420 // } 2421 // }, 2422 // "required": [ "value" ] 2423 // } 2424 // }, 2425 // "required": [ "body" ] 2426 // }] 2427 // } 2428 void request_setVariable(const llvm::json::Object &request) { 2429 llvm::json::Object response; 2430 FillResponse(request, response); 2431 llvm::json::Array variables; 2432 llvm::json::Object body; 2433 auto arguments = request.getObject("arguments"); 2434 // This is a reference to the containing variable/scope 2435 const auto variablesReference = 2436 GetUnsigned(arguments, "variablesReference", 0); 2437 const auto name = GetString(arguments, "name"); 2438 const auto value = GetString(arguments, "value"); 2439 // Set success to false just in case we don't find the variable by name 2440 response.try_emplace("success", false); 2441 2442 lldb::SBValue variable; 2443 int64_t newVariablesReference = 0; 2444 2445 // The "id" is the unique integer ID that is unique within the enclosing 2446 // variablesReference. It is optionally added to any "interface Variable" 2447 // objects to uniquely identify a variable within an enclosing 2448 // variablesReference. It helps to disambiguate between two variables that 2449 // have the same name within the same scope since the "setVariables" request 2450 // only specifies the variable reference of the enclosing scope/variable, and 2451 // the name of the variable. We could have two shadowed variables with the 2452 // same name in "Locals" or "Globals". In our case the "id" absolute index 2453 // of the variable within the g_vsc.variables list. 2454 const auto id_value = GetUnsigned(arguments, "id", UINT64_MAX); 2455 if (id_value != UINT64_MAX) { 2456 variable = g_vsc.variables.GetValueAtIndex(id_value); 2457 } else if (VARREF_IS_SCOPE(variablesReference)) { 2458 // variablesReference is one of our scopes, not an actual variable it is 2459 // asking for a variable in locals or globals or registers 2460 int64_t start_idx = 0; 2461 int64_t end_idx = 0; 2462 switch (variablesReference) { 2463 case VARREF_LOCALS: 2464 start_idx = 0; 2465 end_idx = start_idx + g_vsc.num_locals; 2466 break; 2467 case VARREF_GLOBALS: 2468 start_idx = g_vsc.num_locals; 2469 end_idx = start_idx + g_vsc.num_globals; 2470 break; 2471 case VARREF_REGS: 2472 start_idx = g_vsc.num_locals + g_vsc.num_globals; 2473 end_idx = start_idx + g_vsc.num_regs; 2474 break; 2475 default: 2476 break; 2477 } 2478 2479 // Find the variable by name in the correct scope and hope we don't have 2480 // multiple variables with the same name. We search backwards because 2481 // the list of variables has the top most variables first and variables 2482 // in deeper scopes are last. This means we will catch the deepest 2483 // variable whose name matches which is probably what the user wants. 2484 for (int64_t i = end_idx - 1; i >= start_idx; --i) { 2485 auto curr_variable = g_vsc.variables.GetValueAtIndex(i); 2486 llvm::StringRef variable_name(curr_variable.GetName()); 2487 if (variable_name == name) { 2488 variable = curr_variable; 2489 if (curr_variable.MightHaveChildren()) 2490 newVariablesReference = i; 2491 break; 2492 } 2493 } 2494 } else { 2495 // We have a named item within an actual variable so we need to find it 2496 // withing the container variable by name. 2497 const int64_t var_idx = VARREF_TO_VARIDX(variablesReference); 2498 lldb::SBValue container = g_vsc.variables.GetValueAtIndex(var_idx); 2499 variable = container.GetChildMemberWithName(name.data()); 2500 if (!variable.IsValid()) { 2501 if (name.startswith("[")) { 2502 llvm::StringRef index_str(name.drop_front(1)); 2503 uint64_t index = 0; 2504 if (!index_str.consumeInteger(0, index)) { 2505 if (index_str == "]") 2506 variable = container.GetChildAtIndex(index); 2507 } 2508 } 2509 } 2510 2511 // We don't know the index of the variable in our g_vsc.variables 2512 if (variable.IsValid()) { 2513 if (variable.MightHaveChildren()) { 2514 newVariablesReference = VARIDX_TO_VARREF(g_vsc.variables.GetSize()); 2515 g_vsc.variables.Append(variable); 2516 } 2517 } 2518 } 2519 2520 if (variable.IsValid()) { 2521 lldb::SBError error; 2522 bool success = variable.SetValueFromCString(value.data(), error); 2523 if (success) { 2524 SetValueForKey(variable, body, "value"); 2525 EmplaceSafeString(body, "type", variable.GetType().GetDisplayTypeName()); 2526 body.try_emplace("variablesReference", newVariablesReference); 2527 } else { 2528 EmplaceSafeString(body, "message", std::string(error.GetCString())); 2529 } 2530 response["success"] = llvm::json::Value(success); 2531 } 2532 2533 response.try_emplace("body", std::move(body)); 2534 g_vsc.SendJSON(llvm::json::Value(std::move(response))); 2535 } 2536 2537 // "VariablesRequest": { 2538 // "allOf": [ { "$ref": "#/definitions/Request" }, { 2539 // "type": "object", 2540 // "description": "Variables request; value of command field is 'variables'. 2541 // Retrieves all child variables for the given variable reference. An 2542 // optional filter can be used to limit the fetched children to either named 2543 // or indexed children.", "properties": { 2544 // "command": { 2545 // "type": "string", 2546 // "enum": [ "variables" ] 2547 // }, 2548 // "arguments": { 2549 // "$ref": "#/definitions/VariablesArguments" 2550 // } 2551 // }, 2552 // "required": [ "command", "arguments" ] 2553 // }] 2554 // }, 2555 // "VariablesArguments": { 2556 // "type": "object", 2557 // "description": "Arguments for 'variables' request.", 2558 // "properties": { 2559 // "variablesReference": { 2560 // "type": "integer", 2561 // "description": "The Variable reference." 2562 // }, 2563 // "filter": { 2564 // "type": "string", 2565 // "enum": [ "indexed", "named" ], 2566 // "description": "Optional filter to limit the child variables to either 2567 // named or indexed. If ommited, both types are fetched." 2568 // }, 2569 // "start": { 2570 // "type": "integer", 2571 // "description": "The index of the first variable to return; if omitted 2572 // children start at 0." 2573 // }, 2574 // "count": { 2575 // "type": "integer", 2576 // "description": "The number of variables to return. If count is missing 2577 // or 0, all variables are returned." 2578 // }, 2579 // "format": { 2580 // "$ref": "#/definitions/ValueFormat", 2581 // "description": "Specifies details on how to format the Variable 2582 // values." 2583 // } 2584 // }, 2585 // "required": [ "variablesReference" ] 2586 // }, 2587 // "VariablesResponse": { 2588 // "allOf": [ { "$ref": "#/definitions/Response" }, { 2589 // "type": "object", 2590 // "description": "Response to 'variables' request.", 2591 // "properties": { 2592 // "body": { 2593 // "type": "object", 2594 // "properties": { 2595 // "variables": { 2596 // "type": "array", 2597 // "items": { 2598 // "$ref": "#/definitions/Variable" 2599 // }, 2600 // "description": "All (or a range) of variables for the given 2601 // variable reference." 2602 // } 2603 // }, 2604 // "required": [ "variables" ] 2605 // } 2606 // }, 2607 // "required": [ "body" ] 2608 // }] 2609 // } 2610 void request_variables(const llvm::json::Object &request) { 2611 llvm::json::Object response; 2612 FillResponse(request, response); 2613 llvm::json::Array variables; 2614 auto arguments = request.getObject("arguments"); 2615 const auto variablesReference = 2616 GetUnsigned(arguments, "variablesReference", 0); 2617 const int64_t start = GetSigned(arguments, "start", 0); 2618 const int64_t count = GetSigned(arguments, "count", 0); 2619 bool hex = false; 2620 auto format = arguments->getObject("format"); 2621 if (format) 2622 hex = GetBoolean(format, "hex", false); 2623 2624 if (VARREF_IS_SCOPE(variablesReference)) { 2625 // variablesReference is one of our scopes, not an actual variable it is 2626 // asking for the list of args, locals or globals. 2627 int64_t start_idx = 0; 2628 int64_t num_children = 0; 2629 switch (variablesReference) { 2630 case VARREF_LOCALS: 2631 start_idx = start; 2632 num_children = g_vsc.num_locals; 2633 break; 2634 case VARREF_GLOBALS: 2635 start_idx = start + g_vsc.num_locals + start; 2636 num_children = g_vsc.num_globals; 2637 break; 2638 case VARREF_REGS: 2639 start_idx = start + g_vsc.num_locals + g_vsc.num_globals; 2640 num_children = g_vsc.num_regs; 2641 break; 2642 default: 2643 break; 2644 } 2645 const int64_t end_idx = start_idx + ((count == 0) ? num_children : count); 2646 for (auto i = start_idx; i < end_idx; ++i) { 2647 lldb::SBValue variable = g_vsc.variables.GetValueAtIndex(i); 2648 if (!variable.IsValid()) 2649 break; 2650 variables.emplace_back( 2651 CreateVariable(variable, VARIDX_TO_VARREF(i), i, hex)); 2652 } 2653 } else { 2654 // We are expanding a variable that has children, so we will return its 2655 // children. 2656 const int64_t var_idx = VARREF_TO_VARIDX(variablesReference); 2657 lldb::SBValue variable = g_vsc.variables.GetValueAtIndex(var_idx); 2658 if (variable.IsValid()) { 2659 const auto num_children = variable.GetNumChildren(); 2660 const int64_t end_idx = start + ((count == 0) ? num_children : count); 2661 for (auto i = start; i < end_idx; ++i) { 2662 lldb::SBValue child = variable.GetChildAtIndex(i); 2663 if (!child.IsValid()) 2664 break; 2665 if (child.MightHaveChildren()) { 2666 const int64_t var_idx = g_vsc.variables.GetSize(); 2667 auto childVariablesReferences = VARIDX_TO_VARREF(var_idx); 2668 variables.emplace_back( 2669 CreateVariable(child, childVariablesReferences, var_idx, hex)); 2670 g_vsc.variables.Append(child); 2671 } else { 2672 variables.emplace_back(CreateVariable(child, 0, INT64_MAX, hex)); 2673 } 2674 } 2675 } 2676 } 2677 llvm::json::Object body; 2678 body.try_emplace("variables", std::move(variables)); 2679 response.try_emplace("body", std::move(body)); 2680 g_vsc.SendJSON(llvm::json::Value(std::move(response))); 2681 } 2682 2683 // A request used in testing to get the details on all breakpoints that are 2684 // currently set in the target. This helps us to test "setBreakpoints" and 2685 // "setFunctionBreakpoints" requests to verify we have the correct set of 2686 // breakpoints currently set in LLDB. 2687 void request__testGetTargetBreakpoints(const llvm::json::Object &request) { 2688 llvm::json::Object response; 2689 FillResponse(request, response); 2690 llvm::json::Array response_breakpoints; 2691 for (uint32_t i = 0; g_vsc.target.GetBreakpointAtIndex(i).IsValid(); ++i) { 2692 auto bp = g_vsc.target.GetBreakpointAtIndex(i); 2693 AppendBreakpoint(bp, response_breakpoints); 2694 } 2695 llvm::json::Object body; 2696 body.try_emplace("breakpoints", std::move(response_breakpoints)); 2697 response.try_emplace("body", std::move(body)); 2698 g_vsc.SendJSON(llvm::json::Value(std::move(response))); 2699 } 2700 2701 const std::map<std::string, RequestCallback> &GetRequestHandlers() { 2702 #define REQUEST_CALLBACK(name) \ 2703 { #name, request_##name } 2704 static std::map<std::string, RequestCallback> g_request_handlers = { 2705 // VSCode Debug Adaptor requests 2706 REQUEST_CALLBACK(attach), 2707 REQUEST_CALLBACK(completions), 2708 REQUEST_CALLBACK(continue), 2709 REQUEST_CALLBACK(configurationDone), 2710 REQUEST_CALLBACK(disconnect), 2711 REQUEST_CALLBACK(evaluate), 2712 REQUEST_CALLBACK(exceptionInfo), 2713 REQUEST_CALLBACK(initialize), 2714 REQUEST_CALLBACK(launch), 2715 REQUEST_CALLBACK(next), 2716 REQUEST_CALLBACK(pause), 2717 REQUEST_CALLBACK(scopes), 2718 REQUEST_CALLBACK(setBreakpoints), 2719 REQUEST_CALLBACK(setExceptionBreakpoints), 2720 REQUEST_CALLBACK(setFunctionBreakpoints), 2721 REQUEST_CALLBACK(setVariable), 2722 REQUEST_CALLBACK(source), 2723 REQUEST_CALLBACK(stackTrace), 2724 REQUEST_CALLBACK(stepIn), 2725 REQUEST_CALLBACK(stepOut), 2726 REQUEST_CALLBACK(threads), 2727 REQUEST_CALLBACK(variables), 2728 // Testing requests 2729 REQUEST_CALLBACK(_testGetTargetBreakpoints), 2730 }; 2731 #undef REQUEST_CALLBACK 2732 return g_request_handlers; 2733 } 2734 2735 } // anonymous namespace 2736 2737 int main(int argc, char *argv[]) { 2738 2739 // Initialize LLDB first before we do anything. 2740 lldb::SBDebugger::Initialize(); 2741 2742 if (argc == 2) { 2743 const char *arg = argv[1]; 2744 #if !defined(_WIN32) 2745 if (strcmp(arg, "-g") == 0) { 2746 printf("Paused waiting for debugger to attach (pid = %i)...\n", getpid()); 2747 pause(); 2748 } else { 2749 #else 2750 { 2751 #endif 2752 int portno = atoi(arg); 2753 printf("Listening on port %i...\n", portno); 2754 SOCKET socket_fd = AcceptConnection(portno); 2755 if (socket_fd >= 0) { 2756 g_vsc.input.descriptor = StreamDescriptor::from_socket(socket_fd, true); 2757 g_vsc.output.descriptor = 2758 StreamDescriptor::from_socket(socket_fd, false); 2759 } else { 2760 exit(1); 2761 } 2762 } 2763 } else { 2764 g_vsc.input.descriptor = StreamDescriptor::from_file(fileno(stdin), false); 2765 g_vsc.output.descriptor = 2766 StreamDescriptor::from_file(fileno(stdout), false); 2767 } 2768 auto request_handlers = GetRequestHandlers(); 2769 uint32_t packet_idx = 0; 2770 while (true) { 2771 std::string json = g_vsc.ReadJSON(); 2772 if (json.empty()) 2773 break; 2774 2775 llvm::StringRef json_sref(json); 2776 llvm::Expected<llvm::json::Value> json_value = llvm::json::parse(json_sref); 2777 if (!json_value) { 2778 auto error = json_value.takeError(); 2779 if (g_vsc.log) { 2780 std::string error_str; 2781 llvm::raw_string_ostream strm(error_str); 2782 strm << error; 2783 strm.flush(); 2784 2785 *g_vsc.log << "error: failed to parse JSON: " << error_str << std::endl 2786 << json << std::endl; 2787 } 2788 return 1; 2789 } 2790 2791 auto object = json_value->getAsObject(); 2792 if (!object) { 2793 if (g_vsc.log) 2794 *g_vsc.log << "error: json packet isn't a object" << std::endl; 2795 return 1; 2796 } 2797 2798 const auto packet_type = GetString(object, "type"); 2799 if (packet_type == "request") { 2800 const auto command = GetString(object, "command"); 2801 auto handler_pos = request_handlers.find(command); 2802 if (handler_pos != request_handlers.end()) { 2803 handler_pos->second(*object); 2804 } else { 2805 if (g_vsc.log) 2806 *g_vsc.log << "error: unhandled command \"" << command.data() << std::endl; 2807 return 1; 2808 } 2809 } 2810 ++packet_idx; 2811 } 2812 2813 // We must terminate the debugger in a thread before the C++ destructor 2814 // chain messes everything up. 2815 lldb::SBDebugger::Terminate(); 2816 return 0; 2817 } 2818