1 //===-- 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 "JSONUtils.h" 11 #include "LLDBUtils.h" 12 #include "OutputRedirector.h" 13 #include "lldb/API/SBBreakpoint.h" 14 #include "lldb/API/SBCommandInterpreter.h" 15 #include "lldb/API/SBCommandReturnObject.h" 16 #include "lldb/API/SBLanguageRuntime.h" 17 #include "lldb/API/SBListener.h" 18 #include "lldb/API/SBProcess.h" 19 #include "lldb/API/SBStream.h" 20 #include "lldb/Host/FileSystem.h" 21 #include "lldb/Utility/Status.h" 22 #include "lldb/lldb-defines.h" 23 #include "lldb/lldb-enumerations.h" 24 #include "llvm/ADT/ArrayRef.h" 25 #include "llvm/ADT/StringExtras.h" 26 #include "llvm/ADT/Twine.h" 27 #include "llvm/Support/Error.h" 28 #include "llvm/Support/ErrorHandling.h" 29 #include "llvm/Support/FormatVariadic.h" 30 #include "llvm/Support/raw_ostream.h" 31 #include <algorithm> 32 #include <cassert> 33 #include <chrono> 34 #include <cstdarg> 35 #include <cstdio> 36 #include <fstream> 37 #include <mutex> 38 #include <utility> 39 40 #if defined(_WIN32) 41 #define NOMINMAX 42 #include <fcntl.h> 43 #include <io.h> 44 #include <windows.h> 45 #else 46 #include <unistd.h> 47 #endif 48 49 using namespace lldb_dap; 50 51 namespace { 52 #ifdef _WIN32 53 const char DEV_NULL[] = "nul"; 54 #else 55 const char DEV_NULL[] = "/dev/null"; 56 #endif 57 } // namespace 58 59 namespace lldb_dap { 60 61 DAP::DAP(llvm::StringRef path, std::ofstream *log, ReplMode repl_mode, 62 StreamDescriptor input, StreamDescriptor output) 63 : debug_adaptor_path(path), log(log), input(std::move(input)), 64 output(std::move(output)), broadcaster("lldb-dap"), 65 exception_breakpoints(), focus_tid(LLDB_INVALID_THREAD_ID), 66 stop_at_entry(false), is_attach(false), 67 enable_auto_variable_summaries(false), 68 enable_synthetic_child_debugging(false), 69 display_extended_backtrace(false), 70 restarting_process_id(LLDB_INVALID_PROCESS_ID), 71 configuration_done_sent(false), waiting_for_run_in_terminal(false), 72 progress_event_reporter( 73 [&](const ProgressEvent &event) { SendJSON(event.ToJSON()); }), 74 reverse_request_seq(0), repl_mode(repl_mode) {} 75 76 DAP::~DAP() = default; 77 78 /// Return string with first character capitalized. 79 static std::string capitalize(llvm::StringRef str) { 80 if (str.empty()) 81 return ""; 82 return ((llvm::Twine)llvm::toUpper(str[0]) + str.drop_front()).str(); 83 } 84 85 void DAP::PopulateExceptionBreakpoints() { 86 llvm::call_once(init_exception_breakpoints_flag, [this]() { 87 exception_breakpoints = std::vector<ExceptionBreakpoint>{}; 88 89 if (lldb::SBDebugger::SupportsLanguage(lldb::eLanguageTypeC_plus_plus)) { 90 exception_breakpoints->emplace_back(*this, "cpp_catch", "C++ Catch", 91 lldb::eLanguageTypeC_plus_plus); 92 exception_breakpoints->emplace_back(*this, "cpp_throw", "C++ Throw", 93 lldb::eLanguageTypeC_plus_plus); 94 } 95 if (lldb::SBDebugger::SupportsLanguage(lldb::eLanguageTypeObjC)) { 96 exception_breakpoints->emplace_back( 97 *this, "objc_catch", "Objective-C Catch", lldb::eLanguageTypeObjC); 98 exception_breakpoints->emplace_back( 99 *this, "objc_throw", "Objective-C Throw", lldb::eLanguageTypeObjC); 100 } 101 if (lldb::SBDebugger::SupportsLanguage(lldb::eLanguageTypeSwift)) { 102 exception_breakpoints->emplace_back(*this, "swift_catch", "Swift Catch", 103 lldb::eLanguageTypeSwift); 104 exception_breakpoints->emplace_back(*this, "swift_throw", "Swift Throw", 105 lldb::eLanguageTypeSwift); 106 } 107 // Besides handling the hardcoded list of languages from above, we try to 108 // find any other languages that support exception breakpoints using the 109 // SB API. 110 for (int raw_lang = lldb::eLanguageTypeUnknown; 111 raw_lang < lldb::eNumLanguageTypes; ++raw_lang) { 112 lldb::LanguageType lang = static_cast<lldb::LanguageType>(raw_lang); 113 114 // We first discard any languages already handled above. 115 if (lldb::SBLanguageRuntime::LanguageIsCFamily(lang) || 116 lang == lldb::eLanguageTypeSwift) 117 continue; 118 119 if (!lldb::SBDebugger::SupportsLanguage(lang)) 120 continue; 121 122 const char *name = lldb::SBLanguageRuntime::GetNameForLanguageType(lang); 123 if (!name) 124 continue; 125 std::string raw_lang_name = name; 126 std::string capitalized_lang_name = capitalize(name); 127 128 if (lldb::SBLanguageRuntime::SupportsExceptionBreakpointsOnThrow(lang)) { 129 const char *raw_throw_keyword = 130 lldb::SBLanguageRuntime::GetThrowKeywordForLanguage(lang); 131 std::string throw_keyword = 132 raw_throw_keyword ? raw_throw_keyword : "throw"; 133 134 exception_breakpoints->emplace_back( 135 *this, raw_lang_name + "_" + throw_keyword, 136 capitalized_lang_name + " " + capitalize(throw_keyword), lang); 137 } 138 139 if (lldb::SBLanguageRuntime::SupportsExceptionBreakpointsOnCatch(lang)) { 140 const char *raw_catch_keyword = 141 lldb::SBLanguageRuntime::GetCatchKeywordForLanguage(lang); 142 std::string catch_keyword = 143 raw_catch_keyword ? raw_catch_keyword : "catch"; 144 145 exception_breakpoints->emplace_back( 146 *this, raw_lang_name + "_" + catch_keyword, 147 capitalized_lang_name + " " + capitalize(catch_keyword), lang); 148 } 149 } 150 assert(!exception_breakpoints->empty() && "should not be empty"); 151 }); 152 } 153 154 ExceptionBreakpoint *DAP::GetExceptionBreakpoint(const std::string &filter) { 155 // PopulateExceptionBreakpoints() is called after g_dap.debugger is created 156 // in a request-initialize. 157 // 158 // But this GetExceptionBreakpoint() method may be called before attaching, in 159 // which case, we may not have populated the filter yet. 160 // 161 // We also cannot call PopulateExceptionBreakpoints() in DAP::DAP() because 162 // we need SBDebugger::Initialize() to have been called before this. 163 // 164 // So just calling PopulateExceptionBreakoints(),which does lazy-populating 165 // seems easiest. Two other options include: 166 // + call g_dap.PopulateExceptionBreakpoints() in lldb-dap.cpp::main() 167 // right after the call to SBDebugger::Initialize() 168 // + Just call PopulateExceptionBreakpoints() to get a fresh list everytime 169 // we query (a bit overkill since it's not likely to change?) 170 PopulateExceptionBreakpoints(); 171 172 for (auto &bp : *exception_breakpoints) { 173 if (bp.filter == filter) 174 return &bp; 175 } 176 return nullptr; 177 } 178 179 ExceptionBreakpoint *DAP::GetExceptionBreakpoint(const lldb::break_id_t bp_id) { 180 // See comment in the other GetExceptionBreakpoint(). 181 PopulateExceptionBreakpoints(); 182 183 for (auto &bp : *exception_breakpoints) { 184 if (bp.bp.GetID() == bp_id) 185 return &bp; 186 } 187 return nullptr; 188 } 189 190 llvm::Error DAP::ConfigureIO(std::FILE *overrideOut, std::FILE *overrideErr) { 191 in = lldb::SBFile(std::fopen(DEV_NULL, "r"), /*transfer_ownership=*/true); 192 193 if (auto Error = out.RedirectTo([this](llvm::StringRef output) { 194 SendOutput(OutputType::Stdout, output); 195 })) 196 return Error; 197 198 if (overrideOut) { 199 auto fd = out.GetWriteFileDescriptor(); 200 if (auto Error = fd.takeError()) 201 return Error; 202 203 if (dup2(*fd, fileno(overrideOut)) == -1) 204 return llvm::errorCodeToError(llvm::errnoAsErrorCode()); 205 } 206 207 if (auto Error = err.RedirectTo([this](llvm::StringRef output) { 208 SendOutput(OutputType::Stderr, output); 209 })) 210 return Error; 211 212 if (overrideErr) { 213 auto fd = err.GetWriteFileDescriptor(); 214 if (auto Error = fd.takeError()) 215 return Error; 216 217 if (dup2(*fd, fileno(overrideErr)) == -1) 218 return llvm::errorCodeToError(llvm::errnoAsErrorCode()); 219 } 220 221 return llvm::Error::success(); 222 } 223 224 void DAP::StopIO() { 225 out.Stop(); 226 err.Stop(); 227 } 228 229 // Send the JSON in "json_str" to the "out" stream. Correctly send the 230 // "Content-Length:" field followed by the length, followed by the raw 231 // JSON bytes. 232 void DAP::SendJSON(const std::string &json_str) { 233 output.write_full("Content-Length: "); 234 output.write_full(llvm::utostr(json_str.size())); 235 output.write_full("\r\n\r\n"); 236 output.write_full(json_str); 237 } 238 239 // Serialize the JSON value into a string and send the JSON packet to 240 // the "out" stream. 241 void DAP::SendJSON(const llvm::json::Value &json) { 242 std::string json_str; 243 llvm::raw_string_ostream strm(json_str); 244 strm << json; 245 static std::mutex mutex; 246 std::lock_guard<std::mutex> locker(mutex); 247 SendJSON(json_str); 248 249 if (log) { 250 auto now = std::chrono::duration<double>( 251 std::chrono::system_clock::now().time_since_epoch()); 252 *log << llvm::formatv("{0:f9} <-- ", now.count()).str() << std::endl 253 << "Content-Length: " << json_str.size() << "\r\n\r\n" 254 << llvm::formatv("{0:2}", json).str() << std::endl; 255 } 256 } 257 258 // Read a JSON packet from the "in" stream. 259 std::string DAP::ReadJSON() { 260 std::string length_str; 261 std::string json_str; 262 int length; 263 264 if (!input.read_expected(log, "Content-Length: ")) 265 return json_str; 266 267 if (!input.read_line(log, length_str)) 268 return json_str; 269 270 if (!llvm::to_integer(length_str, length)) 271 return json_str; 272 273 if (!input.read_expected(log, "\r\n")) 274 return json_str; 275 276 if (!input.read_full(log, length, json_str)) 277 return json_str; 278 279 if (log) { 280 auto now = std::chrono::duration<double>( 281 std::chrono::system_clock::now().time_since_epoch()); 282 *log << llvm::formatv("{0:f9} --> ", now.count()).str() << std::endl 283 << "Content-Length: " << length << "\r\n\r\n"; 284 } 285 return json_str; 286 } 287 288 // "OutputEvent": { 289 // "allOf": [ { "$ref": "#/definitions/Event" }, { 290 // "type": "object", 291 // "description": "Event message for 'output' event type. The event 292 // indicates that the target has produced some output.", 293 // "properties": { 294 // "event": { 295 // "type": "string", 296 // "enum": [ "output" ] 297 // }, 298 // "body": { 299 // "type": "object", 300 // "properties": { 301 // "category": { 302 // "type": "string", 303 // "description": "The output category. If not specified, 304 // 'console' is assumed.", 305 // "_enum": [ "console", "stdout", "stderr", "telemetry" ] 306 // }, 307 // "output": { 308 // "type": "string", 309 // "description": "The output to report." 310 // }, 311 // "variablesReference": { 312 // "type": "number", 313 // "description": "If an attribute 'variablesReference' exists 314 // and its value is > 0, the output contains 315 // objects which can be retrieved by passing 316 // variablesReference to the VariablesRequest." 317 // }, 318 // "source": { 319 // "$ref": "#/definitions/Source", 320 // "description": "An optional source location where the output 321 // was produced." 322 // }, 323 // "line": { 324 // "type": "integer", 325 // "description": "An optional source location line where the 326 // output was produced." 327 // }, 328 // "column": { 329 // "type": "integer", 330 // "description": "An optional source location column where the 331 // output was produced." 332 // }, 333 // "data": { 334 // "type":["array","boolean","integer","null","number","object", 335 // "string"], 336 // "description": "Optional data to report. For the 'telemetry' 337 // category the data will be sent to telemetry, for 338 // the other categories the data is shown in JSON 339 // format." 340 // } 341 // }, 342 // "required": ["output"] 343 // } 344 // }, 345 // "required": [ "event", "body" ] 346 // }] 347 // } 348 void DAP::SendOutput(OutputType o, const llvm::StringRef output) { 349 if (output.empty()) 350 return; 351 352 const char *category = nullptr; 353 switch (o) { 354 case OutputType::Console: 355 category = "console"; 356 break; 357 case OutputType::Stdout: 358 category = "stdout"; 359 break; 360 case OutputType::Stderr: 361 category = "stderr"; 362 break; 363 case OutputType::Telemetry: 364 category = "telemetry"; 365 break; 366 } 367 368 // Send each line of output as an individual event, including the newline if 369 // present. 370 ::size_t idx = 0; 371 do { 372 ::size_t end = output.find('\n', idx); 373 if (end == llvm::StringRef::npos) 374 end = output.size() - 1; 375 llvm::json::Object event(CreateEventObject("output")); 376 llvm::json::Object body; 377 body.try_emplace("category", category); 378 EmplaceSafeString(body, "output", output.slice(idx, end + 1).str()); 379 event.try_emplace("body", std::move(body)); 380 SendJSON(llvm::json::Value(std::move(event))); 381 idx = end + 1; 382 } while (idx < output.size()); 383 } 384 385 // interface ProgressStartEvent extends Event { 386 // event: 'progressStart'; 387 // 388 // body: { 389 // /** 390 // * An ID that must be used in subsequent 'progressUpdate' and 391 // 'progressEnd' 392 // * events to make them refer to the same progress reporting. 393 // * IDs must be unique within a debug session. 394 // */ 395 // progressId: string; 396 // 397 // /** 398 // * Mandatory (short) title of the progress reporting. Shown in the UI to 399 // * describe the long running operation. 400 // */ 401 // title: string; 402 // 403 // /** 404 // * The request ID that this progress report is related to. If specified a 405 // * debug adapter is expected to emit 406 // * progress events for the long running request until the request has 407 // been 408 // * either completed or cancelled. 409 // * If the request ID is omitted, the progress report is assumed to be 410 // * related to some general activity of the debug adapter. 411 // */ 412 // requestId?: number; 413 // 414 // /** 415 // * If true, the request that reports progress may be canceled with a 416 // * 'cancel' request. 417 // * So this property basically controls whether the client should use UX 418 // that 419 // * supports cancellation. 420 // * Clients that don't support cancellation are allowed to ignore the 421 // * setting. 422 // */ 423 // cancellable?: boolean; 424 // 425 // /** 426 // * Optional, more detailed progress message. 427 // */ 428 // message?: string; 429 // 430 // /** 431 // * Optional progress percentage to display (value range: 0 to 100). If 432 // * omitted no percentage will be shown. 433 // */ 434 // percentage?: number; 435 // }; 436 // } 437 // 438 // interface ProgressUpdateEvent extends Event { 439 // event: 'progressUpdate'; 440 // 441 // body: { 442 // /** 443 // * The ID that was introduced in the initial 'progressStart' event. 444 // */ 445 // progressId: string; 446 // 447 // /** 448 // * Optional, more detailed progress message. If omitted, the previous 449 // * message (if any) is used. 450 // */ 451 // message?: string; 452 // 453 // /** 454 // * Optional progress percentage to display (value range: 0 to 100). If 455 // * omitted no percentage will be shown. 456 // */ 457 // percentage?: number; 458 // }; 459 // } 460 // 461 // interface ProgressEndEvent extends Event { 462 // event: 'progressEnd'; 463 // 464 // body: { 465 // /** 466 // * The ID that was introduced in the initial 'ProgressStartEvent'. 467 // */ 468 // progressId: string; 469 // 470 // /** 471 // * Optional, more detailed progress message. If omitted, the previous 472 // * message (if any) is used. 473 // */ 474 // message?: string; 475 // }; 476 // } 477 478 void DAP::SendProgressEvent(uint64_t progress_id, const char *message, 479 uint64_t completed, uint64_t total) { 480 progress_event_reporter.Push(progress_id, message, completed, total); 481 } 482 483 void __attribute__((format(printf, 3, 4))) 484 DAP::SendFormattedOutput(OutputType o, const char *format, ...) { 485 char buffer[1024]; 486 va_list args; 487 va_start(args, format); 488 int actual_length = vsnprintf(buffer, sizeof(buffer), format, args); 489 va_end(args); 490 SendOutput( 491 o, llvm::StringRef(buffer, std::min<int>(actual_length, sizeof(buffer)))); 492 } 493 494 ExceptionBreakpoint *DAP::GetExceptionBPFromStopReason(lldb::SBThread &thread) { 495 const auto num = thread.GetStopReasonDataCount(); 496 // Check to see if have hit an exception breakpoint and change the 497 // reason to "exception", but only do so if all breakpoints that were 498 // hit are exception breakpoints. 499 ExceptionBreakpoint *exc_bp = nullptr; 500 for (size_t i = 0; i < num; i += 2) { 501 // thread.GetStopReasonDataAtIndex(i) will return the bp ID and 502 // thread.GetStopReasonDataAtIndex(i+1) will return the location 503 // within that breakpoint. We only care about the bp ID so we can 504 // see if this is an exception breakpoint that is getting hit. 505 lldb::break_id_t bp_id = thread.GetStopReasonDataAtIndex(i); 506 exc_bp = GetExceptionBreakpoint(bp_id); 507 // If any breakpoint is not an exception breakpoint, then stop and 508 // report this as a normal breakpoint 509 if (exc_bp == nullptr) 510 return nullptr; 511 } 512 return exc_bp; 513 } 514 515 lldb::SBThread DAP::GetLLDBThread(const llvm::json::Object &arguments) { 516 auto tid = GetSigned(arguments, "threadId", LLDB_INVALID_THREAD_ID); 517 return target.GetProcess().GetThreadByID(tid); 518 } 519 520 lldb::SBFrame DAP::GetLLDBFrame(const llvm::json::Object &arguments) { 521 const uint64_t frame_id = GetUnsigned(arguments, "frameId", UINT64_MAX); 522 lldb::SBProcess process = target.GetProcess(); 523 // Upper 32 bits is the thread index ID 524 lldb::SBThread thread = 525 process.GetThreadByIndexID(GetLLDBThreadIndexID(frame_id)); 526 // Lower 32 bits is the frame index 527 return thread.GetFrameAtIndex(GetLLDBFrameID(frame_id)); 528 } 529 530 llvm::json::Value DAP::CreateTopLevelScopes() { 531 llvm::json::Array scopes; 532 scopes.emplace_back( 533 CreateScope("Locals", VARREF_LOCALS, variables.locals.GetSize(), false)); 534 scopes.emplace_back(CreateScope("Globals", VARREF_GLOBALS, 535 variables.globals.GetSize(), false)); 536 scopes.emplace_back(CreateScope("Registers", VARREF_REGS, 537 variables.registers.GetSize(), false)); 538 return llvm::json::Value(std::move(scopes)); 539 } 540 541 ReplMode DAP::DetectReplMode(lldb::SBFrame frame, std::string &expression, 542 bool partial_expression) { 543 // Check for the escape hatch prefix. 544 if (!expression.empty() && 545 llvm::StringRef(expression).starts_with(command_escape_prefix)) { 546 expression = expression.substr(command_escape_prefix.size()); 547 return ReplMode::Command; 548 } 549 550 switch (repl_mode) { 551 case ReplMode::Variable: 552 return ReplMode::Variable; 553 case ReplMode::Command: 554 return ReplMode::Command; 555 case ReplMode::Auto: 556 // To determine if the expression is a command or not, check if the first 557 // term is a variable or command. If it's a variable in scope we will prefer 558 // that behavior and give a warning to the user if they meant to invoke the 559 // operation as a command. 560 // 561 // Example use case: 562 // int p and expression "p + 1" > variable 563 // int i and expression "i" > variable 564 // int var and expression "va" > command 565 std::pair<llvm::StringRef, llvm::StringRef> token = 566 llvm::getToken(expression); 567 568 // If the first token is not fully finished yet, we can't 569 // determine whether this will be a variable or a lldb command. 570 if (partial_expression && token.second.empty()) 571 return ReplMode::Auto; 572 573 std::string term = token.first.str(); 574 lldb::SBCommandInterpreter interpreter = debugger.GetCommandInterpreter(); 575 bool term_is_command = interpreter.CommandExists(term.c_str()) || 576 interpreter.UserCommandExists(term.c_str()) || 577 interpreter.AliasExists(term.c_str()); 578 bool term_is_variable = frame.FindVariable(term.c_str()).IsValid(); 579 580 // If we have both a variable and command, warn the user about the conflict. 581 if (term_is_command && term_is_variable) { 582 llvm::errs() 583 << "Warning: Expression '" << term 584 << "' is both an LLDB command and variable. It will be evaluated as " 585 "a variable. To evaluate the expression as an LLDB command, use '" 586 << command_escape_prefix << "' as a prefix.\n"; 587 } 588 589 // Variables take preference to commands in auto, since commands can always 590 // be called using the command_escape_prefix 591 return term_is_variable ? ReplMode::Variable 592 : term_is_command ? ReplMode::Command 593 : ReplMode::Variable; 594 } 595 596 llvm_unreachable("enum cases exhausted."); 597 } 598 599 bool DAP::RunLLDBCommands(llvm::StringRef prefix, 600 llvm::ArrayRef<std::string> commands) { 601 bool required_command_failed = false; 602 std::string output = 603 ::RunLLDBCommands(debugger, prefix, commands, required_command_failed); 604 SendOutput(OutputType::Console, output); 605 return !required_command_failed; 606 } 607 608 static llvm::Error createRunLLDBCommandsErrorMessage(llvm::StringRef category) { 609 return llvm::createStringError( 610 llvm::inconvertibleErrorCode(), 611 llvm::formatv( 612 "Failed to run {0} commands. See the Debug Console for more details.", 613 category) 614 .str() 615 .c_str()); 616 } 617 618 llvm::Error 619 DAP::RunAttachCommands(llvm::ArrayRef<std::string> attach_commands) { 620 if (!RunLLDBCommands("Running attachCommands:", attach_commands)) 621 return createRunLLDBCommandsErrorMessage("attach"); 622 return llvm::Error::success(); 623 } 624 625 llvm::Error 626 DAP::RunLaunchCommands(llvm::ArrayRef<std::string> launch_commands) { 627 if (!RunLLDBCommands("Running launchCommands:", launch_commands)) 628 return createRunLLDBCommandsErrorMessage("launch"); 629 return llvm::Error::success(); 630 } 631 632 llvm::Error DAP::RunInitCommands() { 633 if (!RunLLDBCommands("Running initCommands:", init_commands)) 634 return createRunLLDBCommandsErrorMessage("initCommands"); 635 return llvm::Error::success(); 636 } 637 638 llvm::Error DAP::RunPreInitCommands() { 639 if (!RunLLDBCommands("Running preInitCommands:", pre_init_commands)) 640 return createRunLLDBCommandsErrorMessage("preInitCommands"); 641 return llvm::Error::success(); 642 } 643 644 llvm::Error DAP::RunPreRunCommands() { 645 if (!RunLLDBCommands("Running preRunCommands:", pre_run_commands)) 646 return createRunLLDBCommandsErrorMessage("preRunCommands"); 647 return llvm::Error::success(); 648 } 649 650 void DAP::RunPostRunCommands() { 651 RunLLDBCommands("Running postRunCommands:", post_run_commands); 652 } 653 void DAP::RunStopCommands() { 654 RunLLDBCommands("Running stopCommands:", stop_commands); 655 } 656 657 void DAP::RunExitCommands() { 658 RunLLDBCommands("Running exitCommands:", exit_commands); 659 } 660 661 void DAP::RunTerminateCommands() { 662 RunLLDBCommands("Running terminateCommands:", terminate_commands); 663 } 664 665 lldb::SBTarget 666 DAP::CreateTargetFromArguments(const llvm::json::Object &arguments, 667 lldb::SBError &error) { 668 // Grab the name of the program we need to debug and create a target using 669 // the given program as an argument. Executable file can be a source of target 670 // architecture and platform, if they differ from the host. Setting exe path 671 // in launch info is useless because Target.Launch() will not change 672 // architecture and platform, therefore they should be known at the target 673 // creation. We also use target triple and platform from the launch 674 // configuration, if given, since in some cases ELF file doesn't contain 675 // enough information to determine correct arch and platform (or ELF can be 676 // omitted at all), so it is good to leave the user an apportunity to specify 677 // those. Any of those three can be left empty. 678 llvm::StringRef target_triple = GetString(arguments, "targetTriple"); 679 llvm::StringRef platform_name = GetString(arguments, "platformName"); 680 llvm::StringRef program = GetString(arguments, "program"); 681 auto target = this->debugger.CreateTarget( 682 program.data(), target_triple.data(), platform_name.data(), 683 true, // Add dependent modules. 684 error); 685 686 if (error.Fail()) { 687 // Update message if there was an error. 688 error.SetErrorStringWithFormat( 689 "Could not create a target for a program '%s': %s.", program.data(), 690 error.GetCString()); 691 } 692 693 return target; 694 } 695 696 void DAP::SetTarget(const lldb::SBTarget target) { 697 this->target = target; 698 699 if (target.IsValid()) { 700 // Configure breakpoint event listeners for the target. 701 lldb::SBListener listener = this->debugger.GetListener(); 702 listener.StartListeningForEvents( 703 this->target.GetBroadcaster(), 704 lldb::SBTarget::eBroadcastBitBreakpointChanged); 705 listener.StartListeningForEvents(this->broadcaster, 706 eBroadcastBitStopEventThread); 707 } 708 } 709 710 PacketStatus DAP::GetNextObject(llvm::json::Object &object) { 711 std::string json = ReadJSON(); 712 if (json.empty()) 713 return PacketStatus::EndOfFile; 714 715 llvm::StringRef json_sref(json); 716 llvm::Expected<llvm::json::Value> json_value = llvm::json::parse(json_sref); 717 if (!json_value) { 718 auto error = json_value.takeError(); 719 if (log) { 720 std::string error_str; 721 llvm::raw_string_ostream strm(error_str); 722 strm << error; 723 *log << "error: failed to parse JSON: " << error_str << std::endl 724 << json << std::endl; 725 } 726 return PacketStatus::JSONMalformed; 727 } 728 729 if (log) { 730 *log << llvm::formatv("{0:2}", *json_value).str() << std::endl; 731 } 732 733 llvm::json::Object *object_ptr = json_value->getAsObject(); 734 if (!object_ptr) { 735 if (log) 736 *log << "error: json packet isn't a object" << std::endl; 737 return PacketStatus::JSONNotObject; 738 } 739 object = *object_ptr; 740 return PacketStatus::Success; 741 } 742 743 bool DAP::HandleObject(const llvm::json::Object &object) { 744 const auto packet_type = GetString(object, "type"); 745 if (packet_type == "request") { 746 const auto command = GetString(object, "command"); 747 auto handler_pos = request_handlers.find(command); 748 if (handler_pos == request_handlers.end()) { 749 if (log) 750 *log << "error: unhandled command \"" << command.data() << "\"" 751 << std::endl; 752 return false; // Fail 753 } 754 755 handler_pos->second(*this, object); 756 return true; // Success 757 } 758 759 if (packet_type == "response") { 760 auto id = GetSigned(object, "request_seq", 0); 761 ResponseCallback response_handler = [](llvm::Expected<llvm::json::Value>) { 762 llvm::errs() << "Unhandled response\n"; 763 }; 764 765 { 766 std::lock_guard<std::mutex> locker(call_mutex); 767 auto inflight = inflight_reverse_requests.find(id); 768 if (inflight != inflight_reverse_requests.end()) { 769 response_handler = std::move(inflight->second); 770 inflight_reverse_requests.erase(inflight); 771 } 772 } 773 774 // Result should be given, use null if not. 775 if (GetBoolean(object, "success", false)) { 776 llvm::json::Value Result = nullptr; 777 if (auto *B = object.get("body")) { 778 Result = std::move(*B); 779 } 780 response_handler(Result); 781 } else { 782 llvm::StringRef message = GetString(object, "message"); 783 if (message.empty()) { 784 message = "Unknown error, response failed"; 785 } 786 response_handler(llvm::createStringError( 787 std::error_code(-1, std::generic_category()), message)); 788 } 789 790 return true; 791 } 792 793 return false; 794 } 795 796 llvm::Error DAP::Loop() { 797 while (!disconnecting) { 798 llvm::json::Object object; 799 lldb_dap::PacketStatus status = GetNextObject(object); 800 801 if (status == lldb_dap::PacketStatus::EndOfFile) { 802 break; 803 } 804 805 if (status != lldb_dap::PacketStatus::Success) { 806 return llvm::createStringError(llvm::inconvertibleErrorCode(), 807 "failed to send packet"); 808 } 809 810 if (!HandleObject(object)) { 811 return llvm::createStringError(llvm::inconvertibleErrorCode(), 812 "unhandled packet"); 813 } 814 } 815 816 return llvm::Error::success(); 817 } 818 819 void DAP::SendReverseRequest(llvm::StringRef command, 820 llvm::json::Value arguments, 821 ResponseCallback callback) { 822 int64_t id; 823 { 824 std::lock_guard<std::mutex> locker(call_mutex); 825 id = ++reverse_request_seq; 826 inflight_reverse_requests.emplace(id, std::move(callback)); 827 } 828 829 SendJSON(llvm::json::Object{ 830 {"type", "request"}, 831 {"seq", id}, 832 {"command", command}, 833 {"arguments", std::move(arguments)}, 834 }); 835 } 836 837 void DAP::RegisterRequestCallback(std::string request, 838 RequestCallback callback) { 839 request_handlers[request] = callback; 840 } 841 842 lldb::SBError DAP::WaitForProcessToStop(uint32_t seconds) { 843 lldb::SBError error; 844 lldb::SBProcess process = target.GetProcess(); 845 if (!process.IsValid()) { 846 error.SetErrorString("invalid process"); 847 return error; 848 } 849 auto timeout_time = 850 std::chrono::steady_clock::now() + std::chrono::seconds(seconds); 851 while (std::chrono::steady_clock::now() < timeout_time) { 852 const auto state = process.GetState(); 853 switch (state) { 854 case lldb::eStateAttaching: 855 case lldb::eStateConnected: 856 case lldb::eStateInvalid: 857 case lldb::eStateLaunching: 858 case lldb::eStateRunning: 859 case lldb::eStateStepping: 860 case lldb::eStateSuspended: 861 break; 862 case lldb::eStateDetached: 863 error.SetErrorString("process detached during launch or attach"); 864 return error; 865 case lldb::eStateExited: 866 error.SetErrorString("process exited during launch or attach"); 867 return error; 868 case lldb::eStateUnloaded: 869 error.SetErrorString("process unloaded during launch or attach"); 870 return error; 871 case lldb::eStateCrashed: 872 case lldb::eStateStopped: 873 return lldb::SBError(); // Success! 874 } 875 std::this_thread::sleep_for(std::chrono::microseconds(250)); 876 } 877 error.SetErrorStringWithFormat("process failed to stop within %u seconds", 878 seconds); 879 return error; 880 } 881 882 void Variables::Clear() { 883 locals.Clear(); 884 globals.Clear(); 885 registers.Clear(); 886 referenced_variables.clear(); 887 } 888 889 int64_t Variables::GetNewVariableReference(bool is_permanent) { 890 if (is_permanent) 891 return next_permanent_var_ref++; 892 return next_temporary_var_ref++; 893 } 894 895 bool Variables::IsPermanentVariableReference(int64_t var_ref) { 896 return var_ref >= PermanentVariableStartIndex; 897 } 898 899 lldb::SBValue Variables::GetVariable(int64_t var_ref) const { 900 if (IsPermanentVariableReference(var_ref)) { 901 auto pos = referenced_permanent_variables.find(var_ref); 902 if (pos != referenced_permanent_variables.end()) 903 return pos->second; 904 } else { 905 auto pos = referenced_variables.find(var_ref); 906 if (pos != referenced_variables.end()) 907 return pos->second; 908 } 909 return lldb::SBValue(); 910 } 911 912 int64_t Variables::InsertVariable(lldb::SBValue variable, bool is_permanent) { 913 int64_t var_ref = GetNewVariableReference(is_permanent); 914 if (is_permanent) 915 referenced_permanent_variables.insert(std::make_pair(var_ref, variable)); 916 else 917 referenced_variables.insert(std::make_pair(var_ref, variable)); 918 return var_ref; 919 } 920 921 bool StartDebuggingRequestHandler::DoExecute( 922 lldb::SBDebugger debugger, char **command, 923 lldb::SBCommandReturnObject &result) { 924 // Command format like: `start-debugging <launch|attach> <configuration>` 925 if (!command) { 926 result.SetError("Invalid use of start-debugging, expected format " 927 "`start-debugging <launch|attach> <configuration>`."); 928 return false; 929 } 930 931 if (!command[0] || llvm::StringRef(command[0]).empty()) { 932 result.SetError("start-debugging request type missing."); 933 return false; 934 } 935 936 if (!command[1] || llvm::StringRef(command[1]).empty()) { 937 result.SetError("start-debugging debug configuration missing."); 938 return false; 939 } 940 941 llvm::StringRef request{command[0]}; 942 std::string raw_configuration{command[1]}; 943 944 llvm::Expected<llvm::json::Value> configuration = 945 llvm::json::parse(raw_configuration); 946 947 if (!configuration) { 948 llvm::Error err = configuration.takeError(); 949 std::string msg = "Failed to parse json configuration: " + 950 llvm::toString(std::move(err)) + "\n\n" + 951 raw_configuration; 952 result.SetError(msg.c_str()); 953 return false; 954 } 955 956 dap.SendReverseRequest( 957 "startDebugging", 958 llvm::json::Object{{"request", request}, 959 {"configuration", std::move(*configuration)}}, 960 [](llvm::Expected<llvm::json::Value> value) { 961 if (!value) { 962 llvm::Error err = value.takeError(); 963 llvm::errs() << "reverse start debugging request failed: " 964 << llvm::toString(std::move(err)) << "\n"; 965 } 966 }); 967 968 result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult); 969 970 return true; 971 } 972 973 bool ReplModeRequestHandler::DoExecute(lldb::SBDebugger debugger, 974 char **command, 975 lldb::SBCommandReturnObject &result) { 976 // Command format like: `repl-mode <variable|command|auto>?` 977 // If a new mode is not specified report the current mode. 978 if (!command || llvm::StringRef(command[0]).empty()) { 979 std::string mode; 980 switch (dap.repl_mode) { 981 case ReplMode::Variable: 982 mode = "variable"; 983 break; 984 case ReplMode::Command: 985 mode = "command"; 986 break; 987 case ReplMode::Auto: 988 mode = "auto"; 989 break; 990 } 991 992 result.Printf("lldb-dap repl-mode %s.\n", mode.c_str()); 993 result.SetStatus(lldb::eReturnStatusSuccessFinishResult); 994 995 return true; 996 } 997 998 llvm::StringRef new_mode{command[0]}; 999 1000 if (new_mode == "variable") { 1001 dap.repl_mode = ReplMode::Variable; 1002 } else if (new_mode == "command") { 1003 dap.repl_mode = ReplMode::Command; 1004 } else if (new_mode == "auto") { 1005 dap.repl_mode = ReplMode::Auto; 1006 } else { 1007 lldb::SBStream error_message; 1008 error_message.Printf("Invalid repl-mode '%s'. Expected one of 'variable', " 1009 "'command' or 'auto'.\n", 1010 new_mode.data()); 1011 result.SetError(error_message.GetData()); 1012 return false; 1013 } 1014 1015 result.Printf("lldb-dap repl-mode %s set.\n", new_mode.data()); 1016 result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult); 1017 return true; 1018 } 1019 1020 // Sends a DAP event with an optional body. 1021 // 1022 // See 1023 // https://code.visualstudio.com/api/references/vscode-api#debug.onDidReceiveDebugSessionCustomEvent 1024 bool SendEventRequestHandler::DoExecute(lldb::SBDebugger debugger, 1025 char **command, 1026 lldb::SBCommandReturnObject &result) { 1027 // Command format like: `send-event <name> <body>?` 1028 if (!command || !command[0] || llvm::StringRef(command[0]).empty()) { 1029 result.SetError("Not enough arguments found, expected format " 1030 "`lldb-dap send-event <name> <body>?`."); 1031 return false; 1032 } 1033 1034 llvm::StringRef name{command[0]}; 1035 // Events that are stateful and should be handled by lldb-dap internally. 1036 const std::array internal_events{"breakpoint", "capabilities", "continued", 1037 "exited", "initialize", "loadedSource", 1038 "module", "process", "stopped", 1039 "terminated", "thread"}; 1040 if (std::find(internal_events.begin(), internal_events.end(), name) != 1041 std::end(internal_events)) { 1042 std::string msg = 1043 llvm::formatv("Invalid use of lldb-dap send-event, event \"{0}\" " 1044 "should be handled by lldb-dap internally.", 1045 name) 1046 .str(); 1047 result.SetError(msg.c_str()); 1048 return false; 1049 } 1050 1051 llvm::json::Object event(CreateEventObject(name)); 1052 1053 if (command[1] && !llvm::StringRef(command[1]).empty()) { 1054 // See if we have unused arguments. 1055 if (command[2]) { 1056 result.SetError( 1057 "Additional arguments found, expected `lldb-dap send-event " 1058 "<name> <body>?`."); 1059 return false; 1060 } 1061 1062 llvm::StringRef raw_body{command[1]}; 1063 1064 llvm::Expected<llvm::json::Value> body = llvm::json::parse(raw_body); 1065 1066 if (!body) { 1067 llvm::Error err = body.takeError(); 1068 std::string msg = "Failed to parse custom event body: " + 1069 llvm::toString(std::move(err)); 1070 result.SetError(msg.c_str()); 1071 return false; 1072 } 1073 1074 event.try_emplace("body", std::move(*body)); 1075 } 1076 1077 dap.SendJSON(llvm::json::Value(std::move(event))); 1078 result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult); 1079 return true; 1080 } 1081 1082 void DAP::SetFrameFormat(llvm::StringRef format) { 1083 if (format.empty()) 1084 return; 1085 lldb::SBError error; 1086 frame_format = lldb::SBFormat(format.str().c_str(), error); 1087 if (error.Fail()) { 1088 SendOutput(OutputType::Console, 1089 llvm::formatv( 1090 "The provided frame format '{0}' couldn't be parsed: {1}\n", 1091 format, error.GetCString()) 1092 .str()); 1093 } 1094 } 1095 1096 void DAP::SetThreadFormat(llvm::StringRef format) { 1097 if (format.empty()) 1098 return; 1099 lldb::SBError error; 1100 thread_format = lldb::SBFormat(format.str().c_str(), error); 1101 if (error.Fail()) { 1102 SendOutput(OutputType::Console, 1103 llvm::formatv( 1104 "The provided thread format '{0}' couldn't be parsed: {1}\n", 1105 format, error.GetCString()) 1106 .str()); 1107 } 1108 } 1109 1110 InstructionBreakpoint * 1111 DAP::GetInstructionBreakpoint(const lldb::break_id_t bp_id) { 1112 for (auto &bp : instruction_breakpoints) { 1113 if (bp.second.bp.GetID() == bp_id) 1114 return &bp.second; 1115 } 1116 return nullptr; 1117 } 1118 1119 InstructionBreakpoint * 1120 DAP::GetInstructionBPFromStopReason(lldb::SBThread &thread) { 1121 const auto num = thread.GetStopReasonDataCount(); 1122 InstructionBreakpoint *inst_bp = nullptr; 1123 for (size_t i = 0; i < num; i += 2) { 1124 // thread.GetStopReasonDataAtIndex(i) will return the bp ID and 1125 // thread.GetStopReasonDataAtIndex(i+1) will return the location 1126 // within that breakpoint. We only care about the bp ID so we can 1127 // see if this is an instruction breakpoint that is getting hit. 1128 lldb::break_id_t bp_id = thread.GetStopReasonDataAtIndex(i); 1129 inst_bp = GetInstructionBreakpoint(bp_id); 1130 // If any breakpoint is not an instruction breakpoint, then stop and 1131 // report this as a normal breakpoint 1132 if (inst_bp == nullptr) 1133 return nullptr; 1134 } 1135 return inst_bp; 1136 } 1137 1138 } // namespace lldb_dap 1139