Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions lldb/tools/lldb-dap/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
79 changes: 79 additions & 0 deletions lldb/tools/lldb-dap/Handler/NextRequestHandler.cpp
Original file line number Diff line number Diff line change
@@ -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
7 changes: 7 additions & 0 deletions lldb/tools/lldb-dap/Handler/RequestHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
33 changes: 32 additions & 1 deletion lldb/tools/lldb-dap/Handler/RequestHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -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?
/// @{
Expand All @@ -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;
};

Expand Down Expand Up @@ -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
96 changes: 96 additions & 0 deletions lldb/tools/lldb-dap/Handler/StepInRequestHandler.cpp
Original file line number Diff line number Diff line change
@@ -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
Loading