
The [protocol](https://microsoft.github.io/debug-adapter-protocol//specification.html#Types_Source) expects that `sourceReference` be less than `(2^31)-1`, but we currently represent memory address as source reference, this can be truncated either when sending through json or by the client. Instead, generate new source references based on the memory address. Make the `ResolveSource` function return an optional source.
185 lines
6.5 KiB
C++
185 lines
6.5 KiB
C++
//===-- LocationsRequestHandler.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 "LLDBUtils.h"
|
|
#include "ProtocolUtils.h"
|
|
#include "RequestHandler.h"
|
|
#include "lldb/API/SBAddress.h"
|
|
#include "lldb/API/SBDeclaration.h"
|
|
#include "lldb/API/SBLineEntry.h"
|
|
|
|
namespace lldb_dap {
|
|
|
|
// "LocationsRequest": {
|
|
// "allOf": [ { "$ref": "#/definitions/Request" }, {
|
|
// "type": "object",
|
|
// "description": "Looks up information about a location reference
|
|
// previously returned by the debug adapter.",
|
|
// "properties": {
|
|
// "command": {
|
|
// "type": "string",
|
|
// "enum": [ "locations" ]
|
|
// },
|
|
// "arguments": {
|
|
// "$ref": "#/definitions/LocationsArguments"
|
|
// }
|
|
// },
|
|
// "required": [ "command", "arguments" ]
|
|
// }]
|
|
// },
|
|
// "LocationsArguments": {
|
|
// "type": "object",
|
|
// "description": "Arguments for `locations` request.",
|
|
// "properties": {
|
|
// "locationReference": {
|
|
// "type": "integer",
|
|
// "description": "Location reference to resolve."
|
|
// }
|
|
// },
|
|
// "required": [ "locationReference" ]
|
|
// },
|
|
// "LocationsResponse": {
|
|
// "allOf": [ { "$ref": "#/definitions/Response" }, {
|
|
// "type": "object",
|
|
// "description": "Response to `locations` request.",
|
|
// "properties": {
|
|
// "body": {
|
|
// "type": "object",
|
|
// "properties": {
|
|
// "source": {
|
|
// "$ref": "#/definitions/Source",
|
|
// "description": "The source containing the location; either
|
|
// `source.path` or `source.sourceReference` must be
|
|
// specified."
|
|
// },
|
|
// "line": {
|
|
// "type": "integer",
|
|
// "description": "The line number of the location. The client
|
|
// capability `linesStartAt1` determines whether it
|
|
// is 0- or 1-based."
|
|
// },
|
|
// "column": {
|
|
// "type": "integer",
|
|
// "description": "Position of the location within the `line`. It is
|
|
// measured in UTF-16 code units and the client
|
|
// capability `columnsStartAt1` determines whether
|
|
// it is 0- or 1-based. If no column is given, the
|
|
// first position in the start line is assumed."
|
|
// },
|
|
// "endLine": {
|
|
// "type": "integer",
|
|
// "description": "End line of the location, present if the location
|
|
// refers to a range. The client capability
|
|
// `linesStartAt1` determines whether it is 0- or
|
|
// 1-based."
|
|
// },
|
|
// "endColumn": {
|
|
// "type": "integer",
|
|
// "description": "End position of the location within `endLine`,
|
|
// present if the location refers to a range. It is
|
|
// measured in UTF-16 code units and the client
|
|
// capability `columnsStartAt1` determines whether
|
|
// it is 0- or 1-based."
|
|
// }
|
|
// },
|
|
// "required": [ "source", "line" ]
|
|
// }
|
|
// }
|
|
// }]
|
|
// },
|
|
void LocationsRequestHandler::operator()(
|
|
const llvm::json::Object &request) const {
|
|
llvm::json::Object response;
|
|
FillResponse(request, response);
|
|
auto *arguments = request.getObject("arguments");
|
|
|
|
const auto location_id =
|
|
GetInteger<uint64_t>(arguments, "locationReference").value_or(0);
|
|
// We use the lowest bit to distinguish between value location and declaration
|
|
// location
|
|
auto [var_ref, is_value_location] = UnpackLocation(location_id);
|
|
lldb::SBValue variable = dap.variables.GetVariable(var_ref);
|
|
if (!variable.IsValid()) {
|
|
response["success"] = false;
|
|
response["message"] = "Invalid variable reference";
|
|
dap.SendJSON(llvm::json::Value(std::move(response)));
|
|
return;
|
|
}
|
|
|
|
llvm::json::Object body;
|
|
if (is_value_location) {
|
|
// Get the value location
|
|
if (!variable.GetType().IsPointerType() &&
|
|
!variable.GetType().IsReferenceType()) {
|
|
response["success"] = false;
|
|
response["message"] =
|
|
"Value locations are only available for pointers and references";
|
|
dap.SendJSON(llvm::json::Value(std::move(response)));
|
|
return;
|
|
}
|
|
|
|
lldb::addr_t raw_addr = variable.GetValueAsAddress();
|
|
lldb::SBAddress addr = dap.target.ResolveLoadAddress(raw_addr);
|
|
lldb::SBLineEntry line_entry = GetLineEntryForAddress(dap.target, addr);
|
|
|
|
if (!line_entry.IsValid()) {
|
|
response["success"] = false;
|
|
response["message"] = "Failed to resolve line entry for location";
|
|
dap.SendJSON(llvm::json::Value(std::move(response)));
|
|
return;
|
|
}
|
|
|
|
const std::optional<protocol::Source> source =
|
|
CreateSource(line_entry.GetFileSpec());
|
|
if (!source) {
|
|
response["success"] = false;
|
|
response["message"] = "Failed to resolve file path for location";
|
|
dap.SendJSON(llvm::json::Value(std::move(response)));
|
|
return;
|
|
}
|
|
|
|
body.try_emplace("source", *source);
|
|
if (int line = line_entry.GetLine())
|
|
body.try_emplace("line", line);
|
|
if (int column = line_entry.GetColumn())
|
|
body.try_emplace("column", column);
|
|
} else {
|
|
// Get the declaration location
|
|
lldb::SBDeclaration decl = variable.GetDeclaration();
|
|
if (!decl.IsValid()) {
|
|
response["success"] = false;
|
|
response["message"] = "No declaration location available";
|
|
dap.SendJSON(llvm::json::Value(std::move(response)));
|
|
return;
|
|
}
|
|
|
|
const std::optional<protocol::Source> source =
|
|
CreateSource(decl.GetFileSpec());
|
|
if (!source) {
|
|
response["success"] = false;
|
|
response["message"] = "Failed to resolve file path for location";
|
|
dap.SendJSON(llvm::json::Value(std::move(response)));
|
|
return;
|
|
}
|
|
|
|
body.try_emplace("source", *source);
|
|
if (int line = decl.GetLine())
|
|
body.try_emplace("line", line);
|
|
if (int column = decl.GetColumn())
|
|
body.try_emplace("column", column);
|
|
}
|
|
|
|
response.try_emplace("body", std::move(body));
|
|
dap.SendJSON(llvm::json::Value(std::move(response)));
|
|
}
|
|
|
|
} // namespace lldb_dap
|