https://github.com/JDevlieghere updated https://github.com/llvm/llvm-project/pull/128453
>From 34bd7c56ad67145501217464ef3e6b87a48d587a Mon Sep 17 00:00:00 2001 From: Jonas Devlieghere <jo...@devlieghere.com> Date: Sun, 23 Feb 2025 21:07:55 -0600 Subject: [PATCH 1/2] [lldb-dap] Refactor stepping related request handlers (NFC) Continuation of the work started in #128262. --- lldb/tools/lldb-dap/CMakeLists.txt | 4 + .../lldb-dap/Handler/NextRequestHandler.cpp | 79 ++++ .../tools/lldb-dap/Handler/RequestHandler.cpp | 7 + lldb/tools/lldb-dap/Handler/RequestHandler.h | 33 +- .../lldb-dap/Handler/StepInRequestHandler.cpp | 96 +++++ .../Handler/StepInTargetsRequestHandler.cpp | 149 ++++++++ .../Handler/StepOutRequestHandler.cpp | 68 ++++ lldb/tools/lldb-dap/lldb-dap.cpp | 344 +----------------- 8 files changed, 440 insertions(+), 340 deletions(-) create mode 100644 lldb/tools/lldb-dap/Handler/NextRequestHandler.cpp create mode 100644 lldb/tools/lldb-dap/Handler/StepInRequestHandler.cpp create mode 100644 lldb/tools/lldb-dap/Handler/StepInTargetsRequestHandler.cpp create mode 100644 lldb/tools/lldb-dap/Handler/StepOutRequestHandler.cpp 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..3b1c2b0dc7e31 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 &request) { + if (std::optional<llvm::StringRef> value = request.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 fcefb4137f227..edbf78678dca7 100644 --- a/lldb/tools/lldb-dap/lldb-dap.cpp +++ b/lldb/tools/lldb-dap/lldb-dap.cpp @@ -373,77 +373,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", @@ -1378,269 +1307,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", @@ -2783,16 +2449,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); @@ -2805,9 +2474,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); >From f318fe13f6927ed82646b7f043451b0c40f6587b Mon Sep 17 00:00:00 2001 From: Jonas Devlieghere <jo...@devlieghere.com> Date: Mon, 24 Feb 2025 13:43:10 -0600 Subject: [PATCH 2/2] Rename paramter to `arguments` --- lldb/tools/lldb-dap/Handler/RequestHandler.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.cpp b/lldb/tools/lldb-dap/Handler/RequestHandler.cpp index 3b1c2b0dc7e31..f9502e09846d4 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.cpp @@ -226,8 +226,8 @@ void RequestHandler::PrintWelcomeMessage() { } bool RequestHandler::HasInstructionGranularity( - const llvm::json::Object &request) { - if (std::optional<llvm::StringRef> value = request.getString("granularity")) + const llvm::json::Object &arguments) { + if (std::optional<llvm::StringRef> value = arguments.getString("granularity")) return value == "instruction"; return false; } _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits