Skip to content

Commit 82264d2

Browse files
authored
[lldb-dap] Refactor stepping related request handlers (NFC) (#128453)
Continuation of the work started in #128262.
1 parent 4c9e14b commit 82264d2

File tree

8 files changed

+440
-340
lines changed

8 files changed

+440
-340
lines changed

lldb/tools/lldb-dap/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,12 @@ add_lldb_tool(lldb-dap
4747
Handler/ExceptionInfoRequestHandler.cpp
4848
Handler/InitializeRequestHandler.cpp
4949
Handler/LaunchRequestHandler.cpp
50+
Handler/NextRequestHandler.cpp
5051
Handler/RequestHandler.cpp
5152
Handler/RestartRequestHandler.cpp
53+
Handler/StepInRequestHandler.cpp
54+
Handler/StepInTargetsRequestHandler.cpp
55+
Handler/StepOutRequestHandler.cpp
5256

5357
LINK_LIBS
5458
liblldb
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
//===-- NextRequestHandler.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 "RequestHandler.h"
13+
14+
namespace lldb_dap {
15+
16+
// "NextRequest": {
17+
// "allOf": [ { "$ref": "#/definitions/Request" }, {
18+
// "type": "object",
19+
// "description": "Next request; value of command field is 'next'. The
20+
// request starts the debuggee to run again for one step.
21+
// The debug adapter first sends the NextResponse and then
22+
// a StoppedEvent (event type 'step') after the step has
23+
// completed.",
24+
// "properties": {
25+
// "command": {
26+
// "type": "string",
27+
// "enum": [ "next" ]
28+
// },
29+
// "arguments": {
30+
// "$ref": "#/definitions/NextArguments"
31+
// }
32+
// },
33+
// "required": [ "command", "arguments" ]
34+
// }]
35+
// },
36+
// "NextArguments": {
37+
// "type": "object",
38+
// "description": "Arguments for 'next' request.",
39+
// "properties": {
40+
// "threadId": {
41+
// "type": "integer",
42+
// "description": "Execute 'next' for this thread."
43+
// },
44+
// "granularity": {
45+
// "$ref": "#/definitions/SteppingGranularity",
46+
// "description": "Stepping granularity. If no granularity is specified, a
47+
// granularity of `statement` is assumed."
48+
// }
49+
// },
50+
// "required": [ "threadId" ]
51+
// },
52+
// "NextResponse": {
53+
// "allOf": [ { "$ref": "#/definitions/Response" }, {
54+
// "type": "object",
55+
// "description": "Response to 'next' request. This is just an
56+
// acknowledgement, so no body field is required."
57+
// }]
58+
// }
59+
void NextRequestHandler::operator()(const llvm::json::Object &request) {
60+
llvm::json::Object response;
61+
FillResponse(request, response);
62+
const auto *arguments = request.getObject("arguments");
63+
lldb::SBThread thread = dap.GetLLDBThread(*arguments);
64+
if (thread.IsValid()) {
65+
// Remember the thread ID that caused the resume so we can set the
66+
// "threadCausedFocus" boolean value in the "stopped" events.
67+
dap.focus_tid = thread.GetThreadID();
68+
if (HasInstructionGranularity(*arguments)) {
69+
thread.StepInstruction(/*step_over=*/true);
70+
} else {
71+
thread.StepOver();
72+
}
73+
} else {
74+
response["success"] = llvm::json::Value(false);
75+
}
76+
dap.SendJSON(llvm::json::Value(std::move(response)));
77+
}
78+
79+
} // namespace lldb_dap

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,4 +225,11 @@ void RequestHandler::PrintWelcomeMessage() {
225225
#endif
226226
}
227227

228+
bool RequestHandler::HasInstructionGranularity(
229+
const llvm::json::Object &arguments) {
230+
if (std::optional<llvm::StringRef> value = arguments.getString("granularity"))
231+
return value == "instruction";
232+
return false;
233+
}
234+
228235
} // namespace lldb_dap

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

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ class RequestHandler {
3030

3131
virtual void operator()(const llvm::json::Object &request) = 0;
3232

33+
protected:
3334
/// Helpers used by multiple request handlers.
3435
/// FIXME: Move these into the DAP class?
3536
/// @{
@@ -48,9 +49,11 @@ class RequestHandler {
4849
// This way we can reuse the process launching logic for RestartRequest too.
4950
lldb::SBError LaunchProcess(const llvm::json::Object &request);
5051

52+
// Check if the step-granularity is `instruction`.
53+
bool HasInstructionGranularity(const llvm::json::Object &request);
54+
5155
/// @}
5256

53-
protected:
5457
DAP &dap;
5558
};
5659

@@ -131,6 +134,34 @@ class RestartRequestHandler : public RequestHandler {
131134
void operator()(const llvm::json::Object &request) override;
132135
};
133136

137+
class NextRequestHandler : public RequestHandler {
138+
public:
139+
using RequestHandler::RequestHandler;
140+
static llvm::StringLiteral getCommand() { return "next"; }
141+
void operator()(const llvm::json::Object &request) override;
142+
};
143+
144+
class StepInRequestHandler : public RequestHandler {
145+
public:
146+
using RequestHandler::RequestHandler;
147+
static llvm::StringLiteral getCommand() { return "stepIn"; }
148+
void operator()(const llvm::json::Object &request) override;
149+
};
150+
151+
class StepInTargetsRequestHandler : public RequestHandler {
152+
public:
153+
using RequestHandler::RequestHandler;
154+
static llvm::StringLiteral getCommand() { return "stepInTargets"; }
155+
void operator()(const llvm::json::Object &request) override;
156+
};
157+
158+
class StepOutRequestHandler : public RequestHandler {
159+
public:
160+
using RequestHandler::RequestHandler;
161+
static llvm::StringLiteral getCommand() { return "stepOut"; }
162+
void operator()(const llvm::json::Object &request) override;
163+
};
164+
134165
} // namespace lldb_dap
135166

136167
#endif
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
//===-- StepInRequestHandler.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 "RequestHandler.h"
13+
14+
namespace lldb_dap {
15+
16+
// "StepInRequest": {
17+
// "allOf": [ { "$ref": "#/definitions/Request" }, {
18+
// "type": "object",
19+
// "description": "StepIn request; value of command field is 'stepIn'. The
20+
// request starts the debuggee to step into a function/method if possible.
21+
// If it cannot step into a target, 'stepIn' behaves like 'next'. The debug
22+
// adapter first sends the StepInResponse and then a StoppedEvent (event
23+
// type 'step') after the step has completed. If there are multiple
24+
// function/method calls (or other targets) on the source line, the optional
25+
// argument 'targetId' can be used to control into which target the 'stepIn'
26+
// should occur. The list of possible targets for a given source line can be
27+
// retrieved via the 'stepInTargets' request.", "properties": {
28+
// "command": {
29+
// "type": "string",
30+
// "enum": [ "stepIn" ]
31+
// },
32+
// "arguments": {
33+
// "$ref": "#/definitions/StepInArguments"
34+
// }
35+
// },
36+
// "required": [ "command", "arguments" ]
37+
// }]
38+
// },
39+
// "StepInArguments": {
40+
// "type": "object",
41+
// "description": "Arguments for 'stepIn' request.",
42+
// "properties": {
43+
// "threadId": {
44+
// "type": "integer",
45+
// "description": "Execute 'stepIn' for this thread."
46+
// },
47+
// "targetId": {
48+
// "type": "integer",
49+
// "description": "Optional id of the target to step into."
50+
// },
51+
// "granularity": {
52+
// "$ref": "#/definitions/SteppingGranularity",
53+
// "description": "Stepping granularity. If no granularity is specified, a
54+
// granularity of `statement` is assumed."
55+
// }
56+
// },
57+
// "required": [ "threadId" ]
58+
// },
59+
// "StepInResponse": {
60+
// "allOf": [ { "$ref": "#/definitions/Response" }, {
61+
// "type": "object",
62+
// "description": "Response to 'stepIn' request. This is just an
63+
// acknowledgement, so no body field is required."
64+
// }]
65+
// }
66+
void StepInRequestHandler::operator()(const llvm::json::Object &request) {
67+
llvm::json::Object response;
68+
FillResponse(request, response);
69+
const auto *arguments = request.getObject("arguments");
70+
71+
std::string step_in_target;
72+
uint64_t target_id = GetUnsigned(arguments, "targetId", 0);
73+
auto it = dap.step_in_targets.find(target_id);
74+
if (it != dap.step_in_targets.end())
75+
step_in_target = it->second;
76+
77+
const bool single_thread = GetBoolean(arguments, "singleThread", false);
78+
lldb::RunMode run_mode =
79+
single_thread ? lldb::eOnlyThisThread : lldb::eOnlyDuringStepping;
80+
lldb::SBThread thread = dap.GetLLDBThread(*arguments);
81+
if (thread.IsValid()) {
82+
// Remember the thread ID that caused the resume so we can set the
83+
// "threadCausedFocus" boolean value in the "stopped" events.
84+
dap.focus_tid = thread.GetThreadID();
85+
if (HasInstructionGranularity(*arguments)) {
86+
thread.StepInstruction(/*step_over=*/false);
87+
} else {
88+
thread.StepInto(step_in_target.c_str(), run_mode);
89+
}
90+
} else {
91+
response["success"] = llvm::json::Value(false);
92+
}
93+
dap.SendJSON(llvm::json::Value(std::move(response)));
94+
}
95+
96+
} // namespace lldb_dap

0 commit comments

Comments
 (0)