https://github.com/satyajanga updated https://github.com/llvm/llvm-project/pull/214564
>From 13c660705da62f55c5588d202d633c99bd47e07b Mon Sep 17 00:00:00 2001 From: satya janga <[email protected]> Date: Wed, 3 Jun 2026 13:20:04 -0700 Subject: [PATCH] [lldb-server] Add dynamic loader support to accelerator plugin protocol Add jAcceleratorPluginGetDynamicLoaderLibraryInfo packet for querying shared library information from accelerator plugins. This includes: - AcceleratorSectionInfo for per-section load addresses - AcceleratorDynamicLoaderLibraryInfo with pathname, UUID, load address, native memory location, file offset/size, and loaded sections - AcceleratorDynamicLoaderArgs and AcceleratorDynamicLoaderResponse - GetDynamicLoaderLibraryInfos virtual method on the plugin interface - LLGS packet handler with plugin name routing - Mock plugin implementation returning a test library - Unit tests for all new JSON serialization types - API test verifying the packet round-trip --- lldb/docs/resources/lldbgdbremote.md | 110 ++++++++++++++++++ .../Utility/AcceleratorGDBRemotePackets.h | 65 +++++++++++ .../lldb/Utility/StringExtractorGDBRemote.h | 1 + .../GDBRemoteCommunicationServerLLGS.cpp | 33 ++++++ .../GDBRemoteCommunicationServerLLGS.h | 3 + .../gdb-remote/LLDBServerAcceleratorPlugin.h | 5 + .../Utility/AcceleratorGDBRemotePackets.cpp | 59 ++++++++++ .../Utility/StringExtractorGDBRemote.cpp | 2 + .../mock/TestMockAcceleratorPackets.py | 55 +++++++++ .../Mock/LLDBServerMockAcceleratorPlugin.cpp | 12 ++ .../Mock/LLDBServerMockAcceleratorPlugin.h | 3 + .../AcceleratorGDBRemotePacketsTest.cpp | 81 +++++++++++++ 12 files changed, 429 insertions(+) diff --git a/lldb/docs/resources/lldbgdbremote.md b/lldb/docs/resources/lldbgdbremote.md index 93090c19c5ec0..dafc16dbcb0ff 100644 --- a/lldb/docs/resources/lldbgdbremote.md +++ b/lldb/docs/resources/lldbgdbremote.md @@ -2862,3 +2862,113 @@ STUB REPLIES: {"disable_bp":true,"auto_resume_native":false,"actions":{"plugin_ **Priority To Implement:** Required for hardware accelerator debugging support. Not needed for non-hardware-accelerator debugging. + +### jAcceleratorPluginGetDynamicLoaderLibraryInfo + +Requests shared library information from an accelerator plugin. The client +sends this packet when it needs to load or update the accelerator's shared +library list. This packet requires the `accelerator-plugins+` feature from +`qSupported`. + +``` +LLDB SENDS: jAcceleratorPluginGetDynamicLoaderLibraryInfo:<json> +STUB REPLIES: <json_response> +``` + +The request JSON has the following fields: + +| Key | Type | Description | +|---------------|--------|-------------| +| `plugin_name` | string | Name of the accelerator plugin to query. | +| `full` | bool | If true, return every library the plugin knows about. If false, return only what changed since the last query. | + +A plugin may track thousands of code objects, so `full` lets a client that is +already up to date ask only for the delta instead of re-receiving the whole +list on every stop. It is the plugin that decides what "changed since the last +query" means, and the plugin that keeps that state. + +Because that state lives in the plugin and is not per-client, a client cannot +assume it starts from a known point: an earlier client may have consumed the +pending changes with `full=false`. The first query of a session must therefore +use `full=true`, and a client should also use it whenever it discards its own +module list and needs to rebuild it. + +The response JSON is an object with a single `library_infos` key, holding an +array of library info objects: + +| Key | Type | Description | +|-------------------------|--------|-------------| +| `pathname` | string | Path to the object file, or a unique name for the module when it has no file on disk. | +| `load` | bool | True when the library is being loaded, false when it is being unloaded. | +| `load_address` | int | (optional) Base address the whole object file is slid to. | +| `loaded_sections` | array | (optional) Per-section load addresses, for object files whose sections load at independent addresses. Each entry has `names` (the section name, or a path of nested section names to descend) and `load_address`. | +| `uuid` | string | (optional) UUID of the object file, if the plugin knows it. | +| `native_memory_address` | int | (optional) Address **in the native (host) process** where the object file image can be read, for a library that only exists in memory. | +| `native_memory_size` | int | (optional) Size of that in-memory image. | +| `file_offset` | int | (optional) Byte offset of the object file within `pathname`, for a library embedded in a containing file. | +| `file_size` | int | (optional) Size of the object file within that containing file. | + +`load_address`, `loaded_sections` and neither-of-the-two are three different +requests, and are resolved in that order: + +* `load_address` present: slide the whole object file to that address. +* otherwise `loaded_sections` non-empty: load only the named sections, each at + its own address. +* otherwise: load at the file addresses with no slide. + +An absent `loaded_sections` and an empty `loaded_sections` therefore mean the +same thing here: no per-section addresses were supplied. A plugin that wants +sections loaded must send a non-empty array. + +A module that only exists in the accelerator's memory has no file on disk, so +`pathname` carries a unique name for it instead of a path. That name is what +identifies the module in the target. + +Load `/path/to/lib.so` at address 2130706432: +``` +LLDB SENDS: jAcceleratorPluginGetDynamicLoaderLibraryInfo:{"plugin_name":"mock","full":true} +STUB REPLIES: { + "library_infos": [ + { + "pathname": "/path/to/lib.so", + "load": true, + "load_address": 2130706432 + } + ] +} +``` + +Load only `.text` from `PT_LOAD[1]` and `.data` from `PT_LOAD[3]` in +`/path/to/lib.so`, each at its own address: +``` +LLDB SENDS: jAcceleratorPluginGetDynamicLoaderLibraryInfo:{"plugin_name":"mock","full":true} +STUB REPLIES: { + "library_infos": [ + { + "pathname": "/path/to/lib.so", + "load": true, + "loaded_sections": [ + {"names": ["PT_LOAD[1]", ".text"], "load_address": 2130706432}, + {"names": ["PT_LOAD[3]", ".data"], "load_address": 2130707432} + ] + } + ] +} +``` + +Load `/path/to/lib.so` at the file addresses found in the object file, with no +slide: +``` +LLDB SENDS: jAcceleratorPluginGetDynamicLoaderLibraryInfo:{"plugin_name":"mock","full":true} +STUB REPLIES: { + "library_infos": [ + { + "pathname": "/path/to/lib.so", + "load": true + } + ] +} +``` + +**Priority To Implement:** Required for hardware accelerator debugging +support. Not needed for non-hardware-accelerator debugging. diff --git a/lldb/include/lldb/Utility/AcceleratorGDBRemotePackets.h b/lldb/include/lldb/Utility/AcceleratorGDBRemotePackets.h index faa7f5575f157..dea958c15eebd 100644 --- a/lldb/include/lldb/Utility/AcceleratorGDBRemotePackets.h +++ b/lldb/include/lldb/Utility/AcceleratorGDBRemotePackets.h @@ -166,6 +166,71 @@ bool fromJSON(const llvm::json::Value &value, AcceleratorBreakpointHitResponse &data, llvm::json::Path path); llvm::json::Value toJSON(const AcceleratorBreakpointHitResponse &data); +struct AcceleratorSectionInfo { + /// A list of section names. The first name is located in the module's + /// section list at the root level, and each name after it is found as a + /// child section of the previous one. The final section is the one that gets + /// loaded, e.g. ["PT_LOAD[0]", ".text"]. + std::vector<std::string> names; + /// Address the section named by \a names is loaded at. + uint64_t load_address = 0; +}; + +bool fromJSON(const llvm::json::Value &value, AcceleratorSectionInfo &data, + llvm::json::Path path); +llvm::json::Value toJSON(const AcceleratorSectionInfo &data); + +struct AcceleratorDynamicLoaderLibraryInfo { + /// Path to the object file, or a unique name identifying the module in the + /// target when it has no file on disk. + std::string pathname; + /// UUID of the object file, when the plugin knows it. + std::optional<std::string> uuid_str; + /// False means unload. + bool load = true; + /// Slides the whole object file. If unset, use \a loaded_sections or the + /// file addresses. + std::optional<uint64_t> load_address; + /// Used when sections load at independent addresses. Absent and empty mean + /// the same thing: no per-section addresses were supplied. + std::vector<AcceleratorSectionInfo> loaded_sections; + /// Where the image can be read in the native process, meaning the host + /// process driving the accelerator, not the accelerator itself. Set for a + /// library that only exists in memory. + std::optional<uint64_t> native_memory_address; + std::optional<uint64_t> native_memory_size; + /// Slice of \a pathname holding the object file, when embedded in a + /// container. + std::optional<uint64_t> file_offset; + std::optional<uint64_t> file_size; +}; + +bool fromJSON(const llvm::json::Value &value, + AcceleratorDynamicLoaderLibraryInfo &data, llvm::json::Path path); +llvm::json::Value toJSON(const AcceleratorDynamicLoaderLibraryInfo &data); + +/// Arguments for the jAcceleratorPluginGetDynamicLoaderLibraryInfo packet. +struct AcceleratorDynamicLoaderArgs { + std::string plugin_name; + /// If false, return only what changed since the last query. That state lives + /// in the plugin rather than per-client, so the first query of a session + /// must use true. + bool full = true; +}; + +bool fromJSON(const llvm::json::Value &value, + AcceleratorDynamicLoaderArgs &data, llvm::json::Path path); +llvm::json::Value toJSON(const AcceleratorDynamicLoaderArgs &data); + +/// Response from the jAcceleratorPluginGetDynamicLoaderLibraryInfo packet. +struct AcceleratorDynamicLoaderResponse { + std::vector<AcceleratorDynamicLoaderLibraryInfo> library_infos; +}; + +bool fromJSON(const llvm::json::Value &value, + AcceleratorDynamicLoaderResponse &data, llvm::json::Path path); +llvm::json::Value toJSON(const AcceleratorDynamicLoaderResponse &data); + } // namespace lldb_private #endif // LLDB_UTILITY_ACCELERATORGDBREMOTEPACKETS_H diff --git a/lldb/include/lldb/Utility/StringExtractorGDBRemote.h b/lldb/include/lldb/Utility/StringExtractorGDBRemote.h index 624a2febe857e..0236891dfcde1 100644 --- a/lldb/include/lldb/Utility/StringExtractorGDBRemote.h +++ b/lldb/include/lldb/Utility/StringExtractorGDBRemote.h @@ -176,6 +176,7 @@ class StringExtractorGDBRemote : public StringExtractor { eServerPacketType_jMultiBreakpoint, eServerPacketType_jAcceleratorPluginInitialize, eServerPacketType_jAcceleratorPluginBreakpointHit, + eServerPacketType_jAcceleratorPluginGetDynamicLoaderLibraryInfo, eServerPacketType_qMemTags, // read memory tags eServerPacketType_QMemTags, // write memory tags diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp index 2e824282079b4..161ab863e8223 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp @@ -233,6 +233,11 @@ void GDBRemoteCommunicationServerLLGS::RegisterPacketHandlers() { eServerPacketType_jAcceleratorPluginBreakpointHit, &GDBRemoteCommunicationServerLLGS:: Handle_jAcceleratorPluginBreakpointHit); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote:: + eServerPacketType_jAcceleratorPluginGetDynamicLoaderLibraryInfo, + &GDBRemoteCommunicationServerLLGS:: + Handle_jAcceleratorPluginGetDynamicLoaderLibraryInfo); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_g, &GDBRemoteCommunicationServerLLGS::Handle_g); @@ -4643,3 +4648,31 @@ GDBRemoteCommunicationServerLLGS::Handle_jAcceleratorPluginBreakpointHit( return SendErrorResponse( Status::FromErrorString("unknown accelerator plugin name")); } + +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS:: + Handle_jAcceleratorPluginGetDynamicLoaderLibraryInfo( + StringExtractorGDBRemote &packet) { + packet.ConsumeFront("jAcceleratorPluginGetDynamicLoaderLibraryInfo:"); + llvm::Expected<AcceleratorDynamicLoaderArgs> args = + llvm::json::parse<AcceleratorDynamicLoaderArgs>( + packet.Peek(), "AcceleratorDynamicLoaderArgs"); + if (!args) + return SendErrorResponse(args.takeError()); + + for (std::unique_ptr<lldb_server::LLDBServerAcceleratorPlugin> &plugin_up : + m_accelerator_plugins) { + if (plugin_up->GetPluginName() == args->plugin_name) { + std::optional<AcceleratorDynamicLoaderResponse> response = + plugin_up->GetDynamicLoaderLibraryInfos(*args); + if (!response) + return SendErrorResponse( + Status::FromErrorString("no dynamic loader info available")); + + StreamGDBRemote stream; + stream.PutAsJSON(*response, /*hex_ascii=*/false); + return SendPacketNoLock(stream.GetString()); + } + } + return SendErrorResponse( + Status::FromErrorString("unknown accelerator plugin name")); +} diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h index e5b4c9ec0bed0..3c8afe699bbaf 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h @@ -302,6 +302,9 @@ class GDBRemoteCommunicationServerLLGS PacketResult Handle_jAcceleratorPluginBreakpointHit(StringExtractorGDBRemote &packet); + PacketResult Handle_jAcceleratorPluginGetDynamicLoaderLibraryInfo( + StringExtractorGDBRemote &packet); + void SetCurrentThreadID(lldb::tid_t tid); lldb::tid_t GetCurrentThreadID() const; diff --git a/lldb/source/Plugins/Process/gdb-remote/LLDBServerAcceleratorPlugin.h b/lldb/source/Plugins/Process/gdb-remote/LLDBServerAcceleratorPlugin.h index f16ee82a39d95..2e585d9a64c6a 100644 --- a/lldb/source/Plugins/Process/gdb-remote/LLDBServerAcceleratorPlugin.h +++ b/lldb/source/Plugins/Process/gdb-remote/LLDBServerAcceleratorPlugin.h @@ -47,6 +47,11 @@ class LLDBServerAcceleratorPlugin { ++m_accelerator_action_identifier); } + virtual std::optional<AcceleratorDynamicLoaderResponse> + GetDynamicLoaderLibraryInfos(const AcceleratorDynamicLoaderArgs &args) { + return std::nullopt; + } + protected: GDBServer &m_native_gdb_server; MainLoop &m_native_main_loop; diff --git a/lldb/source/Utility/AcceleratorGDBRemotePackets.cpp b/lldb/source/Utility/AcceleratorGDBRemotePackets.cpp index 3b9edada64c65..180b2121c6155 100644 --- a/lldb/source/Utility/AcceleratorGDBRemotePackets.cpp +++ b/lldb/source/Utility/AcceleratorGDBRemotePackets.cpp @@ -142,4 +142,63 @@ json::Value toJSON(const AcceleratorBreakpointHitResponse &data) { return obj; } +bool fromJSON(const Value &value, AcceleratorSectionInfo &data, Path path) { + ObjectMapper o(value, path); + return o && o.map("names", data.names) && + o.map("load_address", data.load_address); +} + +json::Value toJSON(const AcceleratorSectionInfo &data) { + return Object{{"names", data.names}, + {"load_address", static_cast<int64_t>(data.load_address)}}; +} + +bool fromJSON(const Value &value, AcceleratorDynamicLoaderLibraryInfo &data, + Path path) { + ObjectMapper o(value, path); + return o && o.map("pathname", data.pathname) && + o.mapOptional("uuid", data.uuid_str) && o.map("load", data.load) && + o.mapOptional("load_address", data.load_address) && + o.mapOptional("loaded_sections", data.loaded_sections) && + o.mapOptional("native_memory_address", data.native_memory_address) && + o.mapOptional("native_memory_size", data.native_memory_size) && + o.mapOptional("file_offset", data.file_offset) && + o.mapOptional("file_size", data.file_size); +} + +json::Value toJSON(const AcceleratorDynamicLoaderLibraryInfo &data) { + return Object{ + {"pathname", data.pathname}, + {"uuid", data.uuid_str}, + {"load", data.load}, + {"load_address", data.load_address}, + {"loaded_sections", data.loaded_sections}, + {"native_memory_address", data.native_memory_address}, + {"native_memory_size", data.native_memory_size}, + {"file_offset", data.file_offset}, + {"file_size", data.file_size}, + }; +} + +bool fromJSON(const Value &value, AcceleratorDynamicLoaderArgs &data, + Path path) { + ObjectMapper o(value, path); + return o && o.map("plugin_name", data.plugin_name) && + o.map("full", data.full); +} + +json::Value toJSON(const AcceleratorDynamicLoaderArgs &data) { + return Object{{"plugin_name", data.plugin_name}, {"full", data.full}}; +} + +bool fromJSON(const Value &value, AcceleratorDynamicLoaderResponse &data, + Path path) { + ObjectMapper o(value, path); + return o && o.map("library_infos", data.library_infos); +} + +json::Value toJSON(const AcceleratorDynamicLoaderResponse &data) { + return Object{{"library_infos", data.library_infos}}; +} + } // namespace lldb_private diff --git a/lldb/source/Utility/StringExtractorGDBRemote.cpp b/lldb/source/Utility/StringExtractorGDBRemote.cpp index 6fc3b63e02dd1..953a2cd3090d1 100644 --- a/lldb/source/Utility/StringExtractorGDBRemote.cpp +++ b/lldb/source/Utility/StringExtractorGDBRemote.cpp @@ -338,6 +338,8 @@ StringExtractorGDBRemote::GetServerPacketType() const { return eServerPacketType_jAcceleratorPluginInitialize; if (PACKET_STARTS_WITH("jAcceleratorPluginBreakpointHit:")) return eServerPacketType_jAcceleratorPluginBreakpointHit; + if (PACKET_STARTS_WITH("jAcceleratorPluginGetDynamicLoaderLibraryInfo:")) + return eServerPacketType_jAcceleratorPluginGetDynamicLoaderLibraryInfo; break; case 'v': diff --git a/lldb/test/API/accelerator/mock/TestMockAcceleratorPackets.py b/lldb/test/API/accelerator/mock/TestMockAcceleratorPackets.py index 941e0c97a8f2e..e40e6491e59a0 100644 --- a/lldb/test/API/accelerator/mock/TestMockAcceleratorPackets.py +++ b/lldb/test/API/accelerator/mock/TestMockAcceleratorPackets.py @@ -186,3 +186,58 @@ def test_jAcceleratorPluginBreakpointHit_returns_connect_info(self): connect_info["connect_url"], ) self.assertTrue(connect_info["synchronous"]) + + @add_test_categories(["llgs"]) + def test_jAcceleratorPluginGetDynamicLoaderLibraryInfo(self): + self.build() + self.set_inferior_startup_launch() + self.prep_debug_monitor_and_inferior() + + self.add_qSupported_packets() + self.expect_gdbremote_sequence() + + # Only "full" is exercised. The mock could answer full=False, but what + # a delta contains is entirely up to the plugin, so doing so would only + # test the mock's own bookkeeping. That belongs with a real plugin. + dyld_args = {"plugin_name": "mock", "full": True} + dyld_json = json.dumps(dyld_args, separators=(",", ":")) + escaped_json = escape_binary(dyld_json) + response = self.send_and_decode_json( + "jAcceleratorPluginGetDynamicLoaderLibraryInfo:" + escaped_json + ) + + self.assertIn("library_infos", response) + libs = response["library_infos"] + self.assertGreater(len(libs), 0) + + lib = libs[0] + self.assertEqual(lib["pathname"], "/path/to/lib.so") + self.assertTrue(lib["load"]) + self.assertEqual(lib["load_address"], 0x7F000000) + + @add_test_categories(["llgs"]) + def test_jAcceleratorPluginGetDynamicLoaderLibraryInfo_unknown_plugin(self): + self.build() + self.set_inferior_startup_launch() + self.prep_debug_monitor_and_inferior() + + self.add_qSupported_packets() + self.expect_gdbremote_sequence() + + dyld_args = {"plugin_name": "no-such-plugin", "full": True} + dyld_json = json.dumps(dyld_args, separators=(",", ":")) + escaped_json = escape_binary(dyld_json) + self.test_sequence.add_log_lines( + [ + "read packet: $jAcceleratorPluginGetDynamicLoaderLibraryInfo:%s#00" + % escaped_json, + { + "direction": "send", + "regex": r"^\$(E[0-9a-fA-F]{2}.*)#[0-9a-fA-F]{2}", + "capture": {1: "error"}, + }, + ], + True, + ) + context = self.expect_gdbremote_sequence() + self.assertIsNotNone(context.get("error")) diff --git a/lldb/tools/lldb-server/Plugins/Accelerator/Mock/LLDBServerMockAcceleratorPlugin.cpp b/lldb/tools/lldb-server/Plugins/Accelerator/Mock/LLDBServerMockAcceleratorPlugin.cpp index 6c1d23fef8a71..0cce2955f6e0d 100644 --- a/lldb/tools/lldb-server/Plugins/Accelerator/Mock/LLDBServerMockAcceleratorPlugin.cpp +++ b/lldb/tools/lldb-server/Plugins/Accelerator/Mock/LLDBServerMockAcceleratorPlugin.cpp @@ -220,3 +220,15 @@ LLDBServerMockAcceleratorPlugin::CreateConnection() { info.synchronous = true; return info; } + +std::optional<AcceleratorDynamicLoaderResponse> +LLDBServerMockAcceleratorPlugin::GetDynamicLoaderLibraryInfos( + const AcceleratorDynamicLoaderArgs &args) { + AcceleratorDynamicLoaderResponse response; + AcceleratorDynamicLoaderLibraryInfo lib; + lib.pathname = "/path/to/lib.so"; + lib.load = true; + lib.load_address = 0x7f000000; + response.library_infos.push_back(std::move(lib)); + return response; +} diff --git a/lldb/tools/lldb-server/Plugins/Accelerator/Mock/LLDBServerMockAcceleratorPlugin.h b/lldb/tools/lldb-server/Plugins/Accelerator/Mock/LLDBServerMockAcceleratorPlugin.h index b07266d0ef65f..36f6aa2500ba8 100644 --- a/lldb/tools/lldb-server/Plugins/Accelerator/Mock/LLDBServerMockAcceleratorPlugin.h +++ b/lldb/tools/lldb-server/Plugins/Accelerator/Mock/LLDBServerMockAcceleratorPlugin.h @@ -34,6 +34,9 @@ class LLDBServerMockAcceleratorPlugin : public LLDBServerAcceleratorPlugin { llvm::Expected<AcceleratorBreakpointHitResponse> BreakpointWasHit(AcceleratorBreakpointHitArgs &args) override; + std::optional<AcceleratorDynamicLoaderResponse> GetDynamicLoaderLibraryInfos( + const AcceleratorDynamicLoaderArgs &args) override; + private: // Lazily bring up the mock accelerator GDB server and return its connection // info. Called on the connection breakpoint hit, so inferiors that never diff --git a/lldb/unittests/Utility/AcceleratorGDBRemotePacketsTest.cpp b/lldb/unittests/Utility/AcceleratorGDBRemotePacketsTest.cpp index 571dd2cab124a..8d64b4a8acf78 100644 --- a/lldb/unittests/Utility/AcceleratorGDBRemotePacketsTest.cpp +++ b/lldb/unittests/Utility/AcceleratorGDBRemotePacketsTest.cpp @@ -244,3 +244,84 @@ TEST(AcceleratorGDBRemotePacketsTest, AcceleratorActionsWithoutConnectInfo) { ASSERT_THAT_EXPECTED(deserialized, Succeeded()); EXPECT_FALSE(deserialized->connect_info.has_value()); } + +TEST(AcceleratorGDBRemotePacketsTest, AcceleratorSectionInfo) { + AcceleratorSectionInfo section; + section.names = {"PT_LOAD[0]", ".text"}; + section.load_address = 0x400000; + + Expected<AcceleratorSectionInfo> deserialized = roundtripJSON(section); + ASSERT_THAT_EXPECTED(deserialized, Succeeded()); + EXPECT_EQ(section.names, deserialized->names); + EXPECT_EQ(section.load_address, deserialized->load_address); +} + +TEST(AcceleratorGDBRemotePacketsTest, AcceleratorDynamicLoaderLibraryInfo) { + AcceleratorDynamicLoaderLibraryInfo lib; + lib.pathname = "/usr/lib/libgpu.so"; + lib.uuid_str = "AABBCCDD"; + lib.load = true; + lib.load_address = 0x7f000000; + lib.native_memory_address = 0x1000; + lib.native_memory_size = 0x2000; + lib.file_offset = 4096; + lib.file_size = 8192; + + AcceleratorSectionInfo section; + section.names = {".text"}; + section.load_address = 0x7f001000; + lib.loaded_sections.push_back(std::move(section)); + + Expected<AcceleratorDynamicLoaderLibraryInfo> deserialized = + roundtripJSON(lib); + ASSERT_THAT_EXPECTED(deserialized, Succeeded()); + EXPECT_EQ(lib.pathname, deserialized->pathname); + EXPECT_EQ(lib.uuid_str, deserialized->uuid_str); + EXPECT_EQ(lib.load, deserialized->load); + EXPECT_EQ(lib.load_address, deserialized->load_address); + EXPECT_EQ(lib.native_memory_address, deserialized->native_memory_address); + EXPECT_EQ(lib.native_memory_size, deserialized->native_memory_size); + EXPECT_EQ(lib.file_offset, deserialized->file_offset); + EXPECT_EQ(lib.file_size, deserialized->file_size); + ASSERT_EQ(1u, deserialized->loaded_sections.size()); + EXPECT_EQ(0x7f001000u, deserialized->loaded_sections[0].load_address); +} + +TEST(AcceleratorGDBRemotePacketsTest, AcceleratorDynamicLoaderArgs) { + AcceleratorDynamicLoaderArgs args; + args.plugin_name = "mock"; + args.full = true; + + Expected<AcceleratorDynamicLoaderArgs> deserialized = roundtripJSON(args); + ASSERT_THAT_EXPECTED(deserialized, Succeeded()); + EXPECT_EQ(args.plugin_name, deserialized->plugin_name); + EXPECT_EQ(args.full, deserialized->full); +} + +TEST(AcceleratorGDBRemotePacketsTest, AcceleratorDynamicLoaderResponse) { + AcceleratorDynamicLoaderResponse response; + AcceleratorDynamicLoaderLibraryInfo lib; + lib.pathname = "/path/to/lib.so"; + lib.load = true; + response.library_infos.push_back(std::move(lib)); + + Expected<AcceleratorDynamicLoaderResponse> deserialized = + roundtripJSON(response); + ASSERT_THAT_EXPECTED(deserialized, Succeeded()); + ASSERT_EQ(1u, deserialized->library_infos.size()); + EXPECT_EQ("/path/to/lib.so", deserialized->library_infos[0].pathname); + EXPECT_TRUE(deserialized->library_infos[0].load); +} + +TEST(AcceleratorGDBRemotePacketsTest, DynamicLoaderLibraryInfoOptionalFields) { + // A server with no per-section addresses can omit "loaded_sections". + Expected<AcceleratorDynamicLoaderLibraryInfo> deserialized = + json::parse<AcceleratorDynamicLoaderLibraryInfo>( + R"({"pathname":"/path/to/lib.so","load":true})", + "AcceleratorDynamicLoaderLibraryInfo"); + ASSERT_THAT_EXPECTED(deserialized, Succeeded()); + EXPECT_EQ("/path/to/lib.so", deserialized->pathname); + EXPECT_TRUE(deserialized->load); + EXPECT_TRUE(deserialized->loaded_sections.empty()); + EXPECT_FALSE(deserialized->load_address.has_value()); +} _______________________________________________ lldb-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
