Summary This builds on the accelerator plugin protocol (https://github.com/llvm/llvm-project/pull/201489) by letting a plugin ask the client to create and connect a second target — the mechanism a real backend (e.g. a GPU debug stub) uses to surface the accelerator alongside the CPU process being debugged. ### What this adds **Protocol** — a new `AcceleratorConnectionInfo` describing how the client should bring up the accelerator target. **Client** — when an `AcceleratorActions` carries `connect_info`, `ProcessGDBRemote` creates a new (empty) target, reverse-connects it to the GDB server the plugin points. **Mock server (for testing)** — to exercise this end to end, the mock accelerator plugin stands up an in-process GDB server backed by a minimal fake process: `ProcessMockAccelerator`, `ThreadMockAccelerator` and `RegisterContextMockAccelerator`. ### Scope Intentionally minimal: the goal is to create and show the second (accelerator) target. There is no register/memory modeling beyond what a connection requires. Next set of PRs will build up on this. ### Testing Demo of how this looks with this PR. (explicitly asking the native process to stop at every breakpoint for testability) ``` satyajanga@devgpu011:toolchain $ ./bin/lldb (lldb) file /home/satyajanga/llvm-sand/build/Debug/fbcode-x86_64/toolchain/lldb-test-build.noindex/accelerator/mock/TestMockAcceleratorActions/a.out Current executable set to '/home/satyajanga/llvm-sand/build/Debug/fbcode-x86_64/toolchain/lldb-test-build.noindex/accelerator/mock/TestMockAcceleratorActions/a.out' (x86_64). (lldb) log enable -f /tmp/packets.log gdb-remote packets (lldb) r Process 1430531 launched: '/home/satyajanga/llvm-sand/build/Debug/fbcode-x86_64/toolchain/lldb-test-build.noindex/accelerator/mock/TestMockAcceleratorActions/a.out' (x86_64) Process 1430531 stopped (lldb) target list Current targets: * target #0: /home/satyajanga/llvm-sand/build/Debug/fbcode-x86_64/toolchain/lldb-test-build.noindex/accelerator/mock/TestMockAcceleratorActions/a.out ( arch=x86_64-unknown-linux-gnu, platform=host, pid=1430531, state=stopped ) (lldb) c Process 1430531 resuming Process 1 stopped * thread #1, name = 'Mock Accelerator Thread', stop reason = trace frame #0: 0x0000000000001004 error: memory read failed for 0x1000 Target 0: (a.out) stopped. (lldb) target list Current targets: target #0: /home/satyajanga/llvm-sand/build/Debug/fbcode-x86_64/toolchain/lldb-test-build.noindex/accelerator/mock/TestMockAcceleratorActions/a.out ( arch=x86_64-unknown-linux-gnu, platform=host, pid=1430531, state=stopped ) * target #1: <none> ( arch=x86_64-unknown-linux-gnu, platform=host, pid=1, state=stopped ) (lldb) c Process 1 resuming (lldb) target select 0 Current targets: * target #0: /home/satyajanga/llvm-sand/build/Debug/fbcode-x86_64/toolchain/lldb-test-build.noindex/accelerator/mock/TestMockAcceleratorActions/a.out ( arch=x86_64-unknown-linux-gnu, platform=host, pid=1430531, state=stopped ) target #1: <none> ( arch=x86_64-unknown-linux-gnu, platform=host, pid=1, state=running ) (lldb) c Process 1430531 resuming Process 1430531 stopped (lldb) target list Current targets: * target #0: /home/satyajanga/llvm-sand/build/Debug/fbcode-x86_64/toolchain/lldb-test-build.noindex/accelerator/mock/TestMockAcceleratorActions/a.out ( arch=x86_64-unknown-linux-gnu, platform=host, pid=1430531, state=stopped ) target #1: <none> ( arch=x86_64-unknown-linux-gnu, platform=host, pid=1, state=running ) (lldb) a.out │ internal accelerator-plugin (mock) breakpoint(-4). ``` Packet log, you can notice the actions set with breakpoint info and later responding with connection info. and you can also see the 5 GPRs ``` lldb < 104> send packet: $qSupported:xmlRegisters=i386,arm,mips,arc;multiprocess+;fork-events+;vfork-events+;swbreak+;hwbreak+#cd lldb < 299> read packet: $PacketSize=131072;QStartNoAckMode+;qEcho+;native-signals+;QThreadSuffixSupported+;QListThreadsInStopReply+;qXfer:features:read+;QNonStop+;jMultiBreakpoint+;QPassSignals+;qXfer:auxv:read+;qXfer:libraries-svr4:read+;qXfer:siginfo:read+;accelerator-plugins+;multiprocess+;fork-events+;vfork-events+#86 .. lldb < 32> send packet: $jAcceleratorPluginInitialize#50 lldb < 238> read packet: $[{"breakpoints":[{"by_address":null,"by_name":{"function_name":"mock_gpu_accelerator_initialize","shlib":null}],"identifier":1,"symbol_names":["mock_gpu_accelerator_compute"]}]],"identifier":1,"plugin_name":"mock","session_name":""}]]#2f .. intern-state < 314> send packet: $jAcceleratorPluginBreakpointHit:{"breakpoint":{"by_address":null,"by_name":{"function_name":"mock_gpu_accelerator_initialize","shlib":null}],"identifier":1,"symbol_names":["mock_gpu_accelerator_compute"]}],"plugin_name":"mock","symbol_values":[{"name":"mock_gpu_accelerator_compute","value":93824992235840}]]}]#e7 intern-state < 487> read packet: ${"actions":{"breakpoints":[{"by_address":null,"by_name":{"function_name":"mock_gpu_accelerator_finish","shlib":"a.out"}],"identifier":3,"symbol_names":[]}],{"by_address":{"load_address":93824992235840}],"by_name":null,"identifier":2,"symbol_names":[]}],{"by_address":null,"by_name":{"function_name":"mock_gpu_accelerator_connect","shlib":null}],"identifier":4,"symbol_names":[]}]],"identifier":2,"plugin_name":"mock","session_name":""}],"auto_resume_native":false,"disable_bp":true}]#7d .. .. intern-state < 218> send packet: $jAcceleratorPluginBreakpointHit:{"breakpoint":{"by_address":null,"by_name":{"function_name":"mock_gpu_accelerator_connect","shlib":null}],"identifier":4,"symbol_names":[]}],"plugin_name":"mock","symbol_values":[]}]#d1 intern-state < 268> read packet: ${"actions":{"breakpoints":[],"connect_info":{"connect_url":"connect://localhost:32893","exe_path":null,"synchronous":true,"triple":null}],"identifier":4,"plugin_name":"mock","session_name":"Mock Accelerator Session"}],"auto_resume_native":false,"disable_bp":true}]#8e intern-state < 1> send packet: + intern-state history[1] tid=0x15d41f < 1> send packet: + intern-state < 19> send packet: $QStartNoAckMode#b0 intern-state < 1> read packet: + intern-state < 6> read packet: $OK#9a intern-state < 1> send packet: + intern-state < 104> send packet: $qSupported:xmlRegisters=i386,arm,mips,arc;multiprocess+;fork-events+;vfork-events+;swbreak+;hwbreak+#cd intern-state < 159> read packet: $PacketSize=131072;QStartNoAckMode+;qEcho+;native-signals+;QThreadSuffixSupported+;QListThreadsInStopReply+;qXfer:features:read+;QNonStop+;jMultiBreakpoint+#f3 intern-state < 26> send packet: $QThreadSuffixSupported#e4 intern-state < 6> read packet: $OK#9a intern-state < 27> send packet: $QListThreadsInStopReply#21 intern-state < 6> read packet: $OK#9a intern-state < 13> send packet: $qHostInfo#9b intern-state < 364> read packet: $triple:7838365f36342d2d6c696e75782d676e75;ptrsize:8;watchpoint_exceptions_received:after;endian:little;os_version:6.13.2;os_build:362e31332e322d305f66626b355f 68617264656e65645f7263325f305f67313733613962316463613431;os_kernel:233120534d5020576564204a756c2032332030393a32343a3330205044542032303235;hostname:6465766770753031312e656167322e66616365626f6f6b2e6 36f6d;#c4 intern-state < 10> send packet: $vCont?#49 intern-state < 19> read packet: $vCont;c;C;s;S;t#11 intern-state < 27> send packet: $qVAttachOrWaitSupported#38 intern-state < 6> read packet: $OK#9a intern-state < 23> send packet: $QEnableErrorStrings#8c intern-state < 6> read packet: $OK#9a intern-state < 16> send packet: $qProcessInfo#dc intern-state < 7> read packet: $E01#a6 intern-state < 6> send packet: $qC#b4 intern-state < 7> read packet: $QC1#c5 intern-state < 5> send packet: $?#3f intern-state < 291> read packet: $T00thread:1;name:Mock Accelerator Thread;threads:1;thread-pcs:0000000000001004;00:0010000000000000;01:0110000000000000;02:0210000000000000;03:0310000000000000 ;04:0410000000000000;05:0510000000000000;reason:trace;description:6d6f636b20616363656c657261746f72207468726561642073746f70706564;#83 intern-state < 16> send packet: $qProcessInfo#dc intern-state < 7> read packet: $E01#a6 intern-state < 16> send packet: $qProcessInfo#dc intern-state < 7> read packet: $E01#a6 intern-state < 43> send packet: $qXfer:features:read:target.xml:0,131071#78 intern-state < 889> read packet: $l<?xml version="1.0"?> <target version="1.0"> <architecture>x86_64</architecture> <feature> <reg name="r0" bitsize="64" regnum="0" offset="0" encoding="uint" format="hex" group="General Purpose Registers" /> <reg name="r1" bitsize="64" regnum="1" offset="8" encoding="uint" format="hex" group="General Purpose Registers" /> <reg name="sp" bitsize="64" regnum="2" offset="16" encoding="uint" format="hex" group="General Purpose Registers" generic="sp" /> <reg name="fp" bitsize="64" regnum="3" offset="24" encoding="uint" format="hex" group="General Purpose Registers" generic="fp" /> <reg name="pc" bitsize="64" regnum="4" offset="32" encoding="uint" format="hex" group="General Purpose Registers" generic="pc" /> <reg name="flags" bitsize="64" regnum="5" offset="40" encoding="uint" format="hex" group="General Purpose Registers" /> </feature> </target> #82 intern-state < 19> send packet: $p0;thread:0001;#89 intern-state < 20> read packet: $0010000000000000#01 intern-state < 16> send packet: $qProcessInfo#dc intern-state < 7> read packet: $E01#a6 intern-state < 19> send packet: $p0;thread:0001;#89 intern-state < 20> read packet: $0010000000000000#01 intern-state < 16> send packet: $qProcessInfo#dc intern-state < 7> read packet: $E01#a6 intern-state < 16> send packet: $qProcessInfo#dc intern-state < 7> read packet: $E01#a6 intern-state < 16> send packet: $qProcessInfo#dc intern-state < 7> read packet: $E01#a6 intern-state < 26> send packet: $qStructuredDataPlugins#02 intern-state < 6> read packet: $[]#b8 intern-state < 26> send packet: $qMemoryRegionInfo:1004#d9 intern-state < 41> read packet: $error:6e6f7420696d706c656d656e746564;#f7 intern-state < 16> send packet: $jThreadsInfo#c1 intern-state < 198> read packet: $[{"description":"mock accelerator thread stopped","name":"Mock Accelerator Thread","reason":"trace","registers":{"2":"0210000000000000","3":"0310000000000000" ,"4":"0410000000000000"}],"tid":1}]]#4a ```
146 lines
4.7 KiB
C++
146 lines
4.7 KiB
C++
//===----------------------------------------------------------------------===//
|
|
//
|
|
// 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 "lldb/Utility/AcceleratorGDBRemotePackets.h"
|
|
|
|
using namespace llvm;
|
|
using namespace llvm::json;
|
|
|
|
namespace lldb_private {
|
|
|
|
bool fromJSON(const Value &value, SymbolValue &data, Path path) {
|
|
ObjectMapper o(value, path);
|
|
return o && o.map("name", data.name) && o.map("value", data.value);
|
|
}
|
|
|
|
json::Value toJSON(const SymbolValue &data) {
|
|
return Object{{"name", data.name}, {"value", data.value}};
|
|
}
|
|
|
|
bool fromJSON(const Value &value, AcceleratorBreakpointByName &data,
|
|
Path path) {
|
|
ObjectMapper o(value, path);
|
|
return o && o.mapOptional("shlib", data.shlib) &&
|
|
o.map("function_name", data.function_name);
|
|
}
|
|
|
|
json::Value toJSON(const AcceleratorBreakpointByName &data) {
|
|
return Object{{"shlib", data.shlib}, {"function_name", data.function_name}};
|
|
}
|
|
|
|
bool fromJSON(const Value &value, AcceleratorBreakpointByAddress &data,
|
|
Path path) {
|
|
ObjectMapper o(value, path);
|
|
return o && o.map("load_address", data.load_address);
|
|
}
|
|
|
|
json::Value toJSON(const AcceleratorBreakpointByAddress &data) {
|
|
return Object{{"load_address", static_cast<int64_t>(data.load_address)}};
|
|
}
|
|
|
|
bool fromJSON(const Value &value, AcceleratorBreakpointInfo &data, Path path) {
|
|
ObjectMapper o(value, path);
|
|
return o && o.map("identifier", data.identifier) &&
|
|
o.mapOptional("by_name", data.by_name) &&
|
|
o.mapOptional("by_address", data.by_address) &&
|
|
o.map("symbol_names", data.symbol_names);
|
|
}
|
|
|
|
json::Value toJSON(const AcceleratorBreakpointInfo &data) {
|
|
return Object{
|
|
{"identifier", data.identifier},
|
|
{"by_name", data.by_name},
|
|
{"by_address", data.by_address},
|
|
{"symbol_names", data.symbol_names},
|
|
};
|
|
}
|
|
|
|
bool fromJSON(const Value &value, AcceleratorBreakpointHitArgs &data,
|
|
Path path) {
|
|
ObjectMapper o(value, path);
|
|
return o && o.map("plugin_name", data.plugin_name) &&
|
|
o.map("breakpoint", data.breakpoint) &&
|
|
o.map("symbol_values", data.symbol_values);
|
|
}
|
|
|
|
json::Value toJSON(const AcceleratorBreakpointHitArgs &data) {
|
|
return Object{
|
|
{"plugin_name", data.plugin_name},
|
|
{"breakpoint", data.breakpoint},
|
|
{"symbol_values", data.symbol_values},
|
|
};
|
|
}
|
|
|
|
std::optional<uint64_t>
|
|
AcceleratorBreakpointHitArgs::GetSymbolValue(StringRef symbol_name) const {
|
|
auto it = llvm::find_if(symbol_values, [&](const SymbolValue &symbol) {
|
|
return symbol.name == symbol_name;
|
|
});
|
|
if (it != symbol_values.end())
|
|
return it->value;
|
|
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.mapOptional("connect_info", data.connect_info);
|
|
}
|
|
|
|
json::Value toJSON(const AcceleratorActions &data) {
|
|
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,
|
|
Path path) {
|
|
ObjectMapper o(value, path);
|
|
return o && o.map("disable_bp", data.disable_bp) &&
|
|
o.map("auto_resume_native", data.auto_resume_native) &&
|
|
o.mapOptional("actions", data.actions);
|
|
}
|
|
|
|
json::Value toJSON(const AcceleratorBreakpointHitResponse &data) {
|
|
Object obj{
|
|
{"disable_bp", data.disable_bp},
|
|
{"auto_resume_native", data.auto_resume_native},
|
|
};
|
|
if (data.actions)
|
|
obj["actions"] = *data.actions;
|
|
return obj;
|
|
}
|
|
|
|
} // namespace lldb_private
|