1 //===-- lldb-dap.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 "DAP.h" 10 #include "FifoFiles.h" 11 #include "JSONUtils.h" 12 #include "LLDBUtils.h" 13 #include "RunInTerminal.h" 14 #include "Watchpoint.h" 15 #include "lldb/API/SBDeclaration.h" 16 #include "lldb/API/SBEvent.h" 17 #include "lldb/API/SBInstruction.h" 18 #include "lldb/API/SBListener.h" 19 #include "lldb/API/SBMemoryRegionInfo.h" 20 #include "lldb/API/SBStream.h" 21 #include "lldb/API/SBStringList.h" 22 #include "lldb/Host/Config.h" 23 #include "llvm/ADT/ArrayRef.h" 24 #include "llvm/ADT/DenseMap.h" 25 #include "llvm/ADT/DenseSet.h" 26 #include "llvm/ADT/ScopeExit.h" 27 #include "llvm/ADT/StringExtras.h" 28 #include "llvm/Option/Arg.h" 29 #include "llvm/Option/ArgList.h" 30 #include "llvm/Option/OptTable.h" 31 #include "llvm/Option/Option.h" 32 #include "llvm/Support/Base64.h" 33 #include "llvm/Support/Errno.h" 34 #include "llvm/Support/FileSystem.h" 35 #include "llvm/Support/InitLLVM.h" 36 #include "llvm/Support/Path.h" 37 #include "llvm/Support/PrettyStackTrace.h" 38 #include "llvm/Support/raw_ostream.h" 39 #include <algorithm> 40 #include <array> 41 #include <cassert> 42 #include <climits> 43 #include <cstdarg> 44 #include <cstdint> 45 #include <cstdio> 46 #include <cstdlib> 47 #include <cstring> 48 #include <fcntl.h> 49 #include <map> 50 #include <memory> 51 #include <optional> 52 #include <set> 53 #include <sys/stat.h> 54 #include <sys/types.h> 55 #include <thread> 56 #include <vector> 57 58 #if defined(_WIN32) 59 // We need to #define NOMINMAX in order to skip `min()` and `max()` macro 60 // definitions that conflict with other system headers. 61 // We also need to #undef GetObject (which is defined to GetObjectW) because 62 // the JSON code we use also has methods named `GetObject()` and we conflict 63 // against these. 64 #define NOMINMAX 65 #include <windows.h> 66 #undef GetObject 67 #include <io.h> 68 #else 69 #include <netinet/in.h> 70 #include <sys/socket.h> 71 #include <unistd.h> 72 #endif 73 74 #if defined(__linux__) 75 #include <sys/prctl.h> 76 #endif 77 78 #if defined(_WIN32) 79 #ifndef PATH_MAX 80 #define PATH_MAX MAX_PATH 81 #endif 82 typedef int socklen_t; 83 #endif 84 85 using namespace lldb_dap; 86 87 namespace { 88 using namespace llvm::opt; 89 90 enum ID { 91 OPT_INVALID = 0, // This is not an option ID. 92 #define OPTION(...) LLVM_MAKE_OPT_ID(__VA_ARGS__), 93 #include "Options.inc" 94 #undef OPTION 95 }; 96 97 #define OPTTABLE_STR_TABLE_CODE 98 #include "Options.inc" 99 #undef OPTTABLE_STR_TABLE_CODE 100 101 #define OPTTABLE_PREFIXES_TABLE_CODE 102 #include "Options.inc" 103 #undef OPTTABLE_PREFIXES_TABLE_CODE 104 105 static constexpr llvm::opt::OptTable::Info InfoTable[] = { 106 #define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__), 107 #include "Options.inc" 108 #undef OPTION 109 }; 110 class LLDBDAPOptTable : public llvm::opt::GenericOptTable { 111 public: 112 LLDBDAPOptTable() 113 : llvm::opt::GenericOptTable(OptionStrTable, OptionPrefixesTable, 114 InfoTable, true) {} 115 }; 116 117 typedef void (*RequestCallback)(const llvm::json::Object &command); 118 119 enum LaunchMethod { Launch, Attach, AttachForSuspendedLaunch }; 120 121 /// Page size used for reporting addtional frames in the 'stackTrace' request. 122 constexpr int StackPageSize = 20; 123 124 /// Prints a welcome message on the editor if the preprocessor variable 125 /// LLDB_DAP_WELCOME_MESSAGE is defined. 126 static void PrintWelcomeMessage(DAP &dap) { 127 #ifdef LLDB_DAP_WELCOME_MESSAGE 128 dap.SendOutput(OutputType::Console, LLDB_DAP_WELCOME_MESSAGE); 129 #endif 130 } 131 132 lldb::SBValueList *GetTopLevelScope(DAP &dap, int64_t variablesReference) { 133 switch (variablesReference) { 134 case VARREF_LOCALS: 135 return &dap.variables.locals; 136 case VARREF_GLOBALS: 137 return &dap.variables.globals; 138 case VARREF_REGS: 139 return &dap.variables.registers; 140 default: 141 return nullptr; 142 } 143 } 144 145 SOCKET AcceptConnection(std::ofstream *log, int portno) { 146 // Accept a socket connection from any host on "portno". 147 SOCKET newsockfd = -1; 148 struct sockaddr_in serv_addr, cli_addr; 149 SOCKET sockfd = socket(AF_INET, SOCK_STREAM, 0); 150 if (sockfd < 0) { 151 if (log) 152 *log << "error: opening socket (" << strerror(errno) << ")" << std::endl; 153 } else { 154 memset((char *)&serv_addr, 0, sizeof(serv_addr)); 155 serv_addr.sin_family = AF_INET; 156 // serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); 157 serv_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 158 serv_addr.sin_port = htons(portno); 159 if (bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) { 160 if (log) 161 *log << "error: binding socket (" << strerror(errno) << ")" 162 << std::endl; 163 } else { 164 listen(sockfd, 5); 165 socklen_t clilen = sizeof(cli_addr); 166 newsockfd = 167 llvm::sys::RetryAfterSignal(static_cast<SOCKET>(-1), accept, sockfd, 168 (struct sockaddr *)&cli_addr, &clilen); 169 if (newsockfd < 0) 170 if (log) 171 *log << "error: accept (" << strerror(errno) << ")" << std::endl; 172 } 173 #if defined(_WIN32) 174 closesocket(sockfd); 175 #else 176 close(sockfd); 177 #endif 178 } 179 return newsockfd; 180 } 181 182 std::vector<const char *> MakeArgv(const llvm::ArrayRef<std::string> &strs) { 183 // Create and return an array of "const char *", one for each C string in 184 // "strs" and terminate the list with a NULL. This can be used for argument 185 // vectors (argv) or environment vectors (envp) like those passed to the 186 // "main" function in C programs. 187 std::vector<const char *> argv; 188 for (const auto &s : strs) 189 argv.push_back(s.c_str()); 190 argv.push_back(nullptr); 191 return argv; 192 } 193 194 // Send a "exited" event to indicate the process has exited. 195 void SendProcessExitedEvent(DAP &dap, lldb::SBProcess &process) { 196 llvm::json::Object event(CreateEventObject("exited")); 197 llvm::json::Object body; 198 body.try_emplace("exitCode", (int64_t)process.GetExitStatus()); 199 event.try_emplace("body", std::move(body)); 200 dap.SendJSON(llvm::json::Value(std::move(event))); 201 } 202 203 void SendThreadExitedEvent(DAP &dap, lldb::tid_t tid) { 204 llvm::json::Object event(CreateEventObject("thread")); 205 llvm::json::Object body; 206 body.try_emplace("reason", "exited"); 207 body.try_emplace("threadId", (int64_t)tid); 208 event.try_emplace("body", std::move(body)); 209 dap.SendJSON(llvm::json::Value(std::move(event))); 210 } 211 212 // Send a "continued" event to indicate the process is in the running state. 213 void SendContinuedEvent(DAP &dap) { 214 lldb::SBProcess process = dap.target.GetProcess(); 215 if (!process.IsValid()) { 216 return; 217 } 218 219 // If the focus thread is not set then we haven't reported any thread status 220 // to the client, so nothing to report. 221 if (!dap.configuration_done_sent || dap.focus_tid == LLDB_INVALID_THREAD_ID) { 222 return; 223 } 224 225 llvm::json::Object event(CreateEventObject("continued")); 226 llvm::json::Object body; 227 body.try_emplace("threadId", (int64_t)dap.focus_tid); 228 body.try_emplace("allThreadsContinued", true); 229 event.try_emplace("body", std::move(body)); 230 dap.SendJSON(llvm::json::Value(std::move(event))); 231 } 232 233 // Send a "terminated" event to indicate the process is done being 234 // debugged. 235 void SendTerminatedEvent(DAP &dap) { 236 // Prevent races if the process exits while we're being asked to disconnect. 237 llvm::call_once(dap.terminated_event_flag, [&] { 238 dap.RunTerminateCommands(); 239 // Send a "terminated" event 240 llvm::json::Object event(CreateTerminatedEventObject(dap.target)); 241 dap.SendJSON(llvm::json::Value(std::move(event))); 242 }); 243 } 244 245 // Send a thread stopped event for all threads as long as the process 246 // is stopped. 247 void SendThreadStoppedEvent(DAP &dap) { 248 lldb::SBProcess process = dap.target.GetProcess(); 249 if (process.IsValid()) { 250 auto state = process.GetState(); 251 if (state == lldb::eStateStopped) { 252 llvm::DenseSet<lldb::tid_t> old_thread_ids; 253 old_thread_ids.swap(dap.thread_ids); 254 uint32_t stop_id = process.GetStopID(); 255 const uint32_t num_threads = process.GetNumThreads(); 256 257 // First make a pass through the threads to see if the focused thread 258 // has a stop reason. In case the focus thread doesn't have a stop 259 // reason, remember the first thread that has a stop reason so we can 260 // set it as the focus thread if below if needed. 261 lldb::tid_t first_tid_with_reason = LLDB_INVALID_THREAD_ID; 262 uint32_t num_threads_with_reason = 0; 263 bool focus_thread_exists = false; 264 for (uint32_t thread_idx = 0; thread_idx < num_threads; ++thread_idx) { 265 lldb::SBThread thread = process.GetThreadAtIndex(thread_idx); 266 const lldb::tid_t tid = thread.GetThreadID(); 267 const bool has_reason = ThreadHasStopReason(thread); 268 // If the focus thread doesn't have a stop reason, clear the thread ID 269 if (tid == dap.focus_tid) { 270 focus_thread_exists = true; 271 if (!has_reason) 272 dap.focus_tid = LLDB_INVALID_THREAD_ID; 273 } 274 if (has_reason) { 275 ++num_threads_with_reason; 276 if (first_tid_with_reason == LLDB_INVALID_THREAD_ID) 277 first_tid_with_reason = tid; 278 } 279 } 280 281 // We will have cleared dap.focus_tid if the focus thread doesn't have 282 // a stop reason, so if it was cleared, or wasn't set, or doesn't exist, 283 // then set the focus thread to the first thread with a stop reason. 284 if (!focus_thread_exists || dap.focus_tid == LLDB_INVALID_THREAD_ID) 285 dap.focus_tid = first_tid_with_reason; 286 287 // If no threads stopped with a reason, then report the first one so 288 // we at least let the UI know we stopped. 289 if (num_threads_with_reason == 0) { 290 lldb::SBThread thread = process.GetThreadAtIndex(0); 291 dap.focus_tid = thread.GetThreadID(); 292 dap.SendJSON(CreateThreadStopped(dap, thread, stop_id)); 293 } else { 294 for (uint32_t thread_idx = 0; thread_idx < num_threads; ++thread_idx) { 295 lldb::SBThread thread = process.GetThreadAtIndex(thread_idx); 296 dap.thread_ids.insert(thread.GetThreadID()); 297 if (ThreadHasStopReason(thread)) { 298 dap.SendJSON(CreateThreadStopped(dap, thread, stop_id)); 299 } 300 } 301 } 302 303 for (auto tid : old_thread_ids) { 304 auto end = dap.thread_ids.end(); 305 auto pos = dap.thread_ids.find(tid); 306 if (pos == end) 307 SendThreadExitedEvent(dap, tid); 308 } 309 } else { 310 if (dap.log) 311 *dap.log << "error: SendThreadStoppedEvent() when process" 312 " isn't stopped (" 313 << lldb::SBDebugger::StateAsCString(state) << ')' << std::endl; 314 } 315 } else { 316 if (dap.log) 317 *dap.log << "error: SendThreadStoppedEvent() invalid process" 318 << std::endl; 319 } 320 dap.RunStopCommands(); 321 } 322 323 // "ProcessEvent": { 324 // "allOf": [ 325 // { "$ref": "#/definitions/Event" }, 326 // { 327 // "type": "object", 328 // "description": "Event message for 'process' event type. The event 329 // indicates that the debugger has begun debugging a 330 // new process. Either one that it has launched, or one 331 // that it has attached to.", 332 // "properties": { 333 // "event": { 334 // "type": "string", 335 // "enum": [ "process" ] 336 // }, 337 // "body": { 338 // "type": "object", 339 // "properties": { 340 // "name": { 341 // "type": "string", 342 // "description": "The logical name of the process. This is 343 // usually the full path to process's executable 344 // file. Example: /home/myproj/program.js." 345 // }, 346 // "systemProcessId": { 347 // "type": "integer", 348 // "description": "The system process id of the debugged process. 349 // This property will be missing for non-system 350 // processes." 351 // }, 352 // "isLocalProcess": { 353 // "type": "boolean", 354 // "description": "If true, the process is running on the same 355 // computer as the debug adapter." 356 // }, 357 // "startMethod": { 358 // "type": "string", 359 // "enum": [ "launch", "attach", "attachForSuspendedLaunch" ], 360 // "description": "Describes how the debug engine started 361 // debugging this process.", 362 // "enumDescriptions": [ 363 // "Process was launched under the debugger.", 364 // "Debugger attached to an existing process.", 365 // "A project launcher component has launched a new process in 366 // a suspended state and then asked the debugger to attach." 367 // ] 368 // } 369 // }, 370 // "required": [ "name" ] 371 // } 372 // }, 373 // "required": [ "event", "body" ] 374 // } 375 // ] 376 // } 377 void SendProcessEvent(DAP &dap, LaunchMethod launch_method) { 378 lldb::SBFileSpec exe_fspec = dap.target.GetExecutable(); 379 char exe_path[PATH_MAX]; 380 exe_fspec.GetPath(exe_path, sizeof(exe_path)); 381 llvm::json::Object event(CreateEventObject("process")); 382 llvm::json::Object body; 383 EmplaceSafeString(body, "name", std::string(exe_path)); 384 const auto pid = dap.target.GetProcess().GetProcessID(); 385 body.try_emplace("systemProcessId", (int64_t)pid); 386 body.try_emplace("isLocalProcess", true); 387 const char *startMethod = nullptr; 388 switch (launch_method) { 389 case Launch: 390 startMethod = "launch"; 391 break; 392 case Attach: 393 startMethod = "attach"; 394 break; 395 case AttachForSuspendedLaunch: 396 startMethod = "attachForSuspendedLaunch"; 397 break; 398 } 399 body.try_emplace("startMethod", startMethod); 400 event.try_emplace("body", std::move(body)); 401 dap.SendJSON(llvm::json::Value(std::move(event))); 402 } 403 404 // Grab any STDOUT and STDERR from the process and send it up to VS Code 405 // via an "output" event to the "stdout" and "stderr" categories. 406 void SendStdOutStdErr(DAP &dap, lldb::SBProcess &process) { 407 char buffer[OutputBufferSize]; 408 size_t count; 409 while ((count = process.GetSTDOUT(buffer, sizeof(buffer))) > 0) 410 dap.SendOutput(OutputType::Stdout, llvm::StringRef(buffer, count)); 411 while ((count = process.GetSTDERR(buffer, sizeof(buffer))) > 0) 412 dap.SendOutput(OutputType::Stderr, llvm::StringRef(buffer, count)); 413 } 414 415 void ProgressEventThreadFunction(DAP &dap) { 416 lldb::SBListener listener("lldb-dap.progress.listener"); 417 dap.debugger.GetBroadcaster().AddListener( 418 listener, lldb::SBDebugger::eBroadcastBitProgress | 419 lldb::SBDebugger::eBroadcastBitExternalProgress); 420 dap.broadcaster.AddListener(listener, eBroadcastBitStopProgressThread); 421 lldb::SBEvent event; 422 bool done = false; 423 while (!done) { 424 if (listener.WaitForEvent(1, event)) { 425 const auto event_mask = event.GetType(); 426 if (event.BroadcasterMatchesRef(dap.broadcaster)) { 427 if (event_mask & eBroadcastBitStopProgressThread) { 428 done = true; 429 } 430 } else { 431 uint64_t progress_id = 0; 432 uint64_t completed = 0; 433 uint64_t total = 0; 434 bool is_debugger_specific = false; 435 const char *message = lldb::SBDebugger::GetProgressFromEvent( 436 event, progress_id, completed, total, is_debugger_specific); 437 if (message) 438 dap.SendProgressEvent(progress_id, message, completed, total); 439 } 440 } 441 } 442 } 443 444 // All events from the debugger, target, process, thread and frames are 445 // received in this function that runs in its own thread. We are using a 446 // "FILE *" to output packets back to VS Code and they have mutexes in them 447 // them prevent multiple threads from writing simultaneously so no locking 448 // is required. 449 void EventThreadFunction(DAP &dap) { 450 lldb::SBEvent event; 451 lldb::SBListener listener = dap.debugger.GetListener(); 452 bool done = false; 453 while (!done) { 454 if (listener.WaitForEvent(1, event)) { 455 const auto event_mask = event.GetType(); 456 if (lldb::SBProcess::EventIsProcessEvent(event)) { 457 lldb::SBProcess process = lldb::SBProcess::GetProcessFromEvent(event); 458 if (event_mask & lldb::SBProcess::eBroadcastBitStateChanged) { 459 auto state = lldb::SBProcess::GetStateFromEvent(event); 460 switch (state) { 461 case lldb::eStateInvalid: 462 // Not a state event 463 break; 464 case lldb::eStateUnloaded: 465 break; 466 case lldb::eStateConnected: 467 break; 468 case lldb::eStateAttaching: 469 break; 470 case lldb::eStateLaunching: 471 break; 472 case lldb::eStateStepping: 473 break; 474 case lldb::eStateCrashed: 475 break; 476 case lldb::eStateDetached: 477 break; 478 case lldb::eStateSuspended: 479 break; 480 case lldb::eStateStopped: 481 // We launch and attach in synchronous mode then the first stop 482 // event will not be delivered. If we use "launchCommands" during a 483 // launch or "attachCommands" during an attach we might some process 484 // stop events which we do not want to send an event for. We will 485 // manually send a stopped event in request_configurationDone(...) 486 // so don't send any before then. 487 if (dap.configuration_done_sent) { 488 // Only report a stopped event if the process was not 489 // automatically restarted. 490 if (!lldb::SBProcess::GetRestartedFromEvent(event)) { 491 SendStdOutStdErr(dap, process); 492 SendThreadStoppedEvent(dap); 493 } 494 } 495 break; 496 case lldb::eStateRunning: 497 dap.WillContinue(); 498 SendContinuedEvent(dap); 499 break; 500 case lldb::eStateExited: 501 lldb::SBStream stream; 502 process.GetStatus(stream); 503 dap.SendOutput(OutputType::Console, stream.GetData()); 504 505 // When restarting, we can get an "exited" event for the process we 506 // just killed with the old PID, or even with no PID. In that case 507 // we don't have to terminate the session. 508 if (process.GetProcessID() == LLDB_INVALID_PROCESS_ID || 509 process.GetProcessID() == dap.restarting_process_id) { 510 dap.restarting_process_id = LLDB_INVALID_PROCESS_ID; 511 } else { 512 // Run any exit LLDB commands the user specified in the 513 // launch.json 514 dap.RunExitCommands(); 515 SendProcessExitedEvent(dap, process); 516 SendTerminatedEvent(dap); 517 done = true; 518 } 519 break; 520 } 521 } else if ((event_mask & lldb::SBProcess::eBroadcastBitSTDOUT) || 522 (event_mask & lldb::SBProcess::eBroadcastBitSTDERR)) { 523 SendStdOutStdErr(dap, process); 524 } 525 } else if (lldb::SBBreakpoint::EventIsBreakpointEvent(event)) { 526 if (event_mask & lldb::SBTarget::eBroadcastBitBreakpointChanged) { 527 auto event_type = 528 lldb::SBBreakpoint::GetBreakpointEventTypeFromEvent(event); 529 auto bp = Breakpoint( 530 dap, lldb::SBBreakpoint::GetBreakpointFromEvent(event)); 531 // If the breakpoint was originated from the IDE, it will have the 532 // BreakpointBase::GetBreakpointLabel() label attached. Regardless 533 // of wether the locations were added or removed, the breakpoint 534 // ins't going away, so we the reason is always "changed". 535 if ((event_type & lldb::eBreakpointEventTypeLocationsAdded || 536 event_type & lldb::eBreakpointEventTypeLocationsRemoved) && 537 bp.MatchesName(BreakpointBase::GetBreakpointLabel())) { 538 auto bp_event = CreateEventObject("breakpoint"); 539 llvm::json::Object body; 540 // As VSCode already knows the path of this breakpoint, we don't 541 // need to send it back as part of a "changed" event. This 542 // prevent us from sending to VSCode paths that should be source 543 // mapped. Note that CreateBreakpoint doesn't apply source mapping. 544 // Besides, the current implementation of VSCode ignores the 545 // "source" element of breakpoint events. 546 llvm::json::Value source_bp = CreateBreakpoint(&bp); 547 source_bp.getAsObject()->erase("source"); 548 549 body.try_emplace("breakpoint", source_bp); 550 body.try_emplace("reason", "changed"); 551 bp_event.try_emplace("body", std::move(body)); 552 dap.SendJSON(llvm::json::Value(std::move(bp_event))); 553 } 554 } 555 } else if (event.BroadcasterMatchesRef(dap.broadcaster)) { 556 if (event_mask & eBroadcastBitStopEventThread) { 557 done = true; 558 } 559 } 560 } 561 } 562 } 563 564 lldb::SBValue FindVariable(DAP &dap, uint64_t variablesReference, 565 llvm::StringRef name) { 566 lldb::SBValue variable; 567 if (lldb::SBValueList *top_scope = 568 GetTopLevelScope(dap, variablesReference)) { 569 bool is_duplicated_variable_name = name.contains(" @"); 570 // variablesReference is one of our scopes, not an actual variable it is 571 // asking for a variable in locals or globals or registers 572 int64_t end_idx = top_scope->GetSize(); 573 // Searching backward so that we choose the variable in closest scope 574 // among variables of the same name. 575 for (int64_t i = end_idx - 1; i >= 0; --i) { 576 lldb::SBValue curr_variable = top_scope->GetValueAtIndex(i); 577 std::string variable_name = CreateUniqueVariableNameForDisplay( 578 curr_variable, is_duplicated_variable_name); 579 if (variable_name == name) { 580 variable = curr_variable; 581 break; 582 } 583 } 584 } else { 585 // This is not under the globals or locals scope, so there are no duplicated 586 // names. 587 588 // We have a named item within an actual variable so we need to find it 589 // withing the container variable by name. 590 lldb::SBValue container = dap.variables.GetVariable(variablesReference); 591 variable = container.GetChildMemberWithName(name.data()); 592 if (!variable.IsValid()) { 593 if (name.starts_with("[")) { 594 llvm::StringRef index_str(name.drop_front(1)); 595 uint64_t index = 0; 596 if (!index_str.consumeInteger(0, index)) { 597 if (index_str == "]") 598 variable = container.GetChildAtIndex(index); 599 } 600 } 601 } 602 } 603 return variable; 604 } 605 606 // Both attach and launch take a either a sourcePath or sourceMap 607 // argument (or neither), from which we need to set the target.source-map. 608 void SetSourceMapFromArguments(DAP &dap, const llvm::json::Object &arguments) { 609 const char *sourceMapHelp = 610 "source must be be an array of two-element arrays, " 611 "each containing a source and replacement path string.\n"; 612 613 std::string sourceMapCommand; 614 llvm::raw_string_ostream strm(sourceMapCommand); 615 strm << "settings set target.source-map "; 616 const auto sourcePath = GetString(arguments, "sourcePath"); 617 618 // sourceMap is the new, more general form of sourcePath and overrides it. 619 constexpr llvm::StringRef sourceMapKey = "sourceMap"; 620 621 if (const auto *sourceMapArray = arguments.getArray(sourceMapKey)) { 622 for (const auto &value : *sourceMapArray) { 623 const auto *mapping = value.getAsArray(); 624 if (mapping == nullptr || mapping->size() != 2 || 625 (*mapping)[0].kind() != llvm::json::Value::String || 626 (*mapping)[1].kind() != llvm::json::Value::String) { 627 dap.SendOutput(OutputType::Console, llvm::StringRef(sourceMapHelp)); 628 return; 629 } 630 const auto mapFrom = GetAsString((*mapping)[0]); 631 const auto mapTo = GetAsString((*mapping)[1]); 632 strm << "\"" << mapFrom << "\" \"" << mapTo << "\" "; 633 } 634 } else if (const auto *sourceMapObj = arguments.getObject(sourceMapKey)) { 635 for (const auto &[key, value] : *sourceMapObj) { 636 if (value.kind() == llvm::json::Value::String) { 637 strm << "\"" << key.str() << "\" \"" << GetAsString(value) << "\" "; 638 } 639 } 640 } else { 641 if (ObjectContainsKey(arguments, sourceMapKey)) { 642 dap.SendOutput(OutputType::Console, llvm::StringRef(sourceMapHelp)); 643 return; 644 } 645 if (sourcePath.empty()) 646 return; 647 // Do any source remapping needed before we create our targets 648 strm << "\".\" \"" << sourcePath << "\""; 649 } 650 if (!sourceMapCommand.empty()) { 651 dap.RunLLDBCommands("Setting source map:", {sourceMapCommand}); 652 } 653 } 654 655 // Fill in the stack frames of the thread. 656 // 657 // Threads stacks may contain runtime specific extended backtraces, when 658 // constructing a stack trace first report the full thread stack trace then 659 // perform a breadth first traversal of any extended backtrace frames. 660 // 661 // For example: 662 // 663 // Thread (id=th0) stack=[s0, s1, s2, s3] 664 // \ Extended backtrace "libdispatch" Thread (id=th1) stack=[s0, s1] 665 // \ Extended backtrace "libdispatch" Thread (id=th2) stack=[s0, s1] 666 // \ Extended backtrace "Application Specific Backtrace" Thread (id=th3) 667 // stack=[s0, s1, s2] 668 // 669 // Which will flatten into: 670 // 671 // 0. th0->s0 672 // 1. th0->s1 673 // 2. th0->s2 674 // 3. th0->s3 675 // 4. label - Enqueued from th1, sf=-1, i=-4 676 // 5. th1->s0 677 // 6. th1->s1 678 // 7. label - Enqueued from th2 679 // 8. th2->s0 680 // 9. th2->s1 681 // 10. label - Application Specific Backtrace 682 // 11. th3->s0 683 // 12. th3->s1 684 // 13. th3->s2 685 // 686 // s=3,l=3 = [th0->s3, label1, th1->s0] 687 bool FillStackFrames(DAP &dap, lldb::SBThread &thread, 688 llvm::json::Array &stack_frames, int64_t &offset, 689 const int64_t start_frame, const int64_t levels) { 690 bool reached_end_of_stack = false; 691 for (int64_t i = start_frame; 692 static_cast<int64_t>(stack_frames.size()) < levels; i++) { 693 if (i == -1) { 694 stack_frames.emplace_back( 695 CreateExtendedStackFrameLabel(thread, dap.frame_format)); 696 continue; 697 } 698 699 lldb::SBFrame frame = thread.GetFrameAtIndex(i); 700 if (!frame.IsValid()) { 701 offset += thread.GetNumFrames() + 1 /* label between threads */; 702 reached_end_of_stack = true; 703 break; 704 } 705 706 stack_frames.emplace_back(CreateStackFrame(frame, dap.frame_format)); 707 } 708 709 if (dap.display_extended_backtrace && reached_end_of_stack) { 710 // Check for any extended backtraces. 711 for (uint32_t bt = 0; 712 bt < thread.GetProcess().GetNumExtendedBacktraceTypes(); bt++) { 713 lldb::SBThread backtrace = thread.GetExtendedBacktraceThread( 714 thread.GetProcess().GetExtendedBacktraceTypeAtIndex(bt)); 715 if (!backtrace.IsValid()) 716 continue; 717 718 reached_end_of_stack = FillStackFrames( 719 dap, backtrace, stack_frames, offset, 720 (start_frame - offset) > 0 ? start_frame - offset : -1, levels); 721 if (static_cast<int64_t>(stack_frames.size()) >= levels) 722 break; 723 } 724 } 725 726 return reached_end_of_stack; 727 } 728 729 // "AttachRequest": { 730 // "allOf": [ { "$ref": "#/definitions/Request" }, { 731 // "type": "object", 732 // "description": "Attach request; value of command field is 'attach'.", 733 // "properties": { 734 // "command": { 735 // "type": "string", 736 // "enum": [ "attach" ] 737 // }, 738 // "arguments": { 739 // "$ref": "#/definitions/AttachRequestArguments" 740 // } 741 // }, 742 // "required": [ "command", "arguments" ] 743 // }] 744 // }, 745 // "AttachRequestArguments": { 746 // "type": "object", 747 // "description": "Arguments for 'attach' request.\nThe attach request has no 748 // standardized attributes." 749 // }, 750 // "AttachResponse": { 751 // "allOf": [ { "$ref": "#/definitions/Response" }, { 752 // "type": "object", 753 // "description": "Response to 'attach' request. This is just an 754 // acknowledgement, so no body field is required." 755 // }] 756 // } 757 void request_attach(DAP &dap, const llvm::json::Object &request) { 758 dap.is_attach = true; 759 dap.last_launch_or_attach_request = request; 760 llvm::json::Object response; 761 lldb::SBError error; 762 FillResponse(request, response); 763 lldb::SBAttachInfo attach_info; 764 const int invalid_port = 0; 765 const auto *arguments = request.getObject("arguments"); 766 const lldb::pid_t pid = 767 GetUnsigned(arguments, "pid", LLDB_INVALID_PROCESS_ID); 768 const auto gdb_remote_port = 769 GetUnsigned(arguments, "gdb-remote-port", invalid_port); 770 const auto gdb_remote_hostname = 771 GetString(arguments, "gdb-remote-hostname", "localhost"); 772 if (pid != LLDB_INVALID_PROCESS_ID) 773 attach_info.SetProcessID(pid); 774 const auto wait_for = GetBoolean(arguments, "waitFor", false); 775 attach_info.SetWaitForLaunch(wait_for, false /*async*/); 776 dap.init_commands = GetStrings(arguments, "initCommands"); 777 dap.pre_run_commands = GetStrings(arguments, "preRunCommands"); 778 dap.stop_commands = GetStrings(arguments, "stopCommands"); 779 dap.exit_commands = GetStrings(arguments, "exitCommands"); 780 dap.terminate_commands = GetStrings(arguments, "terminateCommands"); 781 auto attachCommands = GetStrings(arguments, "attachCommands"); 782 llvm::StringRef core_file = GetString(arguments, "coreFile"); 783 const uint64_t timeout_seconds = GetUnsigned(arguments, "timeout", 30); 784 dap.stop_at_entry = 785 core_file.empty() ? GetBoolean(arguments, "stopOnEntry", false) : true; 786 dap.post_run_commands = GetStrings(arguments, "postRunCommands"); 787 const llvm::StringRef debuggerRoot = GetString(arguments, "debuggerRoot"); 788 dap.enable_auto_variable_summaries = 789 GetBoolean(arguments, "enableAutoVariableSummaries", false); 790 dap.enable_synthetic_child_debugging = 791 GetBoolean(arguments, "enableSyntheticChildDebugging", false); 792 dap.display_extended_backtrace = 793 GetBoolean(arguments, "displayExtendedBacktrace", false); 794 dap.command_escape_prefix = GetString(arguments, "commandEscapePrefix", "`"); 795 dap.SetFrameFormat(GetString(arguments, "customFrameFormat")); 796 dap.SetThreadFormat(GetString(arguments, "customThreadFormat")); 797 798 PrintWelcomeMessage(dap); 799 800 // This is a hack for loading DWARF in .o files on Mac where the .o files 801 // in the debug map of the main executable have relative paths which require 802 // the lldb-dap binary to have its working directory set to that relative 803 // root for the .o files in order to be able to load debug info. 804 if (!debuggerRoot.empty()) 805 llvm::sys::fs::set_current_path(debuggerRoot); 806 807 // Run any initialize LLDB commands the user specified in the launch.json 808 if (llvm::Error err = dap.RunInitCommands()) { 809 response["success"] = false; 810 EmplaceSafeString(response, "message", llvm::toString(std::move(err))); 811 dap.SendJSON(llvm::json::Value(std::move(response))); 812 return; 813 } 814 815 SetSourceMapFromArguments(dap, *arguments); 816 817 lldb::SBError status; 818 dap.SetTarget(dap.CreateTargetFromArguments(*arguments, status)); 819 if (status.Fail()) { 820 response["success"] = llvm::json::Value(false); 821 EmplaceSafeString(response, "message", status.GetCString()); 822 dap.SendJSON(llvm::json::Value(std::move(response))); 823 return; 824 } 825 826 // Run any pre run LLDB commands the user specified in the launch.json 827 if (llvm::Error err = dap.RunPreRunCommands()) { 828 response["success"] = false; 829 EmplaceSafeString(response, "message", llvm::toString(std::move(err))); 830 dap.SendJSON(llvm::json::Value(std::move(response))); 831 return; 832 } 833 834 if ((pid == LLDB_INVALID_PROCESS_ID || gdb_remote_port == invalid_port) && 835 wait_for) { 836 char attach_msg[256]; 837 auto attach_msg_len = snprintf(attach_msg, sizeof(attach_msg), 838 "Waiting to attach to \"%s\"...", 839 dap.target.GetExecutable().GetFilename()); 840 dap.SendOutput(OutputType::Console, 841 llvm::StringRef(attach_msg, attach_msg_len)); 842 } 843 if (attachCommands.empty()) { 844 // No "attachCommands", just attach normally. 845 // Disable async events so the attach will be successful when we return from 846 // the launch call and the launch will happen synchronously 847 dap.debugger.SetAsync(false); 848 if (core_file.empty()) { 849 if ((pid != LLDB_INVALID_PROCESS_ID) && 850 (gdb_remote_port != invalid_port)) { 851 // If both pid and port numbers are specified. 852 error.SetErrorString("The user can't specify both pid and port"); 853 } else if (gdb_remote_port != invalid_port) { 854 // If port is specified and pid is not. 855 lldb::SBListener listener = dap.debugger.GetListener(); 856 857 // If the user hasn't provided the hostname property, default localhost 858 // being used. 859 std::string connect_url = 860 llvm::formatv("connect://{0}:", gdb_remote_hostname); 861 connect_url += std::to_string(gdb_remote_port); 862 dap.target.ConnectRemote(listener, connect_url.c_str(), "gdb-remote", 863 error); 864 } else { 865 // Attach by process name or id. 866 dap.target.Attach(attach_info, error); 867 } 868 } else 869 dap.target.LoadCore(core_file.data(), error); 870 // Reenable async events 871 dap.debugger.SetAsync(true); 872 } else { 873 // We have "attachCommands" that are a set of commands that are expected 874 // to execute the commands after which a process should be created. If there 875 // is no valid process after running these commands, we have failed. 876 if (llvm::Error err = dap.RunAttachCommands(attachCommands)) { 877 response["success"] = false; 878 EmplaceSafeString(response, "message", llvm::toString(std::move(err))); 879 dap.SendJSON(llvm::json::Value(std::move(response))); 880 return; 881 } 882 // The custom commands might have created a new target so we should use the 883 // selected target after these commands are run. 884 dap.target = dap.debugger.GetSelectedTarget(); 885 886 // Make sure the process is attached and stopped before proceeding as the 887 // the launch commands are not run using the synchronous mode. 888 error = dap.WaitForProcessToStop(timeout_seconds); 889 } 890 891 if (error.Success() && core_file.empty()) { 892 auto attached_pid = dap.target.GetProcess().GetProcessID(); 893 if (attached_pid == LLDB_INVALID_PROCESS_ID) { 894 if (attachCommands.empty()) 895 error.SetErrorString("failed to attach to a process"); 896 else 897 error.SetErrorString("attachCommands failed to attach to a process"); 898 } 899 } 900 901 if (error.Fail()) { 902 response["success"] = llvm::json::Value(false); 903 EmplaceSafeString(response, "message", std::string(error.GetCString())); 904 } else { 905 dap.RunPostRunCommands(); 906 } 907 908 dap.SendJSON(llvm::json::Value(std::move(response))); 909 if (error.Success()) { 910 SendProcessEvent(dap, Attach); 911 dap.SendJSON(CreateEventObject("initialized")); 912 } 913 } 914 915 // "ContinueRequest": { 916 // "allOf": [ { "$ref": "#/definitions/Request" }, { 917 // "type": "object", 918 // "description": "Continue request; value of command field is 'continue'. 919 // The request starts the debuggee to run again.", 920 // "properties": { 921 // "command": { 922 // "type": "string", 923 // "enum": [ "continue" ] 924 // }, 925 // "arguments": { 926 // "$ref": "#/definitions/ContinueArguments" 927 // } 928 // }, 929 // "required": [ "command", "arguments" ] 930 // }] 931 // }, 932 // "ContinueArguments": { 933 // "type": "object", 934 // "description": "Arguments for 'continue' request.", 935 // "properties": { 936 // "threadId": { 937 // "type": "integer", 938 // "description": "Continue execution for the specified thread (if 939 // possible). If the backend cannot continue on a single 940 // thread but will continue on all threads, it should 941 // set the allThreadsContinued attribute in the response 942 // to true." 943 // } 944 // }, 945 // "required": [ "threadId" ] 946 // }, 947 // "ContinueResponse": { 948 // "allOf": [ { "$ref": "#/definitions/Response" }, { 949 // "type": "object", 950 // "description": "Response to 'continue' request.", 951 // "properties": { 952 // "body": { 953 // "type": "object", 954 // "properties": { 955 // "allThreadsContinued": { 956 // "type": "boolean", 957 // "description": "If true, the continue request has ignored the 958 // specified thread and continued all threads 959 // instead. If this attribute is missing a value 960 // of 'true' is assumed for backward 961 // compatibility." 962 // } 963 // } 964 // } 965 // }, 966 // "required": [ "body" ] 967 // }] 968 // } 969 void request_continue(DAP &dap, const llvm::json::Object &request) { 970 llvm::json::Object response; 971 FillResponse(request, response); 972 lldb::SBProcess process = dap.target.GetProcess(); 973 lldb::SBError error = process.Continue(); 974 llvm::json::Object body; 975 body.try_emplace("allThreadsContinued", true); 976 response.try_emplace("body", std::move(body)); 977 dap.SendJSON(llvm::json::Value(std::move(response))); 978 } 979 980 // "ConfigurationDoneRequest": { 981 // "allOf": [ { "$ref": "#/definitions/Request" }, { 982 // "type": "object", 983 // "description": "ConfigurationDone request; value of command field 984 // is 'configurationDone'.\nThe client of the debug protocol must 985 // send this request at the end of the sequence of configuration 986 // requests (which was started by the InitializedEvent).", 987 // "properties": { 988 // "command": { 989 // "type": "string", 990 // "enum": [ "configurationDone" ] 991 // }, 992 // "arguments": { 993 // "$ref": "#/definitions/ConfigurationDoneArguments" 994 // } 995 // }, 996 // "required": [ "command" ] 997 // }] 998 // }, 999 // "ConfigurationDoneArguments": { 1000 // "type": "object", 1001 // "description": "Arguments for 'configurationDone' request.\nThe 1002 // configurationDone request has no standardized attributes." 1003 // }, 1004 // "ConfigurationDoneResponse": { 1005 // "allOf": [ { "$ref": "#/definitions/Response" }, { 1006 // "type": "object", 1007 // "description": "Response to 'configurationDone' request. This is 1008 // just an acknowledgement, so no body field is required." 1009 // }] 1010 // }, 1011 void request_configurationDone(DAP &dap, const llvm::json::Object &request) { 1012 llvm::json::Object response; 1013 FillResponse(request, response); 1014 dap.SendJSON(llvm::json::Value(std::move(response))); 1015 dap.configuration_done_sent = true; 1016 if (dap.stop_at_entry) 1017 SendThreadStoppedEvent(dap); 1018 else 1019 dap.target.GetProcess().Continue(); 1020 } 1021 1022 // "DisconnectRequest": { 1023 // "allOf": [ { "$ref": "#/definitions/Request" }, { 1024 // "type": "object", 1025 // "description": "Disconnect request; value of command field is 1026 // 'disconnect'.", 1027 // "properties": { 1028 // "command": { 1029 // "type": "string", 1030 // "enum": [ "disconnect" ] 1031 // }, 1032 // "arguments": { 1033 // "$ref": "#/definitions/DisconnectArguments" 1034 // } 1035 // }, 1036 // "required": [ "command" ] 1037 // }] 1038 // }, 1039 // "DisconnectArguments": { 1040 // "type": "object", 1041 // "description": "Arguments for 'disconnect' request.", 1042 // "properties": { 1043 // "terminateDebuggee": { 1044 // "type": "boolean", 1045 // "description": "Indicates whether the debuggee should be terminated 1046 // when the debugger is disconnected. If unspecified, 1047 // the debug adapter is free to do whatever it thinks 1048 // is best. A client can only rely on this attribute 1049 // being properly honored if a debug adapter returns 1050 // true for the 'supportTerminateDebuggee' capability." 1051 // }, 1052 // "restart": { 1053 // "type": "boolean", 1054 // "description": "Indicates whether the debuggee should be restart 1055 // the process." 1056 // } 1057 // } 1058 // }, 1059 // "DisconnectResponse": { 1060 // "allOf": [ { "$ref": "#/definitions/Response" }, { 1061 // "type": "object", 1062 // "description": "Response to 'disconnect' request. This is just an 1063 // acknowledgement, so no body field is required." 1064 // }] 1065 // } 1066 void request_disconnect(DAP &dap, const llvm::json::Object &request) { 1067 llvm::json::Object response; 1068 FillResponse(request, response); 1069 const auto *arguments = request.getObject("arguments"); 1070 1071 bool defaultTerminateDebuggee = dap.is_attach ? false : true; 1072 bool terminateDebuggee = 1073 GetBoolean(arguments, "terminateDebuggee", defaultTerminateDebuggee); 1074 lldb::SBProcess process = dap.target.GetProcess(); 1075 auto state = process.GetState(); 1076 switch (state) { 1077 case lldb::eStateInvalid: 1078 case lldb::eStateUnloaded: 1079 case lldb::eStateDetached: 1080 case lldb::eStateExited: 1081 break; 1082 case lldb::eStateConnected: 1083 case lldb::eStateAttaching: 1084 case lldb::eStateLaunching: 1085 case lldb::eStateStepping: 1086 case lldb::eStateCrashed: 1087 case lldb::eStateSuspended: 1088 case lldb::eStateStopped: 1089 case lldb::eStateRunning: 1090 dap.debugger.SetAsync(false); 1091 lldb::SBError error = terminateDebuggee ? process.Kill() : process.Detach(); 1092 if (!error.Success()) 1093 EmplaceSafeString(response, "error", error.GetCString()); 1094 dap.debugger.SetAsync(true); 1095 break; 1096 } 1097 SendTerminatedEvent(dap); 1098 dap.SendJSON(llvm::json::Value(std::move(response))); 1099 if (dap.event_thread.joinable()) { 1100 dap.broadcaster.BroadcastEventByType(eBroadcastBitStopEventThread); 1101 dap.event_thread.join(); 1102 } 1103 if (dap.progress_event_thread.joinable()) { 1104 dap.broadcaster.BroadcastEventByType(eBroadcastBitStopProgressThread); 1105 dap.progress_event_thread.join(); 1106 } 1107 dap.StopIO(); 1108 dap.disconnecting = true; 1109 } 1110 1111 // "ExceptionInfoRequest": { 1112 // "allOf": [ { "$ref": "#/definitions/Request" }, { 1113 // "type": "object", 1114 // "description": "Retrieves the details of the exception that 1115 // caused this event to be raised. Clients should only call this request if 1116 // the corresponding capability `supportsExceptionInfoRequest` is true.", 1117 // "properties": { 1118 // "command": { 1119 // "type": "string", 1120 // "enum": [ "exceptionInfo" ] 1121 // }, 1122 // "arguments": { 1123 // "$ref": "#/definitions/ExceptionInfoArguments" 1124 // } 1125 // }, 1126 // "required": [ "command", "arguments" ] 1127 // }] 1128 // }, 1129 // "ExceptionInfoArguments": { 1130 // "type": "object", 1131 // "description": "Arguments for `exceptionInfo` request.", 1132 // "properties": { 1133 // "threadId": { 1134 // "type": "integer", 1135 // "description": "Thread for which exception information should be 1136 // retrieved." 1137 // } 1138 // }, 1139 // "required": [ "threadId" ] 1140 // }, 1141 // "ExceptionInfoResponse": { 1142 // "allOf": [ { "$ref": "#/definitions/Response" }, { 1143 // "type": "object", 1144 // "description": "Response to `exceptionInfo` request.", 1145 // "properties": { 1146 // "body": { 1147 // "type": "object", 1148 // "properties": { 1149 // "exceptionId": { 1150 // "type": "string", 1151 // "description": "ID of the exception that was thrown." 1152 // }, 1153 // "description": { 1154 // "type": "string", 1155 // "description": "Descriptive text for the exception." 1156 // }, 1157 // "breakMode": { 1158 // "$ref": "#/definitions/ExceptionBreakMode", 1159 // "description": "Mode that caused the exception notification to 1160 // be raised." 1161 // }, 1162 // "details": { 1163 // "$ref": "#/definitions/ExceptionDetails", 1164 // "description": "Detailed information about the exception." 1165 // } 1166 // }, 1167 // "required": [ "exceptionId", "breakMode" ] 1168 // } 1169 // }, 1170 // "required": [ "body" ] 1171 // }] 1172 // } 1173 // "ExceptionDetails": { 1174 // "type": "object", 1175 // "description": "Detailed information about an exception that has 1176 // occurred.", "properties": { 1177 // "message": { 1178 // "type": "string", 1179 // "description": "Message contained in the exception." 1180 // }, 1181 // "typeName": { 1182 // "type": "string", 1183 // "description": "Short type name of the exception object." 1184 // }, 1185 // "fullTypeName": { 1186 // "type": "string", 1187 // "description": "Fully-qualified type name of the exception object." 1188 // }, 1189 // "evaluateName": { 1190 // "type": "string", 1191 // "description": "An expression that can be evaluated in the current 1192 // scope to obtain the exception object." 1193 // }, 1194 // "stackTrace": { 1195 // "type": "string", 1196 // "description": "Stack trace at the time the exception was thrown." 1197 // }, 1198 // "innerException": { 1199 // "type": "array", 1200 // "items": { 1201 // "$ref": "#/definitions/ExceptionDetails" 1202 // }, 1203 // "description": "Details of the exception contained by this exception, 1204 // if any." 1205 // } 1206 // } 1207 // }, 1208 void request_exceptionInfo(DAP &dap, const llvm::json::Object &request) { 1209 llvm::json::Object response; 1210 FillResponse(request, response); 1211 const auto *arguments = request.getObject("arguments"); 1212 llvm::json::Object body; 1213 lldb::SBThread thread = dap.GetLLDBThread(*arguments); 1214 if (thread.IsValid()) { 1215 auto stopReason = thread.GetStopReason(); 1216 if (stopReason == lldb::eStopReasonSignal) 1217 body.try_emplace("exceptionId", "signal"); 1218 else if (stopReason == lldb::eStopReasonBreakpoint) { 1219 ExceptionBreakpoint *exc_bp = dap.GetExceptionBPFromStopReason(thread); 1220 if (exc_bp) { 1221 EmplaceSafeString(body, "exceptionId", exc_bp->filter); 1222 EmplaceSafeString(body, "description", exc_bp->label); 1223 } else { 1224 body.try_emplace("exceptionId", "exception"); 1225 } 1226 } else { 1227 body.try_emplace("exceptionId", "exception"); 1228 } 1229 if (!ObjectContainsKey(body, "description")) { 1230 char description[1024]; 1231 if (thread.GetStopDescription(description, sizeof(description))) { 1232 EmplaceSafeString(body, "description", std::string(description)); 1233 } 1234 } 1235 body.try_emplace("breakMode", "always"); 1236 auto exception = thread.GetCurrentException(); 1237 if (exception.IsValid()) { 1238 llvm::json::Object details; 1239 lldb::SBStream stream; 1240 if (exception.GetDescription(stream)) { 1241 EmplaceSafeString(details, "message", stream.GetData()); 1242 } 1243 1244 auto exceptionBacktrace = thread.GetCurrentExceptionBacktrace(); 1245 if (exceptionBacktrace.IsValid()) { 1246 lldb::SBStream stream; 1247 exceptionBacktrace.GetDescription(stream); 1248 for (uint32_t i = 0; i < exceptionBacktrace.GetNumFrames(); i++) { 1249 lldb::SBFrame frame = exceptionBacktrace.GetFrameAtIndex(i); 1250 frame.GetDescription(stream); 1251 } 1252 EmplaceSafeString(details, "stackTrace", stream.GetData()); 1253 } 1254 1255 body.try_emplace("details", std::move(details)); 1256 } 1257 // auto excInfoCount = thread.GetStopReasonDataCount(); 1258 // for (auto i=0; i<excInfoCount; ++i) { 1259 // uint64_t exc_data = thread.GetStopReasonDataAtIndex(i); 1260 // } 1261 } else { 1262 response["success"] = llvm::json::Value(false); 1263 } 1264 response.try_emplace("body", std::move(body)); 1265 dap.SendJSON(llvm::json::Value(std::move(response))); 1266 } 1267 1268 // "CompletionsRequest": { 1269 // "allOf": [ { "$ref": "#/definitions/Request" }, { 1270 // "type": "object", 1271 // "description": "Returns a list of possible completions for a given caret 1272 // position and text.\nThe CompletionsRequest may only be called if the 1273 // 'supportsCompletionsRequest' capability exists and is true.", 1274 // "properties": { 1275 // "command": { 1276 // "type": "string", 1277 // "enum": [ "completions" ] 1278 // }, 1279 // "arguments": { 1280 // "$ref": "#/definitions/CompletionsArguments" 1281 // } 1282 // }, 1283 // "required": [ "command", "arguments" ] 1284 // }] 1285 // }, 1286 // "CompletionsArguments": { 1287 // "type": "object", 1288 // "description": "Arguments for 'completions' request.", 1289 // "properties": { 1290 // "frameId": { 1291 // "type": "integer", 1292 // "description": "Returns completions in the scope of this stack frame. 1293 // If not specified, the completions are returned for the global scope." 1294 // }, 1295 // "text": { 1296 // "type": "string", 1297 // "description": "One or more source lines. Typically this is the text a 1298 // user has typed into the debug console before he asked for completion." 1299 // }, 1300 // "column": { 1301 // "type": "integer", 1302 // "description": "The character position for which to determine the 1303 // completion proposals." 1304 // }, 1305 // "line": { 1306 // "type": "integer", 1307 // "description": "An optional line for which to determine the completion 1308 // proposals. If missing the first line of the text is assumed." 1309 // } 1310 // }, 1311 // "required": [ "text", "column" ] 1312 // }, 1313 // "CompletionsResponse": { 1314 // "allOf": [ { "$ref": "#/definitions/Response" }, { 1315 // "type": "object", 1316 // "description": "Response to 'completions' request.", 1317 // "properties": { 1318 // "body": { 1319 // "type": "object", 1320 // "properties": { 1321 // "targets": { 1322 // "type": "array", 1323 // "items": { 1324 // "$ref": "#/definitions/CompletionItem" 1325 // }, 1326 // "description": "The possible completions for ." 1327 // } 1328 // }, 1329 // "required": [ "targets" ] 1330 // } 1331 // }, 1332 // "required": [ "body" ] 1333 // }] 1334 // }, 1335 // "CompletionItem": { 1336 // "type": "object", 1337 // "description": "CompletionItems are the suggestions returned from the 1338 // CompletionsRequest.", "properties": { 1339 // "label": { 1340 // "type": "string", 1341 // "description": "The label of this completion item. By default this is 1342 // also the text that is inserted when selecting this completion." 1343 // }, 1344 // "text": { 1345 // "type": "string", 1346 // "description": "If text is not falsy then it is inserted instead of the 1347 // label." 1348 // }, 1349 // "sortText": { 1350 // "type": "string", 1351 // "description": "A string that should be used when comparing this item 1352 // with other items. When `falsy` the label is used." 1353 // }, 1354 // "type": { 1355 // "$ref": "#/definitions/CompletionItemType", 1356 // "description": "The item's type. Typically the client uses this 1357 // information to render the item in the UI with an icon." 1358 // }, 1359 // "start": { 1360 // "type": "integer", 1361 // "description": "This value determines the location (in the 1362 // CompletionsRequest's 'text' attribute) where the completion text is 1363 // added.\nIf missing the text is added at the location specified by the 1364 // CompletionsRequest's 'column' attribute." 1365 // }, 1366 // "length": { 1367 // "type": "integer", 1368 // "description": "This value determines how many characters are 1369 // overwritten by the completion text.\nIf missing the value 0 is assumed 1370 // which results in the completion text being inserted." 1371 // } 1372 // }, 1373 // "required": [ "label" ] 1374 // }, 1375 // "CompletionItemType": { 1376 // "type": "string", 1377 // "description": "Some predefined types for the CompletionItem. Please note 1378 // that not all clients have specific icons for all of them.", "enum": [ 1379 // "method", "function", "constructor", "field", "variable", "class", 1380 // "interface", "module", "property", "unit", "value", "enum", "keyword", 1381 // "snippet", "text", "color", "file", "reference", "customcolor" ] 1382 // } 1383 void request_completions(DAP &dap, const llvm::json::Object &request) { 1384 llvm::json::Object response; 1385 FillResponse(request, response); 1386 llvm::json::Object body; 1387 const auto *arguments = request.getObject("arguments"); 1388 1389 // If we have a frame, try to set the context for variable completions. 1390 lldb::SBFrame frame = dap.GetLLDBFrame(*arguments); 1391 if (frame.IsValid()) { 1392 frame.GetThread().GetProcess().SetSelectedThread(frame.GetThread()); 1393 frame.GetThread().SetSelectedFrame(frame.GetFrameID()); 1394 } 1395 1396 std::string text = GetString(arguments, "text").str(); 1397 auto original_column = GetSigned(arguments, "column", text.size()); 1398 auto original_line = GetSigned(arguments, "line", 1); 1399 auto offset = original_column - 1; 1400 if (original_line > 1) { 1401 llvm::SmallVector<::llvm::StringRef, 2> lines; 1402 llvm::StringRef(text).split(lines, '\n'); 1403 for (int i = 0; i < original_line - 1; i++) { 1404 offset += lines[i].size(); 1405 } 1406 } 1407 llvm::json::Array targets; 1408 1409 bool had_escape_prefix = 1410 llvm::StringRef(text).starts_with(dap.command_escape_prefix); 1411 ReplMode completion_mode = dap.DetectReplMode(frame, text, true); 1412 1413 // Handle the offset change introduced by stripping out the 1414 // `command_escape_prefix`. 1415 if (had_escape_prefix) { 1416 if (offset < static_cast<int64_t>(dap.command_escape_prefix.size())) { 1417 body.try_emplace("targets", std::move(targets)); 1418 response.try_emplace("body", std::move(body)); 1419 dap.SendJSON(llvm::json::Value(std::move(response))); 1420 return; 1421 } 1422 offset -= dap.command_escape_prefix.size(); 1423 } 1424 1425 // While the user is typing then we likely have an incomplete input and cannot 1426 // reliably determine the precise intent (command vs variable), try completing 1427 // the text as both a command and variable expression, if applicable. 1428 const std::string expr_prefix = "expression -- "; 1429 std::array<std::tuple<ReplMode, std::string, uint64_t>, 2> exprs = { 1430 {std::make_tuple(ReplMode::Command, text, offset), 1431 std::make_tuple(ReplMode::Variable, expr_prefix + text, 1432 offset + expr_prefix.size())}}; 1433 for (const auto &[mode, line, cursor] : exprs) { 1434 if (completion_mode != ReplMode::Auto && completion_mode != mode) 1435 continue; 1436 1437 lldb::SBStringList matches; 1438 lldb::SBStringList descriptions; 1439 if (!dap.debugger.GetCommandInterpreter().HandleCompletionWithDescriptions( 1440 line.c_str(), cursor, 0, 100, matches, descriptions)) 1441 continue; 1442 1443 // The first element is the common substring after the cursor position for 1444 // all the matches. The rest of the elements are the matches so ignore the 1445 // first result. 1446 for (size_t i = 1; i < matches.GetSize(); i++) { 1447 std::string match = matches.GetStringAtIndex(i); 1448 std::string description = descriptions.GetStringAtIndex(i); 1449 1450 llvm::json::Object item; 1451 llvm::StringRef match_ref = match; 1452 for (llvm::StringRef commit_point : {".", "->"}) { 1453 if (match_ref.contains(commit_point)) { 1454 match_ref = match_ref.rsplit(commit_point).second; 1455 } 1456 } 1457 EmplaceSafeString(item, "text", match_ref); 1458 1459 if (description.empty()) 1460 EmplaceSafeString(item, "label", match); 1461 else 1462 EmplaceSafeString(item, "label", match + " -- " + description); 1463 1464 targets.emplace_back(std::move(item)); 1465 } 1466 } 1467 1468 body.try_emplace("targets", std::move(targets)); 1469 response.try_emplace("body", std::move(body)); 1470 dap.SendJSON(llvm::json::Value(std::move(response))); 1471 } 1472 1473 // "EvaluateRequest": { 1474 // "allOf": [ { "$ref": "#/definitions/Request" }, { 1475 // "type": "object", 1476 // "description": "Evaluate request; value of command field is 'evaluate'. 1477 // Evaluates the given expression in the context of the 1478 // top most stack frame. The expression has access to any 1479 // variables and arguments that are in scope.", 1480 // "properties": { 1481 // "command": { 1482 // "type": "string", 1483 // "enum": [ "evaluate" ] 1484 // }, 1485 // "arguments": { 1486 // "$ref": "#/definitions/EvaluateArguments" 1487 // } 1488 // }, 1489 // "required": [ "command", "arguments" ] 1490 // }] 1491 // }, 1492 // "EvaluateArguments": { 1493 // "type": "object", 1494 // "description": "Arguments for 'evaluate' request.", 1495 // "properties": { 1496 // "expression": { 1497 // "type": "string", 1498 // "description": "The expression to evaluate." 1499 // }, 1500 // "frameId": { 1501 // "type": "integer", 1502 // "description": "Evaluate the expression in the scope of this stack 1503 // frame. If not specified, the expression is evaluated 1504 // in the global scope." 1505 // }, 1506 // "context": { 1507 // "type": "string", 1508 // "_enum": [ "watch", "repl", "hover" ], 1509 // "enumDescriptions": [ 1510 // "evaluate is run in a watch.", 1511 // "evaluate is run from REPL console.", 1512 // "evaluate is run from a data hover." 1513 // ], 1514 // "description": "The context in which the evaluate request is run." 1515 // }, 1516 // "format": { 1517 // "$ref": "#/definitions/ValueFormat", 1518 // "description": "Specifies details on how to format the Evaluate 1519 // result." 1520 // } 1521 // }, 1522 // "required": [ "expression" ] 1523 // }, 1524 // "EvaluateResponse": { 1525 // "allOf": [ { "$ref": "#/definitions/Response" }, { 1526 // "type": "object", 1527 // "description": "Response to 'evaluate' request.", 1528 // "properties": { 1529 // "body": { 1530 // "type": "object", 1531 // "properties": { 1532 // "result": { 1533 // "type": "string", 1534 // "description": "The result of the evaluate request." 1535 // }, 1536 // "type": { 1537 // "type": "string", 1538 // "description": "The optional type of the evaluate result." 1539 // }, 1540 // "presentationHint": { 1541 // "$ref": "#/definitions/VariablePresentationHint", 1542 // "description": "Properties of a evaluate result that can be 1543 // used to determine how to render the result in 1544 // the UI." 1545 // }, 1546 // "variablesReference": { 1547 // "type": "number", 1548 // "description": "If variablesReference is > 0, the evaluate 1549 // result is structured and its children can be 1550 // retrieved by passing variablesReference to the 1551 // VariablesRequest." 1552 // }, 1553 // "namedVariables": { 1554 // "type": "number", 1555 // "description": "The number of named child variables. The 1556 // client can use this optional information to 1557 // present the variables in a paged UI and fetch 1558 // them in chunks." 1559 // }, 1560 // "indexedVariables": { 1561 // "type": "number", 1562 // "description": "The number of indexed child variables. The 1563 // client can use this optional information to 1564 // present the variables in a paged UI and fetch 1565 // them in chunks." 1566 // }, 1567 // "valueLocationReference": { 1568 // "type": "integer", 1569 // "description": "A reference that allows the client to request 1570 // the location where the returned value is 1571 // declared. For example, if a function pointer is 1572 // returned, the adapter may be able to look up the 1573 // function's location. This should be present only 1574 // if the adapter is likely to be able to resolve 1575 // the location.\n\nThis reference shares the same 1576 // lifetime as the `variablesReference`. See 1577 // 'Lifetime of Object References' in the 1578 // Overview section for details." 1579 // } 1580 // "memoryReference": { 1581 // "type": "string", 1582 // "description": "A memory reference to a location appropriate 1583 // for this result. For pointer type eval 1584 // results, this is generally a reference to the 1585 // memory address contained in the pointer. This 1586 // attribute may be returned by a debug adapter 1587 // if corresponding capability 1588 // `supportsMemoryReferences` is true." 1589 // }, 1590 // }, 1591 // "required": [ "result", "variablesReference" ] 1592 // } 1593 // }, 1594 // "required": [ "body" ] 1595 // }] 1596 // } 1597 void request_evaluate(DAP &dap, const llvm::json::Object &request) { 1598 llvm::json::Object response; 1599 FillResponse(request, response); 1600 llvm::json::Object body; 1601 const auto *arguments = request.getObject("arguments"); 1602 lldb::SBFrame frame = dap.GetLLDBFrame(*arguments); 1603 std::string expression = GetString(arguments, "expression").str(); 1604 llvm::StringRef context = GetString(arguments, "context"); 1605 bool repeat_last_command = 1606 expression.empty() && dap.last_nonempty_var_expression.empty(); 1607 1608 if (context == "repl" && 1609 (repeat_last_command || 1610 (!expression.empty() && 1611 dap.DetectReplMode(frame, expression, false) == ReplMode::Command))) { 1612 // Since the current expression is not for a variable, clear the 1613 // last_nonempty_var_expression field. 1614 dap.last_nonempty_var_expression.clear(); 1615 // If we're evaluating a command relative to the current frame, set the 1616 // focus_tid to the current frame for any thread related events. 1617 if (frame.IsValid()) { 1618 dap.focus_tid = frame.GetThread().GetThreadID(); 1619 } 1620 auto result = RunLLDBCommandsVerbatim(dap.debugger, llvm::StringRef(), 1621 {std::string(expression)}); 1622 EmplaceSafeString(body, "result", result); 1623 body.try_emplace("variablesReference", (int64_t)0); 1624 } else { 1625 if (context == "repl") { 1626 // If the expression is empty and the last expression was for a 1627 // variable, set the expression to the previous expression (repeat the 1628 // evaluation); otherwise save the current non-empty expression for the 1629 // next (possibly empty) variable expression. 1630 if (expression.empty()) 1631 expression = dap.last_nonempty_var_expression; 1632 else 1633 dap.last_nonempty_var_expression = expression; 1634 } 1635 // Always try to get the answer from the local variables if possible. If 1636 // this fails, then if the context is not "hover", actually evaluate an 1637 // expression using the expression parser. 1638 // 1639 // "frame variable" is more reliable than the expression parser in 1640 // many cases and it is faster. 1641 lldb::SBValue value = frame.GetValueForVariablePath( 1642 expression.data(), lldb::eDynamicDontRunTarget); 1643 1644 // Freeze dry the value in case users expand it later in the debug console 1645 if (value.GetError().Success() && context == "repl") 1646 value = value.Persist(); 1647 1648 if (value.GetError().Fail() && context != "hover") 1649 value = frame.EvaluateExpression(expression.data()); 1650 1651 if (value.GetError().Fail()) { 1652 response["success"] = llvm::json::Value(false); 1653 // This error object must live until we're done with the pointer returned 1654 // by GetCString(). 1655 lldb::SBError error = value.GetError(); 1656 const char *error_cstr = error.GetCString(); 1657 if (error_cstr && error_cstr[0]) 1658 EmplaceSafeString(response, "message", std::string(error_cstr)); 1659 else 1660 EmplaceSafeString(response, "message", "evaluate failed"); 1661 } else { 1662 VariableDescription desc(value, dap.enable_auto_variable_summaries); 1663 EmplaceSafeString(body, "result", desc.GetResult(context)); 1664 EmplaceSafeString(body, "type", desc.display_type_name); 1665 int64_t var_ref = 0; 1666 if (value.MightHaveChildren() || ValuePointsToCode(value)) 1667 var_ref = dap.variables.InsertVariable( 1668 value, /*is_permanent=*/context == "repl"); 1669 if (value.MightHaveChildren()) 1670 body.try_emplace("variablesReference", var_ref); 1671 else 1672 body.try_emplace("variablesReference", (int64_t)0); 1673 if (lldb::addr_t addr = value.GetLoadAddress(); 1674 addr != LLDB_INVALID_ADDRESS) 1675 body.try_emplace("memoryReference", EncodeMemoryReference(addr)); 1676 if (ValuePointsToCode(value)) 1677 body.try_emplace("valueLocationReference", var_ref); 1678 } 1679 } 1680 response.try_emplace("body", std::move(body)); 1681 dap.SendJSON(llvm::json::Value(std::move(response))); 1682 } 1683 1684 // "compileUnitsRequest": { 1685 // "allOf": [ { "$ref": "#/definitions/Request" }, { 1686 // "type": "object", 1687 // "description": "Compile Unit request; value of command field is 1688 // 'compileUnits'.", 1689 // "properties": { 1690 // "command": { 1691 // "type": "string", 1692 // "enum": [ "compileUnits" ] 1693 // }, 1694 // "arguments": { 1695 // "$ref": "#/definitions/compileUnitRequestArguments" 1696 // } 1697 // }, 1698 // "required": [ "command", "arguments" ] 1699 // }] 1700 // }, 1701 // "compileUnitsRequestArguments": { 1702 // "type": "object", 1703 // "description": "Arguments for 'compileUnits' request.", 1704 // "properties": { 1705 // "moduleId": { 1706 // "type": "string", 1707 // "description": "The ID of the module." 1708 // } 1709 // }, 1710 // "required": [ "moduleId" ] 1711 // }, 1712 // "compileUnitsResponse": { 1713 // "allOf": [ { "$ref": "#/definitions/Response" }, { 1714 // "type": "object", 1715 // "description": "Response to 'compileUnits' request.", 1716 // "properties": { 1717 // "body": { 1718 // "description": "Response to 'compileUnits' request. Array of 1719 // paths of compile units." 1720 // } 1721 // } 1722 // }] 1723 // } 1724 void request_compileUnits(DAP &dap, const llvm::json::Object &request) { 1725 llvm::json::Object response; 1726 FillResponse(request, response); 1727 llvm::json::Object body; 1728 llvm::json::Array units; 1729 const auto *arguments = request.getObject("arguments"); 1730 std::string module_id = std::string(GetString(arguments, "moduleId")); 1731 int num_modules = dap.target.GetNumModules(); 1732 for (int i = 0; i < num_modules; i++) { 1733 auto curr_module = dap.target.GetModuleAtIndex(i); 1734 if (module_id == curr_module.GetUUIDString()) { 1735 int num_units = curr_module.GetNumCompileUnits(); 1736 for (int j = 0; j < num_units; j++) { 1737 auto curr_unit = curr_module.GetCompileUnitAtIndex(j); 1738 units.emplace_back(CreateCompileUnit(curr_unit)); 1739 } 1740 body.try_emplace("compileUnits", std::move(units)); 1741 break; 1742 } 1743 } 1744 response.try_emplace("body", std::move(body)); 1745 dap.SendJSON(llvm::json::Value(std::move(response))); 1746 } 1747 1748 // "modulesRequest": { 1749 // "allOf": [ { "$ref": "#/definitions/Request" }, { 1750 // "type": "object", 1751 // "description": "Modules request; value of command field is 1752 // 'modules'.", 1753 // "properties": { 1754 // "command": { 1755 // "type": "string", 1756 // "enum": [ "modules" ] 1757 // }, 1758 // }, 1759 // "required": [ "command" ] 1760 // }] 1761 // }, 1762 // "modulesResponse": { 1763 // "allOf": [ { "$ref": "#/definitions/Response" }, { 1764 // "type": "object", 1765 // "description": "Response to 'modules' request.", 1766 // "properties": { 1767 // "body": { 1768 // "description": "Response to 'modules' request. Array of 1769 // module objects." 1770 // } 1771 // } 1772 // }] 1773 // } 1774 void request_modules(DAP &dap, const llvm::json::Object &request) { 1775 llvm::json::Object response; 1776 FillResponse(request, response); 1777 1778 llvm::json::Array modules; 1779 for (size_t i = 0; i < dap.target.GetNumModules(); i++) { 1780 lldb::SBModule module = dap.target.GetModuleAtIndex(i); 1781 modules.emplace_back(CreateModule(dap.target, module)); 1782 } 1783 1784 llvm::json::Object body; 1785 body.try_emplace("modules", std::move(modules)); 1786 response.try_emplace("body", std::move(body)); 1787 dap.SendJSON(llvm::json::Value(std::move(response))); 1788 } 1789 1790 // "InitializeRequest": { 1791 // "allOf": [ { "$ref": "#/definitions/Request" }, { 1792 // "type": "object", 1793 // "description": "Initialize request; value of command field is 1794 // 'initialize'.", 1795 // "properties": { 1796 // "command": { 1797 // "type": "string", 1798 // "enum": [ "initialize" ] 1799 // }, 1800 // "arguments": { 1801 // "$ref": "#/definitions/InitializeRequestArguments" 1802 // } 1803 // }, 1804 // "required": [ "command", "arguments" ] 1805 // }] 1806 // }, 1807 // "InitializeRequestArguments": { 1808 // "type": "object", 1809 // "description": "Arguments for 'initialize' request.", 1810 // "properties": { 1811 // "clientID": { 1812 // "type": "string", 1813 // "description": "The ID of the (frontend) client using this adapter." 1814 // }, 1815 // "adapterID": { 1816 // "type": "string", 1817 // "description": "The ID of the debug adapter." 1818 // }, 1819 // "locale": { 1820 // "type": "string", 1821 // "description": "The ISO-639 locale of the (frontend) client using 1822 // this adapter, e.g. en-US or de-CH." 1823 // }, 1824 // "linesStartAt1": { 1825 // "type": "boolean", 1826 // "description": "If true all line numbers are 1-based (default)." 1827 // }, 1828 // "columnsStartAt1": { 1829 // "type": "boolean", 1830 // "description": "If true all column numbers are 1-based (default)." 1831 // }, 1832 // "pathFormat": { 1833 // "type": "string", 1834 // "_enum": [ "path", "uri" ], 1835 // "description": "Determines in what format paths are specified. The 1836 // default is 'path', which is the native format." 1837 // }, 1838 // "supportsVariableType": { 1839 // "type": "boolean", 1840 // "description": "Client supports the optional type attribute for 1841 // variables." 1842 // }, 1843 // "supportsVariablePaging": { 1844 // "type": "boolean", 1845 // "description": "Client supports the paging of variables." 1846 // }, 1847 // "supportsRunInTerminalRequest": { 1848 // "type": "boolean", 1849 // "description": "Client supports the runInTerminal request." 1850 // } 1851 // }, 1852 // "required": [ "adapterID" ] 1853 // }, 1854 // "InitializeResponse": { 1855 // "allOf": [ { "$ref": "#/definitions/Response" }, { 1856 // "type": "object", 1857 // "description": "Response to 'initialize' request.", 1858 // "properties": { 1859 // "body": { 1860 // "$ref": "#/definitions/Capabilities", 1861 // "description": "The capabilities of this debug adapter." 1862 // } 1863 // } 1864 // }] 1865 // } 1866 void request_initialize(DAP &dap, const llvm::json::Object &request) { 1867 llvm::json::Object response; 1868 FillResponse(request, response); 1869 llvm::json::Object body; 1870 1871 const auto *arguments = request.getObject("arguments"); 1872 // sourceInitFile option is not from formal DAP specification. It is only 1873 // used by unit tests to prevent sourcing .lldbinit files from environment 1874 // which may affect the outcome of tests. 1875 bool source_init_file = GetBoolean(arguments, "sourceInitFile", true); 1876 1877 // Do not source init files until in/out/err are configured. 1878 dap.debugger = lldb::SBDebugger::Create(false); 1879 dap.debugger.SetInputFile(dap.in); 1880 auto out_fd = dap.out.GetWriteFileDescriptor(); 1881 if (llvm::Error err = out_fd.takeError()) { 1882 response["success"] = false; 1883 EmplaceSafeString(response, "message", llvm::toString(std::move(err))); 1884 dap.SendJSON(llvm::json::Value(std::move(response))); 1885 return; 1886 } 1887 dap.debugger.SetOutputFile(lldb::SBFile(*out_fd, "w", false)); 1888 auto err_fd = dap.err.GetWriteFileDescriptor(); 1889 if (llvm::Error err = err_fd.takeError()) { 1890 response["success"] = false; 1891 EmplaceSafeString(response, "message", llvm::toString(std::move(err))); 1892 dap.SendJSON(llvm::json::Value(std::move(response))); 1893 return; 1894 } 1895 dap.debugger.SetErrorFile(lldb::SBFile(*err_fd, "w", false)); 1896 1897 auto interp = dap.debugger.GetCommandInterpreter(); 1898 1899 if (source_init_file) { 1900 dap.debugger.SkipLLDBInitFiles(false); 1901 dap.debugger.SkipAppInitFiles(false); 1902 lldb::SBCommandReturnObject init; 1903 interp.SourceInitFileInGlobalDirectory(init); 1904 interp.SourceInitFileInHomeDirectory(init); 1905 } 1906 1907 if (llvm::Error err = dap.RunPreInitCommands()) { 1908 response["success"] = false; 1909 EmplaceSafeString(response, "message", llvm::toString(std::move(err))); 1910 dap.SendJSON(llvm::json::Value(std::move(response))); 1911 return; 1912 } 1913 1914 dap.PopulateExceptionBreakpoints(); 1915 auto cmd = dap.debugger.GetCommandInterpreter().AddMultiwordCommand( 1916 "lldb-dap", "Commands for managing lldb-dap."); 1917 if (GetBoolean(arguments, "supportsStartDebuggingRequest", false)) { 1918 cmd.AddCommand( 1919 "start-debugging", new StartDebuggingRequestHandler(dap), 1920 "Sends a startDebugging request from the debug adapter to the client " 1921 "to start a child debug session of the same type as the caller."); 1922 } 1923 cmd.AddCommand( 1924 "repl-mode", new ReplModeRequestHandler(dap), 1925 "Get or set the repl behavior of lldb-dap evaluation requests."); 1926 cmd.AddCommand("send-event", new SendEventRequestHandler(dap), 1927 "Sends an DAP event to the client."); 1928 1929 dap.progress_event_thread = 1930 std::thread(ProgressEventThreadFunction, std::ref(dap)); 1931 1932 // Start our event thread so we can receive events from the debugger, target, 1933 // process and more. 1934 dap.event_thread = std::thread(EventThreadFunction, std::ref(dap)); 1935 1936 // The debug adapter supports the configurationDoneRequest. 1937 body.try_emplace("supportsConfigurationDoneRequest", true); 1938 // The debug adapter supports function breakpoints. 1939 body.try_emplace("supportsFunctionBreakpoints", true); 1940 // The debug adapter supports conditional breakpoints. 1941 body.try_emplace("supportsConditionalBreakpoints", true); 1942 // The debug adapter supports breakpoints that break execution after a 1943 // specified number of hits. 1944 body.try_emplace("supportsHitConditionalBreakpoints", true); 1945 // The debug adapter supports a (side effect free) evaluate request for 1946 // data hovers. 1947 body.try_emplace("supportsEvaluateForHovers", true); 1948 // Available filters or options for the setExceptionBreakpoints request. 1949 llvm::json::Array filters; 1950 for (const auto &exc_bp : *dap.exception_breakpoints) { 1951 filters.emplace_back(CreateExceptionBreakpointFilter(exc_bp)); 1952 } 1953 body.try_emplace("exceptionBreakpointFilters", std::move(filters)); 1954 // The debug adapter supports launching a debugee in intergrated VSCode 1955 // terminal. 1956 body.try_emplace("supportsRunInTerminalRequest", true); 1957 // The debug adapter supports stepping back via the stepBack and 1958 // reverseContinue requests. 1959 body.try_emplace("supportsStepBack", false); 1960 // The debug adapter supports setting a variable to a value. 1961 body.try_emplace("supportsSetVariable", true); 1962 // The debug adapter supports restarting a frame. 1963 body.try_emplace("supportsRestartFrame", false); 1964 // The debug adapter supports the gotoTargetsRequest. 1965 body.try_emplace("supportsGotoTargetsRequest", false); 1966 // The debug adapter supports the stepInTargetsRequest. 1967 body.try_emplace("supportsStepInTargetsRequest", true); 1968 // The debug adapter supports the completions request. 1969 body.try_emplace("supportsCompletionsRequest", true); 1970 // The debug adapter supports the disassembly request. 1971 body.try_emplace("supportsDisassembleRequest", true); 1972 // The debug adapter supports stepping granularities (argument `granularity`) 1973 // for the stepping requests. 1974 body.try_emplace("supportsSteppingGranularity", true); 1975 // The debug adapter support for instruction breakpoint. 1976 body.try_emplace("supportsInstructionBreakpoints", true); 1977 1978 llvm::json::Array completion_characters; 1979 completion_characters.emplace_back("."); 1980 completion_characters.emplace_back(" "); 1981 completion_characters.emplace_back("\t"); 1982 body.try_emplace("completionTriggerCharacters", 1983 std::move(completion_characters)); 1984 1985 // The debug adapter supports the modules request. 1986 body.try_emplace("supportsModulesRequest", true); 1987 // The set of additional module information exposed by the debug adapter. 1988 // body.try_emplace("additionalModuleColumns"] = ColumnDescriptor 1989 // Checksum algorithms supported by the debug adapter. 1990 // body.try_emplace("supportedChecksumAlgorithms"] = ChecksumAlgorithm 1991 // The debug adapter supports the RestartRequest. In this case a client 1992 // should not implement 'restart' by terminating and relaunching the adapter 1993 // but by calling the RestartRequest. 1994 body.try_emplace("supportsRestartRequest", true); 1995 // The debug adapter supports 'exceptionOptions' on the 1996 // setExceptionBreakpoints request. 1997 body.try_emplace("supportsExceptionOptions", true); 1998 // The debug adapter supports a 'format' attribute on the stackTraceRequest, 1999 // variablesRequest, and evaluateRequest. 2000 body.try_emplace("supportsValueFormattingOptions", true); 2001 // The debug adapter supports the exceptionInfo request. 2002 body.try_emplace("supportsExceptionInfoRequest", true); 2003 // The debug adapter supports the 'terminateDebuggee' attribute on the 2004 // 'disconnect' request. 2005 body.try_emplace("supportTerminateDebuggee", true); 2006 // The debug adapter supports the delayed loading of parts of the stack, 2007 // which requires that both the 'startFrame' and 'levels' arguments and the 2008 // 'totalFrames' result of the 'StackTrace' request are supported. 2009 body.try_emplace("supportsDelayedStackTraceLoading", true); 2010 // The debug adapter supports the 'loadedSources' request. 2011 body.try_emplace("supportsLoadedSourcesRequest", false); 2012 // The debug adapter supports sending progress reporting events. 2013 body.try_emplace("supportsProgressReporting", true); 2014 // The debug adapter supports 'logMessage' in breakpoint. 2015 body.try_emplace("supportsLogPoints", true); 2016 // The debug adapter supports data watchpoints. 2017 body.try_emplace("supportsDataBreakpoints", true); 2018 // The debug adapter supports the `readMemory` request. 2019 body.try_emplace("supportsReadMemoryRequest", true); 2020 2021 // Put in non-DAP specification lldb specific information. 2022 llvm::json::Object lldb_json; 2023 lldb_json.try_emplace("version", dap.debugger.GetVersionString()); 2024 body.try_emplace("__lldb", std::move(lldb_json)); 2025 2026 response.try_emplace("body", std::move(body)); 2027 dap.SendJSON(llvm::json::Value(std::move(response))); 2028 } 2029 2030 llvm::Error request_runInTerminal(DAP &dap, 2031 const llvm::json::Object &launch_request, 2032 const uint64_t timeout_seconds) { 2033 dap.is_attach = true; 2034 lldb::SBAttachInfo attach_info; 2035 2036 llvm::Expected<std::shared_ptr<FifoFile>> comm_file_or_err = 2037 CreateRunInTerminalCommFile(); 2038 if (!comm_file_or_err) 2039 return comm_file_or_err.takeError(); 2040 FifoFile &comm_file = *comm_file_or_err.get(); 2041 2042 RunInTerminalDebugAdapterCommChannel comm_channel(comm_file.m_path); 2043 2044 lldb::pid_t debugger_pid = LLDB_INVALID_PROCESS_ID; 2045 #if !defined(_WIN32) 2046 debugger_pid = getpid(); 2047 #endif 2048 llvm::json::Object reverse_request = CreateRunInTerminalReverseRequest( 2049 launch_request, dap.debug_adaptor_path, comm_file.m_path, debugger_pid); 2050 dap.SendReverseRequest("runInTerminal", std::move(reverse_request), 2051 [](llvm::Expected<llvm::json::Value> value) { 2052 if (!value) { 2053 llvm::Error err = value.takeError(); 2054 llvm::errs() 2055 << "runInTerminal request failed: " 2056 << llvm::toString(std::move(err)) << "\n"; 2057 } 2058 }); 2059 2060 if (llvm::Expected<lldb::pid_t> pid = comm_channel.GetLauncherPid()) 2061 attach_info.SetProcessID(*pid); 2062 else 2063 return pid.takeError(); 2064 2065 dap.debugger.SetAsync(false); 2066 lldb::SBError error; 2067 dap.target.Attach(attach_info, error); 2068 2069 if (error.Fail()) 2070 return llvm::createStringError(llvm::inconvertibleErrorCode(), 2071 "Failed to attach to the target process. %s", 2072 comm_channel.GetLauncherError().c_str()); 2073 // This will notify the runInTerminal launcher that we attached. 2074 // We have to make this async, as the function won't return until the launcher 2075 // resumes and reads the data. 2076 std::future<lldb::SBError> did_attach_message_success = 2077 comm_channel.NotifyDidAttach(); 2078 2079 // We just attached to the runInTerminal launcher, which was waiting to be 2080 // attached. We now resume it, so it can receive the didAttach notification 2081 // and then perform the exec. Upon continuing, the debugger will stop the 2082 // process right in the middle of the exec. To the user, what we are doing is 2083 // transparent, as they will only be able to see the process since the exec, 2084 // completely unaware of the preparatory work. 2085 dap.target.GetProcess().Continue(); 2086 2087 // Now that the actual target is just starting (i.e. exec was just invoked), 2088 // we return the debugger to its async state. 2089 dap.debugger.SetAsync(true); 2090 2091 // If sending the notification failed, the launcher should be dead by now and 2092 // the async didAttach notification should have an error message, so we 2093 // return it. Otherwise, everything was a success. 2094 did_attach_message_success.wait(); 2095 error = did_attach_message_success.get(); 2096 if (error.Success()) 2097 return llvm::Error::success(); 2098 return llvm::createStringError(llvm::inconvertibleErrorCode(), 2099 error.GetCString()); 2100 } 2101 2102 // Takes a LaunchRequest object and launches the process, also handling 2103 // runInTerminal if applicable. It doesn't do any of the additional 2104 // initialization and bookkeeping stuff that is needed for `request_launch`. 2105 // This way we can reuse the process launching logic for RestartRequest too. 2106 lldb::SBError LaunchProcess(DAP &dap, const llvm::json::Object &request) { 2107 lldb::SBError error; 2108 const auto *arguments = request.getObject("arguments"); 2109 auto launchCommands = GetStrings(arguments, "launchCommands"); 2110 2111 // Instantiate a launch info instance for the target. 2112 auto launch_info = dap.target.GetLaunchInfo(); 2113 2114 // Grab the current working directory if there is one and set it in the 2115 // launch info. 2116 const auto cwd = GetString(arguments, "cwd"); 2117 if (!cwd.empty()) 2118 launch_info.SetWorkingDirectory(cwd.data()); 2119 2120 // Extract any extra arguments and append them to our program arguments for 2121 // when we launch 2122 auto args = GetStrings(arguments, "args"); 2123 if (!args.empty()) 2124 launch_info.SetArguments(MakeArgv(args).data(), true); 2125 2126 // Pass any environment variables along that the user specified. 2127 const auto envs = GetEnvironmentFromArguments(*arguments); 2128 launch_info.SetEnvironment(envs, true); 2129 2130 auto flags = launch_info.GetLaunchFlags(); 2131 2132 if (GetBoolean(arguments, "disableASLR", true)) 2133 flags |= lldb::eLaunchFlagDisableASLR; 2134 if (GetBoolean(arguments, "disableSTDIO", false)) 2135 flags |= lldb::eLaunchFlagDisableSTDIO; 2136 if (GetBoolean(arguments, "shellExpandArguments", false)) 2137 flags |= lldb::eLaunchFlagShellExpandArguments; 2138 const bool detachOnError = GetBoolean(arguments, "detachOnError", false); 2139 launch_info.SetDetachOnError(detachOnError); 2140 launch_info.SetLaunchFlags(flags | lldb::eLaunchFlagDebug | 2141 lldb::eLaunchFlagStopAtEntry); 2142 const uint64_t timeout_seconds = GetUnsigned(arguments, "timeout", 30); 2143 2144 if (GetBoolean(arguments, "runInTerminal", false)) { 2145 if (llvm::Error err = request_runInTerminal(dap, request, timeout_seconds)) 2146 error.SetErrorString(llvm::toString(std::move(err)).c_str()); 2147 } else if (launchCommands.empty()) { 2148 // Disable async events so the launch will be successful when we return from 2149 // the launch call and the launch will happen synchronously 2150 dap.debugger.SetAsync(false); 2151 dap.target.Launch(launch_info, error); 2152 dap.debugger.SetAsync(true); 2153 } else { 2154 // Set the launch info so that run commands can access the configured 2155 // launch details. 2156 dap.target.SetLaunchInfo(launch_info); 2157 if (llvm::Error err = dap.RunLaunchCommands(launchCommands)) { 2158 error.SetErrorString(llvm::toString(std::move(err)).c_str()); 2159 return error; 2160 } 2161 // The custom commands might have created a new target so we should use the 2162 // selected target after these commands are run. 2163 dap.target = dap.debugger.GetSelectedTarget(); 2164 // Make sure the process is launched and stopped at the entry point before 2165 // proceeding as the launch commands are not run using the synchronous 2166 // mode. 2167 error = dap.WaitForProcessToStop(timeout_seconds); 2168 } 2169 return error; 2170 } 2171 2172 // "LaunchRequest": { 2173 // "allOf": [ { "$ref": "#/definitions/Request" }, { 2174 // "type": "object", 2175 // "description": "Launch request; value of command field is 'launch'.", 2176 // "properties": { 2177 // "command": { 2178 // "type": "string", 2179 // "enum": [ "launch" ] 2180 // }, 2181 // "arguments": { 2182 // "$ref": "#/definitions/LaunchRequestArguments" 2183 // } 2184 // }, 2185 // "required": [ "command", "arguments" ] 2186 // }] 2187 // }, 2188 // "LaunchRequestArguments": { 2189 // "type": "object", 2190 // "description": "Arguments for 'launch' request.", 2191 // "properties": { 2192 // "noDebug": { 2193 // "type": "boolean", 2194 // "description": "If noDebug is true the launch request should launch 2195 // the program without enabling debugging." 2196 // } 2197 // } 2198 // }, 2199 // "LaunchResponse": { 2200 // "allOf": [ { "$ref": "#/definitions/Response" }, { 2201 // "type": "object", 2202 // "description": "Response to 'launch' request. This is just an 2203 // acknowledgement, so no body field is required." 2204 // }] 2205 // } 2206 void request_launch(DAP &dap, const llvm::json::Object &request) { 2207 dap.is_attach = false; 2208 dap.last_launch_or_attach_request = request; 2209 llvm::json::Object response; 2210 FillResponse(request, response); 2211 const auto *arguments = request.getObject("arguments"); 2212 dap.init_commands = GetStrings(arguments, "initCommands"); 2213 dap.pre_run_commands = GetStrings(arguments, "preRunCommands"); 2214 dap.stop_commands = GetStrings(arguments, "stopCommands"); 2215 dap.exit_commands = GetStrings(arguments, "exitCommands"); 2216 dap.terminate_commands = GetStrings(arguments, "terminateCommands"); 2217 dap.post_run_commands = GetStrings(arguments, "postRunCommands"); 2218 dap.stop_at_entry = GetBoolean(arguments, "stopOnEntry", false); 2219 const llvm::StringRef debuggerRoot = GetString(arguments, "debuggerRoot"); 2220 dap.enable_auto_variable_summaries = 2221 GetBoolean(arguments, "enableAutoVariableSummaries", false); 2222 dap.enable_synthetic_child_debugging = 2223 GetBoolean(arguments, "enableSyntheticChildDebugging", false); 2224 dap.display_extended_backtrace = 2225 GetBoolean(arguments, "displayExtendedBacktrace", false); 2226 dap.command_escape_prefix = GetString(arguments, "commandEscapePrefix", "`"); 2227 dap.SetFrameFormat(GetString(arguments, "customFrameFormat")); 2228 dap.SetThreadFormat(GetString(arguments, "customThreadFormat")); 2229 2230 PrintWelcomeMessage(dap); 2231 2232 // This is a hack for loading DWARF in .o files on Mac where the .o files 2233 // in the debug map of the main executable have relative paths which 2234 // require the lldb-dap binary to have its working directory set to that 2235 // relative root for the .o files in order to be able to load debug info. 2236 if (!debuggerRoot.empty()) 2237 llvm::sys::fs::set_current_path(debuggerRoot); 2238 2239 // Run any initialize LLDB commands the user specified in the launch.json. 2240 // This is run before target is created, so commands can't do anything with 2241 // the targets - preRunCommands are run with the target. 2242 if (llvm::Error err = dap.RunInitCommands()) { 2243 response["success"] = false; 2244 EmplaceSafeString(response, "message", llvm::toString(std::move(err))); 2245 dap.SendJSON(llvm::json::Value(std::move(response))); 2246 return; 2247 } 2248 2249 SetSourceMapFromArguments(dap, *arguments); 2250 2251 lldb::SBError status; 2252 dap.SetTarget(dap.CreateTargetFromArguments(*arguments, status)); 2253 if (status.Fail()) { 2254 response["success"] = llvm::json::Value(false); 2255 EmplaceSafeString(response, "message", status.GetCString()); 2256 dap.SendJSON(llvm::json::Value(std::move(response))); 2257 return; 2258 } 2259 2260 // Run any pre run LLDB commands the user specified in the launch.json 2261 if (llvm::Error err = dap.RunPreRunCommands()) { 2262 response["success"] = false; 2263 EmplaceSafeString(response, "message", llvm::toString(std::move(err))); 2264 dap.SendJSON(llvm::json::Value(std::move(response))); 2265 return; 2266 } 2267 2268 status = LaunchProcess(dap, request); 2269 2270 if (status.Fail()) { 2271 response["success"] = llvm::json::Value(false); 2272 EmplaceSafeString(response, "message", std::string(status.GetCString())); 2273 } else { 2274 dap.RunPostRunCommands(); 2275 } 2276 2277 dap.SendJSON(llvm::json::Value(std::move(response))); 2278 2279 if (!status.Fail()) { 2280 if (dap.is_attach) 2281 SendProcessEvent(dap, Attach); // this happens when doing runInTerminal 2282 else 2283 SendProcessEvent(dap, Launch); 2284 } 2285 dap.SendJSON(CreateEventObject("initialized")); 2286 } 2287 2288 // Check if the step-granularity is `instruction` 2289 static bool hasInstructionGranularity(const llvm::json::Object &requestArgs) { 2290 if (std::optional<llvm::StringRef> value = 2291 requestArgs.getString("granularity")) 2292 return value == "instruction"; 2293 return false; 2294 } 2295 2296 // "NextRequest": { 2297 // "allOf": [ { "$ref": "#/definitions/Request" }, { 2298 // "type": "object", 2299 // "description": "Next request; value of command field is 'next'. The 2300 // request starts the debuggee to run again for one step. 2301 // The debug adapter first sends the NextResponse and then 2302 // a StoppedEvent (event type 'step') after the step has 2303 // completed.", 2304 // "properties": { 2305 // "command": { 2306 // "type": "string", 2307 // "enum": [ "next" ] 2308 // }, 2309 // "arguments": { 2310 // "$ref": "#/definitions/NextArguments" 2311 // } 2312 // }, 2313 // "required": [ "command", "arguments" ] 2314 // }] 2315 // }, 2316 // "NextArguments": { 2317 // "type": "object", 2318 // "description": "Arguments for 'next' request.", 2319 // "properties": { 2320 // "threadId": { 2321 // "type": "integer", 2322 // "description": "Execute 'next' for this thread." 2323 // }, 2324 // "granularity": { 2325 // "$ref": "#/definitions/SteppingGranularity", 2326 // "description": "Stepping granularity. If no granularity is specified, a 2327 // granularity of `statement` is assumed." 2328 // } 2329 // }, 2330 // "required": [ "threadId" ] 2331 // }, 2332 // "NextResponse": { 2333 // "allOf": [ { "$ref": "#/definitions/Response" }, { 2334 // "type": "object", 2335 // "description": "Response to 'next' request. This is just an 2336 // acknowledgement, so no body field is required." 2337 // }] 2338 // } 2339 void request_next(DAP &dap, const llvm::json::Object &request) { 2340 llvm::json::Object response; 2341 FillResponse(request, response); 2342 const auto *arguments = request.getObject("arguments"); 2343 lldb::SBThread thread = dap.GetLLDBThread(*arguments); 2344 if (thread.IsValid()) { 2345 // Remember the thread ID that caused the resume so we can set the 2346 // "threadCausedFocus" boolean value in the "stopped" events. 2347 dap.focus_tid = thread.GetThreadID(); 2348 if (hasInstructionGranularity(*arguments)) { 2349 thread.StepInstruction(/*step_over=*/true); 2350 } else { 2351 thread.StepOver(); 2352 } 2353 } else { 2354 response["success"] = llvm::json::Value(false); 2355 } 2356 dap.SendJSON(llvm::json::Value(std::move(response))); 2357 } 2358 2359 // "PauseRequest": { 2360 // "allOf": [ { "$ref": "#/definitions/Request" }, { 2361 // "type": "object", 2362 // "description": "Pause request; value of command field is 'pause'. The 2363 // request suspenses the debuggee. The debug adapter first sends the 2364 // PauseResponse and then a StoppedEvent (event type 'pause') after the 2365 // thread has been paused successfully.", "properties": { 2366 // "command": { 2367 // "type": "string", 2368 // "enum": [ "pause" ] 2369 // }, 2370 // "arguments": { 2371 // "$ref": "#/definitions/PauseArguments" 2372 // } 2373 // }, 2374 // "required": [ "command", "arguments" ] 2375 // }] 2376 // }, 2377 // "PauseArguments": { 2378 // "type": "object", 2379 // "description": "Arguments for 'pause' request.", 2380 // "properties": { 2381 // "threadId": { 2382 // "type": "integer", 2383 // "description": "Pause execution for this thread." 2384 // } 2385 // }, 2386 // "required": [ "threadId" ] 2387 // }, 2388 // "PauseResponse": { 2389 // "allOf": [ { "$ref": "#/definitions/Response" }, { 2390 // "type": "object", 2391 // "description": "Response to 'pause' request. This is just an 2392 // acknowledgement, so no body field is required." 2393 // }] 2394 // } 2395 void request_pause(DAP &dap, const llvm::json::Object &request) { 2396 llvm::json::Object response; 2397 FillResponse(request, response); 2398 lldb::SBProcess process = dap.target.GetProcess(); 2399 lldb::SBError error = process.Stop(); 2400 dap.SendJSON(llvm::json::Value(std::move(response))); 2401 } 2402 2403 // "RestartRequest": { 2404 // "allOf": [ { "$ref": "#/definitions/Request" }, { 2405 // "type": "object", 2406 // "description": "Restarts a debug session. Clients should only call this 2407 // request if the corresponding capability `supportsRestartRequest` is 2408 // true.\nIf the capability is missing or has the value false, a typical 2409 // client emulates `restart` by terminating the debug adapter first and then 2410 // launching it anew.", 2411 // "properties": { 2412 // "command": { 2413 // "type": "string", 2414 // "enum": [ "restart" ] 2415 // }, 2416 // "arguments": { 2417 // "$ref": "#/definitions/RestartArguments" 2418 // } 2419 // }, 2420 // "required": [ "command" ] 2421 // }] 2422 // }, 2423 // "RestartArguments": { 2424 // "type": "object", 2425 // "description": "Arguments for `restart` request.", 2426 // "properties": { 2427 // "arguments": { 2428 // "oneOf": [ 2429 // { "$ref": "#/definitions/LaunchRequestArguments" }, 2430 // { "$ref": "#/definitions/AttachRequestArguments" } 2431 // ], 2432 // "description": "The latest version of the `launch` or `attach` 2433 // configuration." 2434 // } 2435 // } 2436 // }, 2437 // "RestartResponse": { 2438 // "allOf": [ { "$ref": "#/definitions/Response" }, { 2439 // "type": "object", 2440 // "description": "Response to `restart` request. This is just an 2441 // acknowledgement, so no body field is required." 2442 // }] 2443 // }, 2444 void request_restart(DAP &dap, const llvm::json::Object &request) { 2445 llvm::json::Object response; 2446 FillResponse(request, response); 2447 if (!dap.last_launch_or_attach_request) { 2448 response["success"] = llvm::json::Value(false); 2449 EmplaceSafeString(response, "message", 2450 "Restart request received but no process was launched."); 2451 dap.SendJSON(llvm::json::Value(std::move(response))); 2452 return; 2453 } 2454 // Check if we were in a "launch" session or an "attach" session. 2455 // 2456 // Restarting is not well defined when we started the session by attaching to 2457 // an existing process, because we don't know how the process was started, so 2458 // we don't support it. 2459 // 2460 // Note that when using runInTerminal we're technically attached, but it's an 2461 // implementation detail. The adapter *did* launch the process in response to 2462 // a "launch" command, so we can still stop it and re-run it. This is why we 2463 // don't just check `dap.is_attach`. 2464 if (GetString(*dap.last_launch_or_attach_request, "command") == "attach") { 2465 response["success"] = llvm::json::Value(false); 2466 EmplaceSafeString(response, "message", 2467 "Restarting an \"attach\" session is not supported."); 2468 dap.SendJSON(llvm::json::Value(std::move(response))); 2469 return; 2470 } 2471 2472 // The optional `arguments` field in RestartRequest can contain an updated 2473 // version of the launch arguments. If there's one, use it. 2474 const auto *restart_arguments = request.getObject("arguments"); 2475 if (restart_arguments) { 2476 const auto *launch_request_arguments = 2477 restart_arguments->getObject("arguments"); 2478 if (launch_request_arguments) { 2479 (*dap.last_launch_or_attach_request)["arguments"] = 2480 llvm::json::Value(llvm::json::Object(*launch_request_arguments)); 2481 } 2482 } 2483 2484 // Keep track of the old PID so when we get a "process exited" event from the 2485 // killed process we can detect it and not shut down the whole session. 2486 lldb::SBProcess process = dap.target.GetProcess(); 2487 dap.restarting_process_id = process.GetProcessID(); 2488 2489 // Stop the current process if necessary. The logic here is similar to 2490 // CommandObjectProcessLaunchOrAttach::StopProcessIfNecessary, except that 2491 // we don't ask the user for confirmation. 2492 dap.debugger.SetAsync(false); 2493 if (process.IsValid()) { 2494 lldb::StateType state = process.GetState(); 2495 if (state != lldb::eStateConnected) { 2496 process.Kill(); 2497 } 2498 // Clear the list of thread ids to avoid sending "thread exited" events 2499 // for threads of the process we are terminating. 2500 dap.thread_ids.clear(); 2501 } 2502 dap.debugger.SetAsync(true); 2503 LaunchProcess(dap, *dap.last_launch_or_attach_request); 2504 2505 // This is normally done after receiving a "configuration done" request. 2506 // Because we're restarting, configuration has already happened so we can 2507 // continue the process right away. 2508 if (dap.stop_at_entry) { 2509 SendThreadStoppedEvent(dap); 2510 } else { 2511 dap.target.GetProcess().Continue(); 2512 } 2513 2514 dap.SendJSON(llvm::json::Value(std::move(response))); 2515 } 2516 2517 // "ScopesRequest": { 2518 // "allOf": [ { "$ref": "#/definitions/Request" }, { 2519 // "type": "object", 2520 // "description": "Scopes request; value of command field is 'scopes'. The 2521 // request returns the variable scopes for a given stackframe ID.", 2522 // "properties": { 2523 // "command": { 2524 // "type": "string", 2525 // "enum": [ "scopes" ] 2526 // }, 2527 // "arguments": { 2528 // "$ref": "#/definitions/ScopesArguments" 2529 // } 2530 // }, 2531 // "required": [ "command", "arguments" ] 2532 // }] 2533 // }, 2534 // "ScopesArguments": { 2535 // "type": "object", 2536 // "description": "Arguments for 'scopes' request.", 2537 // "properties": { 2538 // "frameId": { 2539 // "type": "integer", 2540 // "description": "Retrieve the scopes for this stackframe." 2541 // } 2542 // }, 2543 // "required": [ "frameId" ] 2544 // }, 2545 // "ScopesResponse": { 2546 // "allOf": [ { "$ref": "#/definitions/Response" }, { 2547 // "type": "object", 2548 // "description": "Response to 'scopes' request.", 2549 // "properties": { 2550 // "body": { 2551 // "type": "object", 2552 // "properties": { 2553 // "scopes": { 2554 // "type": "array", 2555 // "items": { 2556 // "$ref": "#/definitions/Scope" 2557 // }, 2558 // "description": "The scopes of the stackframe. If the array has 2559 // length zero, there are no scopes available." 2560 // } 2561 // }, 2562 // "required": [ "scopes" ] 2563 // } 2564 // }, 2565 // "required": [ "body" ] 2566 // }] 2567 // } 2568 void request_scopes(DAP &dap, const llvm::json::Object &request) { 2569 llvm::json::Object response; 2570 FillResponse(request, response); 2571 llvm::json::Object body; 2572 const auto *arguments = request.getObject("arguments"); 2573 lldb::SBFrame frame = dap.GetLLDBFrame(*arguments); 2574 // As the user selects different stack frames in the GUI, a "scopes" request 2575 // will be sent to the DAP. This is the only way we know that the user has 2576 // selected a frame in a thread. There are no other notifications that are 2577 // sent and VS code doesn't allow multiple frames to show variables 2578 // concurrently. If we select the thread and frame as the "scopes" requests 2579 // are sent, this allows users to type commands in the debugger console 2580 // with a backtick character to run lldb commands and these lldb commands 2581 // will now have the right context selected as they are run. If the user 2582 // types "`bt" into the debugger console and we had another thread selected 2583 // in the LLDB library, we would show the wrong thing to the user. If the 2584 // users switches threads with a lldb command like "`thread select 14", the 2585 // GUI will not update as there are no "event" notification packets that 2586 // allow us to change the currently selected thread or frame in the GUI that 2587 // I am aware of. 2588 if (frame.IsValid()) { 2589 frame.GetThread().GetProcess().SetSelectedThread(frame.GetThread()); 2590 frame.GetThread().SetSelectedFrame(frame.GetFrameID()); 2591 } 2592 2593 dap.variables.locals = frame.GetVariables(/*arguments=*/true, 2594 /*locals=*/true, 2595 /*statics=*/false, 2596 /*in_scope_only=*/true); 2597 dap.variables.globals = frame.GetVariables(/*arguments=*/false, 2598 /*locals=*/false, 2599 /*statics=*/true, 2600 /*in_scope_only=*/true); 2601 dap.variables.registers = frame.GetRegisters(); 2602 body.try_emplace("scopes", dap.CreateTopLevelScopes()); 2603 response.try_emplace("body", std::move(body)); 2604 dap.SendJSON(llvm::json::Value(std::move(response))); 2605 } 2606 2607 // "SetBreakpointsRequest": { 2608 // "allOf": [ { "$ref": "#/definitions/Request" }, { 2609 // "type": "object", 2610 // "description": "SetBreakpoints request; value of command field is 2611 // 'setBreakpoints'. Sets multiple breakpoints for a single source and 2612 // clears all previous breakpoints in that source. To clear all breakpoint 2613 // for a source, specify an empty array. When a breakpoint is hit, a 2614 // StoppedEvent (event type 'breakpoint') is generated.", "properties": { 2615 // "command": { 2616 // "type": "string", 2617 // "enum": [ "setBreakpoints" ] 2618 // }, 2619 // "arguments": { 2620 // "$ref": "#/definitions/SetBreakpointsArguments" 2621 // } 2622 // }, 2623 // "required": [ "command", "arguments" ] 2624 // }] 2625 // }, 2626 // "SetBreakpointsArguments": { 2627 // "type": "object", 2628 // "description": "Arguments for 'setBreakpoints' request.", 2629 // "properties": { 2630 // "source": { 2631 // "$ref": "#/definitions/Source", 2632 // "description": "The source location of the breakpoints; either 2633 // source.path or source.reference must be specified." 2634 // }, 2635 // "breakpoints": { 2636 // "type": "array", 2637 // "items": { 2638 // "$ref": "#/definitions/SourceBreakpoint" 2639 // }, 2640 // "description": "The code locations of the breakpoints." 2641 // }, 2642 // "lines": { 2643 // "type": "array", 2644 // "items": { 2645 // "type": "integer" 2646 // }, 2647 // "description": "Deprecated: The code locations of the breakpoints." 2648 // }, 2649 // "sourceModified": { 2650 // "type": "boolean", 2651 // "description": "A value of true indicates that the underlying source 2652 // has been modified which results in new breakpoint locations." 2653 // } 2654 // }, 2655 // "required": [ "source" ] 2656 // }, 2657 // "SetBreakpointsResponse": { 2658 // "allOf": [ { "$ref": "#/definitions/Response" }, { 2659 // "type": "object", 2660 // "description": "Response to 'setBreakpoints' request. Returned is 2661 // information about each breakpoint created by this request. This includes 2662 // the actual code location and whether the breakpoint could be verified. 2663 // The breakpoints returned are in the same order as the elements of the 2664 // 'breakpoints' (or the deprecated 'lines') in the 2665 // SetBreakpointsArguments.", "properties": { 2666 // "body": { 2667 // "type": "object", 2668 // "properties": { 2669 // "breakpoints": { 2670 // "type": "array", 2671 // "items": { 2672 // "$ref": "#/definitions/Breakpoint" 2673 // }, 2674 // "description": "Information about the breakpoints. The array 2675 // elements are in the same order as the elements of the 2676 // 'breakpoints' (or the deprecated 'lines') in the 2677 // SetBreakpointsArguments." 2678 // } 2679 // }, 2680 // "required": [ "breakpoints" ] 2681 // } 2682 // }, 2683 // "required": [ "body" ] 2684 // }] 2685 // }, 2686 // "SourceBreakpoint": { 2687 // "type": "object", 2688 // "description": "Properties of a breakpoint or logpoint passed to the 2689 // setBreakpoints request.", "properties": { 2690 // "line": { 2691 // "type": "integer", 2692 // "description": "The source line of the breakpoint or logpoint." 2693 // }, 2694 // "column": { 2695 // "type": "integer", 2696 // "description": "An optional source column of the breakpoint." 2697 // }, 2698 // "condition": { 2699 // "type": "string", 2700 // "description": "An optional expression for conditional breakpoints." 2701 // }, 2702 // "hitCondition": { 2703 // "type": "string", 2704 // "description": "An optional expression that controls how many hits of 2705 // the breakpoint are ignored. The backend is expected to interpret the 2706 // expression as needed." 2707 // }, 2708 // "logMessage": { 2709 // "type": "string", 2710 // "description": "If this attribute exists and is non-empty, the backend 2711 // must not 'break' (stop) but log the message instead. Expressions within 2712 // {} are interpolated." 2713 // } 2714 // }, 2715 // "required": [ "line" ] 2716 // } 2717 void request_setBreakpoints(DAP &dap, const llvm::json::Object &request) { 2718 llvm::json::Object response; 2719 lldb::SBError error; 2720 FillResponse(request, response); 2721 const auto *arguments = request.getObject("arguments"); 2722 const auto *source = arguments->getObject("source"); 2723 const auto path = GetString(source, "path"); 2724 const auto *breakpoints = arguments->getArray("breakpoints"); 2725 llvm::json::Array response_breakpoints; 2726 2727 // Decode the source breakpoint infos for this "setBreakpoints" request 2728 SourceBreakpointMap request_bps; 2729 // "breakpoints" may be unset, in which case we treat it the same as being set 2730 // to an empty array. 2731 if (breakpoints) { 2732 for (const auto &bp : *breakpoints) { 2733 const auto *bp_obj = bp.getAsObject(); 2734 if (bp_obj) { 2735 SourceBreakpoint src_bp(dap, *bp_obj); 2736 request_bps.try_emplace(src_bp.line, src_bp); 2737 const auto [iv, inserted] = 2738 dap.source_breakpoints[path].try_emplace(src_bp.line, src_bp); 2739 // We check if this breakpoint already exists to update it 2740 if (inserted) 2741 iv->getSecond().SetBreakpoint(path.data()); 2742 else 2743 iv->getSecond().UpdateBreakpoint(src_bp); 2744 AppendBreakpoint(&iv->getSecond(), response_breakpoints, path, 2745 src_bp.line); 2746 } 2747 } 2748 } 2749 2750 // Delete any breakpoints in this source file that aren't in the 2751 // request_bps set. There is no call to remove breakpoints other than 2752 // calling this function with a smaller or empty "breakpoints" list. 2753 auto old_src_bp_pos = dap.source_breakpoints.find(path); 2754 if (old_src_bp_pos != dap.source_breakpoints.end()) { 2755 for (auto &old_bp : old_src_bp_pos->second) { 2756 auto request_pos = request_bps.find(old_bp.first); 2757 if (request_pos == request_bps.end()) { 2758 // This breakpoint no longer exists in this source file, delete it 2759 dap.target.BreakpointDelete(old_bp.second.bp.GetID()); 2760 old_src_bp_pos->second.erase(old_bp.first); 2761 } 2762 } 2763 } 2764 2765 llvm::json::Object body; 2766 body.try_emplace("breakpoints", std::move(response_breakpoints)); 2767 response.try_emplace("body", std::move(body)); 2768 dap.SendJSON(llvm::json::Value(std::move(response))); 2769 } 2770 2771 // "SetExceptionBreakpointsRequest": { 2772 // "allOf": [ { "$ref": "#/definitions/Request" }, { 2773 // "type": "object", 2774 // "description": "SetExceptionBreakpoints request; value of command field 2775 // is 'setExceptionBreakpoints'. The request configures the debuggers 2776 // response to thrown exceptions. If an exception is configured to break, a 2777 // StoppedEvent is fired (event type 'exception').", "properties": { 2778 // "command": { 2779 // "type": "string", 2780 // "enum": [ "setExceptionBreakpoints" ] 2781 // }, 2782 // "arguments": { 2783 // "$ref": "#/definitions/SetExceptionBreakpointsArguments" 2784 // } 2785 // }, 2786 // "required": [ "command", "arguments" ] 2787 // }] 2788 // }, 2789 // "SetExceptionBreakpointsArguments": { 2790 // "type": "object", 2791 // "description": "Arguments for 'setExceptionBreakpoints' request.", 2792 // "properties": { 2793 // "filters": { 2794 // "type": "array", 2795 // "items": { 2796 // "type": "string" 2797 // }, 2798 // "description": "IDs of checked exception options. The set of IDs is 2799 // returned via the 'exceptionBreakpointFilters' capability." 2800 // }, 2801 // "exceptionOptions": { 2802 // "type": "array", 2803 // "items": { 2804 // "$ref": "#/definitions/ExceptionOptions" 2805 // }, 2806 // "description": "Configuration options for selected exceptions." 2807 // } 2808 // }, 2809 // "required": [ "filters" ] 2810 // }, 2811 // "SetExceptionBreakpointsResponse": { 2812 // "allOf": [ { "$ref": "#/definitions/Response" }, { 2813 // "type": "object", 2814 // "description": "Response to 'setExceptionBreakpoints' request. This is 2815 // just an acknowledgement, so no body field is required." 2816 // }] 2817 // } 2818 void request_setExceptionBreakpoints(DAP &dap, 2819 const llvm::json::Object &request) { 2820 llvm::json::Object response; 2821 lldb::SBError error; 2822 FillResponse(request, response); 2823 const auto *arguments = request.getObject("arguments"); 2824 const auto *filters = arguments->getArray("filters"); 2825 // Keep a list of any exception breakpoint filter names that weren't set 2826 // so we can clear any exception breakpoints if needed. 2827 std::set<std::string> unset_filters; 2828 for (const auto &bp : *dap.exception_breakpoints) 2829 unset_filters.insert(bp.filter); 2830 2831 for (const auto &value : *filters) { 2832 const auto filter = GetAsString(value); 2833 auto *exc_bp = dap.GetExceptionBreakpoint(std::string(filter)); 2834 if (exc_bp) { 2835 exc_bp->SetBreakpoint(); 2836 unset_filters.erase(std::string(filter)); 2837 } 2838 } 2839 for (const auto &filter : unset_filters) { 2840 auto *exc_bp = dap.GetExceptionBreakpoint(filter); 2841 if (exc_bp) 2842 exc_bp->ClearBreakpoint(); 2843 } 2844 dap.SendJSON(llvm::json::Value(std::move(response))); 2845 } 2846 2847 // "SetFunctionBreakpointsRequest": { 2848 // "allOf": [ { "$ref": "#/definitions/Request" }, { 2849 // "type": "object", 2850 // "description": "SetFunctionBreakpoints request; value of command field is 2851 // 'setFunctionBreakpoints'. Sets multiple function breakpoints and clears 2852 // all previous function breakpoints. To clear all function breakpoint, 2853 // specify an empty array. When a function breakpoint is hit, a StoppedEvent 2854 // (event type 'function breakpoint') is generated.", "properties": { 2855 // "command": { 2856 // "type": "string", 2857 // "enum": [ "setFunctionBreakpoints" ] 2858 // }, 2859 // "arguments": { 2860 // "$ref": "#/definitions/SetFunctionBreakpointsArguments" 2861 // } 2862 // }, 2863 // "required": [ "command", "arguments" ] 2864 // }] 2865 // }, 2866 // "SetFunctionBreakpointsArguments": { 2867 // "type": "object", 2868 // "description": "Arguments for 'setFunctionBreakpoints' request.", 2869 // "properties": { 2870 // "breakpoints": { 2871 // "type": "array", 2872 // "items": { 2873 // "$ref": "#/definitions/FunctionBreakpoint" 2874 // }, 2875 // "description": "The function names of the breakpoints." 2876 // } 2877 // }, 2878 // "required": [ "breakpoints" ] 2879 // }, 2880 // "FunctionBreakpoint": { 2881 // "type": "object", 2882 // "description": "Properties of a breakpoint passed to the 2883 // setFunctionBreakpoints request.", "properties": { 2884 // "name": { 2885 // "type": "string", 2886 // "description": "The name of the function." 2887 // }, 2888 // "condition": { 2889 // "type": "string", 2890 // "description": "An optional expression for conditional breakpoints." 2891 // }, 2892 // "hitCondition": { 2893 // "type": "string", 2894 // "description": "An optional expression that controls how many hits of 2895 // the breakpoint are ignored. The backend is expected to interpret the 2896 // expression as needed." 2897 // } 2898 // }, 2899 // "required": [ "name" ] 2900 // }, 2901 // "SetFunctionBreakpointsResponse": { 2902 // "allOf": [ { "$ref": "#/definitions/Response" }, { 2903 // "type": "object", 2904 // "description": "Response to 'setFunctionBreakpoints' request. Returned is 2905 // information about each breakpoint created by this request.", 2906 // "properties": { 2907 // "body": { 2908 // "type": "object", 2909 // "properties": { 2910 // "breakpoints": { 2911 // "type": "array", 2912 // "items": { 2913 // "$ref": "#/definitions/Breakpoint" 2914 // }, 2915 // "description": "Information about the breakpoints. The array 2916 // elements correspond to the elements of the 'breakpoints' array." 2917 // } 2918 // }, 2919 // "required": [ "breakpoints" ] 2920 // } 2921 // }, 2922 // "required": [ "body" ] 2923 // }] 2924 // } 2925 void request_setFunctionBreakpoints(DAP &dap, 2926 const llvm::json::Object &request) { 2927 llvm::json::Object response; 2928 lldb::SBError error; 2929 FillResponse(request, response); 2930 const auto *arguments = request.getObject("arguments"); 2931 const auto *breakpoints = arguments->getArray("breakpoints"); 2932 llvm::json::Array response_breakpoints; 2933 2934 // Disable any function breakpoints that aren't in this request. 2935 // There is no call to remove function breakpoints other than calling this 2936 // function with a smaller or empty "breakpoints" list. 2937 const auto name_iter = dap.function_breakpoints.keys(); 2938 llvm::DenseSet<llvm::StringRef> seen(name_iter.begin(), name_iter.end()); 2939 for (const auto &value : *breakpoints) { 2940 const auto *bp_obj = value.getAsObject(); 2941 if (!bp_obj) 2942 continue; 2943 FunctionBreakpoint fn_bp(dap, *bp_obj); 2944 const auto [it, inserted] = 2945 dap.function_breakpoints.try_emplace(fn_bp.functionName, dap, *bp_obj); 2946 if (inserted) 2947 it->second.SetBreakpoint(); 2948 else 2949 it->second.UpdateBreakpoint(fn_bp); 2950 2951 AppendBreakpoint(&it->second, response_breakpoints); 2952 seen.erase(fn_bp.functionName); 2953 } 2954 2955 // Remove any breakpoints that are no longer in our list 2956 for (const auto &name : seen) { 2957 auto fn_bp = dap.function_breakpoints.find(name); 2958 if (fn_bp == dap.function_breakpoints.end()) 2959 continue; 2960 dap.target.BreakpointDelete(fn_bp->second.bp.GetID()); 2961 dap.function_breakpoints.erase(name); 2962 } 2963 2964 llvm::json::Object body; 2965 body.try_emplace("breakpoints", std::move(response_breakpoints)); 2966 response.try_emplace("body", std::move(body)); 2967 dap.SendJSON(llvm::json::Value(std::move(response))); 2968 } 2969 2970 // "DataBreakpointInfoRequest": { 2971 // "allOf": [ { "$ref": "#/definitions/Request" }, { 2972 // "type": "object", 2973 // "description": "Obtains information on a possible data breakpoint that 2974 // could be set on an expression or variable.\nClients should only call this 2975 // request if the corresponding capability `supportsDataBreakpoints` is 2976 // true.", "properties": { 2977 // "command": { 2978 // "type": "string", 2979 // "enum": [ "dataBreakpointInfo" ] 2980 // }, 2981 // "arguments": { 2982 // "$ref": "#/definitions/DataBreakpointInfoArguments" 2983 // } 2984 // }, 2985 // "required": [ "command", "arguments" ] 2986 // }] 2987 // }, 2988 // "DataBreakpointInfoArguments": { 2989 // "type": "object", 2990 // "description": "Arguments for `dataBreakpointInfo` request.", 2991 // "properties": { 2992 // "variablesReference": { 2993 // "type": "integer", 2994 // "description": "Reference to the variable container if the data 2995 // breakpoint is requested for a child of the container. The 2996 // `variablesReference` must have been obtained in the current suspended 2997 // state. See 'Lifetime of Object References' in the Overview section for 2998 // details." 2999 // }, 3000 // "name": { 3001 // "type": "string", 3002 // "description": "The name of the variable's child to obtain data 3003 // breakpoint information for.\nIf `variablesReference` isn't specified, 3004 // this can be an expression." 3005 // }, 3006 // "frameId": { 3007 // "type": "integer", 3008 // "description": "When `name` is an expression, evaluate it in the scope 3009 // of this stack frame. If not specified, the expression is evaluated in 3010 // the global scope. When `variablesReference` is specified, this property 3011 // has no effect." 3012 // } 3013 // }, 3014 // "required": [ "name" ] 3015 // }, 3016 // "DataBreakpointInfoResponse": { 3017 // "allOf": [ { "$ref": "#/definitions/Response" }, { 3018 // "type": "object", 3019 // "description": "Response to `dataBreakpointInfo` request.", 3020 // "properties": { 3021 // "body": { 3022 // "type": "object", 3023 // "properties": { 3024 // "dataId": { 3025 // "type": [ "string", "null" ], 3026 // "description": "An identifier for the data on which a data 3027 // breakpoint can be registered with the `setDataBreakpoints` 3028 // request or null if no data breakpoint is available. If a 3029 // `variablesReference` or `frameId` is passed, the `dataId` is 3030 // valid in the current suspended state, otherwise it's valid 3031 // indefinitely. See 'Lifetime of Object References' in the Overview 3032 // section for details. Breakpoints set using the `dataId` in the 3033 // `setDataBreakpoints` request may outlive the lifetime of the 3034 // associated `dataId`." 3035 // }, 3036 // "description": { 3037 // "type": "string", 3038 // "description": "UI string that describes on what data the 3039 // breakpoint is set on or why a data breakpoint is not available." 3040 // }, 3041 // "accessTypes": { 3042 // "type": "array", 3043 // "items": { 3044 // "$ref": "#/definitions/DataBreakpointAccessType" 3045 // }, 3046 // "description": "Attribute lists the available access types for a 3047 // potential data breakpoint. A UI client could surface this 3048 // information." 3049 // }, 3050 // "canPersist": { 3051 // "type": "boolean", 3052 // "description": "Attribute indicates that a potential data 3053 // breakpoint could be persisted across sessions." 3054 // } 3055 // }, 3056 // "required": [ "dataId", "description" ] 3057 // } 3058 // }, 3059 // "required": [ "body" ] 3060 // }] 3061 // } 3062 void request_dataBreakpointInfo(DAP &dap, const llvm::json::Object &request) { 3063 llvm::json::Object response; 3064 FillResponse(request, response); 3065 llvm::json::Object body; 3066 lldb::SBError error; 3067 llvm::json::Array accessTypes{"read", "write", "readWrite"}; 3068 const auto *arguments = request.getObject("arguments"); 3069 const auto variablesReference = 3070 GetUnsigned(arguments, "variablesReference", 0); 3071 llvm::StringRef name = GetString(arguments, "name"); 3072 lldb::SBFrame frame = dap.GetLLDBFrame(*arguments); 3073 lldb::SBValue variable = FindVariable(dap, variablesReference, name); 3074 std::string addr, size; 3075 3076 if (variable.IsValid()) { 3077 lldb::addr_t load_addr = variable.GetLoadAddress(); 3078 size_t byte_size = variable.GetByteSize(); 3079 if (load_addr == LLDB_INVALID_ADDRESS) { 3080 body.try_emplace("dataId", nullptr); 3081 body.try_emplace("description", 3082 "does not exist in memory, its location is " + 3083 std::string(variable.GetLocation())); 3084 } else if (byte_size == 0) { 3085 body.try_emplace("dataId", nullptr); 3086 body.try_emplace("description", "variable size is 0"); 3087 } else { 3088 addr = llvm::utohexstr(load_addr); 3089 size = llvm::utostr(byte_size); 3090 } 3091 } else if (variablesReference == 0 && frame.IsValid()) { 3092 lldb::SBValue value = frame.EvaluateExpression(name.data()); 3093 if (value.GetError().Fail()) { 3094 lldb::SBError error = value.GetError(); 3095 const char *error_cstr = error.GetCString(); 3096 body.try_emplace("dataId", nullptr); 3097 body.try_emplace("description", error_cstr && error_cstr[0] 3098 ? std::string(error_cstr) 3099 : "evaluation failed"); 3100 } else { 3101 uint64_t load_addr = value.GetValueAsUnsigned(); 3102 lldb::SBData data = value.GetPointeeData(); 3103 if (data.IsValid()) { 3104 size = llvm::utostr(data.GetByteSize()); 3105 addr = llvm::utohexstr(load_addr); 3106 lldb::SBMemoryRegionInfo region; 3107 lldb::SBError err = 3108 dap.target.GetProcess().GetMemoryRegionInfo(load_addr, region); 3109 // Only lldb-server supports "qMemoryRegionInfo". So, don't fail this 3110 // request if SBProcess::GetMemoryRegionInfo returns error. 3111 if (err.Success()) { 3112 if (!(region.IsReadable() || region.IsWritable())) { 3113 body.try_emplace("dataId", nullptr); 3114 body.try_emplace("description", 3115 "memory region for address " + addr + 3116 " has no read or write permissions"); 3117 } 3118 } 3119 } else { 3120 body.try_emplace("dataId", nullptr); 3121 body.try_emplace("description", 3122 "unable to get byte size for expression: " + 3123 name.str()); 3124 } 3125 } 3126 } else { 3127 body.try_emplace("dataId", nullptr); 3128 body.try_emplace("description", "variable not found: " + name.str()); 3129 } 3130 3131 if (!body.getObject("dataId")) { 3132 body.try_emplace("dataId", addr + "/" + size); 3133 body.try_emplace("accessTypes", std::move(accessTypes)); 3134 body.try_emplace("description", 3135 size + " bytes at " + addr + " " + name.str()); 3136 } 3137 response.try_emplace("body", std::move(body)); 3138 dap.SendJSON(llvm::json::Value(std::move(response))); 3139 } 3140 3141 // "SetDataBreakpointsRequest": { 3142 // "allOf": [ { "$ref": "#/definitions/Request" }, { 3143 // "type": "object", 3144 // "description": "Replaces all existing data breakpoints with new data 3145 // breakpoints.\nTo clear all data breakpoints, specify an empty 3146 // array.\nWhen a data breakpoint is hit, a `stopped` event (with reason 3147 // `data breakpoint`) is generated.\nClients should only call this request 3148 // if the corresponding capability `supportsDataBreakpoints` is true.", 3149 // "properties": { 3150 // "command": { 3151 // "type": "string", 3152 // "enum": [ "setDataBreakpoints" ] 3153 // }, 3154 // "arguments": { 3155 // "$ref": "#/definitions/SetDataBreakpointsArguments" 3156 // } 3157 // }, 3158 // "required": [ "command", "arguments" ] 3159 // }] 3160 // }, 3161 // "SetDataBreakpointsArguments": { 3162 // "type": "object", 3163 // "description": "Arguments for `setDataBreakpoints` request.", 3164 // "properties": { 3165 // "breakpoints": { 3166 // "type": "array", 3167 // "items": { 3168 // "$ref": "#/definitions/DataBreakpoint" 3169 // }, 3170 // "description": "The contents of this array replaces all existing data 3171 // breakpoints. An empty array clears all data breakpoints." 3172 // } 3173 // }, 3174 // "required": [ "breakpoints" ] 3175 // }, 3176 // "SetDataBreakpointsResponse": { 3177 // "allOf": [ { "$ref": "#/definitions/Response" }, { 3178 // "type": "object", 3179 // "description": "Response to `setDataBreakpoints` request.\nReturned is 3180 // information about each breakpoint created by this request.", 3181 // "properties": { 3182 // "body": { 3183 // "type": "object", 3184 // "properties": { 3185 // "breakpoints": { 3186 // "type": "array", 3187 // "items": { 3188 // "$ref": "#/definitions/Breakpoint" 3189 // }, 3190 // "description": "Information about the data breakpoints. The array 3191 // elements correspond to the elements of the input argument 3192 // `breakpoints` array." 3193 // } 3194 // }, 3195 // "required": [ "breakpoints" ] 3196 // } 3197 // }, 3198 // "required": [ "body" ] 3199 // }] 3200 // } 3201 void request_setDataBreakpoints(DAP &dap, const llvm::json::Object &request) { 3202 llvm::json::Object response; 3203 lldb::SBError error; 3204 FillResponse(request, response); 3205 const auto *arguments = request.getObject("arguments"); 3206 const auto *breakpoints = arguments->getArray("breakpoints"); 3207 llvm::json::Array response_breakpoints; 3208 dap.target.DeleteAllWatchpoints(); 3209 std::vector<Watchpoint> watchpoints; 3210 if (breakpoints) { 3211 for (const auto &bp : *breakpoints) { 3212 const auto *bp_obj = bp.getAsObject(); 3213 if (bp_obj) 3214 watchpoints.emplace_back(dap, *bp_obj); 3215 } 3216 } 3217 // If two watchpoints start at the same address, the latter overwrite the 3218 // former. So, we only enable those at first-seen addresses when iterating 3219 // backward. 3220 std::set<lldb::addr_t> addresses; 3221 for (auto iter = watchpoints.rbegin(); iter != watchpoints.rend(); ++iter) { 3222 if (addresses.count(iter->addr) == 0) { 3223 iter->SetWatchpoint(); 3224 addresses.insert(iter->addr); 3225 } 3226 } 3227 for (auto wp : watchpoints) 3228 AppendBreakpoint(&wp, response_breakpoints); 3229 3230 llvm::json::Object body; 3231 body.try_emplace("breakpoints", std::move(response_breakpoints)); 3232 response.try_emplace("body", std::move(body)); 3233 dap.SendJSON(llvm::json::Value(std::move(response))); 3234 } 3235 3236 // "SourceRequest": { 3237 // "allOf": [ { "$ref": "#/definitions/Request" }, { 3238 // "type": "object", 3239 // "description": "Source request; value of command field is 'source'. The 3240 // request retrieves the source code for a given source reference.", 3241 // "properties": { 3242 // "command": { 3243 // "type": "string", 3244 // "enum": [ "source" ] 3245 // }, 3246 // "arguments": { 3247 // "$ref": "#/definitions/SourceArguments" 3248 // } 3249 // }, 3250 // "required": [ "command", "arguments" ] 3251 // }] 3252 // }, 3253 // "SourceArguments": { 3254 // "type": "object", 3255 // "description": "Arguments for 'source' request.", 3256 // "properties": { 3257 // "source": { 3258 // "$ref": "#/definitions/Source", 3259 // "description": "Specifies the source content to load. Either 3260 // source.path or source.sourceReference must be specified." 3261 // }, 3262 // "sourceReference": { 3263 // "type": "integer", 3264 // "description": "The reference to the source. This is the same as 3265 // source.sourceReference. This is provided for backward compatibility 3266 // since old backends do not understand the 'source' attribute." 3267 // } 3268 // }, 3269 // "required": [ "sourceReference" ] 3270 // }, 3271 // "SourceResponse": { 3272 // "allOf": [ { "$ref": "#/definitions/Response" }, { 3273 // "type": "object", 3274 // "description": "Response to 'source' request.", 3275 // "properties": { 3276 // "body": { 3277 // "type": "object", 3278 // "properties": { 3279 // "content": { 3280 // "type": "string", 3281 // "description": "Content of the source reference." 3282 // }, 3283 // "mimeType": { 3284 // "type": "string", 3285 // "description": "Optional content type (mime type) of the source." 3286 // } 3287 // }, 3288 // "required": [ "content" ] 3289 // } 3290 // }, 3291 // "required": [ "body" ] 3292 // }] 3293 // } 3294 void request_source(DAP &dap, const llvm::json::Object &request) { 3295 llvm::json::Object response; 3296 FillResponse(request, response); 3297 llvm::json::Object body{{"content", ""}}; 3298 response.try_emplace("body", std::move(body)); 3299 dap.SendJSON(llvm::json::Value(std::move(response))); 3300 } 3301 3302 // "StackTraceRequest": { 3303 // "allOf": [ { "$ref": "#/definitions/Request" }, { 3304 // "type": "object", 3305 // "description": "StackTrace request; value of command field is 3306 // 'stackTrace'. The request returns a stacktrace from the current execution 3307 // state.", "properties": { 3308 // "command": { 3309 // "type": "string", 3310 // "enum": [ "stackTrace" ] 3311 // }, 3312 // "arguments": { 3313 // "$ref": "#/definitions/StackTraceArguments" 3314 // } 3315 // }, 3316 // "required": [ "command", "arguments" ] 3317 // }] 3318 // }, 3319 // "StackTraceArguments": { 3320 // "type": "object", 3321 // "description": "Arguments for 'stackTrace' request.", 3322 // "properties": { 3323 // "threadId": { 3324 // "type": "integer", 3325 // "description": "Retrieve the stacktrace for this thread." 3326 // }, 3327 // "startFrame": { 3328 // "type": "integer", 3329 // "description": "The index of the first frame to return; if omitted 3330 // frames start at 0." 3331 // }, 3332 // "levels": { 3333 // "type": "integer", 3334 // "description": "The maximum number of frames to return. If levels is 3335 // not specified or 0, all frames are returned." 3336 // }, 3337 // "format": { 3338 // "$ref": "#/definitions/StackFrameFormat", 3339 // "description": "Specifies details on how to format the stack frames. 3340 // The attribute is only honored by a debug adapter if the corresponding 3341 // capability `supportsValueFormattingOptions` is true." 3342 // } 3343 // }, 3344 // "required": [ "threadId" ] 3345 // }, 3346 // "StackTraceResponse": { 3347 // "allOf": [ { "$ref": "#/definitions/Response" }, { 3348 // "type": "object", 3349 // "description": "Response to `stackTrace` request.", 3350 // "properties": { 3351 // "body": { 3352 // "type": "object", 3353 // "properties": { 3354 // "stackFrames": { 3355 // "type": "array", 3356 // "items": { 3357 // "$ref": "#/definitions/StackFrame" 3358 // }, 3359 // "description": "The frames of the stackframe. If the array has 3360 // length zero, there are no stackframes available. This means that 3361 // there is no location information available." 3362 // }, 3363 // "totalFrames": { 3364 // "type": "integer", 3365 // "description": "The total number of frames available in the 3366 // stack. If omitted or if `totalFrames` is larger than the 3367 // available frames, a client is expected to request frames until 3368 // a request returns less frames than requested (which indicates 3369 // the end of the stack). Returning monotonically increasing 3370 // `totalFrames` values for subsequent requests can be used to 3371 // enforce paging in the client." 3372 // } 3373 // }, 3374 // "required": [ "stackFrames" ] 3375 // } 3376 // }, 3377 // "required": [ "body" ] 3378 // }] 3379 // } 3380 void request_stackTrace(DAP &dap, const llvm::json::Object &request) { 3381 llvm::json::Object response; 3382 FillResponse(request, response); 3383 lldb::SBError error; 3384 const auto *arguments = request.getObject("arguments"); 3385 lldb::SBThread thread = dap.GetLLDBThread(*arguments); 3386 llvm::json::Array stack_frames; 3387 llvm::json::Object body; 3388 3389 if (thread.IsValid()) { 3390 const auto start_frame = GetUnsigned(arguments, "startFrame", 0); 3391 const auto levels = GetUnsigned(arguments, "levels", 0); 3392 int64_t offset = 0; 3393 bool reached_end_of_stack = 3394 FillStackFrames(dap, thread, stack_frames, offset, start_frame, 3395 levels == 0 ? INT64_MAX : levels); 3396 body.try_emplace("totalFrames", 3397 start_frame + stack_frames.size() + 3398 (reached_end_of_stack ? 0 : StackPageSize)); 3399 } 3400 3401 body.try_emplace("stackFrames", std::move(stack_frames)); 3402 response.try_emplace("body", std::move(body)); 3403 dap.SendJSON(llvm::json::Value(std::move(response))); 3404 } 3405 3406 // "StepInRequest": { 3407 // "allOf": [ { "$ref": "#/definitions/Request" }, { 3408 // "type": "object", 3409 // "description": "StepIn request; value of command field is 'stepIn'. The 3410 // request starts the debuggee to step into a function/method if possible. 3411 // If it cannot step into a target, 'stepIn' behaves like 'next'. The debug 3412 // adapter first sends the StepInResponse and then a StoppedEvent (event 3413 // type 'step') after the step has completed. If there are multiple 3414 // function/method calls (or other targets) on the source line, the optional 3415 // argument 'targetId' can be used to control into which target the 'stepIn' 3416 // should occur. The list of possible targets for a given source line can be 3417 // retrieved via the 'stepInTargets' request.", "properties": { 3418 // "command": { 3419 // "type": "string", 3420 // "enum": [ "stepIn" ] 3421 // }, 3422 // "arguments": { 3423 // "$ref": "#/definitions/StepInArguments" 3424 // } 3425 // }, 3426 // "required": [ "command", "arguments" ] 3427 // }] 3428 // }, 3429 // "StepInArguments": { 3430 // "type": "object", 3431 // "description": "Arguments for 'stepIn' request.", 3432 // "properties": { 3433 // "threadId": { 3434 // "type": "integer", 3435 // "description": "Execute 'stepIn' for this thread." 3436 // }, 3437 // "targetId": { 3438 // "type": "integer", 3439 // "description": "Optional id of the target to step into." 3440 // }, 3441 // "granularity": { 3442 // "$ref": "#/definitions/SteppingGranularity", 3443 // "description": "Stepping granularity. If no granularity is specified, a 3444 // granularity of `statement` is assumed." 3445 // } 3446 // }, 3447 // "required": [ "threadId" ] 3448 // }, 3449 // "StepInResponse": { 3450 // "allOf": [ { "$ref": "#/definitions/Response" }, { 3451 // "type": "object", 3452 // "description": "Response to 'stepIn' request. This is just an 3453 // acknowledgement, so no body field is required." 3454 // }] 3455 // } 3456 void request_stepIn(DAP &dap, const llvm::json::Object &request) { 3457 llvm::json::Object response; 3458 FillResponse(request, response); 3459 const auto *arguments = request.getObject("arguments"); 3460 3461 std::string step_in_target; 3462 uint64_t target_id = GetUnsigned(arguments, "targetId", 0); 3463 auto it = dap.step_in_targets.find(target_id); 3464 if (it != dap.step_in_targets.end()) 3465 step_in_target = it->second; 3466 3467 const bool single_thread = GetBoolean(arguments, "singleThread", false); 3468 lldb::RunMode run_mode = 3469 single_thread ? lldb::eOnlyThisThread : lldb::eOnlyDuringStepping; 3470 lldb::SBThread thread = dap.GetLLDBThread(*arguments); 3471 if (thread.IsValid()) { 3472 // Remember the thread ID that caused the resume so we can set the 3473 // "threadCausedFocus" boolean value in the "stopped" events. 3474 dap.focus_tid = thread.GetThreadID(); 3475 if (hasInstructionGranularity(*arguments)) { 3476 thread.StepInstruction(/*step_over=*/false); 3477 } else { 3478 thread.StepInto(step_in_target.c_str(), run_mode); 3479 } 3480 } else { 3481 response["success"] = llvm::json::Value(false); 3482 } 3483 dap.SendJSON(llvm::json::Value(std::move(response))); 3484 } 3485 3486 // "StepInTargetsRequest": { 3487 // "allOf": [ { "$ref": "#/definitions/Request" }, { 3488 // "type": "object", 3489 // "description": "This request retrieves the possible step-in targets for 3490 // the specified stack frame.\nThese targets can be used in the `stepIn` 3491 // request.\nClients should only call this request if the corresponding 3492 // capability `supportsStepInTargetsRequest` is true.", "properties": { 3493 // "command": { 3494 // "type": "string", 3495 // "enum": [ "stepInTargets" ] 3496 // }, 3497 // "arguments": { 3498 // "$ref": "#/definitions/StepInTargetsArguments" 3499 // } 3500 // }, 3501 // "required": [ "command", "arguments" ] 3502 // }] 3503 // }, 3504 // "StepInTargetsArguments": { 3505 // "type": "object", 3506 // "description": "Arguments for `stepInTargets` request.", 3507 // "properties": { 3508 // "frameId": { 3509 // "type": "integer", 3510 // "description": "The stack frame for which to retrieve the possible 3511 // step-in targets." 3512 // } 3513 // }, 3514 // "required": [ "frameId" ] 3515 // }, 3516 // "StepInTargetsResponse": { 3517 // "allOf": [ { "$ref": "#/definitions/Response" }, { 3518 // "type": "object", 3519 // "description": "Response to `stepInTargets` request.", 3520 // "properties": { 3521 // "body": { 3522 // "type": "object", 3523 // "properties": { 3524 // "targets": { 3525 // "type": "array", 3526 // "items": { 3527 // "$ref": "#/definitions/StepInTarget" 3528 // }, 3529 // "description": "The possible step-in targets of the specified 3530 // source location." 3531 // } 3532 // }, 3533 // "required": [ "targets" ] 3534 // } 3535 // }, 3536 // "required": [ "body" ] 3537 // }] 3538 // } 3539 void request_stepInTargets(DAP &dap, const llvm::json::Object &request) { 3540 llvm::json::Object response; 3541 FillResponse(request, response); 3542 const auto *arguments = request.getObject("arguments"); 3543 3544 dap.step_in_targets.clear(); 3545 lldb::SBFrame frame = dap.GetLLDBFrame(*arguments); 3546 if (frame.IsValid()) { 3547 lldb::SBAddress pc_addr = frame.GetPCAddress(); 3548 lldb::SBAddress line_end_addr = 3549 pc_addr.GetLineEntry().GetSameLineContiguousAddressRangeEnd(true); 3550 lldb::SBInstructionList insts = dap.target.ReadInstructions( 3551 pc_addr, line_end_addr, /*flavor_string=*/nullptr); 3552 3553 if (!insts.IsValid()) { 3554 response["success"] = false; 3555 response["message"] = "Failed to get instructions for frame."; 3556 dap.SendJSON(llvm::json::Value(std::move(response))); 3557 return; 3558 } 3559 3560 llvm::json::Array step_in_targets; 3561 const auto num_insts = insts.GetSize(); 3562 for (size_t i = 0; i < num_insts; ++i) { 3563 lldb::SBInstruction inst = insts.GetInstructionAtIndex(i); 3564 if (!inst.IsValid()) 3565 break; 3566 3567 lldb::addr_t inst_addr = inst.GetAddress().GetLoadAddress(dap.target); 3568 3569 // Note: currently only x86/x64 supports flow kind. 3570 lldb::InstructionControlFlowKind flow_kind = 3571 inst.GetControlFlowKind(dap.target); 3572 if (flow_kind == lldb::eInstructionControlFlowKindCall) { 3573 // Use call site instruction address as id which is easy to debug. 3574 llvm::json::Object step_in_target; 3575 step_in_target["id"] = inst_addr; 3576 3577 llvm::StringRef call_operand_name = inst.GetOperands(dap.target); 3578 lldb::addr_t call_target_addr; 3579 if (call_operand_name.getAsInteger(0, call_target_addr)) 3580 continue; 3581 3582 lldb::SBAddress call_target_load_addr = 3583 dap.target.ResolveLoadAddress(call_target_addr); 3584 if (!call_target_load_addr.IsValid()) 3585 continue; 3586 3587 // The existing ThreadPlanStepInRange only accept step in target 3588 // function with debug info. 3589 lldb::SBSymbolContext sc = dap.target.ResolveSymbolContextForAddress( 3590 call_target_load_addr, lldb::eSymbolContextFunction); 3591 3592 // The existing ThreadPlanStepInRange only accept step in target 3593 // function with debug info. 3594 std::string step_in_target_name; 3595 if (sc.IsValid() && sc.GetFunction().IsValid()) 3596 step_in_target_name = sc.GetFunction().GetDisplayName(); 3597 3598 // Skip call sites if we fail to resolve its symbol name. 3599 if (step_in_target_name.empty()) 3600 continue; 3601 3602 dap.step_in_targets.try_emplace(inst_addr, step_in_target_name); 3603 step_in_target.try_emplace("label", step_in_target_name); 3604 step_in_targets.emplace_back(std::move(step_in_target)); 3605 } 3606 } 3607 llvm::json::Object body; 3608 body.try_emplace("targets", std::move(step_in_targets)); 3609 response.try_emplace("body", std::move(body)); 3610 } else { 3611 response["success"] = llvm::json::Value(false); 3612 response["message"] = "Failed to get frame for input frameId."; 3613 } 3614 dap.SendJSON(llvm::json::Value(std::move(response))); 3615 } 3616 3617 // "StepOutRequest": { 3618 // "allOf": [ { "$ref": "#/definitions/Request" }, { 3619 // "type": "object", 3620 // "description": "StepOut request; value of command field is 'stepOut'. The 3621 // request starts the debuggee to run again for one step. The debug adapter 3622 // first sends the StepOutResponse and then a StoppedEvent (event type 3623 // 'step') after the step has completed.", "properties": { 3624 // "command": { 3625 // "type": "string", 3626 // "enum": [ "stepOut" ] 3627 // }, 3628 // "arguments": { 3629 // "$ref": "#/definitions/StepOutArguments" 3630 // } 3631 // }, 3632 // "required": [ "command", "arguments" ] 3633 // }] 3634 // }, 3635 // "StepOutArguments": { 3636 // "type": "object", 3637 // "description": "Arguments for 'stepOut' request.", 3638 // "properties": { 3639 // "threadId": { 3640 // "type": "integer", 3641 // "description": "Execute 'stepOut' for this thread." 3642 // } 3643 // }, 3644 // "required": [ "threadId" ] 3645 // }, 3646 // "StepOutResponse": { 3647 // "allOf": [ { "$ref": "#/definitions/Response" }, { 3648 // "type": "object", 3649 // "description": "Response to 'stepOut' request. This is just an 3650 // acknowledgement, so no body field is required." 3651 // }] 3652 // } 3653 void request_stepOut(DAP &dap, const llvm::json::Object &request) { 3654 llvm::json::Object response; 3655 FillResponse(request, response); 3656 const auto *arguments = request.getObject("arguments"); 3657 lldb::SBThread thread = dap.GetLLDBThread(*arguments); 3658 if (thread.IsValid()) { 3659 // Remember the thread ID that caused the resume so we can set the 3660 // "threadCausedFocus" boolean value in the "stopped" events. 3661 dap.focus_tid = thread.GetThreadID(); 3662 thread.StepOut(); 3663 } else { 3664 response["success"] = llvm::json::Value(false); 3665 } 3666 dap.SendJSON(llvm::json::Value(std::move(response))); 3667 } 3668 3669 // "ThreadsRequest": { 3670 // "allOf": [ { "$ref": "#/definitions/Request" }, { 3671 // "type": "object", 3672 // "description": "Thread request; value of command field is 'threads'. The 3673 // request retrieves a list of all threads.", "properties": { 3674 // "command": { 3675 // "type": "string", 3676 // "enum": [ "threads" ] 3677 // } 3678 // }, 3679 // "required": [ "command" ] 3680 // }] 3681 // }, 3682 // "ThreadsResponse": { 3683 // "allOf": [ { "$ref": "#/definitions/Response" }, { 3684 // "type": "object", 3685 // "description": "Response to 'threads' request.", 3686 // "properties": { 3687 // "body": { 3688 // "type": "object", 3689 // "properties": { 3690 // "threads": { 3691 // "type": "array", 3692 // "items": { 3693 // "$ref": "#/definitions/Thread" 3694 // }, 3695 // "description": "All threads." 3696 // } 3697 // }, 3698 // "required": [ "threads" ] 3699 // } 3700 // }, 3701 // "required": [ "body" ] 3702 // }] 3703 // } 3704 void request_threads(DAP &dap, const llvm::json::Object &request) { 3705 lldb::SBProcess process = dap.target.GetProcess(); 3706 llvm::json::Object response; 3707 FillResponse(request, response); 3708 3709 const uint32_t num_threads = process.GetNumThreads(); 3710 llvm::json::Array threads; 3711 for (uint32_t thread_idx = 0; thread_idx < num_threads; ++thread_idx) { 3712 lldb::SBThread thread = process.GetThreadAtIndex(thread_idx); 3713 threads.emplace_back(CreateThread(thread, dap.thread_format)); 3714 } 3715 if (threads.size() == 0) { 3716 response["success"] = llvm::json::Value(false); 3717 } 3718 llvm::json::Object body; 3719 body.try_emplace("threads", std::move(threads)); 3720 response.try_emplace("body", std::move(body)); 3721 dap.SendJSON(llvm::json::Value(std::move(response))); 3722 } 3723 3724 // "SetVariableRequest": { 3725 // "allOf": [ { "$ref": "#/definitions/Request" }, { 3726 // "type": "object", 3727 // "description": "setVariable request; value of command field is 3728 // 'setVariable'. Set the variable with the given name in the variable 3729 // container to a new value.", "properties": { 3730 // "command": { 3731 // "type": "string", 3732 // "enum": [ "setVariable" ] 3733 // }, 3734 // "arguments": { 3735 // "$ref": "#/definitions/SetVariableArguments" 3736 // } 3737 // }, 3738 // "required": [ "command", "arguments" ] 3739 // }] 3740 // }, 3741 // "SetVariableArguments": { 3742 // "type": "object", 3743 // "description": "Arguments for 'setVariable' request.", 3744 // "properties": { 3745 // "variablesReference": { 3746 // "type": "integer", 3747 // "description": "The reference of the variable container." 3748 // }, 3749 // "name": { 3750 // "type": "string", 3751 // "description": "The name of the variable." 3752 // }, 3753 // "value": { 3754 // "type": "string", 3755 // "description": "The value of the variable." 3756 // }, 3757 // "format": { 3758 // "$ref": "#/definitions/ValueFormat", 3759 // "description": "Specifies details on how to format the response value." 3760 // } 3761 // }, 3762 // "required": [ "variablesReference", "name", "value" ] 3763 // }, 3764 // "SetVariableResponse": { 3765 // "allOf": [ { "$ref": "#/definitions/Response" }, { 3766 // "type": "object", 3767 // "description": "Response to 'setVariable' request.", 3768 // "properties": { 3769 // "body": { 3770 // "type": "object", 3771 // "properties": { 3772 // "value": { 3773 // "type": "string", 3774 // "description": "The new value of the variable." 3775 // }, 3776 // "type": { 3777 // "type": "string", 3778 // "description": "The type of the new value. Typically shown in the 3779 // UI when hovering over the value." 3780 // }, 3781 // "variablesReference": { 3782 // "type": "number", 3783 // "description": "If variablesReference is > 0, the new value is 3784 // structured and its children can be retrieved by passing 3785 // variablesReference to the VariablesRequest." 3786 // }, 3787 // "namedVariables": { 3788 // "type": "number", 3789 // "description": "The number of named child variables. The client 3790 // can use this optional information to present the variables in a 3791 // paged UI and fetch them in chunks." 3792 // }, 3793 // "indexedVariables": { 3794 // "type": "number", 3795 // "description": "The number of indexed child variables. The client 3796 // can use this optional information to present the variables in a 3797 // paged UI and fetch them in chunks." 3798 // }, 3799 // "valueLocationReference": { 3800 // "type": "integer", 3801 // "description": "A reference that allows the client to request the 3802 // location where the new value is declared. For example, if the new 3803 // value is function pointer, the adapter may be able to look up the 3804 // function's location. This should be present only if the adapter 3805 // is likely to be able to resolve the location.\n\nThis reference 3806 // shares the same lifetime as the `variablesReference`. See 3807 // 'Lifetime of Object References' in the Overview section for 3808 // details." 3809 // } 3810 // }, 3811 // "required": [ "value" ] 3812 // } 3813 // }, 3814 // "required": [ "body" ] 3815 // }] 3816 // } 3817 void request_setVariable(DAP &dap, const llvm::json::Object &request) { 3818 llvm::json::Object response; 3819 FillResponse(request, response); 3820 llvm::json::Array variables; 3821 llvm::json::Object body; 3822 const auto *arguments = request.getObject("arguments"); 3823 // This is a reference to the containing variable/scope 3824 const auto variablesReference = 3825 GetUnsigned(arguments, "variablesReference", 0); 3826 llvm::StringRef name = GetString(arguments, "name"); 3827 3828 const auto value = GetString(arguments, "value"); 3829 // Set success to false just in case we don't find the variable by name 3830 response.try_emplace("success", false); 3831 3832 lldb::SBValue variable; 3833 3834 // The "id" is the unique integer ID that is unique within the enclosing 3835 // variablesReference. It is optionally added to any "interface Variable" 3836 // objects to uniquely identify a variable within an enclosing 3837 // variablesReference. It helps to disambiguate between two variables that 3838 // have the same name within the same scope since the "setVariables" request 3839 // only specifies the variable reference of the enclosing scope/variable, and 3840 // the name of the variable. We could have two shadowed variables with the 3841 // same name in "Locals" or "Globals". In our case the "id" absolute index 3842 // of the variable within the dap.variables list. 3843 const auto id_value = GetUnsigned(arguments, "id", UINT64_MAX); 3844 if (id_value != UINT64_MAX) { 3845 variable = dap.variables.GetVariable(id_value); 3846 } else { 3847 variable = FindVariable(dap, variablesReference, name); 3848 } 3849 3850 if (variable.IsValid()) { 3851 lldb::SBError error; 3852 bool success = variable.SetValueFromCString(value.data(), error); 3853 if (success) { 3854 VariableDescription desc(variable, dap.enable_auto_variable_summaries); 3855 EmplaceSafeString(body, "result", desc.display_value); 3856 EmplaceSafeString(body, "type", desc.display_type_name); 3857 3858 // We don't know the index of the variable in our dap.variables 3859 // so always insert a new one to get its variablesReference. 3860 // is_permanent is false because debug console does not support 3861 // setVariable request. 3862 int64_t new_var_ref = 3863 dap.variables.InsertVariable(variable, /*is_permanent=*/false); 3864 if (variable.MightHaveChildren()) 3865 body.try_emplace("variablesReference", new_var_ref); 3866 else 3867 body.try_emplace("variablesReference", 0); 3868 if (lldb::addr_t addr = variable.GetLoadAddress(); 3869 addr != LLDB_INVALID_ADDRESS) 3870 body.try_emplace("memoryReference", EncodeMemoryReference(addr)); 3871 if (ValuePointsToCode(variable)) 3872 body.try_emplace("valueLocationReference", new_var_ref); 3873 } else { 3874 EmplaceSafeString(body, "message", std::string(error.GetCString())); 3875 } 3876 response["success"] = llvm::json::Value(success); 3877 } else { 3878 response["success"] = llvm::json::Value(false); 3879 } 3880 3881 response.try_emplace("body", std::move(body)); 3882 dap.SendJSON(llvm::json::Value(std::move(response))); 3883 } 3884 3885 // "VariablesRequest": { 3886 // "allOf": [ { "$ref": "#/definitions/Request" }, { 3887 // "type": "object", 3888 // "description": "Variables request; value of command field is 'variables'. 3889 // Retrieves all child variables for the given variable reference. An 3890 // optional filter can be used to limit the fetched children to either named 3891 // or indexed children.", "properties": { 3892 // "command": { 3893 // "type": "string", 3894 // "enum": [ "variables" ] 3895 // }, 3896 // "arguments": { 3897 // "$ref": "#/definitions/VariablesArguments" 3898 // } 3899 // }, 3900 // "required": [ "command", "arguments" ] 3901 // }] 3902 // }, 3903 // "VariablesArguments": { 3904 // "type": "object", 3905 // "description": "Arguments for 'variables' request.", 3906 // "properties": { 3907 // "variablesReference": { 3908 // "type": "integer", 3909 // "description": "The Variable reference." 3910 // }, 3911 // "filter": { 3912 // "type": "string", 3913 // "enum": [ "indexed", "named" ], 3914 // "description": "Optional filter to limit the child variables to either 3915 // named or indexed. If ommited, both types are fetched." 3916 // }, 3917 // "start": { 3918 // "type": "integer", 3919 // "description": "The index of the first variable to return; if omitted 3920 // children start at 0." 3921 // }, 3922 // "count": { 3923 // "type": "integer", 3924 // "description": "The number of variables to return. If count is missing 3925 // or 0, all variables are returned." 3926 // }, 3927 // "format": { 3928 // "$ref": "#/definitions/ValueFormat", 3929 // "description": "Specifies details on how to format the Variable 3930 // values." 3931 // } 3932 // }, 3933 // "required": [ "variablesReference" ] 3934 // }, 3935 // "VariablesResponse": { 3936 // "allOf": [ { "$ref": "#/definitions/Response" }, { 3937 // "type": "object", 3938 // "description": "Response to 'variables' request.", 3939 // "properties": { 3940 // "body": { 3941 // "type": "object", 3942 // "properties": { 3943 // "variables": { 3944 // "type": "array", 3945 // "items": { 3946 // "$ref": "#/definitions/Variable" 3947 // }, 3948 // "description": "All (or a range) of variables for the given 3949 // variable reference." 3950 // } 3951 // }, 3952 // "required": [ "variables" ] 3953 // } 3954 // }, 3955 // "required": [ "body" ] 3956 // }] 3957 // } 3958 void request_variables(DAP &dap, const llvm::json::Object &request) { 3959 llvm::json::Object response; 3960 FillResponse(request, response); 3961 llvm::json::Array variables; 3962 const auto *arguments = request.getObject("arguments"); 3963 const auto variablesReference = 3964 GetUnsigned(arguments, "variablesReference", 0); 3965 const int64_t start = GetSigned(arguments, "start", 0); 3966 const int64_t count = GetSigned(arguments, "count", 0); 3967 bool hex = false; 3968 const auto *format = arguments->getObject("format"); 3969 if (format) 3970 hex = GetBoolean(format, "hex", false); 3971 3972 if (lldb::SBValueList *top_scope = 3973 GetTopLevelScope(dap, variablesReference)) { 3974 // variablesReference is one of our scopes, not an actual variable it is 3975 // asking for the list of args, locals or globals. 3976 int64_t start_idx = 0; 3977 int64_t num_children = 0; 3978 3979 if (variablesReference == VARREF_REGS) { 3980 // Change the default format of any pointer sized registers in the first 3981 // register set to be the lldb::eFormatAddressInfo so we show the pointer 3982 // and resolve what the pointer resolves to. Only change the format if the 3983 // format was set to the default format or if it was hex as some registers 3984 // have formats set for them. 3985 const uint32_t addr_size = dap.target.GetProcess().GetAddressByteSize(); 3986 lldb::SBValue reg_set = dap.variables.registers.GetValueAtIndex(0); 3987 const uint32_t num_regs = reg_set.GetNumChildren(); 3988 for (uint32_t reg_idx = 0; reg_idx < num_regs; ++reg_idx) { 3989 lldb::SBValue reg = reg_set.GetChildAtIndex(reg_idx); 3990 const lldb::Format format = reg.GetFormat(); 3991 if (format == lldb::eFormatDefault || format == lldb::eFormatHex) { 3992 if (reg.GetByteSize() == addr_size) 3993 reg.SetFormat(lldb::eFormatAddressInfo); 3994 } 3995 } 3996 } 3997 3998 num_children = top_scope->GetSize(); 3999 if (num_children == 0 && variablesReference == VARREF_LOCALS) { 4000 // Check for an error in the SBValueList that might explain why we don't 4001 // have locals. If we have an error display it as the sole value in the 4002 // the locals. 4003 4004 // "error" owns the error string so we must keep it alive as long as we 4005 // want to use the returns "const char *" 4006 lldb::SBError error = top_scope->GetError(); 4007 const char *var_err = error.GetCString(); 4008 if (var_err) { 4009 // Create a fake variable named "error" to explain why variables were 4010 // not available. This new error will help let users know when there was 4011 // a problem that kept variables from being available for display and 4012 // allow users to fix this issue instead of seeing no variables. The 4013 // errors are only set when there is a problem that the user could 4014 // fix, so no error will show up when you have no debug info, only when 4015 // we do have debug info and something that is fixable can be done. 4016 llvm::json::Object object; 4017 EmplaceSafeString(object, "name", "<error>"); 4018 EmplaceSafeString(object, "type", "const char *"); 4019 EmplaceSafeString(object, "value", var_err); 4020 object.try_emplace("variablesReference", (int64_t)0); 4021 variables.emplace_back(std::move(object)); 4022 } 4023 } 4024 const int64_t end_idx = start_idx + ((count == 0) ? num_children : count); 4025 4026 // We first find out which variable names are duplicated 4027 std::map<std::string, int> variable_name_counts; 4028 for (auto i = start_idx; i < end_idx; ++i) { 4029 lldb::SBValue variable = top_scope->GetValueAtIndex(i); 4030 if (!variable.IsValid()) 4031 break; 4032 variable_name_counts[GetNonNullVariableName(variable)]++; 4033 } 4034 4035 // Now we construct the result with unique display variable names 4036 for (auto i = start_idx; i < end_idx; ++i) { 4037 lldb::SBValue variable = top_scope->GetValueAtIndex(i); 4038 4039 if (!variable.IsValid()) 4040 break; 4041 4042 int64_t var_ref = 4043 dap.variables.InsertVariable(variable, /*is_permanent=*/false); 4044 variables.emplace_back(CreateVariable( 4045 variable, var_ref, hex, dap.enable_auto_variable_summaries, 4046 dap.enable_synthetic_child_debugging, 4047 variable_name_counts[GetNonNullVariableName(variable)] > 1)); 4048 } 4049 } else { 4050 // We are expanding a variable that has children, so we will return its 4051 // children. 4052 lldb::SBValue variable = dap.variables.GetVariable(variablesReference); 4053 if (variable.IsValid()) { 4054 auto addChild = [&](lldb::SBValue child, 4055 std::optional<std::string> custom_name = {}) { 4056 if (!child.IsValid()) 4057 return; 4058 bool is_permanent = 4059 dap.variables.IsPermanentVariableReference(variablesReference); 4060 int64_t var_ref = dap.variables.InsertVariable(child, is_permanent); 4061 variables.emplace_back(CreateVariable( 4062 child, var_ref, hex, dap.enable_auto_variable_summaries, 4063 dap.enable_synthetic_child_debugging, 4064 /*is_name_duplicated=*/false, custom_name)); 4065 }; 4066 const int64_t num_children = variable.GetNumChildren(); 4067 int64_t end_idx = start + ((count == 0) ? num_children : count); 4068 int64_t i = start; 4069 for (; i < end_idx && i < num_children; ++i) 4070 addChild(variable.GetChildAtIndex(i)); 4071 4072 // If we haven't filled the count quota from the request, we insert a new 4073 // "[raw]" child that can be used to inspect the raw version of a 4074 // synthetic member. That eliminates the need for the user to go to the 4075 // debug console and type `frame var <variable> to get these values. 4076 if (dap.enable_synthetic_child_debugging && variable.IsSynthetic() && 4077 i == num_children) 4078 addChild(variable.GetNonSyntheticValue(), "[raw]"); 4079 } 4080 } 4081 llvm::json::Object body; 4082 body.try_emplace("variables", std::move(variables)); 4083 response.try_emplace("body", std::move(body)); 4084 dap.SendJSON(llvm::json::Value(std::move(response))); 4085 } 4086 4087 // "LocationsRequest": { 4088 // "allOf": [ { "$ref": "#/definitions/Request" }, { 4089 // "type": "object", 4090 // "description": "Looks up information about a location reference 4091 // previously returned by the debug adapter.", 4092 // "properties": { 4093 // "command": { 4094 // "type": "string", 4095 // "enum": [ "locations" ] 4096 // }, 4097 // "arguments": { 4098 // "$ref": "#/definitions/LocationsArguments" 4099 // } 4100 // }, 4101 // "required": [ "command", "arguments" ] 4102 // }] 4103 // }, 4104 // "LocationsArguments": { 4105 // "type": "object", 4106 // "description": "Arguments for `locations` request.", 4107 // "properties": { 4108 // "locationReference": { 4109 // "type": "integer", 4110 // "description": "Location reference to resolve." 4111 // } 4112 // }, 4113 // "required": [ "locationReference" ] 4114 // }, 4115 // "LocationsResponse": { 4116 // "allOf": [ { "$ref": "#/definitions/Response" }, { 4117 // "type": "object", 4118 // "description": "Response to `locations` request.", 4119 // "properties": { 4120 // "body": { 4121 // "type": "object", 4122 // "properties": { 4123 // "source": { 4124 // "$ref": "#/definitions/Source", 4125 // "description": "The source containing the location; either 4126 // `source.path` or `source.sourceReference` must be 4127 // specified." 4128 // }, 4129 // "line": { 4130 // "type": "integer", 4131 // "description": "The line number of the location. The client 4132 // capability `linesStartAt1` determines whether it 4133 // is 0- or 1-based." 4134 // }, 4135 // "column": { 4136 // "type": "integer", 4137 // "description": "Position of the location within the `line`. It is 4138 // measured in UTF-16 code units and the client 4139 // capability `columnsStartAt1` determines whether 4140 // it is 0- or 1-based. If no column is given, the 4141 // first position in the start line is assumed." 4142 // }, 4143 // "endLine": { 4144 // "type": "integer", 4145 // "description": "End line of the location, present if the location 4146 // refers to a range. The client capability 4147 // `linesStartAt1` determines whether it is 0- or 4148 // 1-based." 4149 // }, 4150 // "endColumn": { 4151 // "type": "integer", 4152 // "description": "End position of the location within `endLine`, 4153 // present if the location refers to a range. It is 4154 // measured in UTF-16 code units and the client 4155 // capability `columnsStartAt1` determines whether 4156 // it is 0- or 1-based." 4157 // } 4158 // }, 4159 // "required": [ "source", "line" ] 4160 // } 4161 // } 4162 // }] 4163 // }, 4164 void request_locations(DAP &dap, const llvm::json::Object &request) { 4165 llvm::json::Object response; 4166 FillResponse(request, response); 4167 auto *arguments = request.getObject("arguments"); 4168 4169 uint64_t location_id = GetUnsigned(arguments, "locationReference", 0); 4170 // We use the lowest bit to distinguish between value location and declaration 4171 // location 4172 auto [var_ref, is_value_location] = UnpackLocation(location_id); 4173 lldb::SBValue variable = dap.variables.GetVariable(var_ref); 4174 if (!variable.IsValid()) { 4175 response["success"] = false; 4176 response["message"] = "Invalid variable reference"; 4177 dap.SendJSON(llvm::json::Value(std::move(response))); 4178 return; 4179 } 4180 4181 llvm::json::Object body; 4182 if (is_value_location) { 4183 // Get the value location 4184 if (!variable.GetType().IsPointerType() && 4185 !variable.GetType().IsReferenceType()) { 4186 response["success"] = false; 4187 response["message"] = 4188 "Value locations are only available for pointers and references"; 4189 dap.SendJSON(llvm::json::Value(std::move(response))); 4190 return; 4191 } 4192 4193 lldb::addr_t addr = variable.GetValueAsAddress(); 4194 lldb::SBLineEntry line_entry = 4195 dap.target.ResolveLoadAddress(addr).GetLineEntry(); 4196 4197 if (!line_entry.IsValid()) { 4198 response["success"] = false; 4199 response["message"] = "Failed to resolve line entry for location"; 4200 dap.SendJSON(llvm::json::Value(std::move(response))); 4201 return; 4202 } 4203 4204 body.try_emplace("source", CreateSource(line_entry.GetFileSpec())); 4205 if (int line = line_entry.GetLine()) 4206 body.try_emplace("line", line); 4207 if (int column = line_entry.GetColumn()) 4208 body.try_emplace("column", column); 4209 } else { 4210 // Get the declaration location 4211 lldb::SBDeclaration decl = variable.GetDeclaration(); 4212 if (!decl.IsValid()) { 4213 response["success"] = false; 4214 response["message"] = "No declaration location available"; 4215 dap.SendJSON(llvm::json::Value(std::move(response))); 4216 return; 4217 } 4218 4219 body.try_emplace("source", CreateSource(decl.GetFileSpec())); 4220 if (int line = decl.GetLine()) 4221 body.try_emplace("line", line); 4222 if (int column = decl.GetColumn()) 4223 body.try_emplace("column", column); 4224 } 4225 4226 response.try_emplace("body", std::move(body)); 4227 dap.SendJSON(llvm::json::Value(std::move(response))); 4228 } 4229 4230 // "DisassembleRequest": { 4231 // "allOf": [ { "$ref": "#/definitions/Request" }, { 4232 // "type": "object", 4233 // "description": "Disassembles code stored at the provided 4234 // location.\nClients should only call this request if the corresponding 4235 // capability `supportsDisassembleRequest` is true.", "properties": { 4236 // "command": { 4237 // "type": "string", 4238 // "enum": [ "disassemble" ] 4239 // }, 4240 // "arguments": { 4241 // "$ref": "#/definitions/DisassembleArguments" 4242 // } 4243 // }, 4244 // "required": [ "command", "arguments" ] 4245 // }] 4246 // }, 4247 // "DisassembleArguments": { 4248 // "type": "object", 4249 // "description": "Arguments for `disassemble` request.", 4250 // "properties": { 4251 // "memoryReference": { 4252 // "type": "string", 4253 // "description": "Memory reference to the base location containing the 4254 // instructions to disassemble." 4255 // }, 4256 // "offset": { 4257 // "type": "integer", 4258 // "description": "Offset (in bytes) to be applied to the reference 4259 // location before disassembling. Can be negative." 4260 // }, 4261 // "instructionOffset": { 4262 // "type": "integer", 4263 // "description": "Offset (in instructions) to be applied after the byte 4264 // offset (if any) before disassembling. Can be negative." 4265 // }, 4266 // "instructionCount": { 4267 // "type": "integer", 4268 // "description": "Number of instructions to disassemble starting at the 4269 // specified location and offset.\nAn adapter must return exactly this 4270 // number of instructions - any unavailable instructions should be 4271 // replaced with an implementation-defined 'invalid instruction' value." 4272 // }, 4273 // "resolveSymbols": { 4274 // "type": "boolean", 4275 // "description": "If true, the adapter should attempt to resolve memory 4276 // addresses and other values to symbolic names." 4277 // } 4278 // }, 4279 // "required": [ "memoryReference", "instructionCount" ] 4280 // }, 4281 // "DisassembleResponse": { 4282 // "allOf": [ { "$ref": "#/definitions/Response" }, { 4283 // "type": "object", 4284 // "description": "Response to `disassemble` request.", 4285 // "properties": { 4286 // "body": { 4287 // "type": "object", 4288 // "properties": { 4289 // "instructions": { 4290 // "type": "array", 4291 // "items": { 4292 // "$ref": "#/definitions/DisassembledInstruction" 4293 // }, 4294 // "description": "The list of disassembled instructions." 4295 // } 4296 // }, 4297 // "required": [ "instructions" ] 4298 // } 4299 // } 4300 // }] 4301 // } 4302 void request_disassemble(DAP &dap, const llvm::json::Object &request) { 4303 llvm::json::Object response; 4304 FillResponse(request, response); 4305 auto *arguments = request.getObject("arguments"); 4306 4307 llvm::StringRef memoryReference = GetString(arguments, "memoryReference"); 4308 auto addr_opt = DecodeMemoryReference(memoryReference); 4309 if (!addr_opt.has_value()) { 4310 response["success"] = false; 4311 response["message"] = 4312 "Malformed memory reference: " + memoryReference.str(); 4313 dap.SendJSON(llvm::json::Value(std::move(response))); 4314 return; 4315 } 4316 lldb::addr_t addr_ptr = *addr_opt; 4317 4318 addr_ptr += GetSigned(arguments, "instructionOffset", 0); 4319 lldb::SBAddress addr(addr_ptr, dap.target); 4320 if (!addr.IsValid()) { 4321 response["success"] = false; 4322 response["message"] = "Memory reference not found in the current binary."; 4323 dap.SendJSON(llvm::json::Value(std::move(response))); 4324 return; 4325 } 4326 4327 const auto inst_count = GetUnsigned(arguments, "instructionCount", 0); 4328 lldb::SBInstructionList insts = dap.target.ReadInstructions(addr, inst_count); 4329 4330 if (!insts.IsValid()) { 4331 response["success"] = false; 4332 response["message"] = "Failed to find instructions for memory address."; 4333 dap.SendJSON(llvm::json::Value(std::move(response))); 4334 return; 4335 } 4336 4337 const bool resolveSymbols = GetBoolean(arguments, "resolveSymbols", false); 4338 llvm::json::Array instructions; 4339 const auto num_insts = insts.GetSize(); 4340 for (size_t i = 0; i < num_insts; ++i) { 4341 lldb::SBInstruction inst = insts.GetInstructionAtIndex(i); 4342 auto addr = inst.GetAddress(); 4343 const auto inst_addr = addr.GetLoadAddress(dap.target); 4344 const char *m = inst.GetMnemonic(dap.target); 4345 const char *o = inst.GetOperands(dap.target); 4346 const char *c = inst.GetComment(dap.target); 4347 auto d = inst.GetData(dap.target); 4348 4349 std::string bytes; 4350 llvm::raw_string_ostream sb(bytes); 4351 for (unsigned i = 0; i < inst.GetByteSize(); i++) { 4352 lldb::SBError error; 4353 uint8_t b = d.GetUnsignedInt8(error, i); 4354 if (error.Success()) { 4355 sb << llvm::format("%2.2x ", b); 4356 } 4357 } 4358 4359 llvm::json::Object disassembled_inst{ 4360 {"address", "0x" + llvm::utohexstr(inst_addr)}, 4361 {"instructionBytes", 4362 bytes.size() > 0 ? bytes.substr(0, bytes.size() - 1) : ""}, 4363 }; 4364 4365 std::string instruction; 4366 llvm::raw_string_ostream si(instruction); 4367 4368 lldb::SBSymbol symbol = addr.GetSymbol(); 4369 // Only add the symbol on the first line of the function. 4370 if (symbol.IsValid() && symbol.GetStartAddress() == addr) { 4371 // If we have a valid symbol, append it as a label prefix for the first 4372 // instruction. This is so you can see the start of a function/callsite 4373 // in the assembly, at the moment VS Code (1.80) does not visualize the 4374 // symbol associated with the assembly instruction. 4375 si << (symbol.GetMangledName() != nullptr ? symbol.GetMangledName() 4376 : symbol.GetName()) 4377 << ": "; 4378 4379 if (resolveSymbols) { 4380 disassembled_inst.try_emplace("symbol", symbol.GetDisplayName()); 4381 } 4382 } 4383 4384 si << llvm::formatv("{0,7} {1,12}", m, o); 4385 if (c && c[0]) { 4386 si << " ; " << c; 4387 } 4388 4389 disassembled_inst.try_emplace("instruction", instruction); 4390 4391 auto line_entry = addr.GetLineEntry(); 4392 // If the line number is 0 then the entry represents a compiler generated 4393 // location. 4394 if (line_entry.GetStartAddress() == addr && line_entry.IsValid() && 4395 line_entry.GetFileSpec().IsValid() && line_entry.GetLine() != 0) { 4396 auto source = CreateSource(line_entry); 4397 disassembled_inst.try_emplace("location", source); 4398 4399 const auto line = line_entry.GetLine(); 4400 if (line && line != LLDB_INVALID_LINE_NUMBER) { 4401 disassembled_inst.try_emplace("line", line); 4402 } 4403 const auto column = line_entry.GetColumn(); 4404 if (column && column != LLDB_INVALID_COLUMN_NUMBER) { 4405 disassembled_inst.try_emplace("column", column); 4406 } 4407 4408 auto end_line_entry = line_entry.GetEndAddress().GetLineEntry(); 4409 if (end_line_entry.IsValid() && 4410 end_line_entry.GetFileSpec() == line_entry.GetFileSpec()) { 4411 const auto end_line = end_line_entry.GetLine(); 4412 if (end_line && end_line != LLDB_INVALID_LINE_NUMBER && 4413 end_line != line) { 4414 disassembled_inst.try_emplace("endLine", end_line); 4415 4416 const auto end_column = end_line_entry.GetColumn(); 4417 if (end_column && end_column != LLDB_INVALID_COLUMN_NUMBER && 4418 end_column != column) { 4419 disassembled_inst.try_emplace("endColumn", end_column - 1); 4420 } 4421 } 4422 } 4423 } 4424 4425 instructions.emplace_back(std::move(disassembled_inst)); 4426 } 4427 4428 llvm::json::Object body; 4429 body.try_emplace("instructions", std::move(instructions)); 4430 response.try_emplace("body", std::move(body)); 4431 dap.SendJSON(llvm::json::Value(std::move(response))); 4432 } 4433 4434 // "ReadMemoryRequest": { 4435 // "allOf": [ { "$ref": "#/definitions/Request" }, { 4436 // "type": "object", 4437 // "description": "Reads bytes from memory at the provided location. Clients 4438 // should only call this request if the corresponding 4439 // capability `supportsReadMemoryRequest` is true.", 4440 // "properties": { 4441 // "command": { 4442 // "type": "string", 4443 // "enum": [ "readMemory" ] 4444 // }, 4445 // "arguments": { 4446 // "$ref": "#/definitions/ReadMemoryArguments" 4447 // } 4448 // }, 4449 // "required": [ "command", "arguments" ] 4450 // }] 4451 // }, 4452 // "ReadMemoryArguments": { 4453 // "type": "object", 4454 // "description": "Arguments for `readMemory` request.", 4455 // "properties": { 4456 // "memoryReference": { 4457 // "type": "string", 4458 // "description": "Memory reference to the base location from which data 4459 // should be read." 4460 // }, 4461 // "offset": { 4462 // "type": "integer", 4463 // "description": "Offset (in bytes) to be applied to the reference 4464 // location before reading data. Can be negative." 4465 // }, 4466 // "count": { 4467 // "type": "integer", 4468 // "description": "Number of bytes to read at the specified location and 4469 // offset." 4470 // } 4471 // }, 4472 // "required": [ "memoryReference", "count" ] 4473 // }, 4474 // "ReadMemoryResponse": { 4475 // "allOf": [ { "$ref": "#/definitions/Response" }, { 4476 // "type": "object", 4477 // "description": "Response to `readMemory` request.", 4478 // "properties": { 4479 // "body": { 4480 // "type": "object", 4481 // "properties": { 4482 // "address": { 4483 // "type": "string", 4484 // "description": "The address of the first byte of data returned. 4485 // Treated as a hex value if prefixed with `0x`, or 4486 // as a decimal value otherwise." 4487 // }, 4488 // "unreadableBytes": { 4489 // "type": "integer", 4490 // "description": "The number of unreadable bytes encountered after 4491 // the last successfully read byte.\nThis can be 4492 // used to determine the number of bytes that should 4493 // be skipped before a subsequent 4494 // `readMemory` request succeeds." 4495 // }, 4496 // "data": { 4497 // "type": "string", 4498 // "description": "The bytes read from memory, encoded using base64. 4499 // If the decoded length of `data` is less than the 4500 // requested `count` in the original `readMemory` 4501 // request, and `unreadableBytes` is zero or 4502 // omitted, then the client should assume it's 4503 // reached the end of readable memory." 4504 // } 4505 // }, 4506 // "required": [ "address" ] 4507 // } 4508 // } 4509 // }] 4510 // }, 4511 void request_readMemory(DAP &dap, const llvm::json::Object &request) { 4512 llvm::json::Object response; 4513 FillResponse(request, response); 4514 auto *arguments = request.getObject("arguments"); 4515 4516 llvm::StringRef memoryReference = GetString(arguments, "memoryReference"); 4517 auto addr_opt = DecodeMemoryReference(memoryReference); 4518 if (!addr_opt.has_value()) { 4519 response["success"] = false; 4520 response["message"] = 4521 "Malformed memory reference: " + memoryReference.str(); 4522 dap.SendJSON(llvm::json::Value(std::move(response))); 4523 return; 4524 } 4525 lldb::addr_t addr_int = *addr_opt; 4526 addr_int += GetSigned(arguments, "offset", 0); 4527 const uint64_t count_requested = GetUnsigned(arguments, "count", 0); 4528 4529 // We also need support reading 0 bytes 4530 // VS Code sends those requests to check if a `memoryReference` 4531 // can be dereferenced. 4532 const uint64_t count_read = std::max<uint64_t>(count_requested, 1); 4533 std::vector<uint8_t> buf; 4534 buf.resize(count_read); 4535 lldb::SBError error; 4536 lldb::SBAddress addr{addr_int, dap.target}; 4537 size_t count_result = 4538 dap.target.ReadMemory(addr, buf.data(), count_read, error); 4539 if (count_result == 0) { 4540 response["success"] = false; 4541 EmplaceSafeString(response, "message", error.GetCString()); 4542 dap.SendJSON(llvm::json::Value(std::move(response))); 4543 return; 4544 } 4545 buf.resize(std::min<size_t>(count_result, count_requested)); 4546 4547 llvm::json::Object body; 4548 std::string formatted_addr = "0x" + llvm::utohexstr(addr_int); 4549 body.try_emplace("address", formatted_addr); 4550 body.try_emplace("data", llvm::encodeBase64(buf)); 4551 response.try_emplace("body", std::move(body)); 4552 dap.SendJSON(llvm::json::Value(std::move(response))); 4553 } 4554 4555 // A request used in testing to get the details on all breakpoints that are 4556 // currently set in the target. This helps us to test "setBreakpoints" and 4557 // "setFunctionBreakpoints" requests to verify we have the correct set of 4558 // breakpoints currently set in LLDB. 4559 void request__testGetTargetBreakpoints(DAP &dap, 4560 const llvm::json::Object &request) { 4561 llvm::json::Object response; 4562 FillResponse(request, response); 4563 llvm::json::Array response_breakpoints; 4564 for (uint32_t i = 0; dap.target.GetBreakpointAtIndex(i).IsValid(); ++i) { 4565 auto bp = Breakpoint(dap, dap.target.GetBreakpointAtIndex(i)); 4566 AppendBreakpoint(&bp, response_breakpoints); 4567 } 4568 llvm::json::Object body; 4569 body.try_emplace("breakpoints", std::move(response_breakpoints)); 4570 response.try_emplace("body", std::move(body)); 4571 dap.SendJSON(llvm::json::Value(std::move(response))); 4572 } 4573 4574 // "SetInstructionBreakpointsRequest": { 4575 // "allOf": [ 4576 // {"$ref": "#/definitions/Request"}, 4577 // { 4578 // "type": "object", 4579 // "description" : 4580 // "Replaces all existing instruction breakpoints. Typically, " 4581 // "instruction breakpoints would be set from a disassembly window. " 4582 // "\nTo clear all instruction breakpoints, specify an empty " 4583 // "array.\nWhen an instruction breakpoint is hit, a `stopped` event " 4584 // "(with reason `instruction breakpoint`) is generated.\nClients " 4585 // "should only call this request if the corresponding capability " 4586 // "`supportsInstructionBreakpoints` is true.", 4587 // "properties": { 4588 // "command": { "type": "string", "enum": ["setInstructionBreakpoints"] 4589 // }, "arguments": {"$ref": 4590 // "#/definitions/SetInstructionBreakpointsArguments"} 4591 // }, 4592 // "required": [ "command", "arguments" ] 4593 // } 4594 // ] 4595 // }, 4596 // "SetInstructionBreakpointsArguments": { 4597 // "type": "object", 4598 // "description": "Arguments for `setInstructionBreakpoints` request", 4599 // "properties": { 4600 // "breakpoints": { 4601 // "type": "array", 4602 // "items": {"$ref": "#/definitions/InstructionBreakpoint"}, 4603 // "description": "The instruction references of the breakpoints" 4604 // } 4605 // }, 4606 // "required": ["breakpoints"] 4607 // }, 4608 // "SetInstructionBreakpointsResponse": { 4609 // "allOf": [ 4610 // {"$ref": "#/definitions/Response"}, 4611 // { 4612 // "type": "object", 4613 // "description": "Response to `setInstructionBreakpoints` request", 4614 // "properties": { 4615 // "body": { 4616 // "type": "object", 4617 // "properties": { 4618 // "breakpoints": { 4619 // "type": "array", 4620 // "items": {"$ref": "#/definitions/Breakpoint"}, 4621 // "description": 4622 // "Information about the breakpoints. The array elements 4623 // " "correspond to the elements of the `breakpoints` 4624 // array." 4625 // } 4626 // }, 4627 // "required": ["breakpoints"] 4628 // } 4629 // }, 4630 // "required": ["body"] 4631 // } 4632 // ] 4633 // }, 4634 // "InstructionBreakpoint": { 4635 // "type": "object", 4636 // "description": "Properties of a breakpoint passed to the " 4637 // "`setInstructionBreakpoints` request", 4638 // "properties": { 4639 // "instructionReference": { 4640 // "type": "string", 4641 // "description" : 4642 // "The instruction reference of the breakpoint.\nThis should be a " 4643 // "memory or instruction pointer reference from an 4644 // `EvaluateResponse`, " 4645 // "`Variable`, `StackFrame`, `GotoTarget`, or `Breakpoint`." 4646 // }, 4647 // "offset": { 4648 // "type": "integer", 4649 // "description": "The offset from the instruction reference in " 4650 // "bytes.\nThis can be negative." 4651 // }, 4652 // "condition": { 4653 // "type": "string", 4654 // "description": "An expression for conditional breakpoints.\nIt is only 4655 // " 4656 // "honored by a debug adapter if the corresponding " 4657 // "capability `supportsConditionalBreakpoints` is true." 4658 // }, 4659 // "hitCondition": { 4660 // "type": "string", 4661 // "description": "An expression that controls how many hits of the " 4662 // "breakpoint are ignored.\nThe debug adapter is expected 4663 // " "to interpret the expression as needed.\nThe 4664 // attribute " "is only honored by a debug adapter if the 4665 // corresponding " "capability 4666 // `supportsHitConditionalBreakpoints` is true." 4667 // }, 4668 // "mode": { 4669 // "type": "string", 4670 // "description": "The mode of this breakpoint. If defined, this must be 4671 // " 4672 // "one of the `breakpointModes` the debug adapter " 4673 // "advertised in its `Capabilities`." 4674 // } 4675 // }, 4676 // "required": ["instructionReference"] 4677 // }, 4678 // "Breakpoint": { 4679 // "type": "object", 4680 // "description" : 4681 // "Information about a breakpoint created in `setBreakpoints`, " 4682 // "`setFunctionBreakpoints`, `setInstructionBreakpoints`, or " 4683 // "`setDataBreakpoints` requests.", 4684 // "properties": { 4685 // "id": { 4686 // "type": "integer", 4687 // "description" : 4688 // "The identifier for the breakpoint. It is needed if breakpoint 4689 // " "events are used to update or remove breakpoints." 4690 // }, 4691 // "verified": { 4692 // "type": "boolean", 4693 // "description": "If true, the breakpoint could be set (but not " 4694 // "necessarily at the desired location)." 4695 // }, 4696 // "message": { 4697 // "type": "string", 4698 // "description": "A message about the state of the breakpoint.\nThis 4699 // " 4700 // "is shown to the user and can be used to explain 4701 // why " "a breakpoint could not be verified." 4702 // }, 4703 // "source": { 4704 // "$ref": "#/definitions/Source", 4705 // "description": "The source where the breakpoint is located." 4706 // }, 4707 // "line": { 4708 // "type": "integer", 4709 // "description" : 4710 // "The start line of the actual range covered by the breakpoint." 4711 // }, 4712 // "column": { 4713 // "type": "integer", 4714 // "description" : 4715 // "Start position of the source range covered by the breakpoint. 4716 // " "It is measured in UTF-16 code units and the client 4717 // capability " 4718 // "`columnsStartAt1` determines whether it is 0- or 1-based." 4719 // }, 4720 // "endLine": { 4721 // "type": "integer", 4722 // "description" : 4723 // "The end line of the actual range covered by the breakpoint." 4724 // }, 4725 // "endColumn": { 4726 // "type": "integer", 4727 // "description" : 4728 // "End position of the source range covered by the breakpoint. It 4729 // " "is measured in UTF-16 code units and the client capability " 4730 // "`columnsStartAt1` determines whether it is 0- or 1-based.\nIf 4731 // " "no end line is given, then the end column is assumed to be 4732 // in " "the start line." 4733 // }, 4734 // "instructionReference": { 4735 // "type": "string", 4736 // "description": "A memory reference to where the breakpoint is 4737 // set." 4738 // }, 4739 // "offset": { 4740 // "type": "integer", 4741 // "description": "The offset from the instruction reference.\nThis " 4742 // "can be negative." 4743 // }, 4744 // "reason": { 4745 // "type": "string", 4746 // "description" : 4747 // "A machine-readable explanation of why a breakpoint may not be 4748 // " "verified. If a breakpoint is verified or a specific reason 4749 // is " "not known, the adapter should omit this property. 4750 // Possible " "values include:\n\n- `pending`: Indicates a 4751 // breakpoint might be " "verified in the future, but the adapter 4752 // cannot verify it in the " "current state.\n - `failed`: 4753 // Indicates a breakpoint was not " "able to be verified, and the 4754 // adapter does not believe it can be " "verified without 4755 // intervention.", 4756 // "enum": [ "pending", "failed" ] 4757 // } 4758 // }, 4759 // "required": ["verified"] 4760 // }, 4761 void request_setInstructionBreakpoints(DAP &dap, 4762 const llvm::json::Object &request) { 4763 llvm::json::Object response; 4764 llvm::json::Array response_breakpoints; 4765 llvm::json::Object body; 4766 FillResponse(request, response); 4767 4768 const auto *arguments = request.getObject("arguments"); 4769 const auto *breakpoints = arguments->getArray("breakpoints"); 4770 4771 // Disable any instruction breakpoints that aren't in this request. 4772 // There is no call to remove instruction breakpoints other than calling this 4773 // function with a smaller or empty "breakpoints" list. 4774 llvm::DenseSet<lldb::addr_t> seen; 4775 for (const auto &addr : dap.instruction_breakpoints) 4776 seen.insert(addr.first); 4777 4778 for (const auto &bp : *breakpoints) { 4779 const auto *bp_obj = bp.getAsObject(); 4780 if (!bp_obj) 4781 continue; 4782 // Read instruction breakpoint request. 4783 InstructionBreakpoint inst_bp(dap, *bp_obj); 4784 const auto [iv, inserted] = dap.instruction_breakpoints.try_emplace( 4785 inst_bp.instructionAddressReference, dap, *bp_obj); 4786 if (inserted) 4787 iv->second.SetBreakpoint(); 4788 else 4789 iv->second.UpdateBreakpoint(inst_bp); 4790 AppendBreakpoint(&iv->second, response_breakpoints); 4791 seen.erase(inst_bp.instructionAddressReference); 4792 } 4793 4794 for (const auto &addr : seen) { 4795 auto inst_bp = dap.instruction_breakpoints.find(addr); 4796 if (inst_bp == dap.instruction_breakpoints.end()) 4797 continue; 4798 dap.target.BreakpointDelete(inst_bp->second.bp.GetID()); 4799 dap.instruction_breakpoints.erase(addr); 4800 } 4801 4802 body.try_emplace("breakpoints", std::move(response_breakpoints)); 4803 response.try_emplace("body", std::move(body)); 4804 dap.SendJSON(llvm::json::Value(std::move(response))); 4805 } 4806 4807 void RegisterRequestCallbacks(DAP &dap) { 4808 dap.RegisterRequestCallback("attach", request_attach); 4809 dap.RegisterRequestCallback("completions", request_completions); 4810 dap.RegisterRequestCallback("continue", request_continue); 4811 dap.RegisterRequestCallback("configurationDone", request_configurationDone); 4812 dap.RegisterRequestCallback("disconnect", request_disconnect); 4813 dap.RegisterRequestCallback("evaluate", request_evaluate); 4814 dap.RegisterRequestCallback("exceptionInfo", request_exceptionInfo); 4815 dap.RegisterRequestCallback("initialize", request_initialize); 4816 dap.RegisterRequestCallback("launch", request_launch); 4817 dap.RegisterRequestCallback("next", request_next); 4818 dap.RegisterRequestCallback("pause", request_pause); 4819 dap.RegisterRequestCallback("restart", request_restart); 4820 dap.RegisterRequestCallback("scopes", request_scopes); 4821 dap.RegisterRequestCallback("setBreakpoints", request_setBreakpoints); 4822 dap.RegisterRequestCallback("setExceptionBreakpoints", 4823 request_setExceptionBreakpoints); 4824 dap.RegisterRequestCallback("setFunctionBreakpoints", 4825 request_setFunctionBreakpoints); 4826 dap.RegisterRequestCallback("dataBreakpointInfo", request_dataBreakpointInfo); 4827 dap.RegisterRequestCallback("setDataBreakpoints", request_setDataBreakpoints); 4828 dap.RegisterRequestCallback("setVariable", request_setVariable); 4829 dap.RegisterRequestCallback("source", request_source); 4830 dap.RegisterRequestCallback("stackTrace", request_stackTrace); 4831 dap.RegisterRequestCallback("stepIn", request_stepIn); 4832 dap.RegisterRequestCallback("stepInTargets", request_stepInTargets); 4833 dap.RegisterRequestCallback("stepOut", request_stepOut); 4834 dap.RegisterRequestCallback("threads", request_threads); 4835 dap.RegisterRequestCallback("variables", request_variables); 4836 dap.RegisterRequestCallback("locations", request_locations); 4837 dap.RegisterRequestCallback("disassemble", request_disassemble); 4838 dap.RegisterRequestCallback("readMemory", request_readMemory); 4839 dap.RegisterRequestCallback("setInstructionBreakpoints", 4840 request_setInstructionBreakpoints); 4841 // Custom requests 4842 dap.RegisterRequestCallback("compileUnits", request_compileUnits); 4843 dap.RegisterRequestCallback("modules", request_modules); 4844 // Testing requests 4845 dap.RegisterRequestCallback("_testGetTargetBreakpoints", 4846 request__testGetTargetBreakpoints); 4847 } 4848 4849 } // anonymous namespace 4850 4851 static void printHelp(LLDBDAPOptTable &table, llvm::StringRef tool_name) { 4852 std::string usage_str = tool_name.str() + " options"; 4853 table.printHelp(llvm::outs(), usage_str.c_str(), "LLDB DAP", false); 4854 4855 std::string examples = R"___( 4856 EXAMPLES: 4857 The debug adapter can be started in two modes. 4858 4859 Running lldb-dap without any arguments will start communicating with the 4860 parent over stdio. Passing a port number causes lldb-dap to start listening 4861 for connections on that port. 4862 4863 lldb-dap -p <port> 4864 4865 Passing --wait-for-debugger will pause the process at startup and wait for a 4866 debugger to attach to the process. 4867 4868 lldb-dap -g 4869 )___"; 4870 llvm::outs() << examples; 4871 } 4872 4873 // If --launch-target is provided, this instance of lldb-dap becomes a 4874 // runInTerminal launcher. It will ultimately launch the program specified in 4875 // the --launch-target argument, which is the original program the user wanted 4876 // to debug. This is done in such a way that the actual debug adaptor can 4877 // place breakpoints at the beginning of the program. 4878 // 4879 // The launcher will communicate with the debug adaptor using a fifo file in the 4880 // directory specified in the --comm-file argument. 4881 // 4882 // Regarding the actual flow, this launcher will first notify the debug adaptor 4883 // of its pid. Then, the launcher will be in a pending state waiting to be 4884 // attached by the adaptor. 4885 // 4886 // Once attached and resumed, the launcher will exec and become the program 4887 // specified by --launch-target, which is the original target the 4888 // user wanted to run. 4889 // 4890 // In case of errors launching the target, a suitable error message will be 4891 // emitted to the debug adaptor. 4892 static void LaunchRunInTerminalTarget(llvm::opt::Arg &target_arg, 4893 llvm::StringRef comm_file, 4894 lldb::pid_t debugger_pid, char *argv[]) { 4895 #if defined(_WIN32) 4896 llvm::errs() << "runInTerminal is only supported on POSIX systems\n"; 4897 exit(EXIT_FAILURE); 4898 #else 4899 4900 // On Linux with the Yama security module enabled, a process can only attach 4901 // to its descendants by default. In the runInTerminal case the target 4902 // process is launched by the client so we need to allow tracing explicitly. 4903 #if defined(__linux__) 4904 if (debugger_pid != LLDB_INVALID_PROCESS_ID) 4905 (void)prctl(PR_SET_PTRACER, debugger_pid, 0, 0, 0); 4906 #endif 4907 4908 RunInTerminalLauncherCommChannel comm_channel(comm_file); 4909 if (llvm::Error err = comm_channel.NotifyPid()) { 4910 llvm::errs() << llvm::toString(std::move(err)) << "\n"; 4911 exit(EXIT_FAILURE); 4912 } 4913 4914 // We will wait to be attached with a timeout. We don't wait indefinitely 4915 // using a signal to prevent being paused forever. 4916 4917 // This env var should be used only for tests. 4918 const char *timeout_env_var = getenv("LLDB_DAP_RIT_TIMEOUT_IN_MS"); 4919 int timeout_in_ms = 4920 timeout_env_var != nullptr ? atoi(timeout_env_var) : 20000; 4921 if (llvm::Error err = comm_channel.WaitUntilDebugAdaptorAttaches( 4922 std::chrono::milliseconds(timeout_in_ms))) { 4923 llvm::errs() << llvm::toString(std::move(err)) << "\n"; 4924 exit(EXIT_FAILURE); 4925 } 4926 4927 const char *target = target_arg.getValue(); 4928 execvp(target, argv); 4929 4930 std::string error = std::strerror(errno); 4931 comm_channel.NotifyError(error); 4932 llvm::errs() << error << "\n"; 4933 exit(EXIT_FAILURE); 4934 #endif 4935 } 4936 4937 /// used only by TestVSCode_redirection_to_console.py 4938 static void redirection_test() { 4939 printf("stdout message\n"); 4940 fprintf(stderr, "stderr message\n"); 4941 fflush(stdout); 4942 fflush(stderr); 4943 } 4944 4945 /// Duplicates a file descriptor, setting FD_CLOEXEC if applicable. 4946 static int DuplicateFileDescriptor(int fd) { 4947 #if defined(F_DUPFD_CLOEXEC) 4948 // Ensure FD_CLOEXEC is set. 4949 return ::fcntl(fd, F_DUPFD_CLOEXEC, 0); 4950 #else 4951 return ::dup(fd); 4952 #endif 4953 } 4954 4955 int main(int argc, char *argv[]) { 4956 llvm::InitLLVM IL(argc, argv, /*InstallPipeSignalExitHandler=*/false); 4957 #if !defined(__APPLE__) 4958 llvm::setBugReportMsg("PLEASE submit a bug report to " LLDB_BUG_REPORT_URL 4959 " and include the crash backtrace.\n"); 4960 #else 4961 llvm::setBugReportMsg("PLEASE submit a bug report to " LLDB_BUG_REPORT_URL 4962 " and include the crash report from " 4963 "~/Library/Logs/DiagnosticReports/.\n"); 4964 #endif 4965 4966 llvm::SmallString<256> program_path(argv[0]); 4967 llvm::sys::fs::make_absolute(program_path); 4968 4969 LLDBDAPOptTable T; 4970 unsigned MAI, MAC; 4971 llvm::ArrayRef<const char *> ArgsArr = llvm::ArrayRef(argv + 1, argc); 4972 llvm::opt::InputArgList input_args = T.ParseArgs(ArgsArr, MAI, MAC); 4973 4974 if (input_args.hasArg(OPT_help)) { 4975 printHelp(T, llvm::sys::path::filename(argv[0])); 4976 return EXIT_SUCCESS; 4977 } 4978 4979 ReplMode default_repl_mode = ReplMode::Auto; 4980 if (input_args.hasArg(OPT_repl_mode)) { 4981 llvm::opt::Arg *repl_mode = input_args.getLastArg(OPT_repl_mode); 4982 llvm::StringRef repl_mode_value = repl_mode->getValue(); 4983 if (repl_mode_value == "auto") { 4984 default_repl_mode = ReplMode::Auto; 4985 } else if (repl_mode_value == "variable") { 4986 default_repl_mode = ReplMode::Variable; 4987 } else if (repl_mode_value == "command") { 4988 default_repl_mode = ReplMode::Command; 4989 } else { 4990 llvm::errs() 4991 << "'" << repl_mode_value 4992 << "' is not a valid option, use 'variable', 'command' or 'auto'.\n"; 4993 return EXIT_FAILURE; 4994 } 4995 } 4996 4997 if (llvm::opt::Arg *target_arg = input_args.getLastArg(OPT_launch_target)) { 4998 if (llvm::opt::Arg *comm_file = input_args.getLastArg(OPT_comm_file)) { 4999 lldb::pid_t pid = LLDB_INVALID_PROCESS_ID; 5000 llvm::opt::Arg *debugger_pid = input_args.getLastArg(OPT_debugger_pid); 5001 if (debugger_pid) { 5002 llvm::StringRef debugger_pid_value = debugger_pid->getValue(); 5003 if (debugger_pid_value.getAsInteger(10, pid)) { 5004 llvm::errs() << "'" << debugger_pid_value 5005 << "' is not a valid " 5006 "PID\n"; 5007 return EXIT_FAILURE; 5008 } 5009 } 5010 int target_args_pos = argc; 5011 for (int i = 0; i < argc; i++) 5012 if (strcmp(argv[i], "--launch-target") == 0) { 5013 target_args_pos = i + 1; 5014 break; 5015 } 5016 LaunchRunInTerminalTarget(*target_arg, comm_file->getValue(), pid, 5017 argv + target_args_pos); 5018 } else { 5019 llvm::errs() << "\"--launch-target\" requires \"--comm-file\" to be " 5020 "specified\n"; 5021 return EXIT_FAILURE; 5022 } 5023 } 5024 5025 int portno = -1; 5026 if (auto *arg = input_args.getLastArg(OPT_port)) { 5027 const auto *optarg = arg->getValue(); 5028 char *remainder; 5029 portno = strtol(optarg, &remainder, 0); 5030 if (remainder == optarg || *remainder != '\0') { 5031 fprintf(stderr, "'%s' is not a valid port number.\n", optarg); 5032 return EXIT_FAILURE; 5033 } 5034 } 5035 5036 #if !defined(_WIN32) 5037 if (input_args.hasArg(OPT_wait_for_debugger)) { 5038 printf("Paused waiting for debugger to attach (pid = %i)...\n", getpid()); 5039 pause(); 5040 } 5041 #endif 5042 5043 std::unique_ptr<std::ofstream> log = nullptr; 5044 const char *log_file_path = getenv("LLDBDAP_LOG"); 5045 if (log_file_path) 5046 log = std::make_unique<std::ofstream>(log_file_path); 5047 5048 // Initialize LLDB first before we do anything. 5049 lldb::SBError error = lldb::SBDebugger::InitializeWithErrorHandling(); 5050 if (error.Fail()) { 5051 lldb::SBStream os; 5052 error.GetDescription(os); 5053 llvm::errs() << "lldb initialize failed: " << os.GetData() << "\n"; 5054 return EXIT_FAILURE; 5055 } 5056 5057 // Terminate the debugger before the C++ destructor chain kicks in. 5058 auto terminate_debugger = 5059 llvm::make_scope_exit([] { lldb::SBDebugger::Terminate(); }); 5060 5061 StreamDescriptor input; 5062 StreamDescriptor output; 5063 std::FILE *redirectOut = nullptr; 5064 std::FILE *redirectErr = nullptr; 5065 if (portno != -1) { 5066 printf("Listening on port %i...\n", portno); 5067 SOCKET socket_fd = AcceptConnection(log.get(), portno); 5068 if (socket_fd < 0) 5069 return EXIT_FAILURE; 5070 5071 input = StreamDescriptor::from_socket(socket_fd, true); 5072 output = StreamDescriptor::from_socket(socket_fd, false); 5073 } else { 5074 #if defined(_WIN32) 5075 // Windows opens stdout and stdin in text mode which converts \n to 13,10 5076 // while the value is just 10 on Darwin/Linux. Setting the file mode to 5077 // binary fixes this. 5078 int result = _setmode(fileno(stdout), _O_BINARY); 5079 assert(result); 5080 result = _setmode(fileno(stdin), _O_BINARY); 5081 UNUSED_IF_ASSERT_DISABLED(result); 5082 assert(result); 5083 #endif 5084 5085 int stdout_fd = DuplicateFileDescriptor(fileno(stdout)); 5086 if (stdout_fd == -1) { 5087 llvm::logAllUnhandledErrors( 5088 llvm::errorCodeToError(llvm::errnoAsErrorCode()), llvm::errs(), 5089 "Failed to configure stdout redirect: "); 5090 return EXIT_FAILURE; 5091 } 5092 5093 redirectOut = stdout; 5094 redirectErr = stderr; 5095 5096 input = StreamDescriptor::from_file(fileno(stdin), false); 5097 output = StreamDescriptor::from_file(stdout_fd, false); 5098 } 5099 5100 DAP dap = DAP(program_path.str(), log.get(), default_repl_mode, 5101 std::move(input), std::move(output)); 5102 5103 // stdout/stderr redirection to the IDE's console 5104 if (auto Err = dap.ConfigureIO(redirectOut, redirectErr)) { 5105 llvm::logAllUnhandledErrors(std::move(Err), llvm::errs(), 5106 "Failed to configure lldb-dap IO operations: "); 5107 return EXIT_FAILURE; 5108 } 5109 5110 RegisterRequestCallbacks(dap); 5111 5112 for (const std::string &arg : 5113 input_args.getAllArgValues(OPT_pre_init_command)) { 5114 dap.pre_init_commands.push_back(arg); 5115 } 5116 5117 // used only by TestVSCode_redirection_to_console.py 5118 if (getenv("LLDB_DAP_TEST_STDOUT_STDERR_REDIRECTION") != nullptr) 5119 redirection_test(); 5120 5121 bool CleanExit = true; 5122 if (auto Err = dap.Loop()) { 5123 if (log) 5124 *log << "Transport Error: " << llvm::toString(std::move(Err)) << "\n"; 5125 CleanExit = false; 5126 } 5127 5128 return CleanExit ? EXIT_SUCCESS : EXIT_FAILURE; 5129 } 5130