Skip to content
Closed
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
6 changes: 5 additions & 1 deletion lldb/tools/lldb-dap/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ add_lldb_tool(lldb-dap
Transport.cpp
Watchpoint.cpp

Events/ExitedEventHandler.cpp
Events/ProcessEventHandler.cpp

Handler/ResponseHandler.cpp
Handler/AttachRequestHandler.cpp
Handler/BreakpointLocationsHandler.cpp
Expand Down Expand Up @@ -75,8 +78,9 @@ add_lldb_tool(lldb-dap
Handler/VariablesRequestHandler.cpp

Protocol/ProtocolBase.cpp
Protocol/ProtocolTypes.cpp
Protocol/ProtocolEvents.cpp
Protocol/ProtocolRequests.cpp
Protocol/ProtocolTypes.cpp

LINK_LIBS
liblldb
Expand Down
5 changes: 4 additions & 1 deletion lldb/tools/lldb-dap/DAP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include "DAP.h"
#include "DAPLog.h"
#include "Events/EventHandler.h"
#include "Handler/RequestHandler.h"
#include "Handler/ResponseHandler.h"
#include "JSONUtils.h"
Expand Down Expand Up @@ -82,7 +83,9 @@ DAP::DAP(llvm::StringRef path, std::ofstream *log,
configuration_done_sent(false), waiting_for_run_in_terminal(false),
progress_event_reporter(
[&](const ProgressEvent &event) { SendJSON(event.ToJSON()); }),
reverse_request_seq(0), repl_mode(default_repl_mode) {}
reverse_request_seq(0), repl_mode(default_repl_mode),
onExited(ExitedEventHandler(*this)),
onProcess(ProcessEventHandler(*this)) {}

DAP::~DAP() = default;

Expand Down
14 changes: 14 additions & 0 deletions lldb/tools/lldb-dap/DAP.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ typedef llvm::StringMap<FunctionBreakpoint> FunctionBreakpointMap;
typedef llvm::DenseMap<lldb::addr_t, InstructionBreakpoint>
InstructionBreakpointMap;

/// A debug adapter initiated event.
template <typename... Args> using OutgoingEvent = std::function<void(Args...)>;

enum class OutputType { Console, Stdout, Stderr, Telemetry };

/// Buffer size for handling output events.
Expand Down Expand Up @@ -230,6 +233,17 @@ struct DAP {
void operator=(const DAP &rhs) = delete;
/// @}

/// Typed Events Handlers
/// @{

/// onExited sends an event that the debuggee has exited.
OutgoingEvent<> onExited;
/// onProcess sends an event that indicates that the debugger has begun
/// debugging a new process.
OutgoingEvent<> onProcess;

/// @}

ExceptionBreakpoint *GetExceptionBreakpoint(const std::string &filter);
ExceptionBreakpoint *GetExceptionBreakpoint(const lldb::break_id_t bp_id);

Expand Down
90 changes: 0 additions & 90 deletions lldb/tools/lldb-dap/EventHelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,87 +32,6 @@ static void SendThreadExitedEvent(DAP &dap, lldb::tid_t tid) {
dap.SendJSON(llvm::json::Value(std::move(event)));
}

// "ProcessEvent": {
// "allOf": [
// { "$ref": "#/definitions/Event" },
// {
// "type": "object",
// "description": "Event message for 'process' event type. The event
// indicates that the debugger has begun debugging a
// new process. Either one that it has launched, or one
// that it has attached to.",
// "properties": {
// "event": {
// "type": "string",
// "enum": [ "process" ]
// },
// "body": {
// "type": "object",
// "properties": {
// "name": {
// "type": "string",
// "description": "The logical name of the process. This is
// usually the full path to process's executable
// file. Example: /home/myproj/program.js."
// },
// "systemProcessId": {
// "type": "integer",
// "description": "The system process id of the debugged process.
// This property will be missing for non-system
// processes."
// },
// "isLocalProcess": {
// "type": "boolean",
// "description": "If true, the process is running on the same
// computer as the debug adapter."
// },
// "startMethod": {
// "type": "string",
// "enum": [ "launch", "attach", "attachForSuspendedLaunch" ],
// "description": "Describes how the debug engine started
// debugging this process.",
// "enumDescriptions": [
// "Process was launched under the debugger.",
// "Debugger attached to an existing process.",
// "A project launcher component has launched a new process in
// a suspended state and then asked the debugger to attach."
// ]
// }
// },
// "required": [ "name" ]
// }
// },
// "required": [ "event", "body" ]
// }
// ]
// }
void SendProcessEvent(DAP &dap, LaunchMethod launch_method) {
lldb::SBFileSpec exe_fspec = dap.target.GetExecutable();
char exe_path[PATH_MAX];
exe_fspec.GetPath(exe_path, sizeof(exe_path));
llvm::json::Object event(CreateEventObject("process"));
llvm::json::Object body;
EmplaceSafeString(body, "name", std::string(exe_path));
const auto pid = dap.target.GetProcess().GetProcessID();
body.try_emplace("systemProcessId", (int64_t)pid);
body.try_emplace("isLocalProcess", true);
const char *startMethod = nullptr;
switch (launch_method) {
case Launch:
startMethod = "launch";
break;
case Attach:
startMethod = "attach";
break;
case AttachForSuspendedLaunch:
startMethod = "attachForSuspendedLaunch";
break;
}
body.try_emplace("startMethod", startMethod);
event.try_emplace("body", std::move(body));
dap.SendJSON(llvm::json::Value(std::move(event)));
}

// Send a thread stopped event for all threads as long as the process
// is stopped.
void SendThreadStoppedEvent(DAP &dap) {
Expand Down Expand Up @@ -235,13 +154,4 @@ void SendContinuedEvent(DAP &dap) {
dap.SendJSON(llvm::json::Value(std::move(event)));
}

// Send a "exited" event to indicate the process has exited.
void SendProcessExitedEvent(DAP &dap, lldb::SBProcess &process) {
llvm::json::Object event(CreateEventObject("exited"));
llvm::json::Object body;
body.try_emplace("exitCode", (int64_t)process.GetExitStatus());
event.try_emplace("body", std::move(body));
dap.SendJSON(llvm::json::Value(std::move(event)));
}

} // namespace lldb_dap
6 changes: 0 additions & 6 deletions lldb/tools/lldb-dap/EventHelper.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,6 @@
namespace lldb_dap {
struct DAP;

enum LaunchMethod { Launch, Attach, AttachForSuspendedLaunch };

void SendProcessEvent(DAP &dap, LaunchMethod launch_method);

void SendThreadStoppedEvent(DAP &dap);

void SendTerminatedEvent(DAP &dap);
Expand All @@ -26,8 +22,6 @@ void SendStdOutStdErr(DAP &dap, lldb::SBProcess &process);

void SendContinuedEvent(DAP &dap);

void SendProcessExitedEvent(DAP &dap, lldb::SBProcess &process);

} // namespace lldb_dap

#endif
57 changes: 57 additions & 0 deletions lldb/tools/lldb-dap/Events/EventHandler.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
//===-- EventHandler.h ----------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//

#ifndef LLDB_TOOLS_LLDB_DAP_EVENTS_EVENT_HANDLER
#define LLDB_TOOLS_LLDB_DAP_EVENTS_EVENT_HANDLER

#include "DAP.h"
#include "Protocol/ProtocolBase.h"
#include "Protocol/ProtocolEvents.h"
#include "lldb/API/SBProcess.h"

namespace lldb_dap {

template <typename Body, typename... Args> class BaseEventHandler {
public:
BaseEventHandler(DAP &dap) : dap(dap) {}

virtual ~BaseEventHandler() = default;

virtual llvm::StringLiteral getEvent() const = 0;
virtual Body Handler(Args...) const = 0;

void operator()(Args... args) const {
Body body = Handler(args...);
protocol::Event event{/*event=*/getEvent().str(), /*body=*/std::move(body)};
Copy link
Member

@vogelsgesang vogelsgesang Mar 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this be using Body.getEvent() instead? Afaict, we wouldn't need a virtual call to getEvent then

dap.Send(event);
}

protected:
DAP &dap;
};

/// Handler for the event indicates that the debuggee has exited and returns its
/// exit code.
class ExitedEventHandler : public BaseEventHandler<protocol::ExitedEventBody> {
public:
using BaseEventHandler::BaseEventHandler;
llvm::StringLiteral getEvent() const override { return "exited"; }
protocol::ExitedEventBody Handler() const override;
};

class ProcessEventHandler
: public BaseEventHandler<protocol::ProcessEventBody> {
public:
using BaseEventHandler::BaseEventHandler;
llvm::StringLiteral getEvent() const override { return "process"; }
protocol::ProcessEventBody Handler() const override;
};

} // end namespace lldb_dap

#endif
20 changes: 20 additions & 0 deletions lldb/tools/lldb-dap/Events/ExitedEventHandler.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//===-- ExitedEventHandler.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 "Events/EventHandler.h"
#include "lldb/API/SBProcess.h"

namespace lldb_dap {

protocol::ExitedEventBody ExitedEventHandler::Handler() const {
protocol::ExitedEventBody body;
body.exitCode = dap.target.GetProcess().GetExitStatus();
return body;
}

} // namespace lldb_dap
34 changes: 34 additions & 0 deletions lldb/tools/lldb-dap/Events/ProcessEventHandler.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//===-- ProcessEventHandler.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 "Events/EventHandler.h"
#include "Protocol/ProtocolEvents.h"
#include "lldb/API/SBProcess.h"
#include "lldb/API/SBTarget.h"

using namespace llvm;
using namespace lldb_dap::protocol;

namespace lldb_dap {

ProcessEventBody ProcessEventHandler::Handler() const {
ProcessEventBody body;

char path[PATH_MAX] = {0};
dap.target.GetExecutable().GetPath(path, sizeof(path));
body.name = path;
body.systemProcessId = dap.target.GetProcess().GetProcessID();
body.isLocalProcess = dap.target.GetPlatform().GetName() ==
lldb::SBPlatform::GetHostPlatform().GetName();
body.startMethod = dap.is_attach ? ProcessEventBody::StartMethod::attach
: ProcessEventBody::StartMethod::launch;
body.pointerSize = dap.target.GetAddressByteSize();
return body;
}

} // namespace lldb_dap
2 changes: 1 addition & 1 deletion lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ void AttachRequestHandler::operator()(const llvm::json::Object &request) const {

dap.SendJSON(llvm::json::Value(std::move(response)));
if (error.Success()) {
SendProcessEvent(dap, Attach);
dap.onProcess();
dap.SendJSON(CreateEventObject("initialized"));
}
}
Expand Down
2 changes: 1 addition & 1 deletion lldb/tools/lldb-dap/Handler/InitializeRequestHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ static void EventThreadFunction(DAP &dap) {
// Run any exit LLDB commands the user specified in the
// launch.json
dap.RunExitCommands();
SendProcessExitedEvent(dap, process);
dap.onExited();
dap.SendTerminatedEvent();
done = true;
}
Expand Down
5 changes: 1 addition & 4 deletions lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -124,10 +124,7 @@ void LaunchRequestHandler::operator()(const llvm::json::Object &request) const {
dap.SendJSON(llvm::json::Value(std::move(response)));

if (!status.Fail()) {
if (dap.is_attach)
SendProcessEvent(dap, Attach); // this happens when doing runInTerminal
else
SendProcessEvent(dap, Launch);
dap.onProcess();
}
dap.SendJSON(CreateEventObject("initialized"));
}
Expand Down
4 changes: 2 additions & 2 deletions lldb/tools/lldb-dap/Protocol/ProtocolBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
//
//===----------------------------------------------------------------------===//

#ifndef LLDB_TOOLS_LLDB_DAP_PROTOCOL_H
#define LLDB_TOOLS_LLDB_DAP_PROTOCOL_H
#ifndef LLDB_TOOLS_LLDB_DAP_PROTOCOL_PROTOCOL_BASE_H
#define LLDB_TOOLS_LLDB_DAP_PROTOCOL_PROTOCOL_BASE_H

#include "llvm/Support/JSON.h"
#include <cstdint>
Expand Down
46 changes: 46 additions & 0 deletions lldb/tools/lldb-dap/Protocol/ProtocolEvents.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
//===-- ProtocolEvents.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 "Protocol/ProtocolEvents.h"
#include "llvm/Support/JSON.h"

using namespace llvm;

namespace lldb_dap::protocol {

json::Value toJSON(const ExitedEventBody &EEB) {
return json::Object{{"exitCode", EEB.exitCode}};
}

json::Value toJSON(const ProcessEventBody::StartMethod &m) {
switch (m) {
case ProcessEventBody::StartMethod::launch:
return "launch";
case ProcessEventBody::StartMethod::attach:
return "attach";
case ProcessEventBody::StartMethod::attachForSuspendedLaunch:
return "attachForSuspendedLaunch";
}
}

json::Value toJSON(const ProcessEventBody &PEB) {
json::Object result{{"name", PEB.name}};

if (PEB.systemProcessId)
result.insert({"systemProcessId", PEB.systemProcessId});
if (PEB.isLocalProcess)
result.insert({"isLocalProcess", PEB.isLocalProcess});
if (PEB.startMethod)
result.insert({"startMethod", PEB.startMethod});
if (PEB.pointerSize)
result.insert({"pointerSize", PEB.pointerSize});

return std::move(result);
}

} // namespace lldb_dap::protocol
Loading