https://github.com/jasonmolenda updated 
https://github.com/llvm/llvm-project/pull/206208

>From c92511f9cb8b400d350d64b3854f72e1d602d673 Mon Sep 17 00:00:00 2001
From: Jason Molenda <[email protected]>
Date: Fri, 26 Jun 2026 16:09:22 -0700
Subject: [PATCH 01/10] [lldb] Add memory region info cache to Process

Every time a memory region is queried in the inferior with a
ProcessGDBRemote connection, lldb needs to send a packet requesting
the information.  When we are querying multiple addresses within
the same region, this can result in many redundant packets - e.g.
to test for whether an address is in stack memory during a backtrace.

This adds a MemoryRegionInfoCache wrapper around RangeDataVector
to save the memory regions that we query, and supply them to future
queries.  The cache is flushed on any process resume in the same
way that the memory cache is; the valid pages may change as a program
executes.

This PR started as a combination of this cache plus extensions to
gdb remote serial protocol packets so the debug stub can provide
memory region infos when we have a public stop (e.g. the info about
each thread's stack memory region) - including changes to both
debugserver and ProcessGDBRemote to implement that.  I'm separating
out the two pieces into separate changes.  The test in this PR
retains the full code in the .c file that I will need to test the
expedited memory region infos still, even though it doesn't do
antyhing but launch the inferior process in the current tests.

rdar://179067896
---
 .../lldb/Target/MemoryRegionInfoCache.h       | 46 ++++++++++++++++
 lldb/include/lldb/Target/Process.h            |  2 +
 lldb/source/Target/CMakeLists.txt             |  1 +
 lldb/source/Target/MemoryRegionInfoCache.cpp  | 53 +++++++++++++++++++
 lldb/source/Target/Process.cpp                | 46 +++++++++++-----
 .../TestMemoryRegionDirtyPages.py             |  4 +-
 .../cached-memory-region-info/Makefile        |  4 ++
 .../TestCachedMemoryRegionInfo.py             | 47 ++++++++++++++++
 .../cached-memory-region-info/main.cpp        | 44 +++++++++++++++
 9 files changed, 234 insertions(+), 13 deletions(-)
 create mode 100644 lldb/include/lldb/Target/MemoryRegionInfoCache.h
 create mode 100644 lldb/source/Target/MemoryRegionInfoCache.cpp
 create mode 100644 
lldb/test/API/tools/lldb-server/cached-memory-region-info/Makefile
 create mode 100644 
lldb/test/API/tools/lldb-server/cached-memory-region-info/TestCachedMemoryRegionInfo.py
 create mode 100644 
lldb/test/API/tools/lldb-server/cached-memory-region-info/main.cpp

diff --git a/lldb/include/lldb/Target/MemoryRegionInfoCache.h 
b/lldb/include/lldb/Target/MemoryRegionInfoCache.h
new file mode 100644
index 0000000000000..36f8d8490f091
--- /dev/null
+++ b/lldb/include/lldb/Target/MemoryRegionInfoCache.h
@@ -0,0 +1,46 @@
+//===-- MemoryRegionInfoCache.h ---------------------------------*- 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_TARGET_MEMORYREGIONINFOCACHE_H
+#define LLDB_TARGET_MEMORYREGIONINFOCACHE_H
+
+#include "lldb/Target/MemoryRegionInfo.h"
+#include "lldb/Utility/RangeMap.h"
+
+#include <mutex>
+#include <optional>
+
+namespace lldb_private {
+class MemoryRegionInfoCache {
+public:
+  MemoryRegionInfoCache() : m_region_infos(), m_mutex() {}
+
+  /// Remove all cached entries.  Should be called whenever
+  /// Process resumes execution of the inferior.
+  void Clear();
+
+  /// Remove cached information about region containing \p addr, if any.
+  void Erase(lldb::addr_t addr, lldb::addr_t size);
+
+  /// Return a MemoryRegionInfo that covers \p load_addr,
+  /// returns empty optional if there is no entry.
+  std::optional<MemoryRegionInfo> GetMemoryRegion(lldb::addr_t load_addr);
+
+  /// Add a MemoryRegionInfo to the collection.
+  void AddRegion(const MemoryRegionInfo &region_info);
+
+private:
+  typedef RangeDataVector<lldb::addr_t, lldb::addr_t,
+                          lldb_private::MemoryRegionInfo>
+      InfoMap;
+  InfoMap m_region_infos;
+  mutable std::recursive_mutex m_mutex;
+};
+} // namespace lldb_private
+
+#endif // LLDB_TARGET_MEMORYREGIONINFOCACHE_H
diff --git a/lldb/include/lldb/Target/Process.h 
b/lldb/include/lldb/Target/Process.h
index 8432c326d3281..aa577d80dbcce 100644
--- a/lldb/include/lldb/Target/Process.h
+++ b/lldb/include/lldb/Target/Process.h
@@ -40,6 +40,7 @@
 #include "lldb/Target/ExecutionContextScope.h"
 #include "lldb/Target/InstrumentationRuntime.h"
 #include "lldb/Target/Memory.h"
+#include "lldb/Target/MemoryRegionInfoCache.h"
 #include "lldb/Target/MemoryTagManager.h"
 #include "lldb/Target/QueueList.h"
 #include "lldb/Target/ThreadList.h"
@@ -3538,6 +3539,7 @@ void PruneThreadPlans();
   std::vector<std::string> m_profile_data;
   Predicate<uint32_t> m_iohandler_sync;
   MemoryCache m_memory_cache;
+  MemoryRegionInfoCache m_memory_region_infos_cache;
   AllocatedMemoryCache m_allocated_memory_cache;
   bool m_should_detach; /// Should we detach if the process object goes away
                         /// with an explicit call to Kill or Detach?
diff --git a/lldb/source/Target/CMakeLists.txt 
b/lldb/source/Target/CMakeLists.txt
index 704de84e25169..8e603f9a4df82 100644
--- a/lldb/source/Target/CMakeLists.txt
+++ b/lldb/source/Target/CMakeLists.txt
@@ -26,6 +26,7 @@ add_lldb_library(lldbTarget
   Memory.cpp
   MemoryHistory.cpp
   MemoryRegionInfo.cpp
+  MemoryRegionInfoCache.cpp
   MemoryTagMap.cpp
   ModuleCache.cpp
   OperatingSystem.cpp
diff --git a/lldb/source/Target/MemoryRegionInfoCache.cpp 
b/lldb/source/Target/MemoryRegionInfoCache.cpp
new file mode 100644
index 0000000000000..15a665e9cec4f
--- /dev/null
+++ b/lldb/source/Target/MemoryRegionInfoCache.cpp
@@ -0,0 +1,53 @@
+//===-- MemoryRegionInfoCache.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/Target/MemoryRegionInfoCache.h"
+#include "lldb/Core/AddressRange.h"
+#include "lldb/Target/MemoryRegionInfo.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Utility/Status.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+void MemoryRegionInfoCache::Clear() { m_region_infos.Clear(); }
+
+void MemoryRegionInfoCache::Erase(addr_t load_addr, addr_t size) {
+  std::lock_guard<std::recursive_mutex> guard(m_mutex);
+  uint32_t start_idx = m_region_infos.FindEntryIndexThatContains(load_addr);
+  uint32_t end_idx =
+      m_region_infos.FindEntryIndexThatContains(load_addr + size);
+  if (start_idx == UINT32_MAX && end_idx == UINT32_MAX)
+    return;
+
+  if (start_idx == UINT32_MAX)
+    m_region_infos.Erase(end_idx, end_idx);
+  else if (end_idx == UINT32_MAX)
+    m_region_infos.Erase(start_idx, start_idx);
+  else
+    m_region_infos.Erase(start_idx, end_idx);
+  m_region_infos.Sort();
+}
+
+std::optional<MemoryRegionInfo>
+MemoryRegionInfoCache::GetMemoryRegion(addr_t load_addr) {
+  std::lock_guard<std::recursive_mutex> guard(m_mutex);
+  uint32_t index = m_region_infos.FindEntryIndexThatContains(load_addr);
+  if (index != UINT32_MAX)
+    return m_region_infos.GetEntryAtIndex(index)->data;
+
+  return std::nullopt;
+}
+
+void MemoryRegionInfoCache::AddRegion(const MemoryRegionInfo &ri) {
+  std::lock_guard<std::recursive_mutex> guard(m_mutex);
+  InfoMap::Entry new_entry(ri.GetRange().GetRangeBase(),
+                           ri.GetRange().GetByteSize(), ri);
+  m_region_infos.Append(new_entry);
+  m_region_infos.Sort();
+}
diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp
index 6e20703f65a45..bc221205209c1 100644
--- a/lldb/source/Target/Process.cpp
+++ b/lldb/source/Target/Process.cpp
@@ -50,6 +50,7 @@
 #include "lldb/Target/LanguageRuntime.h"
 #include "lldb/Target/MemoryHistory.h"
 #include "lldb/Target/MemoryRegionInfo.h"
+#include "lldb/Target/MemoryRegionInfoCache.h"
 #include "lldb/Target/OperatingSystem.h"
 #include "lldb/Target/Platform.h"
 #include "lldb/Target/Process.h"
@@ -479,14 +480,15 @@ Process::Process(lldb::TargetSP target_sp, ListenerSP 
listener_sp,
       m_stdio_communication("process.stdio"), m_stdio_communication_mutex(),
       m_stdin_forward(false), m_stdout_data(), m_stderr_data(),
       m_profile_data_comm_mutex(), m_profile_data(), m_iohandler_sync(0),
-      m_memory_cache(*this), m_allocated_memory_cache(*this),
-      m_should_detach(false), m_next_event_action_up(),
-      m_currently_handling_do_on_removals(false), m_resume_requested(false),
-      m_interrupt_tid(LLDB_INVALID_THREAD_ID), m_finalizing(false),
-      m_destructing(false), m_clear_thread_plans_on_stop(false),
-      m_force_next_event_delivery(false), 
m_last_broadcast_state(eStateInvalid),
-      m_destroy_in_process(false), m_can_interpret_function_calls(false),
-      m_run_thread_plan_lock(), m_can_jit(eCanJITDontKnow),
+      m_memory_cache(*this), m_memory_region_infos_cache(),
+      m_allocated_memory_cache(*this), m_should_detach(false),
+      m_next_event_action_up(), m_currently_handling_do_on_removals(false),
+      m_resume_requested(false), m_interrupt_tid(LLDB_INVALID_THREAD_ID),
+      m_finalizing(false), m_destructing(false),
+      m_clear_thread_plans_on_stop(false), m_force_next_event_delivery(false),
+      m_last_broadcast_state(eStateInvalid), m_destroy_in_process(false),
+      m_can_interpret_function_calls(false), m_run_thread_plan_lock(),
+      m_can_jit(eCanJITDontKnow),
       m_crash_info_dict_sp(new StructuredData::Dictionary()) {
   CheckInWithManager();
 
@@ -595,6 +597,7 @@ void Process::Finalize(bool destructing) {
   m_notifications.swap(empty_notifications);
   m_image_tokens.clear();
   m_memory_cache.Clear();
+  m_memory_region_infos_cache.Clear();
   m_allocated_memory_cache.Clear(/*deallocate_memory=*/true);
   {
     std::lock_guard<std::recursive_mutex> guard(m_language_runtimes_mutex);
@@ -1458,6 +1461,7 @@ void Process::SetPrivateState(StateType new_state) {
       if (!m_mod_id.IsLastResumeForUserExpression())
         m_mod_id.SetStopEventForLastNaturalStopID(event_sp);
       m_memory_cache.Clear();
+      m_memory_region_infos_cache.Clear();
       LLDB_LOGF(log, "(plugin = %s, state = %s, stop_id = %u",
                GetPluginName().data(), StateAsCString(new_state),
                m_mod_id.GetStopID());
@@ -2697,7 +2701,11 @@ addr_t Process::AllocateMemory(size_t size, uint32_t 
permissions,
     return LLDB_INVALID_ADDRESS;
   }
 
-  return m_allocated_memory_cache.AllocateMemory(size, permissions, error);
+  addr_t alloced_addr =
+      m_allocated_memory_cache.AllocateMemory(size, permissions, error);
+  m_memory_region_infos_cache.Erase(alloced_addr, size);
+
+  return alloced_addr;
 }
 
 addr_t Process::CallocateMemory(size_t size, uint32_t permissions,
@@ -2750,6 +2758,7 @@ void Process::SetCanRunCode(bool can_run_code) {
 
 Status Process::DeallocateMemory(addr_t ptr) {
   Status error;
+  m_memory_region_infos_cache.Erase(ptr, 1);
   if (!m_allocated_memory_cache.DeallocateMemory(ptr)) {
     error = Status::FromErrorStringWithFormat(
         "deallocation of memory at 0x%" PRIx64 " failed.", (uint64_t)ptr);
@@ -6269,6 +6278,7 @@ void Process::DidExec() {
   m_instrumentation_runtimes.clear();
   m_thread_list.DiscardThreadPlans();
   m_memory_cache.Clear(true);
+  m_memory_region_infos_cache.Clear();
   DoDidExec();
   CompleteAttach();
   // Flush the process (threads and all stack frames) after running
@@ -6489,10 +6499,22 @@ Status Process::GetMemoryRegionInfo(lldb::addr_t 
load_addr,
                                     MemoryRegionInfo &range_info) {
   if (const lldb::ABISP &abi = GetABI())
     load_addr = abi->FixAnyAddress(load_addr);
+
+  std::optional<MemoryRegionInfo> cached_region =
+      m_memory_region_infos_cache.GetMemoryRegion(load_addr);
+  if (cached_region) {
+    range_info = *cached_region;
+    return Status();
+  }
+
   Status error = DoGetMemoryRegionInfo(load_addr, range_info);
-  // Reject a region that does not contain the requested address.
-  if (error.Success() && !range_info.GetRange().Contains(load_addr))
-    error = Status::FromErrorString("Invalid memory region");
+  if (error.Success()) {
+    // Reject a region that does not contain the requested address.
+    if (!range_info.GetRange().Contains(load_addr))
+      error = Status::FromErrorString("Invalid memory region");
+    else
+      m_memory_region_infos_cache.AddRegion(range_info);
+  }
 
   return error;
 }
diff --git 
a/lldb/test/API/functionalities/gdb_remote_client/TestMemoryRegionDirtyPages.py 
b/lldb/test/API/functionalities/gdb_remote_client/TestMemoryRegionDirtyPages.py
index 695faf896ef5d..f95f2cc257a10 100644
--- 
a/lldb/test/API/functionalities/gdb_remote_client/TestMemoryRegionDirtyPages.py
+++ 
b/lldb/test/API/functionalities/gdb_remote_client/TestMemoryRegionDirtyPages.py
@@ -19,7 +19,9 @@ def as_packet(self):
                 + ",".join([format(a, "x") for a in self.dirty_pages])
                 + ";"
             )
-        return 
f"start:{self.start_addr:x};size:{self.size};permissions:r;{dirty_pages}"
+        return (
+            
f"start:{self.start_addr:x};size:{self.size:x};permissions:r;{dirty_pages}"
+        )
 
     def expected_command_output(self):
         if self.dirty_pages is None:
diff --git a/lldb/test/API/tools/lldb-server/cached-memory-region-info/Makefile 
b/lldb/test/API/tools/lldb-server/cached-memory-region-info/Makefile
new file mode 100644
index 0000000000000..785b17c7fd698
--- /dev/null
+++ b/lldb/test/API/tools/lldb-server/cached-memory-region-info/Makefile
@@ -0,0 +1,4 @@
+CXX_SOURCES := main.cpp
+ENABLE_THREADS := YES
+include Makefile.rules
+
diff --git 
a/lldb/test/API/tools/lldb-server/cached-memory-region-info/TestCachedMemoryRegionInfo.py
 
b/lldb/test/API/tools/lldb-server/cached-memory-region-info/TestCachedMemoryRegionInfo.py
new file mode 100644
index 0000000000000..30695b32a7b45
--- /dev/null
+++ 
b/lldb/test/API/tools/lldb-server/cached-memory-region-info/TestCachedMemoryRegionInfo.py
@@ -0,0 +1,47 @@
+"""
+Test that memory region info results are cached.
+"""
+
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+@skipIfWindowsAndNoLLDBServer
+class MemoryRegionInfoPacketsCached(TestBase):
+    NO_DEBUG_INFO_TESTCASE = True
+
+    def test_cached_packets(self):
+        """Test that qMemoryRegionInfo packets are cached."""
+        logfile = os.path.join(self.getBuildDir(), "log.txt")
+        self.runCmd(f"log enable -f {logfile} gdb-remote packets")
+        self.build()
+        main_source_spec = lldb.SBFileSpec("main.cpp")
+        (
+            target,
+            process,
+            _,
+            _,
+        ) = lldbutil.run_to_source_breakpoint(
+            self, "break", main_source_spec, only_one_thread=False
+        )
+
+        frame = process.GetSelectedThread().GetFrameAtIndex(0)
+        sp = frame.GetSP()
+        pc = frame.GetPC()
+        self.runCmd("memory region 0x%x" % sp)
+        self.runCmd("memory region 0x%x" % pc)
+
+        self.runCmd(f"proc plugin packet send AFTER_MRI_CMD", check=False)
+
+        # We've fetched the memory region info for $sp, now
+        # see that we don't re-fetch it.
+        self.runCmd("memory region 0x%x" % pc)
+        self.runCmd("memory region 0x%x" % (sp + 64))
+
+        self.assertTrue(os.path.exists(logfile))
+        log_text = open(logfile).read()
+
+        log_after_cmd = log_text.split("AFTER_MRI_CMD")[1]
+        self.assertNotIn("qMemoryRegionInfo", log_after_cmd)
diff --git a/lldb/test/API/tools/lldb-server/cached-memory-region-info/main.cpp 
b/lldb/test/API/tools/lldb-server/cached-memory-region-info/main.cpp
new file mode 100644
index 0000000000000..dbbe365faec7c
--- /dev/null
+++ b/lldb/test/API/tools/lldb-server/cached-memory-region-info/main.cpp
@@ -0,0 +1,44 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <chrono>
+#include <thread>
+
+void sleep_for_a_tiny_bit() {
+  std::this_thread::sleep_for(std::chrono::seconds(1));
+}
+
+int var() {
+  // Make all the worker threads stop here, so we can do
+  // backtraces with a few stack frames on each thread.
+  std::this_thread::sleep_for(std::chrono::seconds(100));
+  return 0;
+}
+
+int baz() { return 10 + var(); }
+int bar() { return 15 + baz(); }
+int foo() { return 20 + bar(); }
+void work_primary_thread() {
+  // Allow all threads to get started, and get to their
+  // longer sleep()
+  sleep_for_a_tiny_bit();
+  foo(); // break here
+}
+void work() { foo(); }
+
+int main() {
+  std::thread thread_1(work_primary_thread);
+  std::thread thread_2(work);
+  std::thread thread_3(work);
+  std::thread thread_4(work);
+  std::thread thread_5(work);
+
+  std::this_thread::sleep_for(std::chrono::seconds(20));
+
+  thread_5.join();
+  thread_4.join();
+  thread_3.join();
+  thread_2.join();
+  thread_1.join();
+  return 0;
+}

>From 735e934436a0a0075f89c5924b9f611cfb70100b Mon Sep 17 00:00:00 2001
From: Jason Molenda <[email protected]>
Date: Fri, 26 Jun 2026 16:43:44 -0700
Subject: [PATCH 02/10] update header to follow new coding convention

---
 lldb/include/lldb/Target/MemoryRegionInfoCache.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lldb/include/lldb/Target/MemoryRegionInfoCache.h 
b/lldb/include/lldb/Target/MemoryRegionInfoCache.h
index 36f8d8490f091..42ea708fc9eff 100644
--- a/lldb/include/lldb/Target/MemoryRegionInfoCache.h
+++ b/lldb/include/lldb/Target/MemoryRegionInfoCache.h
@@ -1,4 +1,4 @@
-//===-- MemoryRegionInfoCache.h ---------------------------------*- C++ 
-*-===//
+//===----------------------------------------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.

>From 63deeae45e14fb4ff927f0b0759e0b7c1613c870 Mon Sep 17 00:00:00 2001
From: Jason Molenda <[email protected]>
Date: Mon, 29 Jun 2026 16:17:30 -0700
Subject: [PATCH 03/10] Add unit tests to exercise MemoryRegionInfoCache
 erasing

---
 .../lldb/Target/MemoryRegionInfoCache.h       |  7 +-
 lldb/source/Target/MemoryRegionInfoCache.cpp  |  8 +--
 .../unittests/Target/MemoryRegionInfoTest.cpp | 70 +++++++++++++++++++
 3 files changed, 78 insertions(+), 7 deletions(-)

diff --git a/lldb/include/lldb/Target/MemoryRegionInfoCache.h 
b/lldb/include/lldb/Target/MemoryRegionInfoCache.h
index 42ea708fc9eff..f5c3e93efad68 100644
--- a/lldb/include/lldb/Target/MemoryRegionInfoCache.h
+++ b/lldb/include/lldb/Target/MemoryRegionInfoCache.h
@@ -25,7 +25,7 @@ class MemoryRegionInfoCache {
   void Clear();
 
   /// Remove cached information about region containing \p addr, if any.
-  void Erase(lldb::addr_t addr, lldb::addr_t size);
+  void Erase(lldb::addr_t addr, size_t size);
 
   /// Return a MemoryRegionInfo that covers \p load_addr,
   /// returns empty optional if there is no entry.
@@ -34,9 +34,10 @@ class MemoryRegionInfoCache {
   /// Add a MemoryRegionInfo to the collection.
   void AddRegion(const MemoryRegionInfo &region_info);
 
+  size_t GetSize() { return m_region_infos.GetSize(); }
+
 private:
-  typedef RangeDataVector<lldb::addr_t, lldb::addr_t,
-                          lldb_private::MemoryRegionInfo>
+  typedef RangeDataVector<lldb::addr_t, size_t, lldb_private::MemoryRegionInfo>
       InfoMap;
   InfoMap m_region_infos;
   mutable std::recursive_mutex m_mutex;
diff --git a/lldb/source/Target/MemoryRegionInfoCache.cpp 
b/lldb/source/Target/MemoryRegionInfoCache.cpp
index 15a665e9cec4f..9b6493da9f25c 100644
--- a/lldb/source/Target/MemoryRegionInfoCache.cpp
+++ b/lldb/source/Target/MemoryRegionInfoCache.cpp
@@ -17,7 +17,7 @@ using namespace lldb_private;
 
 void MemoryRegionInfoCache::Clear() { m_region_infos.Clear(); }
 
-void MemoryRegionInfoCache::Erase(addr_t load_addr, addr_t size) {
+void MemoryRegionInfoCache::Erase(addr_t load_addr, size_t size) {
   std::lock_guard<std::recursive_mutex> guard(m_mutex);
   uint32_t start_idx = m_region_infos.FindEntryIndexThatContains(load_addr);
   uint32_t end_idx =
@@ -26,11 +26,11 @@ void MemoryRegionInfoCache::Erase(addr_t load_addr, addr_t 
size) {
     return;
 
   if (start_idx == UINT32_MAX)
-    m_region_infos.Erase(end_idx, end_idx);
+    m_region_infos.Erase(end_idx, end_idx + 1);
   else if (end_idx == UINT32_MAX)
-    m_region_infos.Erase(start_idx, start_idx);
+    m_region_infos.Erase(start_idx, start_idx + 1);
   else
-    m_region_infos.Erase(start_idx, end_idx);
+    m_region_infos.Erase(start_idx, end_idx + 1);
   m_region_infos.Sort();
 }
 
diff --git a/lldb/unittests/Target/MemoryRegionInfoTest.cpp 
b/lldb/unittests/Target/MemoryRegionInfoTest.cpp
index 959984afaa9ad..8d43a8a0549d9 100644
--- a/lldb/unittests/Target/MemoryRegionInfoTest.cpp
+++ b/lldb/unittests/Target/MemoryRegionInfoTest.cpp
@@ -7,6 +7,8 @@
 
//===----------------------------------------------------------------------===//
 
 #include "lldb/Target/MemoryRegionInfo.h"
+#include "lldb/Target/MemoryRegionInfoCache.h"
+#include "lldb/Utility/RangeMap.h"
 #include "llvm/Support/FormatVariadic.h"
 #include "gtest/gtest.h"
 
@@ -17,3 +19,71 @@ TEST(MemoryRegionInfoTest, Formatv) {
   EXPECT_EQ("no", llvm::formatv("{0}", eLazyBoolNo).str());
   EXPECT_EQ("don't know", llvm::formatv("{0}", eLazyBoolDontKnow).str());
 }
+
+TEST(MemoryRegionInfoTest, CacheErasing) {
+  MemoryRegionInfoCache cache;
+  cache.AddRegion(MemoryRegionInfo({0x1000, 0x100}, eLazyBoolYes, eLazyBoolYes,
+                                   eLazyBoolYes, eLazyBoolNo, eLazyBoolNo,
+                                   ConstString("First entry")));
+  cache.AddRegion(MemoryRegionInfo({0x2000, 0x100}, eLazyBoolYes, eLazyBoolYes,
+                                   eLazyBoolYes, eLazyBoolNo, eLazyBoolNo,
+                                   ConstString("Second entry")));
+  cache.AddRegion(MemoryRegionInfo({0x2100, 0x100}, eLazyBoolYes, eLazyBoolYes,
+                                   eLazyBoolYes, eLazyBoolNo, eLazyBoolNo,
+                                   ConstString("Third entry")));
+  cache.AddRegion(MemoryRegionInfo({0x2200, 0x100}, eLazyBoolYes, eLazyBoolYes,
+                                   eLazyBoolYes, eLazyBoolNo, eLazyBoolNo,
+                                   ConstString("Fourth entry")));
+  cache.AddRegion(MemoryRegionInfo({0x2300, 0x100}, eLazyBoolYes, eLazyBoolYes,
+                                   eLazyBoolYes, eLazyBoolNo, eLazyBoolNo,
+                                   ConstString("Fifth entry")));
+  cache.AddRegion(MemoryRegionInfo({0x5000, 0x100}, eLazyBoolYes, eLazyBoolYes,
+                                   eLazyBoolYes, eLazyBoolNo, eLazyBoolNo,
+                                   ConstString("Sixth entry")));
+  cache.AddRegion(MemoryRegionInfo({0x6000, 0x100}, eLazyBoolYes, eLazyBoolYes,
+                                   eLazyBoolYes, eLazyBoolNo, eLazyBoolNo,
+                                   ConstString("Seventh entry")));
+
+  std::optional<MemoryRegionInfo> ri = cache.GetMemoryRegion(0x6000);
+  ASSERT_TRUE(ri);
+
+  // Erase the last entry.
+  ASSERT_EQ(cache.GetSize(), 7U);
+  cache.Erase(0x6000, 1);
+  ASSERT_EQ(cache.GetSize(), 6U);
+  std::optional<MemoryRegionInfo> erased_ri = cache.GetMemoryRegion(0x6000);
+  ASSERT_FALSE(erased_ri);
+  cache.Erase(0x6000, 1); // no-op
+  ASSERT_EQ(cache.GetSize(), 6U);
+
+  // Erase the last entry & beyond.
+  cache.Erase(0x5000, 0x5000000);
+  ASSERT_EQ(cache.GetSize(), 5U);
+  erased_ri = cache.GetMemoryRegion(0x5000);
+  ASSERT_FALSE(erased_ri);
+
+  // Erase from before the first entry, through the first entry.
+  cache.Erase(0x500, 0xb01);
+  ASSERT_EQ(cache.GetSize(), 4U);
+  erased_ri = cache.GetMemoryRegion(0x1000);
+  ASSERT_FALSE(erased_ri);
+
+  // Erase the second and third entries.
+  cache.Erase(0x2000, 0x101);
+  ASSERT_EQ(cache.GetSize(), 2U);
+  erased_ri = cache.GetMemoryRegion(0x2000);
+  ASSERT_FALSE(erased_ri);
+  erased_ri = cache.GetMemoryRegion(0x2100);
+  ASSERT_FALSE(erased_ri);
+
+  ri = cache.GetMemoryRegion(0x2200); // Fourth entry still available.
+  ASSERT_TRUE(ri);
+  ri = cache.GetMemoryRegion(0x2300); // Fifth entry still available.
+  ASSERT_TRUE(ri);
+
+  // Erase some entries that don't exist.
+  cache.Erase(0x2000, 0x101);
+  ASSERT_EQ(cache.GetSize(), 2U);
+  cache.Erase(0x2400, 1);
+  ASSERT_EQ(cache.GetSize(), 2U);
+}

>From 547772bbf775f18ca3e0d9c4432bb00371ab678c Mon Sep 17 00:00:00 2001
From: Jason Molenda <[email protected]>
Date: Mon, 29 Jun 2026 16:58:57 -0700
Subject: [PATCH 04/10] Guard against overflow in Erase method, add test.

---
 lldb/source/Target/MemoryRegionInfoCache.cpp   |  7 +++++++
 lldb/unittests/Target/MemoryRegionInfoTest.cpp | 10 ++++++++++
 2 files changed, 17 insertions(+)

diff --git a/lldb/source/Target/MemoryRegionInfoCache.cpp 
b/lldb/source/Target/MemoryRegionInfoCache.cpp
index 9b6493da9f25c..3a3dee8bfe279 100644
--- a/lldb/source/Target/MemoryRegionInfoCache.cpp
+++ b/lldb/source/Target/MemoryRegionInfoCache.cpp
@@ -19,6 +19,13 @@ void MemoryRegionInfoCache::Clear() { 
m_region_infos.Clear(); }
 
 void MemoryRegionInfoCache::Erase(addr_t load_addr, size_t size) {
   std::lock_guard<std::recursive_mutex> guard(m_mutex);
+
+  // If load_addr+size would overflow, do nothing.
+  // Likely this is an LLDB_INVALID_ADDRESS plus something.
+  uint64_t max_minus_addr = std::numeric_limits<addr_t>::max() - load_addr;
+  if (size > max_minus_addr)
+    return;
+
   uint32_t start_idx = m_region_infos.FindEntryIndexThatContains(load_addr);
   uint32_t end_idx =
       m_region_infos.FindEntryIndexThatContains(load_addr + size);
diff --git a/lldb/unittests/Target/MemoryRegionInfoTest.cpp 
b/lldb/unittests/Target/MemoryRegionInfoTest.cpp
index 8d43a8a0549d9..98a77b9334997 100644
--- a/lldb/unittests/Target/MemoryRegionInfoTest.cpp
+++ b/lldb/unittests/Target/MemoryRegionInfoTest.cpp
@@ -86,4 +86,14 @@ TEST(MemoryRegionInfoTest, CacheErasing) {
   ASSERT_EQ(cache.GetSize(), 2U);
   cache.Erase(0x2400, 1);
   ASSERT_EQ(cache.GetSize(), 2U);
+
+  cache.AddRegion(MemoryRegionInfo({0x0, 0x1000}, eLazyBoolYes, eLazyBoolYes,
+                                   eLazyBoolYes, eLazyBoolNo, eLazyBoolNo,
+                                   ConstString("Zeroth entry")));
+
+  // Do an Erase that overflows, confirm entry at 0 is not erased.
+  cache.Erase(LLDB_INVALID_ADDRESS, 1);
+  ASSERT_EQ(cache.GetSize(), 3U);
+  ri = cache.GetMemoryRegion(0x0);
+  ASSERT_TRUE(ri);
 }

>From 9b1818131e98eaf4d512793f68d1d48db9c8c8d4 Mon Sep 17 00:00:00 2001
From: Jason Molenda <[email protected]>
Date: Mon, 29 Jun 2026 17:09:51 -0700
Subject: [PATCH 05/10] Rename Erase to EraseRange and EraseContaining, for
 either a range of VM addresses or for an entry containing a single address.

---
 lldb/include/lldb/Target/MemoryRegionInfoCache.h |  6 +++++-
 lldb/source/Target/MemoryRegionInfoCache.cpp     |  6 +++++-
 lldb/source/Target/Process.cpp                   |  4 ++--
 lldb/unittests/Target/MemoryRegionInfoTest.cpp   | 16 ++++++++--------
 4 files changed, 20 insertions(+), 12 deletions(-)

diff --git a/lldb/include/lldb/Target/MemoryRegionInfoCache.h 
b/lldb/include/lldb/Target/MemoryRegionInfoCache.h
index f5c3e93efad68..86268ec67ceb4 100644
--- a/lldb/include/lldb/Target/MemoryRegionInfoCache.h
+++ b/lldb/include/lldb/Target/MemoryRegionInfoCache.h
@@ -24,8 +24,12 @@ class MemoryRegionInfoCache {
   /// Process resumes execution of the inferior.
   void Clear();
 
+  /// Remove cached information about region(s) containing \p addr
+  /// through \p addr + \p size, if any.
+  void EraseRange(lldb::addr_t addr, size_t size);
+
   /// Remove cached information about region containing \p addr, if any.
-  void Erase(lldb::addr_t addr, size_t size);
+  void EraseContaining(lldb::addr_t addr);
 
   /// Return a MemoryRegionInfo that covers \p load_addr,
   /// returns empty optional if there is no entry.
diff --git a/lldb/source/Target/MemoryRegionInfoCache.cpp 
b/lldb/source/Target/MemoryRegionInfoCache.cpp
index 3a3dee8bfe279..7b8b70c591156 100644
--- a/lldb/source/Target/MemoryRegionInfoCache.cpp
+++ b/lldb/source/Target/MemoryRegionInfoCache.cpp
@@ -17,7 +17,7 @@ using namespace lldb_private;
 
 void MemoryRegionInfoCache::Clear() { m_region_infos.Clear(); }
 
-void MemoryRegionInfoCache::Erase(addr_t load_addr, size_t size) {
+void MemoryRegionInfoCache::EraseRange(addr_t load_addr, size_t size) {
   std::lock_guard<std::recursive_mutex> guard(m_mutex);
 
   // If load_addr+size would overflow, do nothing.
@@ -41,6 +41,10 @@ void MemoryRegionInfoCache::Erase(addr_t load_addr, size_t 
size) {
   m_region_infos.Sort();
 }
 
+void MemoryRegionInfoCache::EraseContaining(addr_t load_addr) {
+  EraseRange(load_addr, 1);
+}
+
 std::optional<MemoryRegionInfo>
 MemoryRegionInfoCache::GetMemoryRegion(addr_t load_addr) {
   std::lock_guard<std::recursive_mutex> guard(m_mutex);
diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp
index bc221205209c1..959b501d87ef1 100644
--- a/lldb/source/Target/Process.cpp
+++ b/lldb/source/Target/Process.cpp
@@ -2703,7 +2703,7 @@ addr_t Process::AllocateMemory(size_t size, uint32_t 
permissions,
 
   addr_t alloced_addr =
       m_allocated_memory_cache.AllocateMemory(size, permissions, error);
-  m_memory_region_infos_cache.Erase(alloced_addr, size);
+  m_memory_region_infos_cache.EraseRange(alloced_addr, size);
 
   return alloced_addr;
 }
@@ -2758,7 +2758,7 @@ void Process::SetCanRunCode(bool can_run_code) {
 
 Status Process::DeallocateMemory(addr_t ptr) {
   Status error;
-  m_memory_region_infos_cache.Erase(ptr, 1);
+  m_memory_region_infos_cache.EraseContaining(ptr);
   if (!m_allocated_memory_cache.DeallocateMemory(ptr)) {
     error = Status::FromErrorStringWithFormat(
         "deallocation of memory at 0x%" PRIx64 " failed.", (uint64_t)ptr);
diff --git a/lldb/unittests/Target/MemoryRegionInfoTest.cpp 
b/lldb/unittests/Target/MemoryRegionInfoTest.cpp
index 98a77b9334997..f15bdd08d3943 100644
--- a/lldb/unittests/Target/MemoryRegionInfoTest.cpp
+++ b/lldb/unittests/Target/MemoryRegionInfoTest.cpp
@@ -49,27 +49,27 @@ TEST(MemoryRegionInfoTest, CacheErasing) {
 
   // Erase the last entry.
   ASSERT_EQ(cache.GetSize(), 7U);
-  cache.Erase(0x6000, 1);
+  cache.EraseContaining(0x6000);
   ASSERT_EQ(cache.GetSize(), 6U);
   std::optional<MemoryRegionInfo> erased_ri = cache.GetMemoryRegion(0x6000);
   ASSERT_FALSE(erased_ri);
-  cache.Erase(0x6000, 1); // no-op
+  cache.EraseContaining(0x6000); // no-op
   ASSERT_EQ(cache.GetSize(), 6U);
 
   // Erase the last entry & beyond.
-  cache.Erase(0x5000, 0x5000000);
+  cache.EraseRange(0x5000, 0x5000000);
   ASSERT_EQ(cache.GetSize(), 5U);
   erased_ri = cache.GetMemoryRegion(0x5000);
   ASSERT_FALSE(erased_ri);
 
   // Erase from before the first entry, through the first entry.
-  cache.Erase(0x500, 0xb01);
+  cache.EraseRange(0x500, 0xb01);
   ASSERT_EQ(cache.GetSize(), 4U);
   erased_ri = cache.GetMemoryRegion(0x1000);
   ASSERT_FALSE(erased_ri);
 
   // Erase the second and third entries.
-  cache.Erase(0x2000, 0x101);
+  cache.EraseRange(0x2000, 0x101);
   ASSERT_EQ(cache.GetSize(), 2U);
   erased_ri = cache.GetMemoryRegion(0x2000);
   ASSERT_FALSE(erased_ri);
@@ -82,9 +82,9 @@ TEST(MemoryRegionInfoTest, CacheErasing) {
   ASSERT_TRUE(ri);
 
   // Erase some entries that don't exist.
-  cache.Erase(0x2000, 0x101);
+  cache.EraseRange(0x2000, 0x101);
   ASSERT_EQ(cache.GetSize(), 2U);
-  cache.Erase(0x2400, 1);
+  cache.EraseContaining(0x2400);
   ASSERT_EQ(cache.GetSize(), 2U);
 
   cache.AddRegion(MemoryRegionInfo({0x0, 0x1000}, eLazyBoolYes, eLazyBoolYes,
@@ -92,7 +92,7 @@ TEST(MemoryRegionInfoTest, CacheErasing) {
                                    ConstString("Zeroth entry")));
 
   // Do an Erase that overflows, confirm entry at 0 is not erased.
-  cache.Erase(LLDB_INVALID_ADDRESS, 1);
+  cache.EraseContaining(LLDB_INVALID_ADDRESS);
   ASSERT_EQ(cache.GetSize(), 3U);
   ri = cache.GetMemoryRegion(0x0);
   ASSERT_TRUE(ri);

>From cabd7ead89087732d07957dfca879a1ac98a9972 Mon Sep 17 00:00:00 2001
From: Jason Molenda <[email protected]>
Date: Mon, 29 Jun 2026 17:10:36 -0700
Subject: [PATCH 06/10] Update lldb/source/Target/MemoryRegionInfoCache.cpp

Co-authored-by: Jonas Devlieghere <[email protected]>
---
 lldb/source/Target/MemoryRegionInfoCache.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lldb/source/Target/MemoryRegionInfoCache.cpp 
b/lldb/source/Target/MemoryRegionInfoCache.cpp
index 7b8b70c591156..40256b63c6cb6 100644
--- a/lldb/source/Target/MemoryRegionInfoCache.cpp
+++ b/lldb/source/Target/MemoryRegionInfoCache.cpp
@@ -1,4 +1,4 @@
-//===-- MemoryRegionInfoCache.cpp 
-----------------------------------------===//
+//===----------------------------------------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.

>From a217544e71d6f74d4a6d9ecd56209330e8259eae Mon Sep 17 00:00:00 2001
From: Jason Molenda <[email protected]>
Date: Mon, 29 Jun 2026 17:11:58 -0700
Subject: [PATCH 07/10] acquire lock in Clear method.

---
 lldb/source/Target/MemoryRegionInfoCache.cpp | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/lldb/source/Target/MemoryRegionInfoCache.cpp 
b/lldb/source/Target/MemoryRegionInfoCache.cpp
index 40256b63c6cb6..a283f3fb5e61e 100644
--- a/lldb/source/Target/MemoryRegionInfoCache.cpp
+++ b/lldb/source/Target/MemoryRegionInfoCache.cpp
@@ -15,7 +15,10 @@
 using namespace lldb;
 using namespace lldb_private;
 
-void MemoryRegionInfoCache::Clear() { m_region_infos.Clear(); }
+void MemoryRegionInfoCache::Clear() { 
+  std::lock_guard<std::recursive_mutex> guard(m_mutex);
+  m_region_infos.Clear(); 
+}
 
 void MemoryRegionInfoCache::EraseRange(addr_t load_addr, size_t size) {
   std::lock_guard<std::recursive_mutex> guard(m_mutex);

>From 4c1cf1811972bca62afeff3b84898da52c769cfc Mon Sep 17 00:00:00 2001
From: Jason Molenda <[email protected]>
Date: Mon, 29 Jun 2026 17:34:31 -0700
Subject: [PATCH 08/10] Delay sorting entries until we search in the index.

---
 lldb/include/lldb/Target/MemoryRegionInfoCache.h |  3 ++-
 lldb/source/Target/MemoryRegionInfoCache.cpp     | 13 ++++++++++---
 2 files changed, 12 insertions(+), 4 deletions(-)

diff --git a/lldb/include/lldb/Target/MemoryRegionInfoCache.h 
b/lldb/include/lldb/Target/MemoryRegionInfoCache.h
index 86268ec67ceb4..e5bf66e96cb91 100644
--- a/lldb/include/lldb/Target/MemoryRegionInfoCache.h
+++ b/lldb/include/lldb/Target/MemoryRegionInfoCache.h
@@ -18,7 +18,7 @@
 namespace lldb_private {
 class MemoryRegionInfoCache {
 public:
-  MemoryRegionInfoCache() : m_region_infos(), m_mutex() {}
+  MemoryRegionInfoCache() : m_region_infos(), m_is_sorted(true), m_mutex() {}
 
   /// Remove all cached entries.  Should be called whenever
   /// Process resumes execution of the inferior.
@@ -44,6 +44,7 @@ class MemoryRegionInfoCache {
   typedef RangeDataVector<lldb::addr_t, size_t, lldb_private::MemoryRegionInfo>
       InfoMap;
   InfoMap m_region_infos;
+  bool m_is_sorted;
   mutable std::recursive_mutex m_mutex;
 };
 } // namespace lldb_private
diff --git a/lldb/source/Target/MemoryRegionInfoCache.cpp 
b/lldb/source/Target/MemoryRegionInfoCache.cpp
index a283f3fb5e61e..ac11df180a045 100644
--- a/lldb/source/Target/MemoryRegionInfoCache.cpp
+++ b/lldb/source/Target/MemoryRegionInfoCache.cpp
@@ -17,7 +17,8 @@ using namespace lldb_private;
 
 void MemoryRegionInfoCache::Clear() { 
   std::lock_guard<std::recursive_mutex> guard(m_mutex);
-  m_region_infos.Clear(); 
+  m_region_infos.Clear();
+  m_is_sorted = true;
 }
 
 void MemoryRegionInfoCache::EraseRange(addr_t load_addr, size_t size) {
@@ -29,6 +30,8 @@ void MemoryRegionInfoCache::EraseRange(addr_t load_addr, 
size_t size) {
   if (size > max_minus_addr)
     return;
 
+  if (!m_is_sorted)
+    m_region_infos.Sort();
   uint32_t start_idx = m_region_infos.FindEntryIndexThatContains(load_addr);
   uint32_t end_idx =
       m_region_infos.FindEntryIndexThatContains(load_addr + size);
@@ -41,7 +44,7 @@ void MemoryRegionInfoCache::EraseRange(addr_t load_addr, 
size_t size) {
     m_region_infos.Erase(start_idx, start_idx + 1);
   else
     m_region_infos.Erase(start_idx, end_idx + 1);
-  m_region_infos.Sort();
+  m_is_sorted = false;
 }
 
 void MemoryRegionInfoCache::EraseContaining(addr_t load_addr) {
@@ -51,6 +54,10 @@ void MemoryRegionInfoCache::EraseContaining(addr_t 
load_addr) {
 std::optional<MemoryRegionInfo>
 MemoryRegionInfoCache::GetMemoryRegion(addr_t load_addr) {
   std::lock_guard<std::recursive_mutex> guard(m_mutex);
+  if (!m_is_sorted) {
+    m_region_infos.Sort();
+    m_is_sorted = true;
+  }
   uint32_t index = m_region_infos.FindEntryIndexThatContains(load_addr);
   if (index != UINT32_MAX)
     return m_region_infos.GetEntryAtIndex(index)->data;
@@ -63,5 +70,5 @@ void MemoryRegionInfoCache::AddRegion(const MemoryRegionInfo 
&ri) {
   InfoMap::Entry new_entry(ri.GetRange().GetRangeBase(),
                            ri.GetRange().GetByteSize(), ri);
   m_region_infos.Append(new_entry);
-  m_region_infos.Sort();
+  m_is_sorted = false;
 }

>From 9a93d9364cad7c3c75000c9411a9de7cb00e2056 Mon Sep 17 00:00:00 2001
From: Jason Molenda <[email protected]>
Date: Mon, 29 Jun 2026 17:38:39 -0700
Subject: [PATCH 09/10] Remove unneeded includes, whitespace fix

---
 lldb/source/Target/MemoryRegionInfoCache.cpp | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/lldb/source/Target/MemoryRegionInfoCache.cpp 
b/lldb/source/Target/MemoryRegionInfoCache.cpp
index ac11df180a045..86977224406c6 100644
--- a/lldb/source/Target/MemoryRegionInfoCache.cpp
+++ b/lldb/source/Target/MemoryRegionInfoCache.cpp
@@ -7,15 +7,12 @@
 
//===----------------------------------------------------------------------===//
 
 #include "lldb/Target/MemoryRegionInfoCache.h"
-#include "lldb/Core/AddressRange.h"
 #include "lldb/Target/MemoryRegionInfo.h"
-#include "lldb/Target/Process.h"
-#include "lldb/Utility/Status.h"
 
 using namespace lldb;
 using namespace lldb_private;
 
-void MemoryRegionInfoCache::Clear() { 
+void MemoryRegionInfoCache::Clear() {
   std::lock_guard<std::recursive_mutex> guard(m_mutex);
   m_region_infos.Clear();
   m_is_sorted = true;

>From 8d3b8152db32d3bb6b7515d47687cc44ac529401 Mon Sep 17 00:00:00 2001
From: Jason Molenda <[email protected]>
Date: Mon, 29 Jun 2026 17:47:59 -0700
Subject: [PATCH 10/10] fix off by one error with the end of the VM range to
 erase; add unit test.

---
 lldb/source/Target/MemoryRegionInfoCache.cpp   | 2 +-
 lldb/unittests/Target/MemoryRegionInfoTest.cpp | 7 +++++++
 2 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/lldb/source/Target/MemoryRegionInfoCache.cpp 
b/lldb/source/Target/MemoryRegionInfoCache.cpp
index 86977224406c6..c90a4c18b133b 100644
--- a/lldb/source/Target/MemoryRegionInfoCache.cpp
+++ b/lldb/source/Target/MemoryRegionInfoCache.cpp
@@ -31,7 +31,7 @@ void MemoryRegionInfoCache::EraseRange(addr_t load_addr, 
size_t size) {
     m_region_infos.Sort();
   uint32_t start_idx = m_region_infos.FindEntryIndexThatContains(load_addr);
   uint32_t end_idx =
-      m_region_infos.FindEntryIndexThatContains(load_addr + size);
+      m_region_infos.FindEntryIndexThatContains(load_addr + size - 1);
   if (start_idx == UINT32_MAX && end_idx == UINT32_MAX)
     return;
 
diff --git a/lldb/unittests/Target/MemoryRegionInfoTest.cpp 
b/lldb/unittests/Target/MemoryRegionInfoTest.cpp
index f15bdd08d3943..cffde7df6aed4 100644
--- a/lldb/unittests/Target/MemoryRegionInfoTest.cpp
+++ b/lldb/unittests/Target/MemoryRegionInfoTest.cpp
@@ -96,4 +96,11 @@ TEST(MemoryRegionInfoTest, CacheErasing) {
   ASSERT_EQ(cache.GetSize(), 3U);
   ri = cache.GetMemoryRegion(0x0);
   ASSERT_TRUE(ri);
+
+  // Erase fourth entry, with a size just before the fifth entry.
+  // Fifth entry should not be erased.
+  cache.EraseRange(0x2200, 0x100);
+  ASSERT_EQ(cache.GetSize(), 2U);
+  ri = cache.GetMemoryRegion(0x2300);
+  ASSERT_TRUE(ri);
 }

_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to