185 lines · cpp
1//===-- LocationsRequestHandler.cpp ---------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "DAP.h"10#include "EventHelper.h"11#include "JSONUtils.h"12#include "LLDBUtils.h"13#include "ProtocolUtils.h"14#include "RequestHandler.h"15#include "lldb/API/SBAddress.h"16#include "lldb/API/SBDeclaration.h"17#include "lldb/API/SBLineEntry.h"18 19namespace lldb_dap {20 21// "LocationsRequest": {22// "allOf": [ { "$ref": "#/definitions/Request" }, {23// "type": "object",24// "description": "Looks up information about a location reference25// previously returned by the debug adapter.",26// "properties": {27// "command": {28// "type": "string",29// "enum": [ "locations" ]30// },31// "arguments": {32// "$ref": "#/definitions/LocationsArguments"33// }34// },35// "required": [ "command", "arguments" ]36// }]37// },38// "LocationsArguments": {39// "type": "object",40// "description": "Arguments for `locations` request.",41// "properties": {42// "locationReference": {43// "type": "integer",44// "description": "Location reference to resolve."45// }46// },47// "required": [ "locationReference" ]48// },49// "LocationsResponse": {50// "allOf": [ { "$ref": "#/definitions/Response" }, {51// "type": "object",52// "description": "Response to `locations` request.",53// "properties": {54// "body": {55// "type": "object",56// "properties": {57// "source": {58// "$ref": "#/definitions/Source",59// "description": "The source containing the location; either60// `source.path` or `source.sourceReference` must be61// specified."62// },63// "line": {64// "type": "integer",65// "description": "The line number of the location. The client66// capability `linesStartAt1` determines whether it67// is 0- or 1-based."68// },69// "column": {70// "type": "integer",71// "description": "Position of the location within the `line`. It is72// measured in UTF-16 code units and the client73// capability `columnsStartAt1` determines whether74// it is 0- or 1-based. If no column is given, the75// first position in the start line is assumed."76// },77// "endLine": {78// "type": "integer",79// "description": "End line of the location, present if the location80// refers to a range. The client capability81// `linesStartAt1` determines whether it is 0- or82// 1-based."83// },84// "endColumn": {85// "type": "integer",86// "description": "End position of the location within `endLine`,87// present if the location refers to a range. It is88// measured in UTF-16 code units and the client89// capability `columnsStartAt1` determines whether90// it is 0- or 1-based."91// }92// },93// "required": [ "source", "line" ]94// }95// }96// }]97// },98void LocationsRequestHandler::operator()(99 const llvm::json::Object &request) const {100 llvm::json::Object response;101 FillResponse(request, response);102 auto *arguments = request.getObject("arguments");103 104 const auto location_id =105 GetInteger<uint64_t>(arguments, "locationReference").value_or(0);106 // We use the lowest bit to distinguish between value location and declaration107 // location108 auto [var_ref, is_value_location] = UnpackLocation(location_id);109 lldb::SBValue variable = dap.variables.GetVariable(var_ref);110 if (!variable.IsValid()) {111 response["success"] = false;112 response["message"] = "Invalid variable reference";113 dap.SendJSON(llvm::json::Value(std::move(response)));114 return;115 }116 117 llvm::json::Object body;118 if (is_value_location) {119 // Get the value location120 if (!variable.GetType().IsPointerType() &&121 !variable.GetType().IsReferenceType()) {122 response["success"] = false;123 response["message"] =124 "Value locations are only available for pointers and references";125 dap.SendJSON(llvm::json::Value(std::move(response)));126 return;127 }128 129 lldb::addr_t raw_addr = variable.GetValueAsAddress();130 lldb::SBAddress addr = dap.target.ResolveLoadAddress(raw_addr);131 lldb::SBLineEntry line_entry = GetLineEntryForAddress(dap.target, addr);132 133 if (!line_entry.IsValid()) {134 response["success"] = false;135 response["message"] = "Failed to resolve line entry for location";136 dap.SendJSON(llvm::json::Value(std::move(response)));137 return;138 }139 140 const std::optional<protocol::Source> source =141 CreateSource(line_entry.GetFileSpec());142 if (!source) {143 response["success"] = false;144 response["message"] = "Failed to resolve file path for location";145 dap.SendJSON(llvm::json::Value(std::move(response)));146 return;147 }148 149 body.try_emplace("source", *source);150 if (int line = line_entry.GetLine())151 body.try_emplace("line", line);152 if (int column = line_entry.GetColumn())153 body.try_emplace("column", column);154 } else {155 // Get the declaration location156 lldb::SBDeclaration decl = variable.GetDeclaration();157 if (!decl.IsValid()) {158 response["success"] = false;159 response["message"] = "No declaration location available";160 dap.SendJSON(llvm::json::Value(std::move(response)));161 return;162 }163 164 const std::optional<protocol::Source> source =165 CreateSource(decl.GetFileSpec());166 if (!source) {167 response["success"] = false;168 response["message"] = "Failed to resolve file path for location";169 dap.SendJSON(llvm::json::Value(std::move(response)));170 return;171 }172 173 body.try_emplace("source", *source);174 if (int line = decl.GetLine())175 body.try_emplace("line", line);176 if (int column = decl.GetColumn())177 body.try_emplace("column", column);178 }179 180 response.try_emplace("body", std::move(body));181 dap.SendJSON(llvm::json::Value(std::move(response)));182}183 184} // namespace lldb_dap185