Skip to content

[lldb-dap] Adding support for well typed events. #130104

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
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
7 changes: 6 additions & 1 deletion lldb/tools/lldb-dap/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ add_lldb_tool(lldb-dap
Transport.cpp
Watchpoint.cpp

Events/ExitedEventHandler.cpp
Events/ProcessEventHandler.cpp
Events/OutputEventHandler.cpp

Handler/ResponseHandler.cpp
Handler/AttachRequestHandler.cpp
Handler/BreakpointLocationsHandler.cpp
Expand Down Expand Up @@ -75,8 +79,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
134 changes: 19 additions & 115 deletions 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,8 @@ 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), SendExited(*this),
SendProcess(*this), SendOutput(*this) {}

DAP::~DAP() = default;

Expand Down Expand Up @@ -202,12 +204,12 @@ llvm::Error DAP::ConfigureIO(std::FILE *overrideOut, std::FILE *overrideErr) {
in = lldb::SBFile(std::fopen(DEV_NULL, "r"), /*transfer_ownership=*/true);

if (auto Error = out.RedirectTo(overrideOut, [this](llvm::StringRef output) {
SendOutput(OutputType::Stdout, output);
SendOutput(output, OutputCategory::Stdout);
}))
return Error;

if (auto Error = err.RedirectTo(overrideErr, [this](llvm::StringRef output) {
SendOutput(OutputType::Stderr, output);
SendOutput(output, OutputCategory::Stderr);
}))
return Error;

Expand Down Expand Up @@ -246,103 +248,6 @@ void DAP::Send(const protocol::Message &message) {
transport.GetClientName());
}

// "OutputEvent": {
// "allOf": [ { "$ref": "#/definitions/Event" }, {
// "type": "object",
// "description": "Event message for 'output' event type. The event
// indicates that the target has produced some output.",
// "properties": {
// "event": {
// "type": "string",
// "enum": [ "output" ]
// },
// "body": {
// "type": "object",
// "properties": {
// "category": {
// "type": "string",
// "description": "The output category. If not specified,
// 'console' is assumed.",
// "_enum": [ "console", "stdout", "stderr", "telemetry" ]
// },
// "output": {
// "type": "string",
// "description": "The output to report."
// },
// "variablesReference": {
// "type": "number",
// "description": "If an attribute 'variablesReference' exists
// and its value is > 0, the output contains
// objects which can be retrieved by passing
// variablesReference to the VariablesRequest."
// },
// "source": {
// "$ref": "#/definitions/Source",
// "description": "An optional source location where the output
// was produced."
// },
// "line": {
// "type": "integer",
// "description": "An optional source location line where the
// output was produced."
// },
// "column": {
// "type": "integer",
// "description": "An optional source location column where the
// output was produced."
// },
// "data": {
// "type":["array","boolean","integer","null","number","object",
// "string"],
// "description": "Optional data to report. For the 'telemetry'
// category the data will be sent to telemetry, for
// the other categories the data is shown in JSON
// format."
// }
// },
// "required": ["output"]
// }
// },
// "required": [ "event", "body" ]
// }]
// }
void DAP::SendOutput(OutputType o, const llvm::StringRef output) {
if (output.empty())
return;

const char *category = nullptr;
switch (o) {
case OutputType::Console:
category = "console";
break;
case OutputType::Stdout:
category = "stdout";
break;
case OutputType::Stderr:
category = "stderr";
break;
case OutputType::Telemetry:
category = "telemetry";
break;
}

// Send each line of output as an individual event, including the newline if
// present.
::size_t idx = 0;
do {
::size_t end = output.find('\n', idx);
if (end == llvm::StringRef::npos)
end = output.size() - 1;
llvm::json::Object event(CreateEventObject("output"));
llvm::json::Object body;
body.try_emplace("category", category);
EmplaceSafeString(body, "output", output.slice(idx, end + 1).str());
event.try_emplace("body", std::move(body));
SendJSON(llvm::json::Value(std::move(event)));
idx = end + 1;
} while (idx < output.size());
}

// interface ProgressStartEvent extends Event {
// event: 'progressStart';
//
Expand Down Expand Up @@ -441,16 +346,17 @@ void DAP::SendProgressEvent(uint64_t progress_id, const char *message,
progress_event_reporter.Push(progress_id, message, completed, total);
}

void __attribute__((format(printf, 3, 4)))
DAP::SendFormattedOutput(OutputType o, const char *format, ...) {
char buffer[1024];
va_list args;
va_start(args, format);
int actual_length = vsnprintf(buffer, sizeof(buffer), format, args);
va_end(args);
SendOutput(
o, llvm::StringRef(buffer, std::min<int>(actual_length, sizeof(buffer))));
}
// void __attribute__((format(printf, 3, 4)))
// DAP::SendFormattedOutput(OutputType o, const char *format, ...) {
// char buffer[1024];
// va_list args;
// va_start(args, format);
// int actual_length = vsnprintf(buffer, sizeof(buffer), format, args);
// va_end(args);
// SendOutput(
// o, llvm::StringRef(buffer, std::min<int>(actual_length,
// sizeof(buffer))));
// }

