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
32 changes: 28 additions & 4 deletions lldb/docs/resources/lldbgdbremote.md
Original file line number Diff line number Diff line change
Expand Up @@ -2706,6 +2706,20 @@ The packets below support debugging hardware accelerators (e.g. GPUs,
FPGAs) alongside the native host process via accelerator plugins installed
in lldb-server.

An accelerator plugin drives the client by returning a list of
`AcceleratorActions` (currently just breakpoints to set in the native
process). The client can receive `AcceleratorActions` at two points:

1. Once, in response to the `jAcceleratorPluginInitialize` packet sent when
the native process is launched or attached.
2. In response to a `jAcceleratorPluginBreakpointHit` packet, when a
breakpoint the plugin previously requested is hit. The hit response may
carry a further set of `AcceleratorActions`.

Each set of `AcceleratorActions` is tagged with a `plugin_name` and an
`identifier` that is unique within that plugin, so the client can ignore a
set it has already processed if the same actions are delivered again.

### jAcceleratorPluginInitialize

This packet requests initialization data from all accelerator plugins
Expand Down Expand Up @@ -2746,9 +2760,19 @@ If no accelerator plugins are installed, the server does not advertise the
`accelerator-plugins+` feature and this packet should not be sent.

Each `accelerator_action` may include a `breakpoints` array requesting
breakpoints to be set in the native process. See
`jAcceleratorPluginBreakpointHit` for the callback when those breakpoints
are hit.
breakpoints to be set in the native process. The client sets each of these
as an internal breakpoint and sends a `jAcceleratorPluginBreakpointHit`
packet when one is hit. Each breakpoint object has the following fields:

| Key | Type | Description |
|----------------|---------|-------------|
| `identifier` | integer | Identifier for this breakpoint, unique within the plugin. It is echoed back in the `jAcceleratorPluginBreakpointHit` packet so the plugin knows which breakpoint was hit. |
| `by_name` | object | Set the breakpoint by function name. Contains `function_name` (string) and an optional `shlib` (string) to scope the breakpoint to a single shared library. |
| `by_address` | object | Set the breakpoint by load address. Contains `load_address` (integer). |
| `symbol_names` | array | Symbol names whose load addresses the client should resolve and deliver in the `jAcceleratorPluginBreakpointHit` packet when this breakpoint is hit. May be empty. |

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
Expand All @@ -2774,7 +2798,7 @@ The request JSON has the following fields:
|-----------------|--------|-------------|
| `plugin_name` | string | Name of the plugin that requested the breakpoint. |
| `breakpoint` | object | The `AcceleratorBreakpointInfo` that was hit, including its `identifier`. |
| `symbol_values` | array | Array of `{"name": "<name>", "value": <addr>}` for each symbol requested in the breakpoint's `symbol_names`. |
| `symbol_values` | array | Array of `{"name": "<name>", "value": <addr>}`, one entry for each name in the breakpoint's `symbol_names`. `value` is the resolved load address, or `null` if the client could not find the symbol or convert it to a load address. |

The response JSON has the following fields:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "lldb/Target/MemoryRegionInfo.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/UnixSignals.h"
#include "lldb/Utility/AcceleratorGDBRemotePackets.h"
#include "lldb/Utility/Args.h"
#include "lldb/Utility/DataBufferHeap.h"
#include "lldb/Utility/LLDBAssert.h"
Expand All @@ -39,6 +40,7 @@
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Config/llvm-config.h" // for LLVM_ENABLE_ZLIB
#include "llvm/Support/ErrorExtras.h"
#include "llvm/Support/JSON.h"

#if HAVE_LIBCOMPRESSION
Expand Down Expand Up @@ -223,6 +225,79 @@ bool GDBRemoteCommunicationClient::GetMultiBreakpointSupported() {
return m_supports_multi_breakpoint == eLazyBoolYes;
}

bool GDBRemoteCommunicationClient::GetAcceleratorPluginsSupported() {
if (m_supports_accelerator_plugins == eLazyBoolCalculate)
GetRemoteQSupported();
return m_supports_accelerator_plugins == eLazyBoolYes;
}

llvm::Expected<std::vector<AcceleratorActions>>
GDBRemoteCommunicationClient::GetAcceleratorInitializeActions() {
// Get the initial actions (e.g. breakpoints to set) requested by any
// accelerator plugins using the "jAcceleratorPluginInitialize" packet. This
// is sent once when a native process is launched or attached. The empty
// state (no plugins / no actions) is modelled as an empty vector; errors are
// returned to the caller to report.
if (!GetAcceleratorPluginsSupported())
return std::vector<AcceleratorActions>();

StringExtractorGDBRemote response;
response.SetResponseValidatorToJSON();
if (SendPacketAndWaitForResponse("jAcceleratorPluginInitialize", response) !=
PacketResult::Success)
return llvm::createStringError(
"failed to send jAcceleratorPluginInitialize packet");

if (response.IsUnsupportedResponse())
return std::vector<AcceleratorActions>();

if (response.IsErrorResponse())
return response.GetStatus().takeError();

llvm::Expected<std::vector<AcceleratorActions>> actions =
llvm::json::parse<std::vector<AcceleratorActions>>(response.Peek(),
"AcceleratorActions");
if (actions)
return actions;

// A bare JSON parse error (e.g. "missing comma at line 4") is meaningless on
// its own, so include both the full response and the parse error; the caller
// logs this and the user can spot the problem in the response.
return llvm::createStringErrorV(
"malformed jAcceleratorPluginInitialize response '{0}': {1}",
response.GetStringRef(), llvm::toString(actions.takeError()));
}

