| 1 | //===-- ScopesRequestHandler.cpp ------------------------------------------===// |
| 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 "RequestHandler.h" |
| 11 | |
| 12 | using namespace lldb_dap::protocol; |
| 13 | namespace lldb_dap { |
| 14 | |
| 15 | /// Creates a `protocol::Scope` struct. |
| 16 | /// |
| 17 | /// |
| 18 | /// \param[in] name |
| 19 | /// The value to place into the "name" key |
| 20 | /// |
| 21 | /// \param[in] variablesReference |
| 22 | /// The value to place into the "variablesReference" key |
| 23 | /// |
| 24 | /// \param[in] namedVariables |
| 25 | /// The value to place into the "namedVariables" key |
| 26 | /// |
| 27 | /// \param[in] expensive |
| 28 | /// The value to place into the "expensive" key |
| 29 | /// |
| 30 | /// \return |
| 31 | /// A `protocol::Scope` |
| 32 | static Scope CreateScope(const llvm::StringRef name, int64_t variablesReference, |
| 33 | int64_t namedVariables, bool expensive) { |
| 34 | Scope scope; |
| 35 | scope.name = name; |
| 36 | |
| 37 | // TODO: Support "arguments" and "return value" scope. |
| 38 | // At the moment lldb-dap includes the arguments and return_value into the |
| 39 | // "locals" scope. |
| 40 | // vscode only expands the first non-expensive scope, this causes friction |
| 41 | // if we add the arguments above the local scope as the locals scope will not |
| 42 | // be expanded if we enter a function with arguments. It becomes more |
| 43 | // annoying when the scope has arguments, return_value and locals. |
| 44 | if (variablesReference == VARREF_LOCALS) |
| 45 | scope.presentationHint = Scope::eScopePresentationHintLocals; |
| 46 | else if (variablesReference == VARREF_REGS) |
| 47 | scope.presentationHint = Scope::eScopePresentationHintRegisters; |
| 48 | |
| 49 | scope.variablesReference = variablesReference; |
| 50 | scope.namedVariables = namedVariables; |
| 51 | scope.expensive = expensive; |
| 52 | |
| 53 | return scope; |
| 54 | } |
| 55 | |
| 56 | llvm::Expected<ScopesResponseBody> |
| 57 | ScopesRequestHandler::Run(const ScopesArguments &args) const { |
| 58 | lldb::SBFrame frame = dap.GetLLDBFrame(frame_id: args.frameId); |
| 59 | |
| 60 | // As the user selects different stack frames in the GUI, a "scopes" request |
| 61 | // will be sent to the DAP. This is the only way we know that the user has |
| 62 | // selected a frame in a thread. There are no other notifications that are |
| 63 | // sent and VS code doesn't allow multiple frames to show variables |
| 64 | // concurrently. If we select the thread and frame as the "scopes" requests |
| 65 | // are sent, this allows users to type commands in the debugger console |
| 66 | // with a backtick character to run lldb commands and these lldb commands |
| 67 | // will now have the right context selected as they are run. If the user |
| 68 | // types "`bt" into the debugger console, and we had another thread selected |
| 69 | // in the LLDB library, we would show the wrong thing to the user. If the |
| 70 | // users switch threads with a lldb command like "`thread select 14", the |
| 71 | // GUI will not update as there are no "event" notification packets that |
| 72 | // allow us to change the currently selected thread or frame in the GUI that |
| 73 | // I am aware of. |
| 74 | if (frame.IsValid()) { |
| 75 | frame.GetThread().GetProcess().SetSelectedThread(frame.GetThread()); |
| 76 | frame.GetThread().SetSelectedFrame(frame.GetFrameID()); |
| 77 | } |
| 78 | dap.variables.locals = frame.GetVariables(/*arguments=*/true, |
| 79 | /*locals=*/true, |
| 80 | /*statics=*/false, |
| 81 | /*in_scope_only=*/true); |
| 82 | dap.variables.globals = frame.GetVariables(/*arguments=*/false, |
| 83 | /*locals=*/false, |
| 84 | /*statics=*/true, |
| 85 | /*in_scope_only=*/true); |
| 86 | dap.variables.registers = frame.GetRegisters(); |
| 87 | |
| 88 | std::vector scopes = {CreateScope(name: "Locals" , VARREF_LOCALS, |
| 89 | namedVariables: dap.variables.locals.GetSize(), expensive: false), |
| 90 | CreateScope(name: "Globals" , VARREF_GLOBALS, |
| 91 | namedVariables: dap.variables.globals.GetSize(), expensive: false), |
| 92 | CreateScope(name: "Registers" , VARREF_REGS, |
| 93 | namedVariables: dap.variables.registers.GetSize(), expensive: false)}; |
| 94 | |
| 95 | return ScopesResponseBody{.scopes: std::move(scopes)}; |
| 96 | } |
| 97 | |
| 98 | } // namespace lldb_dap |
| 99 | |