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-exception
6//
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 reference
25// 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; either
60// `source.path` or `source.sourceReference` must be
61// specified."
62// },
63// "line": {
64// "type": "integer",
65// "description": "The line number of the location. The client
66// capability `linesStartAt1` determines whether it
67// is 0- or 1-based."
68// },
69// "column": {
70// "type": "integer",
71// "description": "Position of the location within the `line`. It is
72// measured in UTF-16 code units and the client
73// capability `columnsStartAt1` determines whether
74// it is 0- or 1-based. If no column is given, the
75// first position in the start line is assumed."
76// },
77// "endLine": {
78// "type": "integer",
79// "description": "End line of the location, present if the location
80// refers to a range. The client capability
81// `linesStartAt1` determines whether it is 0- or
82// 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 is
88// measured in UTF-16 code units and the client
89// capability `columnsStartAt1` determines whether
90// 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(K: "arguments");
103
104 const auto location_id =
105 GetInteger<uint64_t>(obj: arguments, key: "locationReference").value_or(u: 0);
106 // We use the lowest bit to distinguish between value location and declaration
107 // location
108 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(json: llvm::json::Value(std::move(response)));
114 return;
115 }
116
117 llvm::json::Object body;
118 if (is_value_location) {
119 // Get the value location
120 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(json: 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(vm_addr: raw_addr);
131 lldb::SBLineEntry line_entry = GetLineEntryForAddress(target&: dap.target, address: addr);
132
133 if (!line_entry.IsValid()) {
134 response["success"] = false;
135 response["message"] = "Failed to resolve line entry for location";
136 dap.SendJSON(json: llvm::json::Value(std::move(response)));
137 return;
138 }
139
140 body.try_emplace(K: "source", Args: CreateSource(file: line_entry.GetFileSpec()));
141 if (int line = line_entry.GetLine())
142 body.try_emplace(K: "line", Args&: line);
143 if (int column = line_entry.GetColumn())
144 body.try_emplace(K: "column", Args&: column);
145 } else {
146 // Get the declaration location
147 lldb::SBDeclaration decl = variable.GetDeclaration();
148 if (!decl.IsValid()) {
149 response["success"] = false;
150 response["message"] = "No declaration location available";
151 dap.SendJSON(json: llvm::json::Value(std::move(response)));
152 return;
153 }
154
155 body.try_emplace(K: "source", Args: CreateSource(file: decl.GetFileSpec()));
156 if (int line = decl.GetLine())
157 body.try_emplace(K: "line", Args&: line);
158 if (int column = decl.GetColumn())
159 body.try_emplace(K: "column", Args&: column);
160 }
161
162 response.try_emplace(K: "body", Args: std::move(body));
163 dap.SendJSON(json: llvm::json::Value(std::move(response)));
164}
165
166} // namespace lldb_dap
167

source code of lldb/tools/lldb-dap/Handler/LocationsRequestHandler.cpp