llvm::Expected<AcceleratorBreakpointHitResponse>
GDBRemoteCommunicationClient::AcceleratorBreakpointHit(
const AcceleratorBreakpointHitArgs &args) {
StreamGDBRemote packet;
packet.PutCString("jAcceleratorPluginBreakpointHit:");
packet.PutAsJSON(args, /*hex_ascii=*/false);

StringExtractorGDBRemote response;
if (SendPacketAndWaitForResponse(packet.GetString(), response) !=
PacketResult::Success)
return llvm::createStringError(
"failed to send jAcceleratorPluginBreakpointHit packet");

if (response.IsErrorResponse())
return response.GetStatus().takeError();

llvm::Expected<AcceleratorBreakpointHitResponse> hit_response =
llvm::json::parse<AcceleratorBreakpointHitResponse>(
response.Peek(), "AcceleratorBreakpointHitResponse");
if (hit_response)
return hit_response;

// A bare JSON parse error (e.g. "missing comma at line 4") is meaningless on
// its own, so include both the full response and the parse error; the caller
// logs this and the user can spot the problem in the response.
return llvm::createStringErrorV(
"malformed jAcceleratorPluginBreakpointHit response '{0}': {1}",
response.GetStringRef(), llvm::toString(hit_response.takeError()));
}

bool GDBRemoteCommunicationClient::QueryNoAckModeSupported() {
if (m_supports_not_sending_acks == eLazyBoolCalculate) {
m_send_acks = true;
Expand Down Expand Up @@ -321,6 +396,7 @@ void GDBRemoteCommunicationClient::ResetDiscoverableSettings(bool did_exec) {
m_x_packet_state.reset();
m_supports_reverse_continue = eLazyBoolCalculate;
m_supports_reverse_step = eLazyBoolCalculate;
m_supports_accelerator_plugins = eLazyBoolCalculate;
m_supports_qProcessInfoPID = true;
m_supports_qfProcessInfo = true;
m_supports_qUserName = true;
Expand Down Expand Up @@ -381,6 +457,7 @@ void GDBRemoteCommunicationClient::GetRemoteQSupported() {
m_supports_reverse_step = eLazyBoolNo;
m_supports_multi_mem_read = eLazyBoolNo;
m_supports_multi_breakpoint = eLazyBoolNo;
m_supports_accelerator_plugins = eLazyBoolNo;

m_max_packet_size = UINT64_MAX; // It's supposed to always be there, but if
// not, we assume no limit
Expand Down Expand Up @@ -444,6 +521,8 @@ void GDBRemoteCommunicationClient::GetRemoteQSupported() {
m_supports_multi_mem_read = eLazyBoolYes;
else if (x == "jMultiBreakpoint+")
m_supports_multi_breakpoint = eLazyBoolYes;
else if (x == "accelerator-plugins+")
m_supports_accelerator_plugins = eLazyBoolYes;
// Look for a list of compressions in the features list e.g.
// qXfer:features:read+;PacketSize=20000;qEcho+;SupportedCompressions=zlib-
// deflate,lzma
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include <vector>

#include "lldb/Host/File.h"
#include "lldb/Utility/AcceleratorGDBRemotePackets.h"
#include "lldb/Utility/AddressableBits.h"
#include "lldb/Utility/ArchSpec.h"
#include "lldb/Utility/GDBRemote.h"
Expand Down Expand Up @@ -346,6 +347,26 @@ class GDBRemoteCommunicationClient : public GDBRemoteClientBase {

bool GetMultiBreakpointSupported();

bool GetAcceleratorPluginsSupported();

/// Send the "jAcceleratorPluginInitialize" packet and return the actions
/// requested by each accelerator plugin installed in lldb-server. The packet
/// is only sent if the lldb-server advertised accelerator plugin support via
/// "accelerator-plugins+" in its qSupported response; otherwise (and when no
/// plugin returns actions) this returns an empty vector. Errors are returned
/// for the caller to report.
llvm::Expected<std::vector<AcceleratorActions>>
GetAcceleratorInitializeActions();

/// Send the "jAcceleratorPluginBreakpointHit" packet to notify the
/// accelerator plugin that one of its requested breakpoints was hit, and
/// return the plugin's response. This is only used when the lldb-server
/// advertised accelerator plugin support via "accelerator-plugins+" in its
/// qSupported response, since the breakpoints that trigger it are only set in
/// that case. Errors are returned for the caller to report.
llvm::Expected<AcceleratorBreakpointHitResponse>
AcceleratorBreakpointHit(const AcceleratorBreakpointHitArgs &args);

LazyBool SupportsAllocDeallocMemory() // const
{
// Uncomment this to have lldb pretend the debug server doesn't respond to
Expand Down Expand Up @@ -582,6 +603,7 @@ class GDBRemoteCommunicationClient : public GDBRemoteClientBase {
LazyBool m_supports_reverse_step = eLazyBoolCalculate;
LazyBool m_supports_multi_mem_read = eLazyBoolCalculate;
LazyBool m_supports_multi_breakpoint = eLazyBoolCalculate;
LazyBool m_supports_accelerator_plugins = eLazyBoolCalculate;

bool m_supports_qProcessInfoPID : 1, m_supports_qfProcessInfo : 1,
m_supports_qUserName : 1, m_supports_qGroupName : 1,
Expand Down
Loading