[Lldb-commits] [lldb] [lldb-dap] Refactor lldb-dap.cpp to not use global DAP variable. (PR #116272)
via lldb-commits
lldb-commits at lists.llvm.org
Thu Nov 14 11:58:25 PST 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-lldb
Author: John Harrison (ashgti)
<details>
<summary>Changes</summary>
This removes the global DAP variable and instead allocates a DAP instance in main. This should allow us to refactor lldb-dap to enable a server mode that accepts multiple connections.
---
Patch is 117.71 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/116272.diff
3 Files Affected:
- (modified) lldb/tools/lldb-dap/DAP.cpp (+4-6)
- (modified) lldb/tools/lldb-dap/DAP.h (+1-3)
- (modified) lldb/tools/lldb-dap/lldb-dap.cpp (+543-543)
``````````diff
diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp
index bdb24fc78cfb64..aee6214857bd0d 100644
--- a/lldb/tools/lldb-dap/DAP.cpp
+++ b/lldb/tools/lldb-dap/DAP.cpp
@@ -32,8 +32,6 @@ using namespace lldb_dap;
namespace lldb_dap {
-DAP g_dap;
-
DAP::DAP()
: broadcaster("lldb-dap"), exception_breakpoints(),
focus_tid(LLDB_INVALID_THREAD_ID), stop_at_entry(false), is_attach(false),
@@ -693,15 +691,15 @@ bool DAP::HandleObject(const llvm::json::Object &object) {
if (packet_type == "request") {
const auto command = GetString(object, "command");
auto handler_pos = request_handlers.find(command);
- if (handler_pos != request_handlers.end()) {
- handler_pos->second(object);
- return true; // Success
- } else {
+ if (handler_pos == request_handlers.end()) {
if (log)
*log << "error: unhandled command \"" << command.data() << "\""
<< std::endl;
return false; // Fail
}
+
+ handler_pos->second(*this, object);
+ return true; // Success
}
if (packet_type == "response") {
diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h
index 5381b3271ba96f..c6e86a59875ea2 100644
--- a/lldb/tools/lldb-dap/DAP.h
+++ b/lldb/tools/lldb-dap/DAP.h
@@ -63,7 +63,7 @@ enum DAPBroadcasterBits {
eBroadcastBitStopProgressThread = 1u << 1
};
-typedef void (*RequestCallback)(const llvm::json::Object &command);
+typedef void (*RequestCallback)(DAP &dap, const llvm::json::Object &command);
typedef void (*ResponseCallback)(llvm::Expected<llvm::json::Value> value);
enum class PacketStatus {
@@ -353,8 +353,6 @@ struct DAP {
void SendJSON(const std::string &json_str);
};
-extern DAP g_dap;
-
} // namespace lldb_dap
#endif
diff --git a/lldb/tools/lldb-dap/lldb-dap.cpp b/lldb/tools/lldb-dap/lldb-dap.cpp
index fc22ec03b672e6..055a012ed51c6a 100644
--- a/lldb/tools/lldb-dap/lldb-dap.cpp
+++ b/lldb/tools/lldb-dap/lldb-dap.cpp
@@ -24,7 +24,6 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/ScopeExit.h"
-#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Option/Arg.h"
#include "llvm/Option/ArgList.h"
@@ -119,34 +118,34 @@ constexpr int StackPageSize = 20;
/// Prints a welcome message on the editor if the preprocessor variable
/// LLDB_DAP_WELCOME_MESSAGE is defined.
-static void PrintWelcomeMessage() {
+static void PrintWelcomeMessage(DAP &dap) {
#ifdef LLDB_DAP_WELCOME_MESSAGE
- g_dap.SendOutput(OutputType::Console, LLDB_DAP_WELCOME_MESSAGE);
+ dap.SendOutput(OutputType::Console, LLDB_DAP_WELCOME_MESSAGE);
#endif
}
-lldb::SBValueList *GetTopLevelScope(int64_t variablesReference) {
+lldb::SBValueList *GetTopLevelScope(DAP &dap, int64_t variablesReference) {
switch (variablesReference) {
case VARREF_LOCALS:
- return &g_dap.variables.locals;
+ return &dap.variables.locals;
case VARREF_GLOBALS:
- return &g_dap.variables.globals;
+ return &dap.variables.globals;
case VARREF_REGS:
- return &g_dap.variables.registers;
+ return &dap.variables.registers;
default:
return nullptr;
}
}
-SOCKET AcceptConnection(int portno) {
+SOCKET AcceptConnection(DAP &dap, int portno) {
// Accept a socket connection from any host on "portno".
SOCKET newsockfd = -1;
struct sockaddr_in serv_addr, cli_addr;
SOCKET sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
- if (g_dap.log)
- *g_dap.log << "error: opening socket (" << strerror(errno) << ")"
- << std::endl;
+ if (dap.log)
+ *dap.log << "error: opening socket (" << strerror(errno) << ")"
+ << std::endl;
} else {
memset((char *)&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
@@ -154,9 +153,9 @@ SOCKET AcceptConnection(int portno) {
serv_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
serv_addr.sin_port = htons(portno);
if (bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
- if (g_dap.log)
- *g_dap.log << "error: binding socket (" << strerror(errno) << ")"
- << std::endl;
+ if (dap.log)
+ *dap.log << "error: binding socket (" << strerror(errno) << ")"
+ << std::endl;
} else {
listen(sockfd, 5);
socklen_t clilen = sizeof(cli_addr);
@@ -164,9 +163,8 @@ SOCKET AcceptConnection(int portno) {
llvm::sys::RetryAfterSignal(static_cast<SOCKET>(-1), accept, sockfd,
(struct sockaddr *)&cli_addr, &clilen);
if (newsockfd < 0)
- if (g_dap.log)
- *g_dap.log << "error: accept (" << strerror(errno) << ")"
- << std::endl;
+ if (dap.log)
+ *dap.log << "error: accept (" << strerror(errno) << ")" << std::endl;
}
#if defined(_WIN32)
closesocket(sockfd);
@@ -190,66 +188,65 @@ std::vector<const char *> MakeArgv(const llvm::ArrayRef<std::string> &strs) {
}
// Send a "exited" event to indicate the process has exited.
-void SendProcessExitedEvent(lldb::SBProcess &process) {
+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));
- g_dap.SendJSON(llvm::json::Value(std::move(event)));
+ dap.SendJSON(llvm::json::Value(std::move(event)));
}
-void SendThreadExitedEvent(lldb::tid_t tid) {
+void SendThreadExitedEvent(DAP &dap, lldb::tid_t tid) {
llvm::json::Object event(CreateEventObject("thread"));
llvm::json::Object body;
body.try_emplace("reason", "exited");
body.try_emplace("threadId", (int64_t)tid);
event.try_emplace("body", std::move(body));
- g_dap.SendJSON(llvm::json::Value(std::move(event)));
+ dap.SendJSON(llvm::json::Value(std::move(event)));
}
// Send a "continued" event to indicate the process is in the running state.
-void SendContinuedEvent() {
- lldb::SBProcess process = g_dap.target.GetProcess();
+void SendContinuedEvent(DAP &dap) {
+ lldb::SBProcess process = dap.target.GetProcess();
if (!process.IsValid()) {
return;
}
// If the focus thread is not set then we haven't reported any thread status
// to the client, so nothing to report.
- if (!g_dap.configuration_done_sent ||
- g_dap.focus_tid == LLDB_INVALID_THREAD_ID) {
+ if (!dap.configuration_done_sent || dap.focus_tid == LLDB_INVALID_THREAD_ID) {
return;
}
llvm::json::Object event(CreateEventObject("continued"));
llvm::json::Object body;
- body.try_emplace("threadId", (int64_t)g_dap.focus_tid);
+ body.try_emplace("threadId", (int64_t)dap.focus_tid);
body.try_emplace("allThreadsContinued", true);
event.try_emplace("body", std::move(body));
- g_dap.SendJSON(llvm::json::Value(std::move(event)));
+ dap.SendJSON(llvm::json::Value(std::move(event)));
}
// Send a "terminated" event to indicate the process is done being
// debugged.
-void SendTerminatedEvent() {
+void SendTerminatedEvent(DAP &dap) {
// Prevent races if the process exits while we're being asked to disconnect.
- llvm::call_once(g_dap.terminated_event_flag, [&] {
- g_dap.RunTerminateCommands();
+ llvm::call_once(dap.terminated_event_flag, [&] {
+ dap.RunTerminateCommands();
// Send a "terminated" event
- llvm::json::Object event(CreateTerminatedEventObject(g_dap.target));
- g_dap.SendJSON(llvm::json::Value(std::move(event)));
+ llvm::json::Object event(CreateTerminatedEventObject(dap.target));
+ 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() {
- lldb::SBProcess process = g_dap.target.GetProcess();
+void SendThreadStoppedEvent(DAP &dap) {
+ lldb::SBProcess process = dap.target.GetProcess();
if (process.IsValid()) {
auto state = process.GetState();
if (state == lldb::eStateStopped) {
llvm::DenseSet<lldb::tid_t> old_thread_ids;
- old_thread_ids.swap(g_dap.thread_ids);
+ old_thread_ids.swap(dap.thread_ids);
uint32_t stop_id = process.GetStopID();
const uint32_t num_threads = process.GetNumThreads();
@@ -265,10 +262,10 @@ void SendThreadStoppedEvent() {
const lldb::tid_t tid = thread.GetThreadID();
const bool has_reason = ThreadHasStopReason(thread);
// If the focus thread doesn't have a stop reason, clear the thread ID
- if (tid == g_dap.focus_tid) {
+ if (tid == dap.focus_tid) {
focus_thread_exists = true;
if (!has_reason)
- g_dap.focus_tid = LLDB_INVALID_THREAD_ID;
+ dap.focus_tid = LLDB_INVALID_THREAD_ID;
}
if (has_reason) {
++num_threads_with_reason;
@@ -277,47 +274,46 @@ void SendThreadStoppedEvent() {
}
}
- // We will have cleared g_dap.focus_tid if the focus thread doesn't have
+ // We will have cleared dap.focus_tid if the focus thread doesn't have
// a stop reason, so if it was cleared, or wasn't set, or doesn't exist,
// then set the focus thread to the first thread with a stop reason.
- if (!focus_thread_exists || g_dap.focus_tid == LLDB_INVALID_THREAD_ID)
- g_dap.focus_tid = first_tid_with_reason;
+ if (!focus_thread_exists || dap.focus_tid == LLDB_INVALID_THREAD_ID)
+ dap.focus_tid = first_tid_with_reason;
// If no threads stopped with a reason, then report the first one so
// we at least let the UI know we stopped.
if (num_threads_with_reason == 0) {
lldb::SBThread thread = process.GetThreadAtIndex(0);
- g_dap.focus_tid = thread.GetThreadID();
- g_dap.SendJSON(CreateThreadStopped(g_dap, thread, stop_id));
+ dap.focus_tid = thread.GetThreadID();
+ dap.SendJSON(CreateThreadStopped(dap, thread, stop_id));
} else {
for (uint32_t thread_idx = 0; thread_idx < num_threads; ++thread_idx) {
lldb::SBThread thread = process.GetThreadAtIndex(thread_idx);
- g_dap.thread_ids.insert(thread.GetThreadID());
+ dap.thread_ids.insert(thread.GetThreadID());
if (ThreadHasStopReason(thread)) {
- g_dap.SendJSON(CreateThreadStopped(g_dap, thread, stop_id));
+ dap.SendJSON(CreateThreadStopped(dap, thread, stop_id));
}
}
}
for (auto tid : old_thread_ids) {
- auto end = g_dap.thread_ids.end();
- auto pos = g_dap.thread_ids.find(tid);
+ auto end = dap.thread_ids.end();
+ auto pos = dap.thread_ids.find(tid);
if (pos == end)
- SendThreadExitedEvent(tid);
+ SendThreadExitedEvent(dap, tid);
}
} else {
- if (g_dap.log)
- *g_dap.log << "error: SendThreadStoppedEvent() when process"
- " isn't stopped ("
- << lldb::SBDebugger::StateAsCString(state) << ')'
- << std::endl;
+ if (dap.log)
+ *dap.log << "error: SendThreadStoppedEvent() when process"
+ " isn't stopped ("
+ << lldb::SBDebugger::StateAsCString(state) << ')' << std::endl;
}
} else {
- if (g_dap.log)
- *g_dap.log << "error: SendThreadStoppedEvent() invalid process"
- << std::endl;
+ if (dap.log)
+ *dap.log << "error: SendThreadStoppedEvent() invalid process"
+ << std::endl;
}
- g_dap.RunStopCommands();
+ dap.RunStopCommands();
}
// "ProcessEvent": {
@@ -374,14 +370,14 @@ void SendThreadStoppedEvent() {
// }
// ]
// }
-void SendProcessEvent(LaunchMethod launch_method) {
- lldb::SBFileSpec exe_fspec = g_dap.target.GetExecutable();
+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 = g_dap.target.GetProcess().GetProcessID();
+ const auto pid = dap.target.GetProcess().GetProcessID();
body.try_emplace("systemProcessId", (int64_t)pid);
body.try_emplace("isLocalProcess", true);
const char *startMethod = nullptr;
@@ -398,31 +394,31 @@ void SendProcessEvent(LaunchMethod launch_method) {
}
body.try_emplace("startMethod", startMethod);
event.try_emplace("body", std::move(body));
- g_dap.SendJSON(llvm::json::Value(std::move(event)));
+ dap.SendJSON(llvm::json::Value(std::move(event)));
}
// Grab any STDOUT and STDERR from the process and send it up to VS Code
// via an "output" event to the "stdout" and "stderr" categories.
-void SendStdOutStdErr(lldb::SBProcess &process) {
+void SendStdOutStdErr(DAP &dap, lldb::SBProcess &process) {
char buffer[OutputBufferSize];
size_t count;
while ((count = process.GetSTDOUT(buffer, sizeof(buffer))) > 0)
- g_dap.SendOutput(OutputType::Stdout, llvm::StringRef(buffer, count));
+ dap.SendOutput(OutputType::Stdout, llvm::StringRef(buffer, count));
while ((count = process.GetSTDERR(buffer, sizeof(buffer))) > 0)
- g_dap.SendOutput(OutputType::Stderr, llvm::StringRef(buffer, count));
+ dap.SendOutput(OutputType::Stderr, llvm::StringRef(buffer, count));
}
-void ProgressEventThreadFunction() {
+void ProgressEventThreadFunction(DAP &dap) {
lldb::SBListener listener("lldb-dap.progress.listener");
- g_dap.debugger.GetBroadcaster().AddListener(
+ dap.debugger.GetBroadcaster().AddListener(
listener, lldb::SBDebugger::eBroadcastBitProgress);
- g_dap.broadcaster.AddListener(listener, eBroadcastBitStopProgressThread);
+ dap.broadcaster.AddListener(listener, eBroadcastBitStopProgressThread);
lldb::SBEvent event;
bool done = false;
while (!done) {
if (listener.WaitForEvent(1, event)) {
const auto event_mask = event.GetType();
- if (event.BroadcasterMatchesRef(g_dap.broadcaster)) {
+ if (event.BroadcasterMatchesRef(dap.broadcaster)) {
if (event_mask & eBroadcastBitStopProgressThread) {
done = true;
}
@@ -434,7 +430,7 @@ void ProgressEventThreadFunction() {
const char *message = lldb::SBDebugger::GetProgressFromEvent(
event, progress_id, completed, total, is_debugger_specific);
if (message)
- g_dap.SendProgressEvent(progress_id, message, completed, total);
+ dap.SendProgressEvent(progress_id, message, completed, total);
}
}
}
@@ -445,9 +441,9 @@ void ProgressEventThreadFunction() {
// "FILE *" to output packets back to VS Code and they have mutexes in them
// them prevent multiple threads from writing simultaneously so no locking
// is required.
-void EventThreadFunction() {
+void EventThreadFunction(DAP &dap) {
lldb::SBEvent event;
- lldb::SBListener listener = g_dap.debugger.GetListener();
+ lldb::SBListener listener = dap.debugger.GetListener();
bool done = false;
while (!done) {
if (listener.WaitForEvent(1, event)) {
@@ -483,50 +479,50 @@ void EventThreadFunction() {
// stop events which we do not want to send an event for. We will
// manually send a stopped event in request_configurationDone(...)
// so don't send any before then.
- if (g_dap.configuration_done_sent) {
+ if (dap.configuration_done_sent) {
// Only report a stopped event if the process was not
// automatically restarted.
if (!lldb::SBProcess::GetRestartedFromEvent(event)) {
- SendStdOutStdErr(process);
- SendThreadStoppedEvent();
+ SendStdOutStdErr(dap, process);
+ SendThreadStoppedEvent(dap);
}
}
break;
case lldb::eStateRunning:
- g_dap.WillContinue();
- SendContinuedEvent();
+ dap.WillContinue();
+ SendContinuedEvent(dap);
break;
case lldb::eStateExited:
lldb::SBStream stream;
process.GetStatus(stream);
- g_dap.SendOutput(OutputType::Console, stream.GetData());
+ dap.SendOutput(OutputType::Console, stream.GetData());
// When restarting, we can get an "exited" event for the process we
// just killed with the old PID, or even with no PID. In that case
// we don't have to terminate the session.
if (process.GetProcessID() == LLDB_INVALID_PROCESS_ID ||
- process.GetProcessID() == g_dap.restarting_process_id) {
- g_dap.restarting_process_id = LLDB_INVALID_PROCESS_ID;
+ process.GetProcessID() == dap.restarting_process_id) {
+ dap.restarting_process_id = LLDB_INVALID_PROCESS_ID;
} else {
// Run any exit LLDB commands the user specified in the
// launch.json
- g_dap.RunExitCommands();
- SendProcessExitedEvent(process);
- SendTerminatedEvent();
+ dap.RunExitCommands();
+ SendProcessExitedEvent(dap, process);
+ SendTerminatedEvent(dap);
done = true;
}
break;
}
} else if ((event_mask & lldb::SBProcess::eBroadcastBitSTDOUT) ||
(event_mask & lldb::SBProcess::eBroadcastBitSTDERR)) {
- SendStdOutStdErr(process);
+ SendStdOutStdErr(dap, process);
}
} else if (lldb::SBBreakpoint::EventIsBreakpointEvent(event)) {
if (event_mask & lldb::SBTarget::eBroadcastBitBreakpointChanged) {
auto event_type =
lldb::SBBreakpoint::GetBreakpointEventTypeFromEvent(event);
auto bp = Breakpoint(
- g_dap, lldb::SBBreakpoint::GetBreakpointFromEvent(event));
+ dap, lldb::SBBreakpoint::GetBreakpointFromEvent(event));
// If the breakpoint was originated from the IDE, it will have the
// BreakpointBase::GetBreakpointLabel() label attached. Regardless
// of wether the locations were added or removed, the breakpoint
@@ -548,10 +544,10 @@ void EventThreadFunction() {
body.try_emplace("breakpoint", source_bp);
body.try_emplace("reason", "changed");
bp_event.try_emplace("body", std::move(body));
- g_dap.SendJSON(llvm::json::Value(std::move(bp_event)));
+ dap.SendJSON(llvm::json::Value(std::move(bp_event)));
}
}
- } else if (event.BroadcasterMatchesRef(g_dap.broadcaster)) {
+ } else if (event.BroadcasterMatchesRef(dap.broadcaster)) {
if (event_mask & eBroadcastBitStopEventThread) {
done = true;
}
@@ -560,9 +556,11 @@ void EventThreadFunction() {
}
}
-lldb::SBValue FindVariable(uint64_t variablesReference, llvm::StringRef name) {
+lldb::SBValue FindVariable(DAP &dap, uint64_t variablesReference,
+ llvm::StringRef name) {
lldb::SBValue variable;
- if (lldb::SBValueList *top_scope = GetTopLevelScope(variablesReference)) {
+ if (lldb::SBValueList *top_scope =
+ GetTopLevelScope(dap, variablesReference)) {
bool is_duplicated_variable_name = name.contains(" @");
// variablesReference is one of our scopes, not an actual variable it is
// asking for a variable in locals or globals or registers
@@ -584,7 +582,7 @@ lldb::SBValue FindVariable(uint64_t variablesReference, llvm::StringRef name) {
// We have a named item within an actual variable so we need to find it
// withing the container variable by name.
- lldb::SBValue container = g_dap.variables.GetVariable(variablesReference);
+ lldb::SBValue container = dap.variables.GetVariable(variablesReference);
variable = container.GetChildMemberWithName(name.data());
if (!variable.IsValid()) {
if (name.starts_with("[")) {
@@ -602,7 +600,7 @@ lldb::SBValue FindVariable(uint64_t variablesReference, llvm::StringRef name) {
// Both attach and launch take a either a sourcePath or sourceMap
// argument (or neither), from which we need to set the target.source-map.
-void SetSourceMapFromArguments(const llvm::json::Object &arguments)...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/116272
More information about the lldb-commits
mailing list