Skip to content
Merged
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
15 changes: 12 additions & 3 deletions lldb/docs/resources/lldbgdbremote.md
Original file line number Diff line number Diff line change
Expand Up @@ -2814,9 +2814,18 @@ packet when one is hit. Each breakpoint object has the following fields:
Exactly one of `by_name` or `by_address` must be provided for each
breakpoint.

In future patches, each `accelerator_action` will include additional fields
such as connection info for secondary debug sessions and synchronization
options.
An `accelerator_action` may also include a `connect_info` object asking the
client to create a new target and connect to a separate GDB server that
serves the accelerator's state (for example a GPU debug stub). It has the
following fields:

| Key | Type | Description |
|-----------------|--------|-------------|
| `connect_url` | string | Connection URL to connect to, as used by `process connect <url>`. |
| `platform_name` | string | Name of the platform to select when creating the accelerator target. The platform must be able to handle `triple` and is used to connect to the accelerator's GDB server. |
| `triple` | string | Target triple for the accelerator target, used to ensure the architecture is compatible with `platform_name`. |
| `exe_path` | string | Optional path to the executable to use when creating the accelerator target. If omitted, an empty target is created. |
| `synchronous` | bool | If true, connect synchronously: the client blocks until the accelerator process is connected and stopped before continuing. If false, the connection is made asynchronously. |

**Priority To Implement:** Required for hardware accelerator debugging
support. Not needed for non-hardware-accelerator debugging.
Expand Down
30 changes: 30 additions & 0 deletions lldb/include/lldb/Utility/AcceleratorGDBRemotePackets.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,33 @@ bool fromJSON(const llvm::json::Value &value,
AcceleratorBreakpointHitArgs &data, llvm::json::Path path);
llvm::json::Value toJSON(const AcceleratorBreakpointHitArgs &data);

/// Information the client needs to connect to an accelerator GDB server. When
/// an AcceleratorActions carries this, the client creates a new target and
/// connects to \a connect_url.
struct AcceleratorConnectionInfo {
/// Connection URL the client should connect to (as in "process connect
/// <url>").
std::string connect_url;
/// Name of the platform to select when creating the accelerator target. The
/// platform must be able to handle \a triple and is used to connect to the
/// accelerator's GDB server.
std::string platform_name;
/// Target triple for the accelerator target. Used to ensure the architecture
/// is compatible with \a platform_name.
std::string triple;
/// Path to the executable to use when creating the accelerator target. If
/// not set, an empty target is created.
std::optional<std::string> exe_path;
/// If true, connect synchronously: the client blocks until the accelerator
/// process is connected and stopped before continuing. If false, the
/// connection is made asynchronously.
bool synchronous = false;
};

bool fromJSON(const llvm::json::Value &value, AcceleratorConnectionInfo &data,
llvm::json::Path path);
llvm::json::Value toJSON(const AcceleratorConnectionInfo &data);

/// Actions to be performed in the native process on behalf of an accelerator
/// plugin. AcceleratorActions are returned in the following contexts:
///
Expand Down Expand Up @@ -114,6 +141,9 @@ struct AcceleratorActions {
int64_t identifier = 0;
/// New breakpoints to set. Nothing to set if this is empty.
std::vector<AcceleratorBreakpointInfo> breakpoints;
/// If set, the client should create a new target and connect to the
/// accelerator GDB server described here.
std::optional<AcceleratorConnectionInfo> connect_info;
};

