diff options
Diffstat (limited to 'lldb/tools/debugserver/source/RNBRemote.cpp')
-rw-r--r-- | lldb/tools/debugserver/source/RNBRemote.cpp | 105 |
1 files changed, 104 insertions, 1 deletions
diff --git a/lldb/tools/debugserver/source/RNBRemote.cpp b/lldb/tools/debugserver/source/RNBRemote.cpp index d9fb22c..434e9cf 100644 --- a/lldb/tools/debugserver/source/RNBRemote.cpp +++ b/lldb/tools/debugserver/source/RNBRemote.cpp @@ -22,6 +22,9 @@ #include <mach/mach_vm.h> #include <mach/task_info.h> #include <memory> +#if __has_include(<os/security_config.h>) +#include <os/security_config.h> +#endif #include <pwd.h> #include <string> #include <sys/stat.h> @@ -502,6 +505,8 @@ void RNBRemote::CreatePacketTable() { memory_region_info, &RNBRemote::HandlePacket_MemoryRegionInfo, NULL, "qMemoryRegionInfo", "Return size and attributes of a memory region that " "contains the given address")); + t.push_back(Packet(get_memory_tags, &RNBRemote::HandlePacket_qMemTags, NULL, + "qMemTags", "Return tags for a region of memory")); t.push_back(Packet(get_profile_data, &RNBRemote::HandlePacket_GetProfileData, NULL, "qGetProfileData", "Return profiling data of the current target.")); @@ -3475,6 +3480,18 @@ static bool GetProcessNameFrom_vAttach(const char *&p, return return_val; } +static bool supports_memory_tagging() { + const char *name = "hw.optional.arm.FEAT_MTE4"; + uint32_t val; + size_t len = sizeof(val); + int ret = ::sysctlbyname(name, &val, &len, nullptr, 0); + if (ret != 0) + return false; + + assert(len == sizeof(val)); + return val; +} + rnb_err_t RNBRemote::HandlePacket_qSupported(const char *p) { uint32_t max_packet_size = 128 * 1024; // 128 KiB is a reasonable max packet // size--debugger can always use less @@ -3505,6 +3522,9 @@ rnb_err_t RNBRemote::HandlePacket_qSupported(const char *p) { reply << "SupportedWatchpointTypes=x86_64;"; #endif + if (supports_memory_tagging()) + reply << "memory-tagging+;"; + return SendPacket(reply.str().c_str()); } @@ -4251,7 +4271,6 @@ rnb_err_t RNBRemote::HandlePacket_MemoryRegionInfo(const char *p) { is in unmapped memory Region lookup cannot be performed on this platform or process is not yet launched - This packet isn't implemented Examples of use: qMemoryRegionInfo:3a55140 @@ -4303,6 +4322,16 @@ rnb_err_t RNBRemote::HandlePacket_MemoryRegionInfo(const char *p) { ostrm << 'x'; ostrm << ';'; + if (!region_info.flags.empty()) { + ostrm << "flags:"; + for (size_t i = 0; i < region_info.flags.size(); i++) { + if (i != 0) + ostrm << " "; // Separator is whitespace + ostrm << region_info.flags[i]; + } + ostrm << ";"; + } + ostrm << "dirty-pages:"; if (region_info.dirty_pages.size() > 0) { bool first = true; @@ -4327,6 +4356,62 @@ rnb_err_t RNBRemote::HandlePacket_MemoryRegionInfo(const char *p) { return SendPacket(ostrm.str()); } +// qMemTags:<hex address>,<hex length>:<hex type> +rnb_err_t RNBRemote::HandlePacket_qMemTags(const char *p) { + nub_process_t pid = m_ctx.ProcessID(); + if (pid == INVALID_NUB_PROCESS) + return SendPacket("OK"); + + StdStringExtractor packet(p); + packet.SetFilePos(strlen("qMemTags:")); + + // Address + nub_addr_t addr = + packet.GetHexMaxU64(StdStringExtractor::BigEndian, INVALID_NUB_ADDRESS); + if (addr == INVALID_NUB_ADDRESS) + return HandlePacket_ILLFORMED(__FILE__, __LINE__, p, + "Invalid/missing address in qMemTags packet"); + // , + if (packet.GetChar() != ',') + return HandlePacket_ILLFORMED(__FILE__, __LINE__, p, + "Invalid qMemTags packet format"); + // Length + uint64_t length = packet.GetHexMaxU64(StdStringExtractor::BigEndian, 0); + if (length == 0) + return HandlePacket_ILLFORMED(__FILE__, __LINE__, p, + "Invalid/missing length in qMemTags packet"); + // : + if (packet.GetChar() != ':') + return HandlePacket_ILLFORMED(__FILE__, __LINE__, p, + "Invalid qMemTags packet format"); + // Type + // On the LLDB side this is a `int32_t` serialized as (unsigned) hex, which + // means negative values will show up as large positive values here. Right + // now, we only support MTE (type 1), so we can ignore this complication. + uint32_t type = packet.GetHexMaxU32(StdStringExtractor::BigEndian, 0); + if (type != 1 /* MTE */) + return HandlePacket_ILLFORMED(__FILE__, __LINE__, p, + "Invalid/missing type in qMemTags packet, " + "only MTE (type 1) is supported"); + // <EOF> + if (packet.GetBytesLeft() != 0) + return HandlePacket_ILLFORMED(__FILE__, __LINE__, p, + "Invalid qMemTags packet format"); + + std::vector<uint8_t> tags; + bool ok = DNBProcessGetMemoryTags(pid, addr, length, tags); + if (!ok) + return SendErrorPacket("E91"); + + std::ostringstream ostrm; + ostrm << "m"; // Multi part replies + for (uint8_t tag : tags) { + ostrm << RAWHEX8(tag); // 2 hex chars per tag + } + + return SendPacket(ostrm.str()); +} + // qGetProfileData;scan_type:0xYYYYYYY rnb_err_t RNBRemote::HandlePacket_GetProfileData(const char *p) { nub_process_t pid = m_ctx.ProcessID(); @@ -6162,6 +6247,21 @@ GetCPUTypesFromHost(nub_process_t pid) { return {cputype, cpusubtype}; } +static bool ProcessRunningWithMemoryTagging(pid_t pid) { +#if __has_include(<os/security_config.h>) + if (__builtin_available(macOS 26.0, iOS 26.0, tvOS 26.0, watchOS 26.0, + visionOS 26.0, driverkit 25.0, *)) { + os_security_config_t config; + int ret = ::os_security_config_get_for_proc(pid, &config); + if (ret != 0) + return false; + + return (config & OS_SECURITY_CONFIG_MTE); + } +#endif + return false; +} + // Note that all numeric values returned by qProcessInfo are hex encoded, // including the pid and the cpu type. @@ -6338,6 +6438,9 @@ rnb_err_t RNBRemote::HandlePacket_qProcessInfo(const char *p) { rep << "vendor:apple;"; + if (ProcessRunningWithMemoryTagging(pid)) + rep << "mte:enabled;"; + #if defined(__LITTLE_ENDIAN__) rep << "endian:little;"; #elif defined(__BIG_ENDIAN__) |