Skip to content

Commit 63c0d50

Browse files
committed
[lldb-dap] implement jump to cursor.
1 parent 3c71f71 commit 63c0d50

File tree

9 files changed

+291
-4
lines changed

9 files changed

+291
-4
lines changed

lldb/cmake/modules/LLDBConfig.cmake

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ add_optional_dependency(LLDB_ENABLE_CURSES "Enable curses support in LLDB" Curse
5757
add_optional_dependency(LLDB_ENABLE_LZMA "Enable LZMA compression support in LLDB" LibLZMA LIBLZMA_FOUND)
5858
add_optional_dependency(LLDB_ENABLE_LUA "Enable Lua scripting support in LLDB" LuaAndSwig LUAANDSWIG_FOUND)
5959
add_optional_dependency(LLDB_ENABLE_PYTHON "Enable Python scripting support in LLDB" PythonAndSwig PYTHONANDSWIG_FOUND)
60-
add_optional_dependency(LLDB_ENABLE_LIBXML2 "Enable Libxml 2 support in LLDB" LibXml2 LIBXML2_FOUND VERSION 2.8)
60+
add_optional_dependency(LLDB_ENABLE_LIBXML2 "Enable Libxml 2 support in LLDB" LibXml2 LIBXML2_FOUND VERSION)
6161
add_optional_dependency(LLDB_ENABLE_FBSDVMCORE "Enable libfbsdvmcore support in LLDB" FBSDVMCore FBSDVMCore_FOUND QUIET)
6262

6363
option(LLDB_USE_ENTITLEMENTS "When codesigning, use entitlements if available" ON)

lldb/tools/lldb-dap/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ add_lldb_tool(lldb-dap
5050
Handler/DisconnectRequestHandler.cpp
5151
Handler/EvaluateRequestHandler.cpp
5252
Handler/ExceptionInfoRequestHandler.cpp
53+
Handler/GoToRequestHandler.cpp
54+
Handler/GoToTargetsRequestHandler.cpp
5355
Handler/InitializeRequestHandler.cpp
5456
Handler/LaunchRequestHandler.cpp
5557
Handler/LocationsRequestHandler.cpp

lldb/tools/lldb-dap/DAP.cpp

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ DAP::DAP(std::string name, llvm::StringRef path, std::ofstream *log,
7676
configuration_done_sent(false), waiting_for_run_in_terminal(false),
7777
progress_event_reporter(
7878
[&](const ProgressEvent &event) { SendJSON(event.ToJSON()); }),
79-
reverse_request_seq(0), repl_mode(repl_mode) {}
79+
reverse_request_seq(0), repl_mode(repl_mode), goto_id_map() {}
8080

8181
DAP::~DAP() = default;
8282

@@ -899,6 +899,27 @@ lldb::SBError DAP::WaitForProcessToStop(uint32_t seconds) {
899899
return error;
900900
}
901901

902+
std::optional<lldb::SBLineEntry> Gotos::GetLineEntry(uint64_t id) const {
903+
const auto iter = line_entries.find(id);
904+
if (iter != line_entries.end())
905+
return iter->second;
906+
907+
return std::nullopt;
908+
}
909+
910+
uint64_t Gotos::InsertLineEntry(lldb::SBLineEntry line_entry) {
911+
const auto spec_id = this->NewSpecId();
912+
line_entries.insert(std::make_pair(spec_id, line_entry));
913+
return spec_id;
914+
}
915+
916+
void Gotos::Clear() {
917+
new_id = 0UL;
918+
line_entries.clear();
919+
}
920+
921+
uint64_t Gotos::NewSpecId() { return new_id++; }
922+
902923
void Variables::Clear() {
903924
locals.Clear();
904925
globals.Clear();

lldb/tools/lldb-dap/DAP.h

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,27 @@ enum class PacketStatus {
7979

8080
enum class ReplMode { Variable = 0, Command, Auto };
8181

82+
class Gotos {
83+
public:
84+
/// \return the line_entry corresponding with \p id
85+
///
86+
/// If \p id is invalid std::nullopt is returned.
87+
std::optional<lldb::SBLineEntry> GetLineEntry(uint64_t id) const;
88+
89+
/// Insert a new \p line_entry.
90+
/// \return id assigned to this line_entry.
91+
uint64_t InsertLineEntry(lldb::SBLineEntry line_entry);
92+
93+
/// clears all line entries and reset the generated ids.
94+
void Clear();
95+
96+
private:
97+
uint64_t NewSpecId();
98+
99+
llvm::DenseMap<uint64_t, lldb::SBLineEntry> line_entries;
100+
uint64_t new_id = 0ul;
101+
};
102+
82103
struct Variables {
83104
/// Variable_reference start index of permanent expandable variable.
84105
static constexpr int64_t PermanentVariableStartIndex = (1ll << 32);
@@ -209,6 +230,7 @@ struct DAP {
209230
// empty; if the previous expression was a variable expression, this string
210231
// will contain that expression.
211232
std::string last_nonempty_var_expression;
233+
Gotos goto_id_map;
212234

213235
DAP(std::string name, llvm::StringRef path, std::ofstream *log,
214236
lldb::IOObjectSP input, lldb::IOObjectSP output, ReplMode repl_mode,
@@ -352,7 +374,10 @@ struct DAP {
352374
}
353375

354376
/// Debuggee will continue from stopped state.
355-
void WillContinue() { variables.Clear(); }
377+
void WillContinue() {
378+
variables.Clear();
379+
goto_id_map.Clear();
380+
}
356381

357382
/// Poll the process to wait for it to reach the eStateStopped state.
358383
///
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
//===-- GoToRequestHandler.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+
13+
namespace lldb_dap {
14+
15+
// "GotoRequest": {
16+
// "allOf": [ { "$ref": "#/definitions/Request" }, {
17+
// "type": "object",
18+
// "description": "The request sets the location where the debuggee will
19+
// continue to run.\nThis makes it possible to skip the execution of code or
20+
// to execute code again.\nThe code between the current location and the
21+
// goto target is not executed but skipped.\nThe debug adapter first sends
22+
// the response and then a `stopped` event with reason `goto`.\nClients
23+
// should only call this request if the corresponding capability
24+
// `supportsGotoTargetsRequest` is true (because only then goto targets
25+
// exist that can be passed as arguments).", "properties": {
26+
// "command": {
27+
// "type": "string",
28+
// "enum": [ "goto" ]
29+
// },
30+
// "arguments": {
31+
// "$ref": "#/definitions/GotoArguments"
32+
// }
33+
// },
34+
// "required": [ "command", "arguments" ]
35+
// }]
36+
// }
37+
// "GotoArguments": {
38+
// "type": "object",
39+
// "description": "Arguments for `goto` request.",
40+
// "properties": {
41+
// "threadId": {
42+
// "type": "integer",
43+
// "description": "Set the goto target for this thread."
44+
// },
45+
// "targetId": {
46+
// "type": "integer",
47+
// "description": "The location where the debuggee will continue to run."
48+
// }
49+
// },
50+
// "required": [ "threadId", "targetId" ]
51+
// }
52+
// "GotoResponse": {
53+
// "allOf": [ { "$ref": "#/definitions/Response" }, {
54+
// "type": "object",
55+
// "description": "Response to `goto` request. This is just an
56+
// acknowledgement, so no body field is required."
57+
// }]
58+
// }
59+
void GoToRequestHandler::operator()(const llvm::json::Object &request) const {
60+
llvm::json::Object response;
61+
FillResponse(request, response);
62+
63+
auto SendError = [&](auto &&message) {
64+
response["success"] = false;
65+
response["message"] = message;
66+
dap.SendJSON(llvm::json::Value(std::move(response)));
67+
};
68+
69+
const auto *goto_arguments = request.getObject("arguments");
70+
if (goto_arguments == nullptr) {
71+
SendError("Arguments is empty");
72+
return;
73+
}
74+
75+
lldb::SBThread current_thread = dap.GetLLDBThread(*goto_arguments);
76+
if (!current_thread.IsValid()) {
77+
SendError(llvm::formatv("Thread id `{0}` is not valid",
78+
current_thread.GetThreadID()));
79+
return;
80+
}
81+
82+
const auto target_id = GetInteger<uint64_t>(goto_arguments, "targetId");
83+
const auto line_entry = dap.goto_id_map.GetLineEntry(target_id.value());
84+
if (!target_id || !line_entry) {
85+
SendError(llvm::formatv("Target id `{0}` is not valid",
86+
current_thread.GetThreadID()));
87+
return;
88+
}
89+
90+
auto file_spec = line_entry->GetFileSpec();
91+
const auto error =
92+
current_thread.JumpToLine(file_spec, line_entry->GetLine());
93+
if (error.Fail()) {
94+
SendError(error.GetCString());
95+
return;
96+
}
97+
98+
dap.SendJSON(llvm::json::Value(std::move(response)));
99+
100+
SendThreadStoppedEvent(dap);
101+
}
102+
103+
} // namespace lldb_dap
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
//===-- GoToTargetsRequestHandler.cpp
2+
//--------------------------------------===//
3+
//
4+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5+
// See https://llvm.org/LICENSE.txt for license information.
6+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
#include "DAP.h"
11+
12+
#include "JSONUtils.h"
13+
14+
#include <lldb/API/SBStream.h>
15+
16+
namespace lldb_dap {
17+
18+
// "GotoTargetsRequest": {
19+
// "allOf": [ { "$ref": "#/definitions/Request" }, {
20+
// "type": "object",
21+
// "description": "This request retrieves the possible goto targets for the
22+
// specified source location.\nThese targets can be used in the `goto`
23+
// request.\nClients should only call this request if the corresponding
24+
// capability `supportsGotoTargetsRequest` is true.", "properties": {
25+
// "command": {
26+
// "type": "string",
27+
// "enum": [ "gotoTargets" ]
28+
// },
29+
// "arguments": {
30+
// "$ref": "#/definitions/GotoTargetsArguments"
31+
// }
32+
// },
33+
// "required": [ "command", "arguments" ]
34+
// }]
35+
// },
36+
// "GotoTargetsArguments": {
37+
// "type": "object",
38+
// "description": "Arguments for `gotoTargets` request.",
39+
// "properties": {
40+
// "source": {
41+
// "$ref": "#/definitions/Source",
42+
// "description": "The source location for which the goto targets are
43+
// determined."
44+
// },
45+
// "line": {
46+
// "type": "integer",
47+
// "description": "The line location for which the goto targets are
48+
// determined."
49+
// },
50+
// "column": {
51+
// "type": "integer",
52+
// "description": "The position within `line` for which the goto targets
53+
// are determined. It is measured in UTF-16 code units and the client
54+
// capability `columnsStartAt1` determines whether it is 0- or 1-based."
55+
// }
56+
// },
57+
// "required": [ "source", "line" ]
58+
// },
59+
// "GotoTargetsResponse": {
60+
// "allOf": [ { "$ref": "#/definitions/Response" }, {
61+
// "type": "object",
62+
// "description": "Response to `gotoTargets` request.",
63+
// "properties": {
64+
// "body": {
65+
// "type": "object",
66+
// "properties": {
67+
// "targets": {
68+
// "type": "array",
69+
// "items": {
70+
// "$ref": "#/definitions/GotoTarget"
71+
// },
72+
// "description": "The possible goto targets of the specified
73+
// location."
74+
// }
75+
// },
76+
// "required": [ "targets" ]
77+
// }
78+
// },
79+
// "required": [ "body" ]
80+
// }]
81+
// },
82+
void GoToTargetsRequestHandler::operator()(
83+
const llvm::json::Object &request) const {
84+
llvm::json::Object response;
85+
FillResponse(request, response);
86+
const auto *arguments = request.getObject("arguments");
87+
const auto *source = arguments->getObject("source");
88+
const std::string path = GetString(source, "path").str();
89+
90+
const auto goto_line = GetInteger<uint64_t>(arguments, "line").value_or(0u);
91+
const auto goto_column =
92+
GetInteger<uint64_t>(arguments, "column").value_or(0u);
93+
94+
lldb::SBLineEntry line_entry{};
95+
const lldb::SBFileSpec file_spec(path.c_str(), true);
96+
line_entry.SetFileSpec(file_spec);
97+
line_entry.SetLine(goto_line);
98+
line_entry.SetColumn(goto_column);
99+
100+
const auto target_id = dap.goto_id_map.InsertLineEntry(line_entry);
101+
llvm::json::Array response_targets;
102+
const auto target_line = line_entry.GetLine();
103+
const auto target_column = line_entry.GetColumn();
104+
auto target = llvm::json::Object();
105+
target.try_emplace("id", target_id);
106+
107+
lldb::SBStream stream;
108+
line_entry.GetDescription(stream);
109+
target.try_emplace("label",
110+
llvm::StringRef(stream.GetData(), stream.GetSize()));
111+
target.try_emplace("column", target_column);
112+
target.try_emplace("line", target_line);
113+
114+
response_targets.push_back(std::move(target));
115+
llvm::json::Object body;
116+
body.try_emplace("targets", std::move(response_targets));
117+
response.try_emplace("body", std::move(body));
118+
dap.SendJSON(llvm::json::Value(std::move(response)));
119+
}
120+
} // namespace lldb_dap

lldb/tools/lldb-dap/Handler/InitializeRequestHandler.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -406,7 +406,7 @@ void InitializeRequestHandler::operator()(
406406
// The debug adapter supports restarting a frame.
407407
body.try_emplace("supportsRestartFrame", false);
408408
// The debug adapter supports the gotoTargetsRequest.
409-
body.try_emplace("supportsGotoTargetsRequest", false);
409+
body.try_emplace("supportsGotoTargetsRequest", true);
410410
// The debug adapter supports the stepInTargetsRequest.
411411
body.try_emplace("supportsStepInTargetsRequest", true);
412412
// The debug adapter supports the completions request.

lldb/tools/lldb-dap/Handler/RequestHandler.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,20 @@ class ExceptionInfoRequestHandler : public RequestHandler {
113113
void operator()(const llvm::json::Object &request) const override;
114114
};
115115

116+
class GoToRequestHandler : public RequestHandler {
117+
public:
118+
using RequestHandler::RequestHandler;
119+
static llvm::StringLiteral getCommand() { return "goto"; }
120+
void operator()(const llvm::json::Object &request) const override;
121+
};
122+
123+
class GoToTargetsRequestHandler : public RequestHandler {
124+
public:
125+
using RequestHandler::RequestHandler;
126+
static llvm::StringLiteral getCommand() { return "gotoTargets"; }
127+
void operator()(const llvm::json::Object &request) const override;
128+
};
129+
116130
class InitializeRequestHandler : public RequestHandler {
117131
public:
118132
using RequestHandler::RequestHandler;

lldb/tools/lldb-dap/lldb-dap.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,8 @@ static void RegisterRequestCallbacks(DAP &dap) {
124124
dap.RegisterRequest<EvaluateRequestHandler>();
125125
dap.RegisterRequest<ExceptionInfoRequestHandler>();
126126
dap.RegisterRequest<InitializeRequestHandler>();
127+
dap.RegisterRequest<GoToRequestHandler>();
128+
dap.RegisterRequest<GoToTargetsRequestHandler>();
127129
dap.RegisterRequest<LaunchRequestHandler>();
128130
dap.RegisterRequest<LocationsRequestHandler>();
129131
dap.RegisterRequest<NextRequestHandler>();

0 commit comments

Comments
 (0)