ExceptionBreakpoint *DAP::GetExceptionBPFromStopReason(lldb::SBThread &thread) {
const auto num = thread.GetStopReasonDataCount();
Expand Down Expand Up @@ -564,7 +470,7 @@ bool DAP::RunLLDBCommands(llvm::StringRef prefix,
bool required_command_failed = false;
std::string output =
::RunLLDBCommands(debugger, prefix, commands, required_command_failed);
SendOutput(OutputType::Console, output);
SendOutput(output);
return !required_command_failed;
}

Expand Down Expand Up @@ -1041,8 +947,7 @@ void DAP::SetFrameFormat(llvm::StringRef format) {
lldb::SBError error;
frame_format = lldb::SBFormat(format.str().c_str(), error);
if (error.Fail()) {
SendOutput(OutputType::Console,
llvm::formatv(
SendOutput(llvm::formatv(
"The provided frame format '{0}' couldn't be parsed: {1}\n",
format, error.GetCString())
.str());
Expand All @@ -1055,8 +960,7 @@ void DAP::SetThreadFormat(llvm::StringRef format) {
lldb::SBError error;
thread_format = lldb::SBFormat(format.str().c_str(), error);
if (error.Fail()) {
SendOutput(OutputType::Console,
llvm::formatv(
SendOutput(llvm::formatv(
"The provided thread format '{0}' couldn't be parsed: {1}\n",
format, error.GetCString())
.str());
Expand Down
21 changes: 14 additions & 7 deletions lldb/tools/lldb-dap/DAP.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#define LLDB_TOOLS_LLDB_DAP_DAP_H

#include "DAPForward.h"
#include "Events/EventHandler.h"
#include "ExceptionBreakpoint.h"
#include "FunctionBreakpoint.h"
#include "InstructionBreakpoint.h"
Expand Down Expand Up @@ -58,8 +59,6 @@ typedef llvm::StringMap<FunctionBreakpoint> FunctionBreakpointMap;
typedef llvm::DenseMap<lldb::addr_t, InstructionBreakpoint>
InstructionBreakpointMap;

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

/// Buffer size for handling output events.
constexpr uint64_t OutputBufferSize = (1u << 12);

Expand Down Expand Up @@ -230,6 +229,19 @@ struct DAP {
void operator=(const DAP &rhs) = delete;
/// @}

/// Typed Events Handlers
/// @{

/// Sends an event that the debuggee has exited.
ExitedEventHandler SendExited;
/// Sends an event that indicates that the debugger has begun debugging a new
/// process.
ProcessEventHandler SendProcess;
/// Sends an event that indicates the target has produced some output.
OutputEventHandler SendOutput;

/// @}

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

Expand All @@ -249,14 +261,9 @@ struct DAP {
/// Send the given message to the client
void Send(const protocol::Message &message);

void SendOutput(OutputType o, const llvm::StringRef output);

void SendProgressEvent(uint64_t progress_id, const char *message,
uint64_t completed, uint64_t total);

void __attribute__((format(printf, 3, 4)))
SendFormattedOutput(OutputType o, const char *format, ...);

static int64_t GetNextSourceReference();

ExceptionBreakpoint *GetExceptionBPFromStopReason(lldb::SBThread &thread);
Expand Down
95 changes: 3 additions & 92 deletions lldb/tools/lldb-dap/EventHelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include "EventHelper.h"
#include "DAP.h"
#include "Events/EventHandler.h"
#include "JSONUtils.h"
#include "LLDBUtils.h"
#include "lldb/API/SBFileSpec.h"
Expand All @@ -32,87 +33,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 @@ -209,9 +129,9 @@ void SendStdOutStdErr(DAP &dap, lldb::SBProcess &process) {
char buffer[OutputBufferSize];
size_t count;
while ((count = process.GetSTDOUT(buffer, sizeof(buffer))) > 0)
dap.SendOutput(OutputType::Stdout, llvm::StringRef(buffer, count));
dap.SendOutput(llvm::StringRef(buffer, count), OutputCategory::Stdout);
while ((count = process.GetSTDERR(buffer, sizeof(buffer))) > 0)
dap.SendOutput(OutputType::Stderr, llvm::StringRef(buffer, count));
dap.SendOutput(llvm::StringRef(buffer, count), OutputCategory::Stderr);
}

// Send a "continued" event to indicate the process is in the running state.
Expand All @@ -235,13 +155,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
Loading