[Lldb-commits] [lldb] [debugserver] Support for `qMemTags` packet (PR #160952)

via lldb-commits lldb-commits at lists.llvm.org
Fri Sep 26 14:26:08 PDT 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-lldb

Author: Julian Lettner (yln)

<details>
<summary>Changes</summary>

Support for `qMemTags` packet in debugserver which allows usage of LLDB's `memory tag read` on Darwin.

---

Patch is 26.64 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/160952.diff


16 Files Affected:

- (modified) lldb/packages/Python/lldbsuite/test/cpu_feature.py (+1-1) 
- (added) lldb/test/API/macosx/mte/Makefile (+12) 
- (added) lldb/test/API/macosx/mte/TestDarwinMTE.py (+90) 
- (added) lldb/test/API/macosx/mte/main.c (+29) 
- (added) lldb/test/API/macosx/mte/mte-entitlements.plist (+10) 
- (modified) lldb/tools/debugserver/source/DNB.cpp (+10) 
- (modified) lldb/tools/debugserver/source/DNB.h (+3) 
- (modified) lldb/tools/debugserver/source/DNBDefs.h (+2-1) 
- (modified) lldb/tools/debugserver/source/MacOSX/MachTask.h (+2) 
- (modified) lldb/tools/debugserver/source/MacOSX/MachTask.mm (+19-2) 
- (modified) lldb/tools/debugserver/source/MacOSX/MachVMMemory.cpp (+59) 
- (modified) lldb/tools/debugserver/source/MacOSX/MachVMMemory.h (+2) 
- (modified) lldb/tools/debugserver/source/MacOSX/MachVMRegion.cpp (+46) 
- (modified) lldb/tools/debugserver/source/MacOSX/MachVMRegion.h (+2-1) 
- (modified) lldb/tools/debugserver/source/RNBRemote.cpp (+104-1) 
- (modified) lldb/tools/debugserver/source/RNBRemote.h (+2) 


``````````diff
diff --git a/lldb/packages/Python/lldbsuite/test/cpu_feature.py b/lldb/packages/Python/lldbsuite/test/cpu_feature.py
index b46a5acc596f0..d7668c1884e40 100644
--- a/lldb/packages/Python/lldbsuite/test/cpu_feature.py
+++ b/lldb/packages/Python/lldbsuite/test/cpu_feature.py
@@ -62,7 +62,7 @@ def _is_supported_darwin(self, cmd_runner):
 class AArch64:
     FPMR = CPUFeature("fpmr")
     GCS = CPUFeature("gcs")
-    MTE = CPUFeature("mte")
+    MTE = CPUFeature("mte", "hw.optional.arm.FEAT_MTE4")
     MTE_STORE_ONLY = CPUFeature("mtestoreonly")
     PTR_AUTH = CPUFeature("paca", "hw.optional.arm.FEAT_PAuth2")
     SME = CPUFeature("sme", "hw.optional.arm.FEAT_SME")
diff --git a/lldb/test/API/macosx/mte/Makefile b/lldb/test/API/macosx/mte/Makefile
new file mode 100644
index 0000000000000..cb20942805e2a
--- /dev/null
+++ b/lldb/test/API/macosx/mte/Makefile
@@ -0,0 +1,12 @@
+C_SOURCES := main.c
+
+EXE := uaf_mte
+
+all: uaf_mte sign
+
+include Makefile.rules
+
+sign: mte-entitlements.plist uaf_mte
+ifeq ($(OS),Darwin)
+	codesign -s - -f --entitlements $^
+endif
diff --git a/lldb/test/API/macosx/mte/TestDarwinMTE.py b/lldb/test/API/macosx/mte/TestDarwinMTE.py
new file mode 100644
index 0000000000000..787f29e3530cd
--- /dev/null
+++ b/lldb/test/API/macosx/mte/TestDarwinMTE.py
@@ -0,0 +1,90 @@
+"""Test MTE Memory Tagging on Apple platforms"""
+
+import lldb
+import re
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+import lldbsuite.test.cpu_feature as cpu_feature
+
+exe_name = "uaf_mte"  # Must match Makefile
+
+
+class TestDarwinMTE(TestBase):
+    NO_DEBUG_INFO_TESTCASE = True
+
+    @skipUnlessFeature(cpu_feature.AArch64.MTE)
+    def test_tag_fault(self):
+        self.build()
+        exe = self.getBuildArtifact(exe_name)
+
+        target = self.dbg.CreateTarget(exe)
+        self.assertTrue(target, VALID_TARGET)
+
+        process = target.LaunchSimple(None, None, None)
+        self.assertState(process.GetState(), lldb.eStateStopped, PROCESS_STOPPED)
+
+        self.expect(
+            "thread info",
+            substrs=["stop reason = EXC_ARM_MTE_TAG_FAULT", "MTE tag mismatch detected"],
+        )
+
+    @skipUnlessFeature(cpu_feature.AArch64.MTE)
+    def test_memory_read_with_tags(self):
+        self.build()
+        lldbutil.run_to_source_breakpoint(
+            self, "// before free", lldb.SBFileSpec("main.c"), exe_name=exe_name
+        )
+
+        # (lldb) memory read ptr-16 ptr+48 --show-tags
+        # 0x7d2c00930: 00 00 00 00 00 00 00 00 d0 e3 a5 0a 02 00 00 00  ................ (tag: 0x3)
+        # 0x7d2c00940: 48 65 6c 6c 6f 00 00 00 00 00 00 00 00 00 00 00  Hello........... (tag: 0xb)
+        # 0x7d2c00950: 57 6f 72 6c 64 00 00 00 00 00 00 00 00 00 00 00  World........... (tag: 0xb)
+        # 0x7d2c00960: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................ (tag: 0x9)
+        self.expect(
+            "memory read ptr-16 ptr+48 --show-tags",
+            substrs=[" Hello...........", " World..........."],
+            patterns=[r"(.*\(tag: 0x[0-9a-f]\)\n){4}"])
+
+    def _parse_pointer_tag(self):
+        return re.search(r"Logical tag: (0x[0-9a-f])", self.res.GetOutput()).group(1)
+
+    def _parse_memory_tags(self, expected_tag_count):
+        tags = re.findall(r"\): (0x[0-9a-f])", self.res.GetOutput())
+        self.assertEqual(len(tags), expected_tag_count)
+        return tags
+
+    @skipUnlessFeature(cpu_feature.AArch64.MTE)
+    def test_memory_tag_read(self):
+        self.build()
+        lldbutil.run_to_source_breakpoint(
+            self, "// before free", lldb.SBFileSpec("main.c"), exe_name=exe_name
+        )
+
+        # (lldb) memory tag read ptr-1 ptr+33
+        # Logical tag: 0x5
+        # Allocation tags:
+        # [0x100a65a40, 0x100a65a50): 0xf (mismatch)
+        # [0x100a65a50, 0x100a65a60): 0x5
+        # [0x100a65a60, 0x100a65a70): 0x5
+        # [0x100a65a70, 0x100a65a80): 0x2 (mismatch)
+        self.expect(
+            "memory tag read ptr-1 ptr+33",
+            substrs=["Logical tag: 0x", "Allocation tags:", "(mismatch)"],
+            patterns=[r"(\[.*\): 0x[0-9a-f].*\n){4}"]
+        )
+        self.assertEqual(self.res.GetOutput().count("(mismatch)"), 2)
+        ptr_tag = self._parse_pointer_tag()
+        tags = self._parse_memory_tags(4)
+        self.assertEqual(tags[1], ptr_tag)
+        self.assertEqual(tags[2], ptr_tag)
+        self.assertNotEqual(tags[0], ptr_tag)
+        self.assertNotEqual(tags[3], ptr_tag)
+
+        # Continue running until MTE fault
+        self.runCmd("process continue")
+
+        self.runCmd("memory tag read ptr-1 ptr+33")
+        self.assertEqual(self.res.GetOutput().count("(mismatch)"), 4)
+        tags = self._parse_memory_tags(4)
+        self.assertTrue(all(t != ptr_tag for t in tags))
diff --git a/lldb/test/API/macosx/mte/main.c b/lldb/test/API/macosx/mte/main.c
new file mode 100644
index 0000000000000..ca61c05b19a38
--- /dev/null
+++ b/lldb/test/API/macosx/mte/main.c
@@ -0,0 +1,29 @@
+#include <malloc/malloc.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+// Produce some names on the trace
+const size_t tag_granule = 16;
+uint8_t *my_malloc(void) { return malloc(2 * tag_granule); }
+uint8_t *allocate(void) { return my_malloc(); }
+
+void my_free(void *ptr) { free(ptr); }
+void deallocate(void *ptr) { my_free(ptr); }
+
+void touch_memory(uint8_t *ptr) { ptr[7] = 1; }  // invalid access
+void modify(uint8_t *ptr) { touch_memory(ptr); }
+
+int main() {
+  uint8_t *ptr = allocate();
+  printf("ptr: %p\n", ptr);
+
+  strcpy((char *)ptr, "Hello");
+  strcpy((char *)ptr+16, "World");
+
+  deallocate(ptr);  // before free
+
+  modify(ptr);  // use-after-free
+
+  return 0;
+}
diff --git a/lldb/test/API/macosx/mte/mte-entitlements.plist b/lldb/test/API/macosx/mte/mte-entitlements.plist
new file mode 100644
index 0000000000000..6de5d5634d878
--- /dev/null
+++ b/lldb/test/API/macosx/mte/mte-entitlements.plist
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+    <key>com.apple.security.hardened-process</key>
+    <true/>
+    <key>com.apple.security.hardened-process.checked-allocations</key>
+    <true/>
+</dict>
+</plist>
diff --git a/lldb/tools/debugserver/source/DNB.cpp b/lldb/tools/debugserver/source/DNB.cpp
index f541134b43a1b..0cd48d91a682a 100644
--- a/lldb/tools/debugserver/source/DNB.cpp
+++ b/lldb/tools/debugserver/source/DNB.cpp
@@ -1386,6 +1386,16 @@ int DNBProcessMemoryRegionInfo(nub_process_t pid, nub_addr_t addr,
   return -1;
 }
 
+nub_bool_t DNBProcessGetMemoryTags(nub_process_t pid, nub_addr_t addr,
+                                   nub_size_t size,
+                                   std::vector<uint8_t> &tags) {
+  MachProcessSP procSP;
+  if (GetProcessSP(pid, procSP))
+    return procSP->Task().GetMemoryTags(addr, size, tags);
+
+  return false;
+}
+
 std::string DNBProcessGetProfileData(nub_process_t pid,
                                      DNBProfileDataScanType scanType) {
   MachProcessSP procSP;
diff --git a/lldb/tools/debugserver/source/DNB.h b/lldb/tools/debugserver/source/DNB.h
index 10d1f68794355..1f3d5392c588f 100644
--- a/lldb/tools/debugserver/source/DNB.h
+++ b/lldb/tools/debugserver/source/DNB.h
@@ -105,6 +105,9 @@ nub_bool_t DNBProcessMemoryDeallocate(nub_process_t pid,
                                       nub_addr_t addr) DNB_EXPORT;
 int DNBProcessMemoryRegionInfo(nub_process_t pid, nub_addr_t addr,
                                DNBRegionInfo *region_info) DNB_EXPORT;
+nub_bool_t DNBProcessGetMemoryTags(nub_process_t pid, nub_addr_t addr,
+                                   nub_size_t size,
+                                   std::vector<uint8_t> &tags) DNB_EXPORT;
 std::string
 DNBProcessGetProfileData(nub_process_t pid,
                          DNBProfileDataScanType scanType) DNB_EXPORT;
diff --git a/lldb/tools/debugserver/source/DNBDefs.h b/lldb/tools/debugserver/source/DNBDefs.h
index df8ca809d412c..d98399aed5e19 100644
--- a/lldb/tools/debugserver/source/DNBDefs.h
+++ b/lldb/tools/debugserver/source/DNBDefs.h
@@ -358,10 +358,11 @@ struct DNBExecutableImageInfo {
 struct DNBRegionInfo {
 public:
   DNBRegionInfo()
-      : addr(0), size(0), permissions(0), dirty_pages(), vm_types() {}
+      : addr(0), size(0), permissions(0), flags(), dirty_pages(), vm_types() {}
   nub_addr_t addr;
   nub_addr_t size;
   uint32_t permissions;
+  std::vector<std::string> flags;
   std::vector<nub_addr_t> dirty_pages;
   std::vector<std::string> vm_types;
 };
diff --git a/lldb/tools/debugserver/source/MacOSX/MachTask.h b/lldb/tools/debugserver/source/MacOSX/MachTask.h
index 2284f6b99de91..c4a20b80fda95 100644
--- a/lldb/tools/debugserver/source/MacOSX/MachTask.h
+++ b/lldb/tools/debugserver/source/MacOSX/MachTask.h
@@ -56,6 +56,8 @@ class MachTask {
   nub_size_t ReadMemory(nub_addr_t addr, nub_size_t size, void *buf);
   nub_size_t WriteMemory(nub_addr_t addr, nub_size_t size, const void *buf);
   int GetMemoryRegionInfo(nub_addr_t addr, DNBRegionInfo *region_info);
+  nub_bool_t GetMemoryTags(nub_addr_t addr, nub_size_t size,
+                           std::vector<uint8_t> &tags);
   std::string GetProfileData(DNBProfileDataScanType scanType);
 
   nub_addr_t AllocateMemory(nub_size_t size, uint32_t permissions);
diff --git a/lldb/tools/debugserver/source/MacOSX/MachTask.mm b/lldb/tools/debugserver/source/MacOSX/MachTask.mm
index 8ae9d4df99657..f25cfac7b030a 100644
--- a/lldb/tools/debugserver/source/MacOSX/MachTask.mm
+++ b/lldb/tools/debugserver/source/MacOSX/MachTask.mm
@@ -213,7 +213,7 @@
 }
 
 //----------------------------------------------------------------------
-// MachTask::MemoryRegionInfo
+// MachTask::GetMemoryRegionInfo
 //----------------------------------------------------------------------
 int MachTask::GetMemoryRegionInfo(nub_addr_t addr, DNBRegionInfo *region_info) {
   task_t task = TaskPort();
@@ -221,7 +221,7 @@
     return -1;
 
   int ret = m_vm_memory.GetMemoryRegionInfo(task, addr, region_info);
-  DNBLogThreadedIf(LOG_MEMORY, "MachTask::MemoryRegionInfo ( addr = 0x%8.8llx "
+  DNBLogThreadedIf(LOG_MEMORY, "MachTask::GetMemoryRegionInfo ( addr = 0x%8.8llx "
                                ") => %i  (start = 0x%8.8llx, size = 0x%8.8llx, "
                                "permissions = %u)",
                    (uint64_t)addr, ret, (uint64_t)region_info->addr,
@@ -229,6 +229,23 @@
   return ret;
 }
 
+//----------------------------------------------------------------------
+// MachTask::GetMemoryTags
+//----------------------------------------------------------------------
+nub_bool_t MachTask::GetMemoryTags(nub_addr_t addr, nub_size_t size,
+                                   std::vector<uint8_t> &tags) {
+  task_t task = TaskPort();
+  if (task == TASK_NULL)
+    return false;
+
+  bool ok = m_vm_memory.GetMemoryTags(task, addr, size, tags);
+  DNBLogThreadedIf(LOG_MEMORY, "MachTask::GetMemoryTags ( addr = 0x%8.8llx, "
+                               "size = 0x%8.8llx ) => %s ( tag count = %llu)",
+                  (uint64_t)addr, (uint64_t)size, (ok ? "ok" : "err"),
+                  (uint64_t)tags.size());
+  return ok;
+}
+
 #define TIME_VALUE_TO_TIMEVAL(a, r)                                            \
   do {                                                                         \
     (r)->tv_sec = (a)->seconds;                                                \
diff --git a/lldb/tools/debugserver/source/MacOSX/MachVMMemory.cpp b/lldb/tools/debugserver/source/MacOSX/MachVMMemory.cpp
index f3aa4d7d980fd..7ecd57e7bbfeb 100644
--- a/lldb/tools/debugserver/source/MacOSX/MachVMMemory.cpp
+++ b/lldb/tools/debugserver/source/MacOSX/MachVMMemory.cpp
@@ -13,6 +13,7 @@
 #include "MachVMMemory.h"
 #include "DNBLog.h"
 #include "MachVMRegion.h"
+#include <cassert>
 #include <dlfcn.h>
 #include <mach/mach_vm.h>
 #include <mach/shared_region.h>
@@ -123,6 +124,7 @@ nub_bool_t MachVMMemory::GetMemoryRegionInfo(task_t task, nub_addr_t address,
     region_info->addr = vmRegion.StartAddress();
     region_info->size = vmRegion.GetByteSize();
     region_info->permissions = vmRegion.GetDNBPermissions();
+    region_info->flags = vmRegion.GetFlags();
     region_info->dirty_pages =
         get_dirty_pages(task, vmRegion.StartAddress(), vmRegion.GetByteSize());
     region_info->vm_types = vmRegion.GetMemoryTypes();
@@ -150,6 +152,63 @@ nub_bool_t MachVMMemory::GetMemoryRegionInfo(task_t task, nub_addr_t address,
   return true;
 }
 
+// API availability:
+//  mach_vm_update_pointers_with_remote_tags() - 26.0
+//  VM_OFFSET_LIST_MAX macro - 26.1
+#ifndef VM_OFFSET_LIST_MAX
+#define VM_OFFSET_LIST_MAX 512
+#endif
+using mach_vm_offset_list_t = mach_vm_offset_t *;
+using mach_vm_update_pointers_with_remote_tags_t = kern_return_t(
+    mach_port_name_t target, mach_vm_offset_list_t in_pointer_list,
+    mach_msg_type_number_t in_pointer_listCnt,
+    mach_vm_offset_list_t out_pointer_list,
+    mach_msg_type_number_t *out_pointer_listCnt);
+
+nub_bool_t MachVMMemory::GetMemoryTags(task_t task, nub_addr_t address,
+                                       nub_size_t size,
+                                       std::vector<uint8_t> &tags) {
+  static auto mach_vm_update_pointers_with_remote_tags =
+      (mach_vm_update_pointers_with_remote_tags_t *)dlsym(
+          RTLD_DEFAULT, "mach_vm_update_pointers_with_remote_tags");
+  assert(mach_vm_update_pointers_with_remote_tags);
+
+  // Max batch size supported by mach_vm_update_pointers_with_remote_tags()
+  constexpr uint32_t max_ptr_count = VM_OFFSET_LIST_MAX;
+  constexpr uint32_t tag_shift = 56;
+  constexpr nub_addr_t tag_mask =
+      ((nub_addr_t)0x0f << tag_shift); // Lower half of top byte
+  constexpr uint32_t tag_granule = 16;
+
+  mach_msg_type_number_t ptr_count =
+      (size / tag_granule) + ((size % tag_granule > 0) ? 1 : 0);
+  ptr_count = std::min(ptr_count, max_ptr_count);
+
+  auto ptr_arr = std::make_unique<mach_vm_offset_t[]>(ptr_count);
+  for (size_t i = 0; i < ptr_count; i++)
+    ptr_arr[i] = (address + i * tag_granule);
+
+  mach_msg_type_number_t ptr_count_out = ptr_count;
+  m_err = mach_vm_update_pointers_with_remote_tags(
+      task, ptr_arr.get(), ptr_count, ptr_arr.get(), &ptr_count_out);
+
+  const bool failed = (m_err.Fail() || (ptr_count != ptr_count_out));
+  if (failed || DNBLogCheckLogBit(LOG_MEMORY))
+    m_err.LogThreaded("::mach_vm_update_pointers_with_remote_tags ( task = "
+                      "0x%4.4x, ptr_count = %d ) => %i ( ptr_count_out = %d)",
+                      task, ptr_count, m_err.Status(), ptr_count_out);
+  if (failed)
+    return false;
+
+  tags.reserve(ptr_count);
+  for (size_t i = 0; i < ptr_count; i++) {
+    nub_addr_t tag = (ptr_arr[i] & tag_mask) >> tag_shift;
+    tags.push_back(tag);
+  }
+
+  return true;
+}
+
 static uint64_t GetPhysicalMemory() {
   // This doesn't change often at all. No need to poll each time.
   static uint64_t physical_memory = 0;
diff --git a/lldb/tools/debugserver/source/MacOSX/MachVMMemory.h b/lldb/tools/debugserver/source/MacOSX/MachVMMemory.h
index 05d2c029b9980..8a7616091fbb3 100644
--- a/lldb/tools/debugserver/source/MacOSX/MachVMMemory.h
+++ b/lldb/tools/debugserver/source/MacOSX/MachVMMemory.h
@@ -28,6 +28,8 @@ class MachVMMemory {
   nub_size_t PageSize(task_t task);
   nub_bool_t GetMemoryRegionInfo(task_t task, nub_addr_t address,
                                  DNBRegionInfo *region_info);
+  nub_bool_t GetMemoryTags(task_t task, nub_addr_t address, nub_size_t size,
+                           std::vector<uint8_t> &tags);
   nub_bool_t GetMemoryProfile(DNBProfileDataScanType scanType, task_t task,
                               struct task_basic_info ti, cpu_type_t cputype,
                               nub_process_t pid, vm_statistics64_data_t &vminfo,
diff --git a/lldb/tools/debugserver/source/MacOSX/MachVMRegion.cpp b/lldb/tools/debugserver/source/MacOSX/MachVMRegion.cpp
index 97908b4acaf28..9d0d60fdaaed9 100644
--- a/lldb/tools/debugserver/source/MacOSX/MachVMRegion.cpp
+++ b/lldb/tools/debugserver/source/MacOSX/MachVMRegion.cpp
@@ -114,6 +114,11 @@ bool MachVMRegion::RestoreProtections() {
   return false;
 }
 
+#ifdef VM_REGION_FLAG_JIT_ENABLED
+#define VM_REGION_HAS_FLAGS 1
+#else
+#define VM_REGION_HAS_FLAGS 0
+#endif
 bool MachVMRegion::GetRegionForAddress(nub_addr_t addr) {
   // Restore any original protections and clear our vars
   Clear();
@@ -140,6 +145,30 @@ bool MachVMRegion::GetRegionForAddress(nub_addr_t addr) {
   if (failed)
     return false;
   if (log_protections) {
+#if VM_REGION_HAS_FLAGS
+    DNBLogThreaded("info = { prot = %u, "
+                   "max_prot = %u, "
+                   "inheritance = 0x%8.8x, "
+                   "offset = 0x%8.8llx, "
+                   "user_tag = 0x%8.8x, "
+                   "ref_count = %u, "
+                   "shadow_depth = %u, "
+                   "ext_pager = %u, "
+                   "share_mode = %u, "
+                   "is_submap = %d, "
+                   "behavior = %d, "
+                   "object_id = 0x%8.8x, "
+                   "user_wired_count = 0x%4.4x, "
+                   "flags = %d }",
+                   m_data.protection, m_data.max_protection, m_data.inheritance,
+                   (uint64_t)m_data.offset, m_data.user_tag, m_data.ref_count,
+                   m_data.shadow_depth, m_data.external_pager,
+                   m_data.share_mode, m_data.is_submap, m_data.behavior,
+                   m_data.object_id, m_data.user_wired_count, m_data.flags);
+#else
+    // Duplicate log call instead of #if-defing printing of flags to avoid
+    // compiler warning: 'embedding a directive within macro arguments has
+    // undefined behavior'
     DNBLogThreaded("info = { prot = %u, "
                    "max_prot = %u, "
                    "inheritance = 0x%8.8x, "
@@ -158,6 +187,7 @@ bool MachVMRegion::GetRegionForAddress(nub_addr_t addr) {
                    m_data.shadow_depth, m_data.external_pager,
                    m_data.share_mode, m_data.is_submap, m_data.behavior,
                    m_data.object_id, m_data.user_wired_count);
+#endif
   }
   m_curr_protection = m_data.protection;
 
@@ -183,6 +213,22 @@ uint32_t MachVMRegion::GetDNBPermissions() const {
   return dnb_permissions;
 }
 
+#ifndef VM_REGION_FLAG_MTE_ENABLED
+#define VM_REGION_FLAG_MTE_ENABLED 0x4
+#endif
+std::vector<std::string> MachVMRegion::GetFlags() const {
+  std::vector<std::string> flags;
+#if VM_REGION_HAS_FLAGS
+  if (m_data.flags & VM_REGION_FLAG_JIT_ENABLED)
+    flags.push_back("jit");
+  if (m_data.flags & VM_REGION_FLAG_TPRO_ENABLED)
+    flags.push_back("tpro");
+  if (m_data.flags & VM_REGION_FLAG_MTE_ENABLED)
+    flags.push_back("mt");
+#endif
+  return flags;
+}
+
 std::vector<std::string> MachVMRegion::GetMemoryTypes() const {
   std::vector<std::string> types;
   if (m_data.user_tag == VM_MEMORY_STACK) {
diff --git a/lldb/tools/debugserver/source/MacOSX/MachVMRegion.h b/lldb/tools/debugserver/source/MacOSX/MachVMRegion.h
index cb7705893c7ed..ba6e1f3bfa70e 100644
--- a/lldb/tools/debugserver/source/MacOSX/MachVMRegion.h
+++ b/lldb/tools/debugserver/source/MacOSX/MachVMRegion.h
@@ -40,9 +40,10 @@ class MachVMRegion {
                       vm_prot_t prot);
   bool RestoreProtections();
   bool GetRegionForAddress(nub_addr_t addr);
-  std::vector<std::string> GetMemoryTypes() const;
 
   uint32_t GetDNBPermissions() const;
+  std::vector<std::string> GetFlags() const;
+  std::vector<std::string> GetMemoryTypes() const;
 
   const DNBError &GetError() { return m_err; }
 
diff --git a/lldb/tools/debugserver/source/RNBRemote.cpp b/lldb/tools/debugserver/source/RNBRemote.cpp
index d9fb22c6a1c06..be7108f633517 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...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/160952


More information about the lldb-commits mailing list