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