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 | |