99 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9#include "DAP.h"10#include "RequestHandler.h"11 12using namespace lldb_dap::protocol;13namespace lldb_dap {14 15/// Creates a `protocol::Scope` struct.16///17///18/// \param[in] name19/// The value to place into the "name" key20///21/// \param[in] variablesReference22/// The value to place into the "variablesReference" key23///24/// \param[in] namedVariables25/// The value to place into the "namedVariables" key26///27/// \param[in] expensive28/// The value to place into the "expensive" key29///30/// \return31/// A `protocol::Scope`32static 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 the39 // "locals" scope.40 // vscode only expands the first non-expensive scope, this causes friction41 // if we add the arguments above the local scope as the locals scope will not42 // be expanded if we enter a function with arguments. It becomes more43 // 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 56llvm::Expected<ScopesResponseBody>57ScopesRequestHandler::Run(const ScopesArguments &args) const {58 lldb::SBFrame frame = dap.GetLLDBFrame(args.frameId);59 60 // As the user selects different stack frames in the GUI, a "scopes" request61 // will be sent to the DAP. This is the only way we know that the user has62 // selected a frame in a thread. There are no other notifications that are63 // sent and VS code doesn't allow multiple frames to show variables64 // concurrently. If we select the thread and frame as the "scopes" requests65 // are sent, this allows users to type commands in the debugger console66 // with a backtick character to run lldb commands and these lldb commands67 // will now have the right context selected as they are run. If the user68 // types "`bt" into the debugger console, and we had another thread selected69 // in the LLDB library, we would show the wrong thing to the user. If the70 // users switch threads with a lldb command like "`thread select 14", the71 // GUI will not update as there are no "event" notification packets that72 // allow us to change the currently selected thread or frame in the GUI that73 // 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("Locals", VARREF_LOCALS,89 dap.variables.locals.GetSize(), false),90 CreateScope("Globals", VARREF_GLOBALS,91 dap.variables.globals.GetSize(), false),92 CreateScope("Registers", VARREF_REGS,93 dap.variables.registers.GetSize(), false)};94 95 return ScopesResponseBody{std::move(scopes)};96}97 98} // namespace lldb_dap99