//===-- ScopesRequestHandler.cpp ------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "DAP.h" #include "RequestHandler.h" using namespace lldb_dap::protocol; namespace lldb_dap { /// Creates a `protocol::Scope` struct. /// /// /// \param[in] name /// The value to place into the "name" key /// /// \param[in] variablesReference /// The value to place into the "variablesReference" key /// /// \param[in] namedVariables /// The value to place into the "namedVariables" key /// /// \param[in] expensive /// The value to place into the "expensive" key /// /// \return /// A `protocol::Scope` static Scope CreateScope(const llvm::StringRef name, int64_t variablesReference, int64_t namedVariables, bool expensive) { Scope scope; scope.name = name; // TODO: Support "arguments" and "return value" scope. // At the moment lldb-dap includes the arguments and return_value into the // "locals" scope. // vscode only expands the first non-expensive scope, this causes friction // if we add the arguments above the local scope as the locals scope will not // be expanded if we enter a function with arguments. It becomes more // annoying when the scope has arguments, return_value and locals. if (variablesReference == VARREF_LOCALS) scope.presentationHint = Scope::eScopePresentationHintLocals; else if (variablesReference == VARREF_REGS) scope.presentationHint = Scope::eScopePresentationHintRegisters; scope.variablesReference = variablesReference; scope.namedVariables = namedVariables; scope.expensive = expensive; return scope; } llvm::Expected ScopesRequestHandler::Run(const ScopesArguments &args) const { lldb::SBFrame frame = dap.GetLLDBFrame(args.frameId); // As the user selects different stack frames in the GUI, a "scopes" request // will be sent to the DAP. This is the only way we know that the user has // selected a frame in a thread. There are no other notifications that are // sent and VS code doesn't allow multiple frames to show variables // concurrently. If we select the thread and frame as the "scopes" requests // are sent, this allows users to type commands in the debugger console // with a backtick character to run lldb commands and these lldb commands // will now have the right context selected as they are run. If the user // types "`bt" into the debugger console, and we had another thread selected // in the LLDB library, we would show the wrong thing to the user. If the // users switch threads with a lldb command like "`thread select 14", the // GUI will not update as there are no "event" notification packets that // allow us to change the currently selected thread or frame in the GUI that // I am aware of. if (frame.IsValid()) { frame.GetThread().GetProcess().SetSelectedThread(frame.GetThread()); frame.GetThread().SetSelectedFrame(frame.GetFrameID()); } dap.variables.locals = frame.GetVariables(/*arguments=*/true, /*locals=*/true, /*statics=*/false, /*in_scope_only=*/true); dap.variables.globals = frame.GetVariables(/*arguments=*/false, /*locals=*/false, /*statics=*/true, /*in_scope_only=*/true); dap.variables.registers = frame.GetRegisters(); std::vector scopes = {CreateScope("Locals", VARREF_LOCALS, dap.variables.locals.GetSize(), false), CreateScope("Globals", VARREF_GLOBALS, dap.variables.globals.GetSize(), false), CreateScope("Registers", VARREF_REGS, dap.variables.registers.GetSize(), false)}; return ScopesResponseBody{std::move(scopes)}; } } // namespace lldb_dap