[Lldb-commits] [lldb] [lldb-dap] Refactor remaining request handlers (NFC)Remaining request handlers (PR #128551)
via lldb-commits
lldb-commits at lists.llvm.org
Mon Feb 24 11:11:15 PST 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-lldb
Author: Jonas Devlieghere (JDevlieghere)
<details>
<summary>Changes</summary>
Continuation of the work started in https://github.com/llvm/llvm-project/pull/128262. Builds on top of https://github.com/llvm/llvm-project/pull/128550.
---
Patch is 230.81 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/128551.diff
27 Files Affected:
- (modified) lldb/tools/lldb-dap/CMakeLists.txt (+23)
- (added) lldb/tools/lldb-dap/Handler/CompileUnitsRequestHandler.cpp (+80)
- (added) lldb/tools/lldb-dap/Handler/DataBreakpointInfoRequestHandler.cpp (+190)
- (added) lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp (+222)
- (added) lldb/tools/lldb-dap/Handler/LocationsRequestHandler.cpp (+160)
- (added) lldb/tools/lldb-dap/Handler/ModulesRequestHandler.cpp (+58)
- (added) lldb/tools/lldb-dap/Handler/NextRequestHandler.cpp (+79)
- (added) lldb/tools/lldb-dap/Handler/PauseRequestHandler.cpp (+60)
- (added) lldb/tools/lldb-dap/Handler/ReadMemoryRequestHandler.cpp (+139)
- (modified) lldb/tools/lldb-dap/Handler/RequestHandler.cpp (+62)
- (modified) lldb/tools/lldb-dap/Handler/RequestHandler.h (+176-1)
- (added) lldb/tools/lldb-dap/Handler/ScopesRequestHandler.cpp (+106)
- (added) lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp (+182)
- (added) lldb/tools/lldb-dap/Handler/SetDataBreakpointsRequestHandler.cpp (+114)
- (added) lldb/tools/lldb-dap/Handler/SetExceptionBreakpointsRequestHandler.cpp (+93)
- (added) lldb/tools/lldb-dap/Handler/SetFunctionBreakpointsRequestHandler.cpp (+139)
- (added) lldb/tools/lldb-dap/Handler/SetInstructionBreakpointsRequestHandler.cpp (+249)
- (added) lldb/tools/lldb-dap/Handler/SetVariableRequestHandler.cpp (+177)
- (added) lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp (+82)
- (added) lldb/tools/lldb-dap/Handler/StackTraceRequestHandler.cpp (+197)
- (added) lldb/tools/lldb-dap/Handler/StepInRequestHandler.cpp (+96)
- (added) lldb/tools/lldb-dap/Handler/StepInTargetsRequestHandler.cpp (+149)
- (added) lldb/tools/lldb-dap/Handler/StepOutRequestHandler.cpp (+68)
- (added) lldb/tools/lldb-dap/Handler/TestGetTargetBreakpointsRequestHandler.cpp (+31)
- (added) lldb/tools/lldb-dap/Handler/ThreadsRequestHandler.cpp (+71)
- (added) lldb/tools/lldb-dap/Handler/VariablesRequestHandler.cpp (+217)
- (modified) lldb/tools/lldb-dap/lldb-dap.cpp (+29-2676)
``````````diff
diff --git a/lldb/tools/lldb-dap/CMakeLists.txt b/lldb/tools/lldb-dap/CMakeLists.txt
index 73762af5c2fd7..804dd8e4cc2a0 100644
--- a/lldb/tools/lldb-dap/CMakeLists.txt
+++ b/lldb/tools/lldb-dap/CMakeLists.txt
@@ -39,16 +39,39 @@ add_lldb_tool(lldb-dap
Handler/AttachRequestHandler.cpp
Handler/BreakpointLocationsHandler.cpp
+ Handler/CompileUnitsRequestHandler.cpp
Handler/CompletionsHandler.cpp
Handler/ConfigurationDoneRequestHandler.cpp
Handler/ContinueRequestHandler.cpp
+ Handler/DataBreakpointInfoRequestHandler.cpp
+ Handler/DisassembleRequestHandler.cpp
Handler/DisconnectRequestHandler.cpp
Handler/EvaluateRequestHandler.cpp
Handler/ExceptionInfoRequestHandler.cpp
Handler/InitializeRequestHandler.cpp
Handler/LaunchRequestHandler.cpp
+ Handler/LocationsRequestHandler.cpp
+ Handler/ModulesRequestHandler.cpp
+ Handler/NextRequestHandler.cpp
+ Handler/PauseRequestHandler.cpp
+ Handler/ReadMemoryRequestHandler.cpp
Handler/RequestHandler.cpp
Handler/RestartRequestHandler.cpp
+ Handler/ScopesRequestHandler.cpp
+ Handler/SetBreakpointsRequestHandler.cpp
+ Handler/SetDataBreakpointsRequestHandler.cpp
+ Handler/SetExceptionBreakpointsRequestHandler.cpp
+ Handler/SetFunctionBreakpointsRequestHandler.cpp
+ Handler/SetInstructionBreakpointsRequestHandler.cpp
+ Handler/SetVariableRequestHandler.cpp
+ Handler/SourceRequestHandler.cpp
+ Handler/StackTraceRequestHandler.cpp
+ Handler/StepInRequestHandler.cpp
+ Handler/StepInTargetsRequestHandler.cpp
+ Handler/StepOutRequestHandler.cpp
+ Handler/TestGetTargetBreakpointsRequestHandler.cpp
+ Handler/ThreadsRequestHandler.cpp
+ Handler/VariablesRequestHandler.cpp
LINK_LIBS
liblldb
diff --git a/lldb/tools/lldb-dap/Handler/CompileUnitsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/CompileUnitsRequestHandler.cpp
new file mode 100644
index 0000000000000..c541d1cd039c8
--- /dev/null
+++ b/lldb/tools/lldb-dap/Handler/CompileUnitsRequestHandler.cpp
@@ -0,0 +1,80 @@
+//===-- CompileUnitsRequestHandler.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 {
+
+// "compileUnitsRequest": {
+// "allOf": [ { "$ref": "#/definitions/Request" }, {
+// "type": "object",
+// "description": "Compile Unit request; value of command field is
+// 'compileUnits'.",
+// "properties": {
+// "command": {
+// "type": "string",
+// "enum": [ "compileUnits" ]
+// },
+// "arguments": {
+// "$ref": "#/definitions/compileUnitRequestArguments"
+// }
+// },
+// "required": [ "command", "arguments" ]
+// }]
+// },
+// "compileUnitsRequestArguments": {
+// "type": "object",
+// "description": "Arguments for 'compileUnits' request.",
+// "properties": {
+// "moduleId": {
+// "type": "string",
+// "description": "The ID of the module."
+// }
+// },
+// "required": [ "moduleId" ]
+// },
+// "compileUnitsResponse": {
+// "allOf": [ { "$ref": "#/definitions/Response" }, {
+// "type": "object",
+// "description": "Response to 'compileUnits' request.",
+// "properties": {
+// "body": {
+// "description": "Response to 'compileUnits' request. Array of
+// paths of compile units."
+// }
+// }
+// }]
+// }
+void CompileUnitsRequestHandler::operator()(const llvm::json::Object &request) {
+ llvm::json::Object response;
+ FillResponse(request, response);
+ llvm::json::Object body;
+ llvm::json::Array units;
+ const auto *arguments = request.getObject("arguments");
+ std::string module_id = std::string(GetString(arguments, "moduleId"));
+ int num_modules = dap.target.GetNumModules();
+ for (int i = 0; i < num_modules; i++) {
+ auto curr_module = dap.target.GetModuleAtIndex(i);
+ if (module_id == curr_module.GetUUIDString()) {
+ int num_units = curr_module.GetNumCompileUnits();
+ for (int j = 0; j < num_units; j++) {
+ auto curr_unit = curr_module.GetCompileUnitAtIndex(j);
+ units.emplace_back(CreateCompileUnit(curr_unit));
+ }
+ body.try_emplace("compileUnits", std::move(units));
+ break;
+ }
+ }
+ response.try_emplace("body", std::move(body));
+ dap.SendJSON(llvm::json::Value(std::move(response)));
+}
+
+} // namespace lldb_dap
diff --git a/lldb/tools/lldb-dap/Handler/DataBreakpointInfoRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/DataBreakpointInfoRequestHandler.cpp
new file mode 100644
index 0000000000000..519a9c728e4b3
--- /dev/null
+++ b/lldb/tools/lldb-dap/Handler/DataBreakpointInfoRequestHandler.cpp
@@ -0,0 +1,190 @@
+//===-- DataBreakpointInfoRequestHandler.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"
+#include "lldb/API/SBMemoryRegionInfo.h"
+#include "llvm/ADT/StringExtras.h"
+
+namespace lldb_dap {
+
+// "DataBreakpointInfoRequest": {
+// "allOf": [ { "$ref": "#/definitions/Request" }, {
+// "type": "object",
+// "description": "Obtains information on a possible data breakpoint that
+// could be set on an expression or variable.\nClients should only call this
+// request if the corresponding capability `supportsDataBreakpoints` is
+// true.", "properties": {
+// "command": {
+// "type": "string",
+// "enum": [ "dataBreakpointInfo" ]
+// },
+// "arguments": {
+// "$ref": "#/definitions/DataBreakpointInfoArguments"
+// }
+// },
+// "required": [ "command", "arguments" ]
+// }]
+// },
+// "DataBreakpointInfoArguments": {
+// "type": "object",
+// "description": "Arguments for `dataBreakpointInfo` request.",
+// "properties": {
+// "variablesReference": {
+// "type": "integer",
+// "description": "Reference to the variable container if the data
+// breakpoint is requested for a child of the container. The
+// `variablesReference` must have been obtained in the current suspended
+// state. See 'Lifetime of Object References' in the Overview section for
+// details."
+// },
+// "name": {
+// "type": "string",
+// "description": "The name of the variable's child to obtain data
+// breakpoint information for.\nIf `variablesReference` isn't specified,
+// this can be an expression."
+// },
+// "frameId": {
+// "type": "integer",
+// "description": "When `name` is an expression, evaluate it in the scope
+// of this stack frame. If not specified, the expression is evaluated in
+// the global scope. When `variablesReference` is specified, this property
+// has no effect."
+// }
+// },
+// "required": [ "name" ]
+// },
+// "DataBreakpointInfoResponse": {
+// "allOf": [ { "$ref": "#/definitions/Response" }, {
+// "type": "object",
+// "description": "Response to `dataBreakpointInfo` request.",
+// "properties": {
+// "body": {
+// "type": "object",
+// "properties": {
+// "dataId": {
+// "type": [ "string", "null" ],
+// "description": "An identifier for the data on which a data
+// breakpoint can be registered with the `setDataBreakpoints`
+// request or null if no data breakpoint is available. If a
+// `variablesReference` or `frameId` is passed, the `dataId` is
+// valid in the current suspended state, otherwise it's valid
+// indefinitely. See 'Lifetime of Object References' in the Overview
+// section for details. Breakpoints set using the `dataId` in the
+// `setDataBreakpoints` request may outlive the lifetime of the
+// associated `dataId`."
+// },
+// "description": {
+// "type": "string",
+// "description": "UI string that describes on what data the
+// breakpoint is set on or why a data breakpoint is not available."
+// },
+// "accessTypes": {
+// "type": "array",
+// "items": {
+// "$ref": "#/definitions/DataBreakpointAccessType"
+// },
+// "description": "Attribute lists the available access types for a
+// potential data breakpoint. A UI client could surface this
+// information."
+// },
+// "canPersist": {
+// "type": "boolean",
+// "description": "Attribute indicates that a potential data
+// breakpoint could be persisted across sessions."
+// }
+// },
+// "required": [ "dataId", "description" ]
+// }
+// },
+// "required": [ "body" ]
+// }]
+// }
+void DataBreakpointInfoRequestHandler::operator()(
+ const llvm::json::Object &request) {
+ llvm::json::Object response;
+ FillResponse(request, response);
+ llvm::json::Object body;
+ lldb::SBError error;
+ llvm::json::Array accessTypes{"read", "write", "readWrite"};
+ const auto *arguments = request.getObject("arguments");
+ const auto variablesReference =
+ GetUnsigned(arguments, "variablesReference", 0);
+ llvm::StringRef name = GetString(arguments, "name");
+ lldb::SBFrame frame = dap.GetLLDBFrame(*arguments);
+ lldb::SBValue variable = FindVariable(variablesReference, name);
+ std::string addr, size;
+
+ if (variable.IsValid()) {
+ lldb::addr_t load_addr = variable.GetLoadAddress();
+ size_t byte_size = variable.GetByteSize();
+ if (load_addr == LLDB_INVALID_ADDRESS) {
+ body.try_emplace("dataId", nullptr);
+ body.try_emplace("description",
+ "does not exist in memory, its location is " +
+ std::string(variable.GetLocation()));
+ } else if (byte_size == 0) {
+ body.try_emplace("dataId", nullptr);
+ body.try_emplace("description", "variable size is 0");
+ } else {
+ addr = llvm::utohexstr(load_addr);
+ size = llvm::utostr(byte_size);
+ }
+ } else if (variablesReference == 0 && frame.IsValid()) {
+ lldb::SBValue value = frame.EvaluateExpression(name.data());
+ if (value.GetError().Fail()) {
+ lldb::SBError error = value.GetError();
+ const char *error_cstr = error.GetCString();
+ body.try_emplace("dataId", nullptr);
+ body.try_emplace("description", error_cstr && error_cstr[0]
+ ? std::string(error_cstr)
+ : "evaluation failed");
+ } else {
+ uint64_t load_addr = value.GetValueAsUnsigned();
+ lldb::SBData data = value.GetPointeeData();
+ if (data.IsValid()) {
+ size = llvm::utostr(data.GetByteSize());
+ addr = llvm::utohexstr(load_addr);
+ lldb::SBMemoryRegionInfo region;
+ lldb::SBError err =
+ dap.target.GetProcess().GetMemoryRegionInfo(load_addr, region);
+ // Only lldb-server supports "qMemoryRegionInfo". So, don't fail this
+ // request if SBProcess::GetMemoryRegionInfo returns error.
+ if (err.Success()) {
+ if (!(region.IsReadable() || region.IsWritable())) {
+ body.try_emplace("dataId", nullptr);
+ body.try_emplace("description",
+ "memory region for address " + addr +
+ " has no read or write permissions");
+ }
+ }
+ } else {
+ body.try_emplace("dataId", nullptr);
+ body.try_emplace("description",
+ "unable to get byte size for expression: " +
+ name.str());
+ }
+ }
+ } else {
+ body.try_emplace("dataId", nullptr);
+ body.try_emplace("description", "variable not found: " + name.str());
+ }
+
+ if (!body.getObject("dataId")) {
+ body.try_emplace("dataId", addr + "/" + size);
+ body.try_emplace("accessTypes", std::move(accessTypes));
+ body.try_emplace("description",
+ size + " bytes at " + addr + " " + name.str());
+ }
+ response.try_emplace("body", std::move(body));
+ dap.SendJSON(llvm::json::Value(std::move(response)));
+}
+
+} // namespace lldb_dap
diff --git a/lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp
new file mode 100644
index 0000000000000..6d25ef0fc5d74
--- /dev/null
+++ b/lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp
@@ -0,0 +1,222 @@
+//===-- DisassembleRequestHandler.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"
+#include "lldb/API/SBInstruction.h"
+#include "llvm/ADT/StringExtras.h"
+
+namespace lldb_dap {
+
+// "DisassembleRequest": {
+// "allOf": [ { "$ref": "#/definitions/Request" }, {
+// "type": "object",
+// "description": "Disassembles code stored at the provided
+// location.\nClients should only call this request if the corresponding
+// capability `supportsDisassembleRequest` is true.", "properties": {
+// "command": {
+// "type": "string",
+// "enum": [ "disassemble" ]
+// },
+// "arguments": {
+// "$ref": "#/definitions/DisassembleArguments"
+// }
+// },
+// "required": [ "command", "arguments" ]
+// }]
+// },
+// "DisassembleArguments": {
+// "type": "object",
+// "description": "Arguments for `disassemble` request.",
+// "properties": {
+// "memoryReference": {
+// "type": "string",
+// "description": "Memory reference to the base location containing the
+// instructions to disassemble."
+// },
+// "offset": {
+// "type": "integer",
+// "description": "Offset (in bytes) to be applied to the reference
+// location before disassembling. Can be negative."
+// },
+// "instructionOffset": {
+// "type": "integer",
+// "description": "Offset (in instructions) to be applied after the byte
+// offset (if any) before disassembling. Can be negative."
+// },
+// "instructionCount": {
+// "type": "integer",
+// "description": "Number of instructions to disassemble starting at the
+// specified location and offset.\nAn adapter must return exactly this
+// number of instructions - any unavailable instructions should be
+// replaced with an implementation-defined 'invalid instruction' value."
+// },
+// "resolveSymbols": {
+// "type": "boolean",
+// "description": "If true, the adapter should attempt to resolve memory
+// addresses and other values to symbolic names."
+// }
+// },
+// "required": [ "memoryReference", "instructionCount" ]
+// },
+// "DisassembleResponse": {
+// "allOf": [ { "$ref": "#/definitions/Response" }, {
+// "type": "object",
+// "description": "Response to `disassemble` request.",
+// "properties": {
+// "body": {
+// "type": "object",
+// "properties": {
+// "instructions": {
+// "type": "array",
+// "items": {
+// "$ref": "#/definitions/DisassembledInstruction"
+// },
+// "description": "The list of disassembled instructions."
+// }
+// },
+// "required": [ "instructions" ]
+// }
+// }
+// }]
+// }
+void DisassembleRequestHandler::operator()(const llvm::json::Object &request) {
+ llvm::json::Object response;
+ FillResponse(request, response);
+ auto *arguments = request.getObject("arguments");
+
+ llvm::StringRef memoryReference = GetString(arguments, "memoryReference");
+ auto addr_opt = DecodeMemoryReference(memoryReference);
+ if (!addr_opt.has_value()) {
+ response["success"] = false;
+ response["message"] =
+ "Malformed memory reference: " + memoryReference.str();
+ dap.SendJSON(llvm::json::Value(std::move(response)));
+ return;
+ }
+ lldb::addr_t addr_ptr = *addr_opt;
+
+ addr_ptr += GetSigned(arguments, "instructionOffset", 0);
+ lldb::SBAddress addr(addr_ptr, dap.target);
+ if (!addr.IsValid()) {
+ response["success"] = false;
+ response["message"] = "Memory reference not found in the current binary.";
+ dap.SendJSON(llvm::json::Value(std::move(response)));
+ return;
+ }
+
+ const auto inst_count = GetUnsigned(arguments, "instructionCount", 0);
+ lldb::SBInstructionList insts = dap.target.ReadInstructions(addr, inst_count);
+
+ if (!insts.IsValid()) {
+ response["success"] = false;
+ response["message"] = "Failed to find instructions for memory address.";
+ dap.SendJSON(llvm::json::Value(std::move(response)));
+ return;
+ }
+
+ const bool resolveSymbols = GetBoolean(arguments, "resolveSymbols", false);
+ llvm::json::Array instructions;
+ const auto num_insts = insts.GetSize();
+ for (size_t i = 0; i < num_insts; ++i) {
+ lldb::SBInstruction inst = insts.GetInstructionAtIndex(i);
+ auto addr = inst.GetAddress();
+ const auto inst_addr = addr.GetLoadAddress(dap.target);
+ const char *m = inst.GetMnemonic(dap.target);
+ const char *o = inst.GetOperands(dap.target);
+ const char *c = inst.GetComment(dap.target);
+ auto d = inst.GetData(dap.target);
+
+ std::string bytes;
+ llvm::raw_string_ostream sb(bytes);
+ for (unsigned i = 0; i < inst.GetByteSize(); i++) {
+ lldb::SBError error;
+ uint8_t b = d.GetUnsignedInt8(error, i);
+ if (error.Success()) {
+ sb << llvm::format("%2.2x ", b);
+ }
+ }
+
+ llvm::json::Object disassembled_inst{
+ {"address", "0x" + llvm::utohexstr(inst_addr)},
+ {"instructionBytes",
+ bytes.size() > 0 ? bytes.substr(0, bytes.size() - 1) : ""},
+ };
+
+ std::string instruction;
+ llvm::raw_string_ostream si(instruction);
+
+ lldb::SBSymbol symbol = addr.GetSymbol();
+ // Only add the symbol on the first line of the function.
+ if (symbol.IsValid() && symbol.GetStartAddress() == addr) {
+ // If we have a valid symbol, append it as a label prefix for the first
+ // instruction. This is so you can see the start of a function/callsite
+ // in the assembly, at the moment VS Code (1.80) does not visualize the
+ // symbol associated with the assembly instruction.
+ si << (symbol.GetMangledName() != nullptr ? symbol.GetMangledName()
+ : symbol.GetName())
+ << ": ";
+
+ if (resolveSymbols) {
+ disassembled_inst.try_emplace("symbol", symbol.GetDisplayName());
+ }
+ }
+
+ si << llvm::formatv("{0,7} {1,12}", m, o);
+ if (c && c[0]) {
+ si << " ; " << c;
+ }
+
+ disassembled_inst.try_emplace("instruction", instruction);
+
+ auto line_entry = addr.GetLineEntry();
+ // If the line number is 0 then the entry represents a compiler generated
+ // location.
+ if (line_entry.GetStartAddress() == addr && line_entry.IsValid() &&
+ line_entry.GetFileSpec().IsValid() && line_entry.GetLine() != 0) {
+ auto source = CreateSource(line_entry);
+ disassembled_inst.try_emplace("location", source);
+
+ const auto line = line_entry.GetLine();
+ if (line && line != LLDB_INVALID_LINE_NUMBER) {
+ disassembled_inst.try_emplace("line", line);
+ }
+ const auto column = line_entry.GetColumn();
+ if (column && column != LLDB_INVALID_COLUMN_NUMBER) {
+ disassembled_inst.try_emplace("column", column);...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/128551
More information about the lldb-commits
mailing list