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