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