[Lldb-commits] [lldb] 82264d2 - [lldb-dap] Refactor stepping related request handlers (NFC) (#128453)
via lldb-commits
lldb-commits at lists.llvm.org
Mon Feb 24 11:50:15 PST 2025
Author: Jonas Devlieghere
Date: 2025-02-24T13:50:11-06:00
New Revision: 82264d23a1cc2ad9334f9a277cb92043a8bac446
URL: https://github.com/llvm/llvm-project/commit/82264d23a1cc2ad9334f9a277cb92043a8bac446
DIFF: https://github.com/llvm/llvm-project/commit/82264d23a1cc2ad9334f9a277cb92043a8bac446.diff
LOG: [lldb-dap] Refactor stepping related request handlers (NFC) (#128453)
Continuation of the work started in #128262.
Added:
lldb/tools/lldb-dap/Handler/NextRequestHandler.cpp
lldb/tools/lldb-dap/Handler/StepInRequestHandler.cpp
lldb/tools/lldb-dap/Handler/StepInTargetsRequestHandler.cpp
lldb/tools/lldb-dap/Handler/StepOutRequestHandler.cpp
Modified:
lldb/tools/lldb-dap/CMakeLists.txt
lldb/tools/lldb-dap/Handler/RequestHandler.cpp
lldb/tools/lldb-dap/Handler/RequestHandler.h
lldb/tools/lldb-dap/lldb-dap.cpp
Removed:
################################################################################
diff --git a/lldb/tools/lldb-dap/CMakeLists.txt b/lldb/tools/lldb-dap/CMakeLists.txt
index 73762af5c2fd7..61271e1a9f2a6 100644
--- a/lldb/tools/lldb-dap/CMakeLists.txt
+++ b/lldb/tools/lldb-dap/CMakeLists.txt
@@ -47,8 +47,12 @@ add_lldb_tool(lldb-dap
Handler/ExceptionInfoRequestHandler.cpp
Handler/InitializeRequestHandler.cpp
Handler/LaunchRequestHandler.cpp
+ Handler/NextRequestHandler.cpp
Handler/RequestHandler.cpp
Handler/RestartRequestHandler.cpp
+ Handler/StepInRequestHandler.cpp
+ Handler/StepInTargetsRequestHandler.cpp
+ Handler/StepOutRequestHandler.cpp
LINK_LIBS
liblldb
diff --git a/lldb/tools/lldb-dap/Handler/NextRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/NextRequestHandler.cpp
new file mode 100644
index 0000000000000..695703fe301b3
--- /dev/null
+++ b/lldb/tools/lldb-dap/Handler/NextRequestHandler.cpp
@@ -0,0 +1,79 @@
+//===-- NextRequestHandler.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 "RequestHandler.h"
+
+namespace lldb_dap {
+
+// "NextRequest": {
+// "allOf": [ { "$ref": "#/definitions/Request" }, {
+// "type": "object",
+// "description": "Next request; value of command field is 'next'. The
+// request starts the debuggee to run again for one step.
+// The debug adapter first sends the NextResponse and then
+// a StoppedEvent (event type 'step') after the step has
+// completed.",
+// "properties": {
+// "command": {
+// "type": "string",
+// "enum": [ "next" ]
+// },
+// "arguments": {
+// "$ref": "#/definitions/NextArguments"
+// }
+// },
+// "required": [ "command", "arguments" ]
+// }]
+// },
+// "NextArguments": {
+// "type": "object",
+// "description": "Arguments for 'next' request.",
+// "properties": {
+// "threadId": {
+// "type": "integer",
+// "description": "Execute 'next' for this thread."
+// },
+// "granularity": {
+// "$ref": "#/definitions/SteppingGranularity",
+// "description": "Stepping granularity. If no granularity is specified, a
+// granularity of `statement` is assumed."
+// }
+// },
+// "required": [ "threadId" ]
+// },
+// "NextResponse": {
+// "allOf": [ { "$ref": "#/definitions/Response" }, {
+// "type": "object",
+// "description": "Response to 'next' request. This is just an
+// acknowledgement, so no body field is required."
+// }]
+// }
+void NextRequestHandler::operator()(const llvm::json::Object &request) {
+ llvm::json::Object response;
+ FillResponse(request, response);
+ const auto *arguments = request.getObject("arguments");
+ lldb::SBThread thread = dap.GetLLDBThread(*arguments);
+ if (thread.IsValid()) {
+ // Remember the thread ID that caused the resume so we can set the
+ // "threadCausedFocus" boolean value in the "stopped" events.
+ dap.focus_tid = thread.GetThreadID();
+ if (HasInstructionGranularity(*arguments)) {
+ thread.StepInstruction(/*step_over=*/true);
+ } else {
+ thread.StepOver();
+ }
+ } else {
+ response["success"] = llvm::json::Value(false);
+ }
+ dap.SendJSON(llvm::json::Value(std::move(response)));
+}
+
+} // namespace lldb_dap
diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.cpp b/lldb/tools/lldb-dap/Handler/RequestHandler.cpp
index c09ddf55dd5e9..f9502e09846d4 100644
--- a/lldb/tools/lldb-dap/Handler/RequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/RequestHandler.cpp
@@ -225,4 +225,11 @@ void RequestHandler::PrintWelcomeMessage() {
#endif
}
+bool RequestHandler::HasInstructionGranularity(
+ const llvm::json::Object &arguments) {
+ if (std::optional<llvm::StringRef> value = arguments.getString("granularity"))
+ return value == "instruction";
+ return false;
+}
+
} // namespace lldb_dap
diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h
index 9bc8e60dbb858..2610a3d21ebc4 100644
--- a/lldb/tools/lldb-dap/Handler/RequestHandler.h
+++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h
@@ -30,6 +30,7 @@ class RequestHandler {
virtual void operator()(const llvm::json::Object &request) = 0;
+protected:
/// Helpers used by multiple request handlers.
/// FIXME: Move these into the DAP class?
/// @{
@@ -48,9 +49,11 @@ class RequestHandler {
// This way we can reuse the process launching logic for RestartRequest too.
lldb::SBError LaunchProcess(const llvm::json::Object &request);
+ // Check if the step-granularity is `instruction`.
+ bool HasInstructionGranularity(const llvm::json::Object &request);
+
/// @}
-protected:
DAP &dap;
};
@@ -131,6 +134,34 @@ class RestartRequestHandler : public RequestHandler {
void operator()(const llvm::json::Object &request) override;
};
+class NextRequestHandler : public RequestHandler {
+public:
+ using RequestHandler::RequestHandler;
+ static llvm::StringLiteral getCommand() { return "next"; }
+ void operator()(const llvm::json::Object &request) override;
+};
+
+class StepInRequestHandler : public RequestHandler {
+public:
+ using RequestHandler::RequestHandler;
+ static llvm::StringLiteral getCommand() { return "stepIn"; }
+ void operator()(const llvm::json::Object &request) override;
+};
+
+class StepInTargetsRequestHandler : public RequestHandler {
+public:
+ using RequestHandler::RequestHandler;
+ static llvm::StringLiteral getCommand() { return "stepInTargets"; }
+ void operator()(const llvm::json::Object &request) override;
+};
+
+class StepOutRequestHandler : public RequestHandler {
+public:
+ using RequestHandler::RequestHandler;
+ static llvm::StringLiteral getCommand() { return "stepOut"; }
+ void operator()(const llvm::json::Object &request) override;
+};
+
} // namespace lldb_dap
#endif
diff --git a/lldb/tools/lldb-dap/Handler/StepInRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/StepInRequestHandler.cpp
new file mode 100644
index 0000000000000..f435436734538
--- /dev/null
+++ b/lldb/tools/lldb-dap/Handler/StepInRequestHandler.cpp
@@ -0,0 +1,96 @@
+//===-- StepInRequestHandler.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 "RequestHandler.h"
+
+namespace lldb_dap {
+
+// "StepInRequest": {
+// "allOf": [ { "$ref": "#/definitions/Request" }, {
+// "type": "object",
+// "description": "StepIn request; value of command field is 'stepIn'. The
+// request starts the debuggee to step into a function/method if possible.
+// If it cannot step into a target, 'stepIn' behaves like 'next'. The debug
+// adapter first sends the StepInResponse and then a StoppedEvent (event
+// type 'step') after the step has completed. If there are multiple
+// function/method calls (or other targets) on the source line, the optional
+// argument 'targetId' can be used to control into which target the 'stepIn'
+// should occur. The list of possible targets for a given source line can be
+// retrieved via the 'stepInTargets' request.", "properties": {
+// "command": {
+// "type": "string",
+// "enum": [ "stepIn" ]
+// },
+// "arguments": {
+// "$ref": "#/definitions/StepInArguments"
+// }
+// },
+// "required": [ "command", "arguments" ]
+// }]
+// },
+// "StepInArguments": {
+// "type": "object",
+// "description": "Arguments for 'stepIn' request.",
+// "properties": {
+// "threadId": {
+// "type": "integer",
+// "description": "Execute 'stepIn' for this thread."
+// },
+// "targetId": {
+// "type": "integer",
+// "description": "Optional id of the target to step into."
+// },
+// "granularity": {
+// "$ref": "#/definitions/SteppingGranularity",
+// "description": "Stepping granularity. If no granularity is specified, a
+// granularity of `statement` is assumed."
+// }
+// },
+// "required": [ "threadId" ]
+// },
+// "StepInResponse": {
+// "allOf": [ { "$ref": "#/definitions/Response" }, {
+// "type": "object",
+// "description": "Response to 'stepIn' request. This is just an
+// acknowledgement, so no body field is required."
+// }]
+// }
+void StepInRequestHandler::operator()(const llvm::json::Object &request) {
+ llvm::json::Object response;
+ FillResponse(request, response);
+ const auto *arguments = request.getObject("arguments");
+
+ std::string step_in_target;
+ uint64_t target_id = GetUnsigned(arguments, "targetId", 0);
+ auto it = dap.step_in_targets.find(target_id);
+ if (it != dap.step_in_targets.end())
+ step_in_target = it->second;
+
+ const bool single_thread = GetBoolean(arguments, "singleThread", false);
+ lldb::RunMode run_mode =
+ single_thread ? lldb::eOnlyThisThread : lldb::eOnlyDuringStepping;
+ lldb::SBThread thread = dap.GetLLDBThread(*arguments);
+ if (thread.IsValid()) {
+ // Remember the thread ID that caused the resume so we can set the
+ // "threadCausedFocus" boolean value in the "stopped" events.
+ dap.focus_tid = thread.GetThreadID();
+ if (HasInstructionGranularity(*arguments)) {
+ thread.StepInstruction(/*step_over=*/false);
+ } else {
+ thread.StepInto(step_in_target.c_str(), run_mode);
+ }
+ } else {
+ response["success"] = llvm::json::Value(false);
+ }
+ dap.SendJSON(llvm::json::Value(std::move(response)));
+}
+
+} // namespace lldb_dap
diff --git a/lldb/tools/lldb-dap/Handler/StepInTargetsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/StepInTargetsRequestHandler.cpp
new file mode 100644
index 0000000000000..e771780711ae9
--- /dev/null
+++ b/lldb/tools/lldb-dap/Handler/StepInTargetsRequestHandler.cpp
@@ -0,0 +1,149 @@
+//===-- StepInTargetsRequestHandler.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 "RequestHandler.h"
+#include "lldb/API/SBInstruction.h"
+
+namespace lldb_dap {
+
+// "StepInTargetsRequest": {
+// "allOf": [ { "$ref": "#/definitions/Request" }, {
+// "type": "object",
+// "description": "This request retrieves the possible step-in targets for
+// the specified stack frame.\nThese targets can be used in the `stepIn`
+// request.\nClients should only call this request if the corresponding
+// capability `supportsStepInTargetsRequest` is true.", "properties": {
+// "command": {
+// "type": "string",
+// "enum": [ "stepInTargets" ]
+// },
+// "arguments": {
+// "$ref": "#/definitions/StepInTargetsArguments"
+// }
+// },
+// "required": [ "command", "arguments" ]
+// }]
+// },
+// "StepInTargetsArguments": {
+// "type": "object",
+// "description": "Arguments for `stepInTargets` request.",
+// "properties": {
+// "frameId": {
+// "type": "integer",
+// "description": "The stack frame for which to retrieve the possible
+// step-in targets."
+// }
+// },
+// "required": [ "frameId" ]
+// },
+// "StepInTargetsResponse": {
+// "allOf": [ { "$ref": "#/definitions/Response" }, {
+// "type": "object",
+// "description": "Response to `stepInTargets` request.",
+// "properties": {
+// "body": {
+// "type": "object",
+// "properties": {
+// "targets": {
+// "type": "array",
+// "items": {
+// "$ref": "#/definitions/StepInTarget"
+// },
+// "description": "The possible step-in targets of the specified
+// source location."
+// }
+// },
+// "required": [ "targets" ]
+// }
+// },
+// "required": [ "body" ]
+// }]
+// }
+void StepInTargetsRequestHandler::operator()(
+ const llvm::json::Object &request) {
+ llvm::json::Object response;
+ FillResponse(request, response);
+ const auto *arguments = request.getObject("arguments");
+
+ dap.step_in_targets.clear();
+ lldb::SBFrame frame = dap.GetLLDBFrame(*arguments);
+ if (frame.IsValid()) {
+ lldb::SBAddress pc_addr = frame.GetPCAddress();
+ lldb::SBAddress line_end_addr =
+ pc_addr.GetLineEntry().GetSameLineContiguousAddressRangeEnd(true);
+ lldb::SBInstructionList insts = dap.target.ReadInstructions(
+ pc_addr, line_end_addr, /*flavor_string=*/nullptr);
+
+ if (!insts.IsValid()) {
+ response["success"] = false;
+ response["message"] = "Failed to get instructions for frame.";
+ dap.SendJSON(llvm::json::Value(std::move(response)));
+ return;
+ }
+
+ llvm::json::Array step_in_targets;
+ const auto num_insts = insts.GetSize();
+ for (size_t i = 0; i < num_insts; ++i) {
+ lldb::SBInstruction inst = insts.GetInstructionAtIndex(i);
+ if (!inst.IsValid())
+ break;
+
+ lldb::addr_t inst_addr = inst.GetAddress().GetLoadAddress(dap.target);
+
+ // Note: currently only x86/x64 supports flow kind.
+ lldb::InstructionControlFlowKind flow_kind =
+ inst.GetControlFlowKind(dap.target);
+ if (flow_kind == lldb::eInstructionControlFlowKindCall) {
+ // Use call site instruction address as id which is easy to debug.
+ llvm::json::Object step_in_target;
+ step_in_target["id"] = inst_addr;
+
+ llvm::StringRef call_operand_name = inst.GetOperands(dap.target);
+ lldb::addr_t call_target_addr;
+ if (call_operand_name.getAsInteger(0, call_target_addr))
+ continue;
+
+ lldb::SBAddress call_target_load_addr =
+ dap.target.ResolveLoadAddress(call_target_addr);
+ if (!call_target_load_addr.IsValid())
+ continue;
+
+ // The existing ThreadPlanStepInRange only accept step in target
+ // function with debug info.
+ lldb::SBSymbolContext sc = dap.target.ResolveSymbolContextForAddress(
+ call_target_load_addr, lldb::eSymbolContextFunction);
+
+ // The existing ThreadPlanStepInRange only accept step in target
+ // function with debug info.
+ std::string step_in_target_name;
+ if (sc.IsValid() && sc.GetFunction().IsValid())
+ step_in_target_name = sc.GetFunction().GetDisplayName();
+
+ // Skip call sites if we fail to resolve its symbol name.
+ if (step_in_target_name.empty())
+ continue;
+
+ dap.step_in_targets.try_emplace(inst_addr, step_in_target_name);
+ step_in_target.try_emplace("label", step_in_target_name);
+ step_in_targets.emplace_back(std::move(step_in_target));
+ }
+ }
+ llvm::json::Object body;
+ body.try_emplace("targets", std::move(step_in_targets));
+ response.try_emplace("body", std::move(body));
+ } else {
+ response["success"] = llvm::json::Value(false);
+ response["message"] = "Failed to get frame for input frameId.";
+ }
+ dap.SendJSON(llvm::json::Value(std::move(response)));
+}
+
+} // namespace lldb_dap
diff --git a/lldb/tools/lldb-dap/Handler/StepOutRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/StepOutRequestHandler.cpp
new file mode 100644
index 0000000000000..d71547d579f1f
--- /dev/null
+++ b/lldb/tools/lldb-dap/Handler/StepOutRequestHandler.cpp
@@ -0,0 +1,68 @@
+//===-- StepOutRequestHandler.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 "RequestHandler.h"
+
+namespace lldb_dap {
+
+// "StepOutRequest": {
+// "allOf": [ { "$ref": "#/definitions/Request" }, {
+// "type": "object",
+// "description": "StepOut request; value of command field is 'stepOut'. The
+// request starts the debuggee to run again for one step. The debug adapter
+// first sends the StepOutResponse and then a StoppedEvent (event type
+// 'step') after the step has completed.", "properties": {
+// "command": {
+// "type": "string",
+// "enum": [ "stepOut" ]
+// },
+// "arguments": {
+// "$ref": "#/definitions/StepOutArguments"
+// }
+// },
+// "required": [ "command", "arguments" ]
+// }]
+// },
+// "StepOutArguments": {
+// "type": "object",
+// "description": "Arguments for 'stepOut' request.",
+// "properties": {
+// "threadId": {
+// "type": "integer",
+// "description": "Execute 'stepOut' for this thread."
+// }
+// },
+// "required": [ "threadId" ]
+// },
+// "StepOutResponse": {
+// "allOf": [ { "$ref": "#/definitions/Response" }, {
+// "type": "object",
+// "description": "Response to 'stepOut' request. This is just an
+// acknowledgement, so no body field is required."
+// }]
+// }
+void StepOutRequestHandler::operator()(const llvm::json::Object &request) {
+ llvm::json::Object response;
+ FillResponse(request, response);
+ const auto *arguments = request.getObject("arguments");
+ lldb::SBThread thread = dap.GetLLDBThread(*arguments);
+ if (thread.IsValid()) {
+ // Remember the thread ID that caused the resume so we can set the
+ // "threadCausedFocus" boolean value in the "stopped" events.
+ dap.focus_tid = thread.GetThreadID();
+ thread.StepOut();
+ } else {
+ response["success"] = llvm::json::Value(false);
+ }
+ dap.SendJSON(llvm::json::Value(std::move(response)));
+}
+
+} // namespace lldb_dap
diff --git a/lldb/tools/lldb-dap/lldb-dap.cpp b/lldb/tools/lldb-dap/lldb-dap.cpp
index 7935e88dba71a..22fff86066659 100644
--- a/lldb/tools/lldb-dap/lldb-dap.cpp
+++ b/lldb/tools/lldb-dap/lldb-dap.cpp
@@ -367,77 +367,6 @@ void request_modules(DAP &dap, const llvm::json::Object &request) {
dap.SendJSON(llvm::json::Value(std::move(response)));
}
-// Check if the step-granularity is `instruction`
-static bool hasInstructionGranularity(const llvm::json::Object &requestArgs) {
- if (std::optional<llvm::StringRef> value =
- requestArgs.getString("granularity"))
- return value == "instruction";
- return false;
-}
-
-// "NextRequest": {
-// "allOf": [ { "$ref": "#/definitions/Request" }, {
-// "type": "object",
-// "description": "Next request; value of command field is 'next'. The
-// request starts the debuggee to run again for one step.
-// The debug adapter first sends the NextResponse and then
-// a StoppedEvent (event type 'step') after the step has
-// completed.",
-// "properties": {
-// "command": {
-// "type": "string",
-// "enum": [ "next" ]
-// },
-// "arguments": {
-// "$ref": "#/definitions/NextArguments"
-// }
-// },
-// "required": [ "command", "arguments" ]
-// }]
-// },
-// "NextArguments": {
-// "type": "object",
-// "description": "Arguments for 'next' request.",
-// "properties": {
-// "threadId": {
-// "type": "integer",
-// "description": "Execute 'next' for this thread."
-// },
-// "granularity": {
-// "$ref": "#/definitions/SteppingGranularity",
-// "description": "Stepping granularity. If no granularity is specified, a
-// granularity of `statement` is assumed."
-// }
-// },
-// "required": [ "threadId" ]
-// },
-// "NextResponse": {
-// "allOf": [ { "$ref": "#/definitions/Response" }, {
-// "type": "object",
-// "description": "Response to 'next' request. This is just an
-// acknowledgement, so no body field is required."
-// }]
-// }
-void request_next(DAP &dap, const llvm::json::Object &request) {
- llvm::json::Object response;
- FillResponse(request, response);
- const auto *arguments = request.getObject("arguments");
- lldb::SBThread thread = dap.GetLLDBThread(*arguments);
- if (thread.IsValid()) {
- // Remember the thread ID that caused the resume so we can set the
- // "threadCausedFocus" boolean value in the "stopped" events.
- dap.focus_tid = thread.GetThreadID();
- if (hasInstructionGranularity(*arguments)) {
- thread.StepInstruction(/*step_over=*/true);
- } else {
- thread.StepOver();
- }
- } else {
- response["success"] = llvm::json::Value(false);
- }
- dap.SendJSON(llvm::json::Value(std::move(response)));
-}
-
// "PauseRequest": {
// "allOf": [ { "$ref": "#/definitions/Request" }, {
// "type": "object",
@@ -1372,269 +1301,6 @@ void request_stackTrace(DAP &dap, const llvm::json::Object &request) {
dap.SendJSON(llvm::json::Value(std::move(response)));
}
-// "StepInRequest": {
-// "allOf": [ { "$ref": "#/definitions/Request" }, {
-// "type": "object",
-// "description": "StepIn request; value of command field is 'stepIn'. The
-// request starts the debuggee to step into a function/method if possible.
-// If it cannot step into a target, 'stepIn' behaves like 'next'. The debug
-// adapter first sends the StepInResponse and then a StoppedEvent (event
-// type 'step') after the step has completed. If there are multiple
-// function/method calls (or other targets) on the source line, the optional
-// argument 'targetId' can be used to control into which target the 'stepIn'
-// should occur. The list of possible targets for a given source line can be
-// retrieved via the 'stepInTargets' request.", "properties": {
-// "command": {
-// "type": "string",
-// "enum": [ "stepIn" ]
-// },
-// "arguments": {
-// "$ref": "#/definitions/StepInArguments"
-// }
-// },
-// "required": [ "command", "arguments" ]
-// }]
-// },
-// "StepInArguments": {
-// "type": "object",
-// "description": "Arguments for 'stepIn' request.",
-// "properties": {
-// "threadId": {
-// "type": "integer",
-// "description": "Execute 'stepIn' for this thread."
-// },
-// "targetId": {
-// "type": "integer",
-// "description": "Optional id of the target to step into."
-// },
-// "granularity": {
-// "$ref": "#/definitions/SteppingGranularity",
-// "description": "Stepping granularity. If no granularity is specified, a
-// granularity of `statement` is assumed."
-// }
-// },
-// "required": [ "threadId" ]
-// },
-// "StepInResponse": {
-// "allOf": [ { "$ref": "#/definitions/Response" }, {
-// "type": "object",
-// "description": "Response to 'stepIn' request. This is just an
-// acknowledgement, so no body field is required."
-// }]
-// }
-void request_stepIn(DAP &dap, const llvm::json::Object &request) {
- llvm::json::Object response;
- FillResponse(request, response);
- const auto *arguments = request.getObject("arguments");
-
- std::string step_in_target;
- uint64_t target_id = GetUnsigned(arguments, "targetId", 0);
- auto it = dap.step_in_targets.find(target_id);
- if (it != dap.step_in_targets.end())
- step_in_target = it->second;
-
- const bool single_thread = GetBoolean(arguments, "singleThread", false);
- lldb::RunMode run_mode =
- single_thread ? lldb::eOnlyThisThread : lldb::eOnlyDuringStepping;
- lldb::SBThread thread = dap.GetLLDBThread(*arguments);
- if (thread.IsValid()) {
- // Remember the thread ID that caused the resume so we can set the
- // "threadCausedFocus" boolean value in the "stopped" events.
- dap.focus_tid = thread.GetThreadID();
- if (hasInstructionGranularity(*arguments)) {
- thread.StepInstruction(/*step_over=*/false);
- } else {
- thread.StepInto(step_in_target.c_str(), run_mode);
- }
- } else {
- response["success"] = llvm::json::Value(false);
- }
- dap.SendJSON(llvm::json::Value(std::move(response)));
-}
-
-// "StepInTargetsRequest": {
-// "allOf": [ { "$ref": "#/definitions/Request" }, {
-// "type": "object",
-// "description": "This request retrieves the possible step-in targets for
-// the specified stack frame.\nThese targets can be used in the `stepIn`
-// request.\nClients should only call this request if the corresponding
-// capability `supportsStepInTargetsRequest` is true.", "properties": {
-// "command": {
-// "type": "string",
-// "enum": [ "stepInTargets" ]
-// },
-// "arguments": {
-// "$ref": "#/definitions/StepInTargetsArguments"
-// }
-// },
-// "required": [ "command", "arguments" ]
-// }]
-// },
-// "StepInTargetsArguments": {
-// "type": "object",
-// "description": "Arguments for `stepInTargets` request.",
-// "properties": {
-// "frameId": {
-// "type": "integer",
-// "description": "The stack frame for which to retrieve the possible
-// step-in targets."
-// }
-// },
-// "required": [ "frameId" ]
-// },
-// "StepInTargetsResponse": {
-// "allOf": [ { "$ref": "#/definitions/Response" }, {
-// "type": "object",
-// "description": "Response to `stepInTargets` request.",
-// "properties": {
-// "body": {
-// "type": "object",
-// "properties": {
-// "targets": {
-// "type": "array",
-// "items": {
-// "$ref": "#/definitions/StepInTarget"
-// },
-// "description": "The possible step-in targets of the specified
-// source location."
-// }
-// },
-// "required": [ "targets" ]
-// }
-// },
-// "required": [ "body" ]
-// }]
-// }
-void request_stepInTargets(DAP &dap, const llvm::json::Object &request) {
- llvm::json::Object response;
- FillResponse(request, response);
- const auto *arguments = request.getObject("arguments");
-
- dap.step_in_targets.clear();
- lldb::SBFrame frame = dap.GetLLDBFrame(*arguments);
- if (frame.IsValid()) {
- lldb::SBAddress pc_addr = frame.GetPCAddress();
- lldb::SBAddress line_end_addr =
- pc_addr.GetLineEntry().GetSameLineContiguousAddressRangeEnd(true);
- lldb::SBInstructionList insts = dap.target.ReadInstructions(
- pc_addr, line_end_addr, /*flavor_string=*/nullptr);
-
- if (!insts.IsValid()) {
- response["success"] = false;
- response["message"] = "Failed to get instructions for frame.";
- dap.SendJSON(llvm::json::Value(std::move(response)));
- return;
- }
-
- llvm::json::Array step_in_targets;
- const auto num_insts = insts.GetSize();
- for (size_t i = 0; i < num_insts; ++i) {
- lldb::SBInstruction inst = insts.GetInstructionAtIndex(i);
- if (!inst.IsValid())
- break;
-
- lldb::addr_t inst_addr = inst.GetAddress().GetLoadAddress(dap.target);
-
- // Note: currently only x86/x64 supports flow kind.
- lldb::InstructionControlFlowKind flow_kind =
- inst.GetControlFlowKind(dap.target);
- if (flow_kind == lldb::eInstructionControlFlowKindCall) {
- // Use call site instruction address as id which is easy to debug.
- llvm::json::Object step_in_target;
- step_in_target["id"] = inst_addr;
-
- llvm::StringRef call_operand_name = inst.GetOperands(dap.target);
- lldb::addr_t call_target_addr;
- if (call_operand_name.getAsInteger(0, call_target_addr))
- continue;
-
- lldb::SBAddress call_target_load_addr =
- dap.target.ResolveLoadAddress(call_target_addr);
- if (!call_target_load_addr.IsValid())
- continue;
-
- // The existing ThreadPlanStepInRange only accept step in target
- // function with debug info.
- lldb::SBSymbolContext sc = dap.target.ResolveSymbolContextForAddress(
- call_target_load_addr, lldb::eSymbolContextFunction);
-
- // The existing ThreadPlanStepInRange only accept step in target
- // function with debug info.
- std::string step_in_target_name;
- if (sc.IsValid() && sc.GetFunction().IsValid())
- step_in_target_name = sc.GetFunction().GetDisplayName();
-
- // Skip call sites if we fail to resolve its symbol name.
- if (step_in_target_name.empty())
- continue;
-
- dap.step_in_targets.try_emplace(inst_addr, step_in_target_name);
- step_in_target.try_emplace("label", step_in_target_name);
- step_in_targets.emplace_back(std::move(step_in_target));
- }
- }
- llvm::json::Object body;
- body.try_emplace("targets", std::move(step_in_targets));
- response.try_emplace("body", std::move(body));
- } else {
- response["success"] = llvm::json::Value(false);
- response["message"] = "Failed to get frame for input frameId.";
- }
- dap.SendJSON(llvm::json::Value(std::move(response)));
-}
-
-// "StepOutRequest": {
-// "allOf": [ { "$ref": "#/definitions/Request" }, {
-// "type": "object",
-// "description": "StepOut request; value of command field is 'stepOut'. The
-// request starts the debuggee to run again for one step. The debug adapter
-// first sends the StepOutResponse and then a StoppedEvent (event type
-// 'step') after the step has completed.", "properties": {
-// "command": {
-// "type": "string",
-// "enum": [ "stepOut" ]
-// },
-// "arguments": {
-// "$ref": "#/definitions/StepOutArguments"
-// }
-// },
-// "required": [ "command", "arguments" ]
-// }]
-// },
-// "StepOutArguments": {
-// "type": "object",
-// "description": "Arguments for 'stepOut' request.",
-// "properties": {
-// "threadId": {
-// "type": "integer",
-// "description": "Execute 'stepOut' for this thread."
-// }
-// },
-// "required": [ "threadId" ]
-// },
-// "StepOutResponse": {
-// "allOf": [ { "$ref": "#/definitions/Response" }, {
-// "type": "object",
-// "description": "Response to 'stepOut' request. This is just an
-// acknowledgement, so no body field is required."
-// }]
-// }
-void request_stepOut(DAP &dap, const llvm::json::Object &request) {
- llvm::json::Object response;
- FillResponse(request, response);
- const auto *arguments = request.getObject("arguments");
- lldb::SBThread thread = dap.GetLLDBThread(*arguments);
- if (thread.IsValid()) {
- // Remember the thread ID that caused the resume so we can set the
- // "threadCausedFocus" boolean value in the "stopped" events.
- dap.focus_tid = thread.GetThreadID();
- thread.StepOut();
- } else {
- response["success"] = llvm::json::Value(false);
- }
- dap.SendJSON(llvm::json::Value(std::move(response)));
-}
-
// "ThreadsRequest": {
// "allOf": [ { "$ref": "#/definitions/Request" }, {
// "type": "object",
@@ -2777,16 +2443,19 @@ void RegisterRequestCallbacks(DAP &dap) {
dap.RegisterRequest<AttachRequestHandler>();
dap.RegisterRequest<BreakpointLocationsRequestHandler>();
dap.RegisterRequest<CompletionsRequestHandler>();
- dap.RegisterRequest<ContinueRequestHandler>();
dap.RegisterRequest<ConfigurationDoneRequestHandler>();
+ dap.RegisterRequest<ContinueRequestHandler>();
dap.RegisterRequest<DisconnectRequestHandler>();
dap.RegisterRequest<EvaluateRequestHandler>();
dap.RegisterRequest<ExceptionInfoRequestHandler>();
dap.RegisterRequest<InitializeRequestHandler>();
dap.RegisterRequest<LaunchRequestHandler>();
+ dap.RegisterRequest<NextRequestHandler>();
dap.RegisterRequest<RestartRequestHandler>();
+ dap.RegisterRequest<StepInRequestHandler>();
+ dap.RegisterRequest<StepInTargetsRequestHandler>();
+ dap.RegisterRequest<StepOutRequestHandler>();
- dap.RegisterRequestCallback("next", request_next);
dap.RegisterRequestCallback("pause", request_pause);
dap.RegisterRequestCallback("scopes", request_scopes);
dap.RegisterRequestCallback("setBreakpoints", request_setBreakpoints);
@@ -2799,9 +2468,6 @@ void RegisterRequestCallbacks(DAP &dap) {
dap.RegisterRequestCallback("setVariable", request_setVariable);
dap.RegisterRequestCallback("source", request_source);
dap.RegisterRequestCallback("stackTrace", request_stackTrace);
- dap.RegisterRequestCallback("stepIn", request_stepIn);
- dap.RegisterRequestCallback("stepInTargets", request_stepInTargets);
- dap.RegisterRequestCallback("stepOut", request_stepOut);
dap.RegisterRequestCallback("threads", request_threads);
dap.RegisterRequestCallback("variables", request_variables);
dap.RegisterRequestCallback("locations", request_locations);
More information about the lldb-commits
mailing list