llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-lldb
Author: satyanarayana reddy janga (satyajanga)
<details>
<summary>Changes</summary>
Add a generic mechanism for a process to report the address spaces it exposes.
Most processes have a single flat address space, but some (such as GPUs) have
multiple address spaces where the same numeric address refers to different
storage depending on the address space (for example global, local, private or
generic memory).
This is process-agnostic and lives entirely in the generic layers (no
plugin-specific code):
- Utility/AddressSpace.{h,cpp}: AddressSpaceInfo {name, value,
is_thread_specific} with JSON serialization.
- New "jAddressSpacesInfo" gdb-remote packet: NativeProcessProtocol gains a
virtual GetAddressSpaces() (default empty); LLGS serves it via
Handle_jAddressSpacesInfo; the client queries it via GetAddressSpaces() and
caches "unsupported" so processes without address spaces pay nothing.
- Process caches the result (Process::GetAddressSpaces()); ProcessGDBRemote
populates it on connect.
- Documented in docs/resources/lldbgdbremote.md.
Tests: AddressSpaceInfo JSON round-trip unit tests, and a
GDBRemoteCommunicationClient round-trip test (supported + unsupported)
exercising the full packet encode/escape/parse path.
---
Patch is 21.27 KiB, truncated to 20.00 KiB below, full version:
https://github.com/llvm/llvm-project/pull/206370.diff
16 Files Affected:
- (modified) lldb/docs/resources/lldbgdbremote.md (+31)
- (modified) lldb/include/lldb/Host/common/NativeProcessProtocol.h (+7)
- (modified) lldb/include/lldb/Target/Process.h (+11)
- (added) lldb/include/lldb/Utility/AddressSpace.h (+37)
- (modified) lldb/include/lldb/Utility/StringExtractorGDBRemote.h (+1)
- (modified)
lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp (+34)
- (modified)
lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h (+7)
- (modified)
lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
(+28)
- (modified)
lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h (+2)
- (modified) lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp (+3)
- (added) lldb/source/Utility/AddressSpace.cpp (+28)
- (modified) lldb/source/Utility/CMakeLists.txt (+1)
- (modified) lldb/source/Utility/StringExtractorGDBRemote.cpp (+2)
- (modified)
lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp (+33)
- (added) lldb/unittests/Utility/AddressSpaceTest.cpp (+55)
- (modified) lldb/unittests/Utility/CMakeLists.txt (+1)
``````````diff
diff --git a/lldb/docs/resources/lldbgdbremote.md
b/lldb/docs/resources/lldbgdbremote.md
index 577a5ad31674f..f43f1958aeca0 100644
--- a/lldb/docs/resources/lldbgdbremote.md
+++ b/lldb/docs/resources/lldbgdbremote.md
@@ -825,6 +825,37 @@ This is a performance optimization, which speeds up
debugging by avoiding
multiple round-trips for retrieving thread information. The information from
this
packet can be retrieved using a combination of `qThreadStopInfo` and `m`
packets.
+## jAddressSpacesInfo
+
+Ask the server for the address spaces the process exposes.
+
+Most processes have a single, flat address space, but some (such as GPUs) have
+multiple address spaces where the same numeric address refers to different
+storage depending on the address space (for example global, local, private or
+generic memory). This packet lets the client discover those address spaces.
+
+The response is a JSON array of dictionaries, one per address space:
+```
+ [
+ {"name":"global","value":1,"is_thread_specific":false},
+ {"name":"local","value":2,"is_thread_specific":true}
+ ]
+```
+
+Each dictionary has the following keys:
+
+* `name`: the human readable name of the address space.
+* `value`: the integer identifier of the address space.
+* `is_thread_specific`: `true` if the same address-space value resolves to
+ different storage for different threads.
+
+The server replies with an unsupported (empty) response when the process has no
+address spaces, so the default flat-address-space case costs nothing.
+
+**Priority To Implement:** Low
+
+Only needed for targets that expose more than one address space.
+
### MultiMemRead
Read memory from multiple memory ranges.
diff --git a/lldb/include/lldb/Host/common/NativeProcessProtocol.h
b/lldb/include/lldb/Host/common/NativeProcessProtocol.h
index 435185a38f3f9..52534b7d84ca3 100644
--- a/lldb/include/lldb/Host/common/NativeProcessProtocol.h
+++ b/lldb/include/lldb/Host/common/NativeProcessProtocol.h
@@ -14,6 +14,7 @@
#include "NativeWatchpointList.h"
#include "lldb/Host/Host.h"
#include "lldb/Host/MainLoop.h"
+#include "lldb/Utility/AddressSpace.h"
#include "lldb/Utility/ArchSpec.h"
#include "lldb/Utility/Iterable.h"
#include "lldb/Utility/Status.h"
@@ -96,6 +97,12 @@ class NativeProcessProtocol {
virtual Status GetMemoryRegionInfo(lldb::addr_t load_addr,
MemoryRegionInfo &range_info);
+ /// Return the address spaces this process exposes. The default
+ /// implementation returns an empty list; processes that have multiple
+ /// address spaces (such as GPUs) override this. Served over the
+ /// "jAddressSpacesInfo" packet.
+ virtual std::vector<AddressSpaceInfo> GetAddressSpaces() { return {}; }
+
virtual Status ReadMemory(lldb::addr_t addr, void *buf, size_t size,
size_t &bytes_read) = 0;
diff --git a/lldb/include/lldb/Target/Process.h
b/lldb/include/lldb/Target/Process.h
index 8432c326d3281..ff186d0b65cb7 100644
--- a/lldb/include/lldb/Target/Process.h
+++ b/lldb/include/lldb/Target/Process.h
@@ -45,6 +45,7 @@
#include "lldb/Target/ThreadList.h"
#include "lldb/Target/ThreadPlanStack.h"
#include "lldb/Target/Trace.h"
+#include "lldb/Utility/AddressSpace.h"
#include "lldb/Utility/AddressableBits.h"
#include "lldb/Utility/ArchSpec.h"
#include "lldb/Utility/Args.h"
@@ -2045,6 +2046,13 @@ class Process : public
std::enable_shared_from_this<Process>,
virtual Status
GetMemoryRegions(lldb_private::MemoryRegionInfos ®ion_list);
+ /// Get the address spaces this process exposes (for example a GPU's global,
+ /// local, private or generic memory). Empty for processes with a single
+ /// address space. Populated from the process plugin when it connects.
+ const std::vector<AddressSpaceInfo> &GetAddressSpaces() const {
+ return m_address_spaces;
+ }
+
/// Get the number of watchpoints supported by this target.
///
/// We may be able to determine the number of watchpoints available
@@ -3498,6 +3506,9 @@ void PruneThreadPlans();
ThreadList
m_extended_thread_list; ///< Constituent for extended threads that may be
/// generated, cleared on natural stops
+ std::vector<AddressSpaceInfo>
+ m_address_spaces; ///< Address spaces reported by the process plugin,
+ /// empty for single-address-space processes.
lldb::RunDirection m_base_direction; ///< ThreadPlanBase run direction
uint32_t m_extended_thread_stop_id; ///< The natural stop id when
///extended_thread_list was last updated
diff --git a/lldb/include/lldb/Utility/AddressSpace.h
b/lldb/include/lldb/Utility/AddressSpace.h
new file mode 100644
index 0000000000000..adee7aef3e8db
--- /dev/null
+++ b/lldb/include/lldb/Utility/AddressSpace.h
@@ -0,0 +1,37 @@
+//===-- AddressSpace.h
----------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_UTILITY_ADDRESSSPACE_H
+#define LLDB_UTILITY_ADDRESSSPACE_H
+
+#include "lldb/lldb-types.h"
+#include "llvm/Support/JSON.h"
+#include <string>
+#include <vector>
+
+namespace lldb_private {
+
+/// Describes a single address space reported by a process. Processes such as
+/// GPUs can have multiple address spaces (for example global, local, private
or
+/// generic memory) where the same numeric address refers to different storage
+/// depending on the address space. See the "jAddressSpacesInfo" packet in
+/// docs/resources/lldbgdbremote.md for the wire format.
+struct AddressSpaceInfo {
+ std::string name; ///< The name of the address space.
+ uint64_t value; ///< The integer identifier of the address space.
+ bool is_thread_specific; ///< True if the address space is thread specific.
+};
+
+bool fromJSON(const llvm::json::Value &value, AddressSpaceInfo &data,
+ llvm::json::Path path);
+
+llvm::json::Value toJSON(const AddressSpaceInfo &data);
+
+} // namespace lldb_private
+
+#endif // LLDB_UTILITY_ADDRESSSPACE_H
diff --git a/lldb/include/lldb/Utility/StringExtractorGDBRemote.h
b/lldb/include/lldb/Utility/StringExtractorGDBRemote.h
index 624a2febe857e..a16dfcfe1601a 100644
--- a/lldb/include/lldb/Utility/StringExtractorGDBRemote.h
+++ b/lldb/include/lldb/Utility/StringExtractorGDBRemote.h
@@ -108,6 +108,7 @@ class StringExtractorGDBRemote : public StringExtractor {
eServerPacketType_QThreadSuffixSupported,
eServerPacketType_jThreadsInfo,
+ eServerPacketType_jAddressSpacesInfo,
eServerPacketType_qsThreadInfo,
eServerPacketType_qfThreadInfo,
eServerPacketType_qGetPid,
diff --git
a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
index 698bf5f7049cf..0c6bdfb636399 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
@@ -384,6 +384,7 @@ void
GDBRemoteCommunicationClient::ResetDiscoverableSettings(bool did_exec) {
m_attach_or_wait_reply = eLazyBoolCalculate;
m_avoid_g_packets = eLazyBoolCalculate;
m_supports_multiprocess = eLazyBoolCalculate;
+ m_supports_address_spaces = eLazyBoolCalculate;
m_supports_qSaveCore = eLazyBoolCalculate;
m_supports_qXfer_auxv_read = eLazyBoolCalculate;
m_supports_qXfer_libraries_read = eLazyBoolCalculate;
@@ -1158,6 +1159,39 @@
GDBRemoteCommunicationClient::GetProcessStandaloneBinaries() {
return m_binary_addresses;
}
+std::vector<AddressSpaceInfo> GDBRemoteCommunicationClient::GetAddressSpaces()
{
+ // The server replies with the unsupported response when it has no address
+ // spaces, so cache that to avoid re-sending the packet on every call.
+ if (m_supports_address_spaces == eLazyBoolNo)
+ return {};
+
+ StringExtractorGDBRemote response;
+ response.SetResponseValidatorToJSON();
+ if (SendPacketAndWaitForResponse("jAddressSpacesInfo", response) !=
+ PacketResult::Success)
+ return {};
+
+ if (response.IsUnsupportedResponse() || response.IsErrorResponse()) {
+ m_supports_address_spaces = eLazyBoolNo;
+ return {};
+ }
+ m_supports_address_spaces = eLazyBoolYes;
+
+ llvm::Expected<std::vector<AddressSpaceInfo>> info =
+ llvm::json::parse<std::vector<AddressSpaceInfo>>(response.Peek(),
+ "AddressSpaceInfo");
+ if (info)
+ return std::move(*info);
+
+ // A bare JSON parse error is meaningless on its own, so log both the full
+ // response and the parse error rather than surfacing it to the user.
+ Log *log = GetLog(GDBRLog::Process);
+ LLDB_LOG_ERROR(log, info.takeError(),
+ "malformed jAddressSpacesInfo response '{1}': {0}",
+ response.GetStringRef());
+ return {};
+}
+
bool GDBRemoteCommunicationClient::GetGDBServerVersion() {
if (m_qGDBServerVersion_is_valid == eLazyBoolCalculate) {
m_gdb_server_name.clear();
diff --git
a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
index 3a0a34f840c21..5fd208ba2a0d5 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
@@ -20,6 +20,7 @@
#include "lldb/Host/File.h"
#include "lldb/Utility/AcceleratorGDBRemotePackets.h"
+#include "lldb/Utility/AddressSpace.h"
#include "lldb/Utility/AddressableBits.h"
#include "lldb/Utility/ArchSpec.h"
#include "lldb/Utility/GDBRemote.h"
@@ -223,6 +224,11 @@ class GDBRemoteCommunicationClient : public
GDBRemoteClientBase {
std::vector<lldb::addr_t> GetProcessStandaloneBinaries();
+ /// Query the process for the address spaces it exposes via the
+ /// "jAddressSpacesInfo" packet. Returns an empty list if the process does
+ /// not support address spaces.
+ std::vector<AddressSpaceInfo> GetAddressSpaces();
+
void GetRemoteQSupported();
bool GetVContSupported(llvm::StringRef flavor);
@@ -606,6 +612,7 @@ class GDBRemoteCommunicationClient : public
GDBRemoteClientBase {
LazyBool m_supports_error_string_reply = eLazyBoolCalculate;
LazyBool m_supports_multiprocess = eLazyBoolCalculate;
LazyBool m_supports_memory_tagging = eLazyBoolCalculate;
+ LazyBool m_supports_address_spaces = eLazyBoolCalculate;
LazyBool m_supports_qSaveCore = eLazyBoolCalculate;
LazyBool m_uses_native_signals = eLazyBoolCalculate;
std::optional<xPacketState> m_x_packet_state;
diff --git
a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
index f265fcb71be4e..787c305e73dcc 100644
---
a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
+++
b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
@@ -162,6 +162,9 @@ void
GDBRemoteCommunicationServerLLGS::RegisterPacketHandlers() {
RegisterMemberFunctionHandler(
StringExtractorGDBRemote::eServerPacketType_jThreadsInfo,
&GDBRemoteCommunicationServerLLGS::Handle_jThreadsInfo);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_jAddressSpacesInfo,
+ &GDBRemoteCommunicationServerLLGS::Handle_jAddressSpacesInfo);
RegisterMemberFunctionHandler(
StringExtractorGDBRemote::eServerPacketType_qWatchpointSupportInfo,
&GDBRemoteCommunicationServerLLGS::Handle_qWatchpointSupportInfo);
@@ -3909,6 +3912,31 @@ GDBRemoteCommunicationServerLLGS::Handle_jThreadsInfo(
return SendPacketNoLock(escaped_response.GetString());
}
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_jAddressSpacesInfo(
+ StringExtractorGDBRemote &packet) {
+ Log *log = GetLog(LLDBLog::Process);
+
+ // Ensure we have a process.
+ if (!m_current_process ||
+ (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) {
+ LLDB_LOGF(log,
+ "GDBRemoteCommunicationServerLLGS::%s failed, no process "
+ "available",
+ __FUNCTION__);
+ return SendErrorResponse(Status::FromErrorString("invalid process"));
+ }
+
+ std::vector<AddressSpaceInfo> address_spaces =
+ m_current_process->GetAddressSpaces();
+ if (address_spaces.empty())
+ return SendUnimplementedResponse(packet.GetStringRef().data());
+
+ StreamGDBRemote response;
+ response.PutAsJSONArray(address_spaces, /*hex_ascii=*/false);
+ return SendPacketNoLock(response.GetString());
+}
+
GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServerLLGS::Handle_qWatchpointSupportInfo(
StringExtractorGDBRemote &packet) {
diff --git
a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h
b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h
index e5b4c9ec0bed0..eaef6100445a8 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h
@@ -268,6 +268,8 @@ class GDBRemoteCommunicationServerLLGS
PacketResult Handle_jThreadsInfo(StringExtractorGDBRemote &packet);
+ PacketResult Handle_jAddressSpacesInfo(StringExtractorGDBRemote &packet);
+
PacketResult Handle_qWatchpointSupportInfo(StringExtractorGDBRemote &packet);
PacketResult Handle_qFileLoadAddress(StringExtractorGDBRemote &packet);
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index a986d0350bf57..fecf23d7eb4f2 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -1192,6 +1192,9 @@ void ProcessGDBRemote::LoadStubBinaries() {
allow_memory_image_last_resort);
}
}
+
+ // Cache the address spaces the remote exposes (empty for most processes).
+ m_address_spaces = m_gdb_comm.GetAddressSpaces();
}
void ProcessGDBRemote::MaybeLoadExecutableModule() {
diff --git a/lldb/source/Utility/AddressSpace.cpp
b/lldb/source/Utility/AddressSpace.cpp
new file mode 100644
index 0000000000000..c118259706510
--- /dev/null
+++ b/lldb/source/Utility/AddressSpace.cpp
@@ -0,0 +1,28 @@
+//===-- AddressSpace.cpp
--------------------------------------------------===//
+//
+// 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/AddressSpace.h"
+
+using namespace llvm;
+using namespace llvm::json;
+
+namespace lldb_private {
+
+bool fromJSON(const json::Value &value, AddressSpaceInfo &data, Path path) {
+ ObjectMapper o(value, path);
+ return o && o.map("name", data.name) && o.map("value", data.value) &&
+ o.map("is_thread_specific", data.is_thread_specific);
+}
+
+json::Value toJSON(const AddressSpaceInfo &data) {
+ return json::Value(Object{{"name", data.name},
+ {"value", data.value},
+ {"is_thread_specific", data.is_thread_specific}});
+}
+
+} // namespace lldb_private
diff --git a/lldb/source/Utility/CMakeLists.txt
b/lldb/source/Utility/CMakeLists.txt
index e6d918c1ce9c7..f6000b9c330fb 100644
--- a/lldb/source/Utility/CMakeLists.txt
+++ b/lldb/source/Utility/CMakeLists.txt
@@ -25,6 +25,7 @@ endif()
add_lldb_library(lldbUtility NO_INTERNAL_DEPENDENCIES
AddressableBits.cpp
+ AddressSpace.cpp
ArchSpec.cpp
Args.cpp
Baton.cpp
diff --git a/lldb/source/Utility/StringExtractorGDBRemote.cpp
b/lldb/source/Utility/StringExtractorGDBRemote.cpp
index 6fc3b63e02dd1..20237aec70c50 100644
--- a/lldb/source/Utility/StringExtractorGDBRemote.cpp
+++ b/lldb/source/Utility/StringExtractorGDBRemote.cpp
@@ -321,6 +321,8 @@ StringExtractorGDBRemote::GetServerPacketType() const {
return eServerPacketType_jSignalsInfo;
if (PACKET_MATCHES("jThreadsInfo"))
return eServerPacketType_jThreadsInfo;
+ if (PACKET_MATCHES("jAddressSpacesInfo"))
+ return eServerPacketType_jAddressSpacesInfo;
if (PACKET_MATCHES("jLLDBTraceSupported"))
return eServerPacketType_jLLDBTraceSupported;
diff --git
a/lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp
b/lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp
index 3ec212b1c205d..9ea40e285aaae 100644
--- a/lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp
+++ b/lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp
@@ -11,7 +11,9 @@
#include "lldb/Host/ConnectionFileDescriptor.h"
#include "lldb/Host/XML.h"
#include "lldb/Target/MemoryRegionInfo.h"
+#include "lldb/Utility/AddressSpace.h"
#include "lldb/Utility/DataBuffer.h"
+#include "lldb/Utility/GDBRemote.h"
#include "lldb/Utility/StructuredData.h"
#include "lldb/lldb-enumerations.h"
#include "llvm/ADT/ArrayRef.h"
@@ -191,6 +193,37 @@ TEST_F(GDBRemoteCommunicationClientTest, ReadRegister) {
memcmp(buffer_sp->GetBytes(), all_registers, sizeof
all_registers));
}
+TEST_F(GDBRemoteCommunicationClientTest, GetAddressSpaces) {
+ std::future<std::vector<AddressSpaceInfo>> result =
+ std::async(std::launch::async, [&] { return client.GetAddressSpaces();
});
+ // JSON responses are sent with the gdb-remote escaping applied (the same way
+ // the server's StreamGDBRemote::PutAsJSONArray does), so '{' and '}' survive
+ // the round trip.
+ StreamGDBRemote escaped;
+ llvm::StringRef json =
+ R"([{"name":"global","value":1,"is_thread_specific":false},)"
+ R"({"name":"local","value":2,"is_thread_specific":true}])";
+ escaped.PutEscapedBytes(json.data(), json.size());
+ HandlePacket(server, "jAddressSpacesInfo", escaped.GetString());
+
+ std::vector<AddressSpaceInfo> spaces = result.get();
+ ASSERT_EQ(spaces.size(), 2u);
+ EXPECT_EQ(spaces[0].name, "global");
+ EXPECT_EQ(spaces[0].value, 1u);
+ EXPECT_FALSE(spaces[0].is_thread_specific);
+ EXPECT_EQ(spaces[1].name, "local");
+ EXPECT_EQ(spaces[1].value, 2u);
+ EXPECT_TRUE(spaces[1].is_thread_specific);
+}
+
+TEST_F(GDBRemoteCommunicationClientTest, GetAddressSpacesUnsupported) {
+ std::future<std::vector<AddressSpaceInfo>> result =
+ std::async(std::launch::async, [&] { return client.GetAddressSpaces();
});
+ // An empty response is the "unsupported" reply.
+ HandlePacket(server, "jAddressSpacesInfo", "");
+ EXPECT_TRUE(result.get().empty());
+}
+
TEST_F(GDBRemoteCommunicationClientTest, SaveRestoreRegistersNoSuffix) {
const lldb::tid_t tid = 0x47;
uint32_t save_id;
diff --git a/lldb/unittests/Utility/AddressSpaceTest.cpp
b/lldb/unittests/Utility/AddressSpaceTest.cpp
new file mode 100644
index 0000000000000..7a4cf04cc8d2b
--- /dev/null
+++ b/lldb/unittests/Utility/AddressSpaceTest.cpp
@@ -0,0 +1,55 @@
+//===-- AddressSpaceTest.cpp
----------------------------------------------===//
+//
+// 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/AddressSpace.h"
+#include "llvm/Support/JSON.h"
+#include "llvm/Testing/Support/Error.h"
+#include "gtest/gtest.h"
+
+using namespace lldb_private;
+
+static std::string ToString(const llvm::json::Value &value) {
+ return llvm::formatv("{0}", value).str();
+}
+
+TEST(AddressSpaceTest, RoundTrip) {
+ AddressSpaceInfo info{"global", 1, /*is_thread_specific=*/false};
+ llvm::Expected<AddressSpaceInfo> parsed =
llvm::json::parse<AddressSpaceInfo>(
+ ToString(toJSON(info)), "AddressSpaceInfo");
+ ASSERT_THAT_EXPECTED(parsed, llvm::Succeeded());
+ EXPECT_EQ(parsed->name, "global");
+ EXPECT_EQ(parsed->value, 1u);
+ EXPECT_FALSE(parsed->is_thread_specific);
+}
+
+TEST(AddressSpaceTest, ArrayRoundTrip) {
+ std::vector<AddressSpaceInfo> spaces = {
+...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/206370
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits