//===-- 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 "EventHelper.h" #include "JSONUtils.h" #include "RequestHandler.h" namespace lldb_dap { // "ScopesRequest": { // "allOf": [ { "$ref": "#/definitions/Request" }, { // "type": "object", // "description": "Scopes request; value of command field is 'scopes'. The // request returns the variable scopes for a given stackframe ID.", // "properties": { // "command": { // "type": "string", // "enum": [ "scopes" ] // }, // "arguments": { // "$ref": "#/definitions/ScopesArguments" // } // }, // "required": [ "command", "arguments" ] // }] // }, // "ScopesArguments": { // "type": "object", // "description": "Arguments for 'scopes' request.", // "properties": { // "frameId": { // "type": "integer", // "description": "Retrieve the scopes for this stackframe." // } // }, // "required": [ "frameId" ] // }, // "ScopesResponse": { // "allOf": [ { "$ref": "#/definitions/Response" }, { // "type": "object", // "description": "Response to 'scopes' request.", // "properties": { // "body": { // "type": "object", // "properties": { // "scopes": { // "type": "array", // "items": { // "$ref": "#/definitions/Scope" // }, // "description": "The scopes of the stackframe. If the array has // length zero, there are no scopes available." // } // }, // "required": [ "scopes" ] // } // }, // "required": [ "body" ] // }] // } void ScopesRequestHandler::operator()(const llvm::json::Object &request) const { llvm::json::Object response; FillResponse(request, response); llvm::json::Object body; const auto *arguments = request.getObject("arguments"); lldb::SBFrame frame = dap.GetLLDBFrame(*arguments); // 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 switches 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(); body.try_emplace("scopes", dap.CreateTopLevelScopes()); response.try_emplace("body", std::move(body)); dap.SendJSON(llvm::json::Value(std::move(response))); } } // namespace lldb_dap