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