
Refactor code revolving source objects such that most logics will be reused. The main change is to expose a single `CreateSource(addr, target)` that can return either a normal or an assembly source object, and call `ShouldDisplayAssemblySource()` only from this function instead of multiple places across the code. Other functions can use `source.IsAssemblySource()` in order to check which type the source is.
167 lines
6.0 KiB
C++
167 lines
6.0 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;
|
|
}
|
|
|
|
body.try_emplace("source", CreateSource(line_entry.GetFileSpec()));
|
|
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;
|
|
}
|
|
|
|
body.try_emplace("source", CreateSource(decl.GetFileSpec()));
|
|
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
|