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