aboutsummaryrefslogtreecommitdiff
path: root/lldb/tools/lldb-dap/Handler
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/tools/lldb-dap/Handler')
-rw-r--r--lldb/tools/lldb-dap/Handler/CompletionsHandler.cpp173
-rw-r--r--lldb/tools/lldb-dap/Handler/ConfigurationDoneRequestHandler.cpp6
-rw-r--r--lldb/tools/lldb-dap/Handler/DataBreakpointInfoRequestHandler.cpp2
-rw-r--r--lldb/tools/lldb-dap/Handler/ModuleSymbolsRequestHandler.cpp90
-rw-r--r--lldb/tools/lldb-dap/Handler/RequestHandler.h23
-rw-r--r--lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp1
6 files changed, 145 insertions, 150 deletions
diff --git a/lldb/tools/lldb-dap/Handler/CompletionsHandler.cpp b/lldb/tools/lldb-dap/Handler/CompletionsHandler.cpp
index c72fc56..de9a15d 100644
--- a/lldb/tools/lldb-dap/Handler/CompletionsHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/CompletionsHandler.cpp
@@ -8,156 +8,46 @@
#include "DAP.h"
#include "JSONUtils.h"
+#include "Protocol/ProtocolRequests.h"
+#include "Protocol/ProtocolTypes.h"
#include "RequestHandler.h"
#include "lldb/API/SBStringList.h"
-namespace lldb_dap {
+using namespace llvm;
+using namespace lldb_dap;
+using namespace lldb_dap::protocol;
-// "CompletionsRequest": {
-// "allOf": [ { "$ref": "#/definitions/Request" }, {
-// "type": "object",
-// "description": "Returns a list of possible completions for a given caret
-// position and text.\nThe CompletionsRequest may only be called if the
-// 'supportsCompletionsRequest' capability exists and is true.",
-// "properties": {
-// "command": {
-// "type": "string",
-// "enum": [ "completions" ]
-// },
-// "arguments": {
-// "$ref": "#/definitions/CompletionsArguments"
-// }
-// },
-// "required": [ "command", "arguments" ]
-// }]
-// },
-// "CompletionsArguments": {
-// "type": "object",
-// "description": "Arguments for 'completions' request.",
-// "properties": {
-// "frameId": {
-// "type": "integer",
-// "description": "Returns completions in the scope of this stack frame.
-// If not specified, the completions are returned for the global scope."
-// },
-// "text": {
-// "type": "string",
-// "description": "One or more source lines. Typically this is the text a
-// user has typed into the debug console before he asked for completion."
-// },
-// "column": {
-// "type": "integer",
-// "description": "The character position for which to determine the
-// completion proposals."
-// },
-// "line": {
-// "type": "integer",
-// "description": "An optional line for which to determine the completion
-// proposals. If missing the first line of the text is assumed."
-// }
-// },
-// "required": [ "text", "column" ]
-// },
-// "CompletionsResponse": {
-// "allOf": [ { "$ref": "#/definitions/Response" }, {
-// "type": "object",
-// "description": "Response to 'completions' request.",
-// "properties": {
-// "body": {
-// "type": "object",
-// "properties": {
-// "targets": {
-// "type": "array",
-// "items": {
-// "$ref": "#/definitions/CompletionItem"
-// },
-// "description": "The possible completions for ."
-// }
-// },
-// "required": [ "targets" ]
-// }
-// },
-// "required": [ "body" ]
-// }]
-// },
-// "CompletionItem": {
-// "type": "object",
-// "description": "CompletionItems are the suggestions returned from the
-// CompletionsRequest.", "properties": {
-// "label": {
-// "type": "string",
-// "description": "The label of this completion item. By default this is
-// also the text that is inserted when selecting this completion."
-// },
-// "text": {
-// "type": "string",
-// "description": "If text is not falsy then it is inserted instead of the
-// label."
-// },
-// "sortText": {
-// "type": "string",
-// "description": "A string that should be used when comparing this item
-// with other items. When `falsy` the label is used."
-// },
-// "type": {
-// "$ref": "#/definitions/CompletionItemType",
-// "description": "The item's type. Typically the client uses this
-// information to render the item in the UI with an icon."
-// },
-// "start": {
-// "type": "integer",
-// "description": "This value determines the location (in the
-// CompletionsRequest's 'text' attribute) where the completion text is
-// added.\nIf missing the text is added at the location specified by the
-// CompletionsRequest's 'column' attribute."
-// },
-// "length": {
-// "type": "integer",
-// "description": "This value determines how many characters are
-// overwritten by the completion text.\nIf missing the value 0 is assumed
-// which results in the completion text being inserted."
-// }
-// },
-// "required": [ "label" ]
-// },
-// "CompletionItemType": {
-// "type": "string",
-// "description": "Some predefined types for the CompletionItem. Please note
-// that not all clients have specific icons for all of them.", "enum": [
-// "method", "function", "constructor", "field", "variable", "class",
-// "interface", "module", "property", "unit", "value", "enum", "keyword",
-// "snippet", "text", "color", "file", "reference", "customcolor" ]
-// }
-void CompletionsRequestHandler::operator()(
- const llvm::json::Object &request) const {
- llvm::json::Object response;
- FillResponse(request, response);
- llvm::json::Object body;
- const auto *arguments = request.getObject("arguments");
+namespace lldb_dap {
+/// Returns a list of possible completions for a given caret position and text.
+///
+/// Clients should only call this request if the corresponding capability
+/// `supportsCompletionsRequest` is true.
+Expected<CompletionsResponseBody>
+CompletionsRequestHandler::Run(const CompletionsArguments &args) const {
// If we have a frame, try to set the context for variable completions.
- lldb::SBFrame frame = dap.GetLLDBFrame(*arguments);
+ lldb::SBFrame frame = dap.GetLLDBFrame(args.frameId);
if (frame.IsValid()) {
frame.GetThread().GetProcess().SetSelectedThread(frame.GetThread());
frame.GetThread().SetSelectedFrame(frame.GetFrameID());
}
- std::string text = GetString(arguments, "text").value_or("").str();
- auto original_column =
- GetInteger<int64_t>(arguments, "column").value_or(text.size());
- auto original_line = GetInteger<int64_t>(arguments, "line").value_or(1);
+ std::string text = args.text;
+ auto original_column = args.column;
+ auto original_line = args.line;
auto offset = original_column - 1;
if (original_line > 1) {
- llvm::SmallVector<::llvm::StringRef, 2> lines;
- llvm::StringRef(text).split(lines, '\n');
+ SmallVector<StringRef, 2> lines;
+ StringRef(text).split(lines, '\n');
for (int i = 0; i < original_line - 1; i++) {
offset += lines[i].size();
}
}
- llvm::json::Array targets;
+
+ std::vector<CompletionItem> targets;
bool had_escape_prefix =
- llvm::StringRef(text).starts_with(dap.configuration.commandEscapePrefix);
+ StringRef(text).starts_with(dap.configuration.commandEscapePrefix);
ReplMode completion_mode = dap.DetectReplMode(frame, text, true);
// Handle the offset change introduced by stripping out the
@@ -165,10 +55,7 @@ void CompletionsRequestHandler::operator()(
if (had_escape_prefix) {
if (offset <
static_cast<int64_t>(dap.configuration.commandEscapePrefix.size())) {
- body.try_emplace("targets", std::move(targets));
- response.try_emplace("body", std::move(body));
- dap.SendJSON(llvm::json::Value(std::move(response)));
- return;
+ return CompletionsResponseBody{std::move(targets)};
}
offset -= dap.configuration.commandEscapePrefix.size();
}
@@ -198,27 +85,25 @@ void CompletionsRequestHandler::operator()(
std::string match = matches.GetStringAtIndex(i);
std::string description = descriptions.GetStringAtIndex(i);
- llvm::json::Object item;
- llvm::StringRef match_ref = match;
- for (llvm::StringRef commit_point : {".", "->"}) {
+ CompletionItem item;
+ StringRef match_ref = match;
+ for (StringRef commit_point : {".", "->"}) {
if (match_ref.contains(commit_point)) {
match_ref = match_ref.rsplit(commit_point).second;
}
}
- EmplaceSafeString(item, "text", match_ref);
+ item.text = match_ref;
if (description.empty())
- EmplaceSafeString(item, "label", match);
+ item.label = match;
else
- EmplaceSafeString(item, "label", match + " -- " + description);
+ item.label = match + " -- " + description;
targets.emplace_back(std::move(item));
}
}
- body.try_emplace("targets", std::move(targets));
- response.try_emplace("body", std::move(body));
- dap.SendJSON(llvm::json::Value(std::move(response)));
+ return CompletionsResponseBody{std::move(targets)};
}
} // namespace lldb_dap
diff --git a/lldb/tools/lldb-dap/Handler/ConfigurationDoneRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/ConfigurationDoneRequestHandler.cpp
index e7735a7..1bfe7b7 100644
--- a/lldb/tools/lldb-dap/Handler/ConfigurationDoneRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/ConfigurationDoneRequestHandler.cpp
@@ -9,6 +9,7 @@
#include "DAP.h"
#include "EventHelper.h"
#include "LLDBUtils.h"
+#include "Protocol/ProtocolEvents.h"
#include "Protocol/ProtocolRequests.h"
#include "ProtocolUtils.h"
#include "RequestHandler.h"
@@ -44,7 +45,10 @@ ConfigurationDoneRequestHandler::Run(const ConfigurationDoneArguments &) const {
// Waiting until 'configurationDone' to send target based capabilities in case
// the launch or attach scripts adjust the target. The initial dummy target
// may have different capabilities than the final target.
- SendTargetBasedCapabilities(dap);
+
+ /// Also send here custom capabilities to the client, which is consumed by the
+ /// lldb-dap specific editor extension.
+ SendExtraCapabilities(dap);
// Clients can request a baseline of currently existing threads after
// we acknowledge the configurationDone request.
diff --git a/lldb/tools/lldb-dap/Handler/DataBreakpointInfoRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/DataBreakpointInfoRequestHandler.cpp
index 8cb25d0..87b93fc 100644
--- a/lldb/tools/lldb-dap/Handler/DataBreakpointInfoRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/DataBreakpointInfoRequestHandler.cpp
@@ -23,7 +23,7 @@ llvm::Expected<protocol::DataBreakpointInfoResponseBody>
DataBreakpointInfoRequestHandler::Run(
const protocol::DataBreakpointInfoArguments &args) const {
protocol::DataBreakpointInfoResponseBody response;
- lldb::SBFrame frame = dap.GetLLDBFrame(args.frameId.value_or(UINT64_MAX));
+ lldb::SBFrame frame = dap.GetLLDBFrame(args.frameId);
lldb::SBValue variable = dap.variables.FindVariable(
args.variablesReference.value_or(0), args.name);
std::string addr, size;
diff --git a/lldb/tools/lldb-dap/Handler/ModuleSymbolsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/ModuleSymbolsRequestHandler.cpp
new file mode 100644
index 0000000..4a9d256
--- /dev/null
+++ b/lldb/tools/lldb-dap/Handler/ModuleSymbolsRequestHandler.cpp
@@ -0,0 +1,90 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 "DAPError.h"
+#include "Protocol/DAPTypes.h"
+#include "RequestHandler.h"
+#include "lldb/API/SBAddress.h"
+#include "lldb/API/SBFileSpec.h"
+#include "lldb/API/SBModule.h"
+#include "lldb/API/SBModuleSpec.h"
+#include "lldb/Utility/UUID.h"
+#include "llvm/Support/Error.h"
+#include <cstddef>
+
+using namespace lldb_dap::protocol;
+namespace lldb_dap {
+
+llvm::Expected<ModuleSymbolsResponseBody>
+ModuleSymbolsRequestHandler::Run(const ModuleSymbolsArguments &args) const {
+ ModuleSymbolsResponseBody response;
+
+ lldb::SBModuleSpec module_spec;
+ if (!args.moduleId.empty()) {
+ llvm::SmallVector<uint8_t, 20> uuid_bytes;
+ if (!lldb_private::UUID::DecodeUUIDBytesFromString(args.moduleId,
+ uuid_bytes)
+ .empty())
+ return llvm::make_error<DAPError>("invalid module ID");
+
+ module_spec.SetUUIDBytes(uuid_bytes.data(), uuid_bytes.size());
+ }
+
+ if (!args.moduleName.empty()) {
+ lldb::SBFileSpec file_spec;
+ file_spec.SetFilename(args.moduleName.c_str());
+ module_spec.SetFileSpec(file_spec);
+ }
+
+ // Empty request, return empty response.
+ if (!module_spec.IsValid())
+ return response;
+
+ std::vector<Symbol> &symbols = response.symbols;
+ lldb::SBModule module = dap.target.FindModule(module_spec);
+ if (!module.IsValid())
+ return llvm::make_error<DAPError>("module not found");
+
+ const size_t num_symbols = module.GetNumSymbols();
+ const size_t start_index = args.startIndex.value_or(0);
+ const size_t end_index =
+ std::min(start_index + args.count.value_or(num_symbols), num_symbols);
+ for (size_t i = start_index; i < end_index; ++i) {
+ lldb::SBSymbol symbol = module.GetSymbolAtIndex(i);
+ if (!symbol.IsValid())
+ continue;
+
+ Symbol dap_symbol;
+ dap_symbol.id = symbol.GetID();
+ dap_symbol.type = symbol.GetType();
+ dap_symbol.isDebug = symbol.IsDebug();
+ dap_symbol.isSynthetic = symbol.IsSynthetic();
+ dap_symbol.isExternal = symbol.IsExternal();
+
+ lldb::SBAddress start_address = symbol.GetStartAddress();
+ if (start_address.IsValid()) {
+ lldb::addr_t file_address = start_address.GetFileAddress();
+ if (file_address != LLDB_INVALID_ADDRESS)
+ dap_symbol.fileAddress = file_address;
+
+ lldb::addr_t load_address = start_address.GetLoadAddress(dap.target);
+ if (load_address != LLDB_INVALID_ADDRESS)
+ dap_symbol.loadAddress = load_address;
+ }
+
+ dap_symbol.size = symbol.GetSize();
+ if (const char *symbol_name = symbol.GetName())
+ dap_symbol.name = symbol_name;
+ symbols.push_back(std::move(dap_symbol));
+ }
+
+ return response;
+}
+
+} // namespace lldb_dap
diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h
index 16f8062..977a247 100644
--- a/lldb/tools/lldb-dap/Handler/RequestHandler.h
+++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h
@@ -243,14 +243,17 @@ public:
uint32_t end_line) const;
};
-class CompletionsRequestHandler : public LegacyRequestHandler {
+class CompletionsRequestHandler
+ : public RequestHandler<protocol::CompletionsArguments,
+ llvm::Expected<protocol::CompletionsResponseBody>> {
public:
- using LegacyRequestHandler::LegacyRequestHandler;
+ using RequestHandler::RequestHandler;
static llvm::StringLiteral GetCommand() { return "completions"; }
FeatureSet GetSupportedFeatures() const override {
return {protocol::eAdapterFeatureCompletionsRequest};
}
- void operator()(const llvm::json::Object &request) const override;
+ llvm::Expected<protocol::CompletionsResponseBody>
+ Run(const protocol::CompletionsArguments &args) const override;
};
class ContinueRequestHandler
@@ -594,6 +597,20 @@ public:
llvm::Error Run(const protocol::CancelArguments &args) const override;
};
+class ModuleSymbolsRequestHandler
+ : public RequestHandler<
+ protocol::ModuleSymbolsArguments,
+ llvm::Expected<protocol::ModuleSymbolsResponseBody>> {
+public:
+ using RequestHandler::RequestHandler;
+ static llvm::StringLiteral GetCommand() { return "__lldb_moduleSymbols"; }
+ FeatureSet GetSupportedFeatures() const override {
+ return {protocol::eAdapterFeatureSupportsModuleSymbolsRequest};
+ }
+ llvm::Expected<protocol::ModuleSymbolsResponseBody>
+ Run(const protocol::ModuleSymbolsArguments &args) const override;
+};
+
/// A request used in testing to get the details on all breakpoints that are
/// currently set in the target. This helps us to test "setBreakpoints" and
/// "setFunctionBreakpoints" requests to verify we have the correct set of
diff --git a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp
index 5d336af..142351f 100644
--- a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp
@@ -9,7 +9,6 @@
#include "DAP.h"
#include "Protocol/ProtocolRequests.h"
#include "RequestHandler.h"
-#include <vector>
namespace lldb_dap {