bool fromJSON(const llvm::json::Value &value, AcceleratorActions &data,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,13 @@

#include "LLDBServerAcceleratorPlugin.h"

#include "GDBRemoteCommunicationServerLLGS.h"

using namespace lldb_private::lldb_server;

LLDBServerAcceleratorPlugin::LLDBServerAcceleratorPlugin(GDBServer &gdb_server,
MainLoop &main_loop)
: m_gdb_server(gdb_server), m_main_loop(main_loop) {}
LLDBServerAcceleratorPlugin::LLDBServerAcceleratorPlugin(
GDBServer &native_gdb_server, MainLoop &native_main_loop)
: m_native_gdb_server(native_gdb_server),
m_native_main_loop(native_main_loop) {}

LLDBServerAcceleratorPlugin::~LLDBServerAcceleratorPlugin() = default;
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@
#define LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_LLDBSERVERACCELERATORPLUGIN_H

#include "lldb/Host/MainLoop.h"
#include "lldb/Host/common/NativeProcessProtocol.h"
#include "lldb/Utility/AcceleratorGDBRemotePackets.h"
#include "llvm/ADT/StringRef.h"
#include <memory>
#include <optional>

namespace lldb_private {
Expand All @@ -25,8 +27,10 @@ namespace lldb_server {
class LLDBServerAcceleratorPlugin {
public:
using GDBServer = process_gdb_remote::GDBRemoteCommunicationServerLLGS;
using Manager = NativeProcessProtocol::Manager;

LLDBServerAcceleratorPlugin(GDBServer &gdb_server, MainLoop &main_loop);
LLDBServerAcceleratorPlugin(GDBServer &native_gdb_server,
MainLoop &native_main_loop);
virtual ~LLDBServerAcceleratorPlugin();

virtual llvm::StringRef GetPluginName() = 0;
Expand All @@ -36,9 +40,19 @@ class LLDBServerAcceleratorPlugin {
virtual llvm::Expected<AcceleratorBreakpointHitResponse>
BreakpointWasHit(AcceleratorBreakpointHitArgs &args) = 0;

/// Create an AcceleratorActions with an identifier unique within this plugin,
/// so identifiers from different actions don't collide.
AcceleratorActions GetNewAcceleratorAction() {
return AcceleratorActions(GetPluginName(),
++m_accelerator_action_identifier);
}

protected:
GDBServer &m_gdb_server;
MainLoop &m_main_loop;
GDBServer &m_native_gdb_server;
MainLoop &m_native_main_loop;
std::unique_ptr<Manager> m_process_manager_up;
std::unique_ptr<GDBServer> m_accelerator_gdb_server;
int64_t m_accelerator_action_identifier = 0;
};

} // namespace lldb_server
Expand Down
66 changes: 63 additions & 3 deletions lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
#include "lldb/Interpreter/CommandReturnObject.h"
#include "lldb/Interpreter/OptionArgParser.h"
#include "lldb/Interpreter/OptionGroupBoolean.h"
#include "lldb/Interpreter/OptionGroupPlatform.h"
#include "lldb/Interpreter/OptionGroupUInt64.h"
#include "lldb/Interpreter/OptionValueProperties.h"
#include "lldb/Interpreter/Options.h"
Expand Down Expand Up @@ -4238,6 +4239,59 @@ ProcessGDBRemote::HandleAcceleratorActions(const AcceleratorActions &actions) {
return error;
}

if (actions.connect_info) {
if (llvm::Error error = HandleAcceleratorConnection(actions))
return error;
}

return llvm::Error::success();
}

llvm::Error ProcessGDBRemote::HandleAcceleratorConnection(
const AcceleratorActions &actions) {
const AcceleratorConnectionInfo &connect_info = *actions.connect_info;
Debugger &debugger = GetTarget().GetDebugger();

OptionGroupPlatform platform_options(/*include_platform_option=*/false);
platform_options.SetPlatformName(connect_info.platform_name.c_str());
std::string exe_path = connect_info.exe_path.value_or("");
TargetSP accelerator_target_sp;
Status error = debugger.GetTargetList().CreateTarget(
debugger, exe_path, connect_info.triple, eLoadDependentsNo,
&platform_options, accelerator_target_sp);
if (error.Fail())
return error.takeError();
if (!accelerator_target_sp)
return llvm::createStringError("failed to create accelerator target");

PlatformSP platform_sp = accelerator_target_sp->GetPlatform();
if (!platform_sp)
return llvm::createStringErrorV(
"no platform '{0}' compatible with triple '{1}' for the accelerator "
"target",
connect_info.platform_name, connect_info.triple);
ProcessSP process_sp =
connect_info.synchronous
? platform_sp->ConnectProcessSynchronous(
connect_info.connect_url, GetPluginNameStatic(), debugger,
*debugger.GetAsyncOutputStream(), accelerator_target_sp.get(),
error)
: platform_sp->ConnectProcess(connect_info.connect_url,
GetPluginNameStatic(), debugger,
accelerator_target_sp.get(), error);
if (error.Fail())
return error.takeError();
if (!process_sp)
return llvm::createStringError("failed to connect to the accelerator");

accelerator_target_sp->SetTargetSessionName(actions.session_name);

// Broadcast the new-target event so API clients can detect it.
auto event_sp = std::make_shared<Event>(
Target::eBroadcastBitNewTargetCreated,
new Target::TargetEventData(GetTarget().shared_from_this(),
accelerator_target_sp));
GetTarget().BroadcastEvent(event_sp);
return llvm::Error::success();
}

Expand Down Expand Up @@ -4372,9 +4426,15 @@ bool ProcessGDBRemote::AcceleratorBreakpointHit(
// The plugin may request new actions (e.g. additional breakpoints) in
// response to this breakpoint being hit.
if (response->actions) {
if (llvm::Error error = HandleAcceleratorActions(*response->actions))
LLDB_LOG_ERROR(log, std::move(error),
"failed to handle accelerator actions: {0}");
if (llvm::Error error = HandleAcceleratorActions(*response->actions)) {
// Also print the failure to the user; during a stop, logging alone is
// invisible.
std::string message = llvm::toString(std::move(error));
LLDB_LOG(log, "failed to handle accelerator actions: {0}", message);
target.GetDebugger().GetAsyncErrorStream()->Printf(
"error: accelerator plugin '%s': %s\n",
response->actions->plugin_name.c_str(), message.c_str());
}
}

// Returning true stops the native process; false auto-resumes it.
Expand Down
4 changes: 4 additions & 0 deletions lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
Original file line number Diff line number Diff line change
Expand Up @@ -488,6 +488,10 @@ class ProcessGDBRemote : public Process,
/// breakpoints are still set.
llvm::Error HandleAcceleratorBreakpoints(const AcceleratorActions &actions);

/// Create a new target for an accelerator and connect it to the GDB server
/// described by the action's connection info.
llvm::Error HandleAcceleratorConnection(const AcceleratorActions &actions);

/// Breakpoint callback invoked when an accelerator-plugin-requested
/// breakpoint is hit. Resolves any requested symbol values, notifies the
/// plugin via the "jAcceleratorPluginBreakpointHit" packet, and handles the
Expand Down
25 changes: 23 additions & 2 deletions lldb/source/Utility/AcceleratorGDBRemotePackets.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,21 +86,42 @@ AcceleratorBreakpointHitArgs::GetSymbolValue(StringRef symbol_name) const {
return std::nullopt;
}

bool fromJSON(const Value &value, AcceleratorConnectionInfo &data, Path path) {
ObjectMapper o(value, path);
return o && o.map("connect_url", data.connect_url) &&
o.map("platform_name", data.platform_name) &&
o.map("triple", data.triple) &&
o.mapOptional("exe_path", data.exe_path) &&
o.map("synchronous", data.synchronous);
}

json::Value toJSON(const AcceleratorConnectionInfo &data) {
return Object{
{"connect_url", data.connect_url}, {"platform_name", data.platform_name},
{"triple", data.triple}, {"exe_path", data.exe_path},
{"synchronous", data.synchronous},
};
}

bool fromJSON(const Value &value, AcceleratorActions &data, Path path) {
ObjectMapper o(value, path);
return o && o.map("plugin_name", data.plugin_name) &&
o.map("session_name", data.session_name) &&
o.map("identifier", data.identifier) &&
o.map("breakpoints", data.breakpoints);
o.map("breakpoints", data.breakpoints) &&
o.mapOptional("connect_info", data.connect_info);
}

json::Value toJSON(const AcceleratorActions &data) {
return Object{
Object obj{
{"plugin_name", data.plugin_name},
{"session_name", data.session_name},
{"identifier", data.identifier},
{"breakpoints", data.breakpoints},
};
if (data.connect_info)
obj["connect_info"] = *data.connect_info;
return obj;
}

bool fromJSON(const Value &value, AcceleratorBreakpointHitResponse &data,
Expand Down
Loading