https://github.com/igorkudrin updated 
https://github.com/llvm/llvm-project/pull/176099

>From 69a7a99ac530de807877954a3dbcf0c636fc443e Mon Sep 17 00:00:00 2001
From: Igor Kudrin <[email protected]>
Date: Wed, 14 Jan 2026 22:19:01 -0800
Subject: [PATCH 1/7] [lldb] Fix setting CanJIT if memory cannot be allocated

When a server is unable to allocate memory for the `_M` packet, it may
respond with an error code. In this case,
`GDBRemoteCommunicationClient::AllocateMemory()` sets
`m_supports_alloc_dealloc_memory` to `eLazyBoolYes`; `eLazyBoolNo` is
only used if the server cannot handle the packet at all. Before this
patch, `ProcessGDBRemote::DoAllocateMemory()` checked this flag and
returned `LLDB_INVALID_ADDRESS` without setting an error, which caused
`Process::CanJIT()` to set `m_can_jit = eCanJITYes`, resulting in
`IRMemoryMap::FindSpace()` attempting to allocate memory in the inferior
process and failing. With the patch,
`ProcessGDBRemote::DoAllocateMemory()` returns an error and `m_can_jit`
is set to `eCanJITNo`.

Example debug session:
```
(lldb) platform connect...
(lldb) file test
(lldb) br set...
(lldb) run
Process 100 launched:...
Process 100 stopped
* thread #1,...
(lldb) expr $x0
error: Couldn't allocate space for materialized struct: Couldn't malloc: 
address space is full
error: errored out in virtual lldb_private::LLVMUserExpression::DoExecute, 
couldn't PrepareToExecuteJITExpression
```
---
 .../Python/lldbsuite/test/lldbgdbclient.py    |  7 ++-
 .../Process/gdb-remote/ProcessGDBRemote.cpp   |  6 +--
 .../gdb_remote_client/TestExprNoAlloc.py      | 44 +++++++++++++++++++
 3 files changed, 52 insertions(+), 5 deletions(-)
 create mode 100644 
lldb/test/API/functionalities/gdb_remote_client/TestExprNoAlloc.py

diff --git a/lldb/packages/Python/lldbsuite/test/lldbgdbclient.py 
b/lldb/packages/Python/lldbsuite/test/lldbgdbclient.py
index 9b2a89e934132..6c68254d42628 100644
--- a/lldb/packages/Python/lldbsuite/test/lldbgdbclient.py
+++ b/lldb/packages/Python/lldbsuite/test/lldbgdbclient.py
@@ -32,7 +32,7 @@ def tearDown(self):
         self.server.stop()
         TestBase.tearDown(self)
 
-    def createTarget(self, yaml_path):
+    def createTarget(self, yaml_path, triple=""):
         """
         Create a target by auto-generating the object based on the given yaml
         instructions.
@@ -43,7 +43,10 @@ def createTarget(self, yaml_path):
         yaml_base, ext = os.path.splitext(yaml_path)
         obj_path = self.getBuildArtifact(yaml_base)
         self.yaml2obj(yaml_path, obj_path)
-        return self.dbg.CreateTarget(obj_path)
+        if triple:
+            return self.dbg.CreateTargetWithFileAndTargetTriple(obj_path, 
triple)
+        else:
+            return self.dbg.CreateTarget(obj_path)
 
     def connect(self, target, plugin="gdb-remote"):
         """
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp 
b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index 80a8f441da12e..445ce820030d3 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -3170,9 +3170,9 @@ lldb::addr_t ProcessGDBRemote::DoAllocateMemory(size_t 
size,
 
   if (m_gdb_comm.SupportsAllocDeallocMemory() != eLazyBoolNo) {
     allocated_addr = m_gdb_comm.AllocateMemory(size, permissions);
-    if (allocated_addr != LLDB_INVALID_ADDRESS ||
-        m_gdb_comm.SupportsAllocDeallocMemory() == eLazyBoolYes)
-      return allocated_addr;
+    assert((allocated_addr == LLDB_INVALID_ADDRESS ||
+            m_gdb_comm.SupportsAllocDeallocMemory() == eLazyBoolYes) &&
+           "Memory can only be allocated if the support is enabled");
   }
 
   if (m_gdb_comm.SupportsAllocDeallocMemory() == eLazyBoolNo) {
diff --git a/lldb/test/API/functionalities/gdb_remote_client/TestExprNoAlloc.py 
b/lldb/test/API/functionalities/gdb_remote_client/TestExprNoAlloc.py
new file mode 100644
index 0000000000000..3a77ceed32b57
--- /dev/null
+++ b/lldb/test/API/functionalities/gdb_remote_client/TestExprNoAlloc.py
@@ -0,0 +1,44 @@
+from textwrap import dedent
+import lldb
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test.decorators import *
+from lldbsuite.test.gdbclientutils import *
+from lldbsuite.test.lldbgdbclient import GDBRemoteTestBase
+
+
+class MyResponder(MockGDBServerResponder):
+    def other(self, packet) -> str:
+        if packet.startswith("_M"):
+            return "E04"
+        else:
+            return super().other(packet)
+
+    def readRegister(self, regnum):
+        return "E01"
+
+    def readRegisters(self):
+        return 
"20000000000000002000000000000000f0c154bfffff00005daa985a8fea0b48f0b954bfffff0000ad13cce570150b48380000000000000070456abfffff0000a700000000000000000000000000000001010101010101010000000000000000f0c154bfffff00000f2700000000000008e355bfffff0000080e55bfffff0000281041000000000010de61bfffff00005c05000000000000f0c154bfffff000090fcffffffff00008efcffffffff00008ffcffffffff00000000000000000000001000000000000090fcffffffff000000d06cbfffff0000f0c154bfffff00000100000000000000d0b954bfffff0000e407400000000000d0b954bfffff0000e40740000000000000100000"
+
+
+class TestExprNoAlloc(GDBRemoteTestBase):
+    @skipIfRemote
+    @skipIfLLVMTargetMissing("AArch64")
+    def test(self):
+        """
+        Test that a simple expression can be evaluated when the server 
supports the '_M'
+        packet, but memory cannot be allocated, and it returns an error code 
response.
+        In this case, 'CanJIT' used to be set to 'eCanJITYes', so 
'IRMemoryMap' tried to
+        allocated memory in the inferior process and failed.
+        """
+
+        self.server.responder = MyResponder()
+        # Note: DynamicLoaderStatic disables JIT by calling 
'm_process->SetCanJIT(false)'
+        # in LoadAllImagesAtFileAddresses(). Specifying a triple with "-linux" 
enables
+        # DynamicLoaderPOSIXDYLD to be used instead.
+        self.target = self.createTarget("basic_eh_frame-aarch64.yaml", 
"aarch64-linux")
+        process = self.connect(self.target)
+        lldbutil.expect_state_changes(
+            self, self.dbg.GetListener(), process, [lldb.eStateStopped]
+        )
+
+        self.expect_expr("$x1", result_type="unsigned long", result_value="32")

>From 40b49a3f02aaecf98eed3e2a9b10712833920a6c Mon Sep 17 00:00:00 2001
From: Igor Kudrin <[email protected]>
Date: Thu, 15 Jan 2026 13:56:08 -0800
Subject: [PATCH 2/7] fixup! simplify GDBRemoteTestBase.createTarget()

---
 lldb/packages/Python/lldbsuite/test/lldbgdbclient.py | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/lldb/packages/Python/lldbsuite/test/lldbgdbclient.py 
b/lldb/packages/Python/lldbsuite/test/lldbgdbclient.py
index 6c68254d42628..6a56f57964b93 100644
--- a/lldb/packages/Python/lldbsuite/test/lldbgdbclient.py
+++ b/lldb/packages/Python/lldbsuite/test/lldbgdbclient.py
@@ -43,10 +43,7 @@ def createTarget(self, yaml_path, triple=""):
         yaml_base, ext = os.path.splitext(yaml_path)
         obj_path = self.getBuildArtifact(yaml_base)
         self.yaml2obj(yaml_path, obj_path)
-        if triple:
-            return self.dbg.CreateTargetWithFileAndTargetTriple(obj_path, 
triple)
-        else:
-            return self.dbg.CreateTarget(obj_path)
+        return self.dbg.CreateTargetWithFileAndTargetTriple(obj_path, triple)
 
     def connect(self, target, plugin="gdb-remote"):
         """

>From 7b1f907208ad192804d569894653685fb0949d4d Mon Sep 17 00:00:00 2001
From: Igor Kudrin <[email protected]>
Date: Thu, 15 Jan 2026 21:55:30 -0800
Subject: [PATCH 3/7] fixup! remove redundant import

---
 .../API/functionalities/gdb_remote_client/TestExprNoAlloc.py     | 1 -
 1 file changed, 1 deletion(-)

diff --git a/lldb/test/API/functionalities/gdb_remote_client/TestExprNoAlloc.py 
b/lldb/test/API/functionalities/gdb_remote_client/TestExprNoAlloc.py
index 3a77ceed32b57..ead7fdea2799c 100644
--- a/lldb/test/API/functionalities/gdb_remote_client/TestExprNoAlloc.py
+++ b/lldb/test/API/functionalities/gdb_remote_client/TestExprNoAlloc.py
@@ -1,4 +1,3 @@
-from textwrap import dedent
 import lldb
 from lldbsuite.test.lldbtest import *
 from lldbsuite.test.decorators import *

>From ca23b8634c7cf87baafae05738202a21f1121476 Mon Sep 17 00:00:00 2001
From: Igor Kudrin <[email protected]>
Date: Thu, 15 Jan 2026 21:59:10 -0800
Subject: [PATCH 4/7] fixup! add handlers for '_M' and '_m' to
 MockGDBServerResponder

---
 .../Python/lldbsuite/test/gdbclientutils.py         | 13 +++++++++++++
 .../gdb_remote_client/TestExprNoAlloc.py            |  7 ++-----
 2 files changed, 15 insertions(+), 5 deletions(-)

diff --git a/lldb/packages/Python/lldbsuite/test/gdbclientutils.py 
b/lldb/packages/Python/lldbsuite/test/gdbclientutils.py
index 4c40299f3256d..ed8ea7c981c2c 100644
--- a/lldb/packages/Python/lldbsuite/test/gdbclientutils.py
+++ b/lldb/packages/Python/lldbsuite/test/gdbclientutils.py
@@ -261,6 +261,13 @@ def _respond_impl(self, packet) -> Union[Response, 
List[Response]]:
             return self.qRegisterInfo(regnum)
         if packet == "k":
             return self.k()
+        if packet[0:2] == "_M":
+            size_str, permissions = packet[2:].split(",")
+            size = int(size_str, 16)
+            return self._M(size, permissions)
+        if packet[0:2] == "_m":
+            addr = int(packet[2:], 16)
+            return self._m(addr)
 
         return self.other(packet)
 
@@ -409,6 +416,12 @@ def qRegisterInfo(self, num) -> str:
     def k(self):
         return ["W01", self.RESPONSE_DISCONNECT]
 
+    def _M(self, size, permissions):
+        return ""
+
+    def _m(self, addr):
+        return ""
+
     """
     Raised when we receive a packet for which there is no default action.
     Override the responder class to implement behavior suitable for the test at
diff --git a/lldb/test/API/functionalities/gdb_remote_client/TestExprNoAlloc.py 
b/lldb/test/API/functionalities/gdb_remote_client/TestExprNoAlloc.py
index ead7fdea2799c..aaeb96291411d 100644
--- a/lldb/test/API/functionalities/gdb_remote_client/TestExprNoAlloc.py
+++ b/lldb/test/API/functionalities/gdb_remote_client/TestExprNoAlloc.py
@@ -6,11 +6,8 @@
 
 
 class MyResponder(MockGDBServerResponder):
-    def other(self, packet) -> str:
-        if packet.startswith("_M"):
-            return "E04"
-        else:
-            return super().other(packet)
+    def _M(self, size, permissions) -> str:
+        return "E04"
 
     def readRegister(self, regnum):
         return "E01"

>From d2a6c9676e4a9b8032296d628576629b308db3db Mon Sep 17 00:00:00 2001
From: Igor Kudrin <[email protected]>
Date: Thu, 15 Jan 2026 22:02:56 -0800
Subject: [PATCH 5/7] fixup! simplify the response string in 'readRegisters()'

---
 .../gdb_remote_client/TestExprNoAlloc.py            | 13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/lldb/test/API/functionalities/gdb_remote_client/TestExprNoAlloc.py 
b/lldb/test/API/functionalities/gdb_remote_client/TestExprNoAlloc.py
index aaeb96291411d..254c70ccbb971 100644
--- a/lldb/test/API/functionalities/gdb_remote_client/TestExprNoAlloc.py
+++ b/lldb/test/API/functionalities/gdb_remote_client/TestExprNoAlloc.py
@@ -13,7 +13,16 @@ def readRegister(self, regnum):
         return "E01"
 
     def readRegisters(self):
-        return 
"20000000000000002000000000000000f0c154bfffff00005daa985a8fea0b48f0b954bfffff0000ad13cce570150b48380000000000000070456abfffff0000a700000000000000000000000000000001010101010101010000000000000000f0c154bfffff00000f2700000000000008e355bfffff0000080e55bfffff0000281041000000000010de61bfffff00005c05000000000000f0c154bfffff000090fcffffffff00008efcffffffff00008ffcffffffff00000000000000000000001000000000000090fcffffffff000000d06cbfffff0000f0c154bfffff00000100000000000000d0b954bfffff0000e407400000000000d0b954bfffff0000e40740000000000000100000"
+        return "".join(
+            [
+                # x0
+                "2000000000000000",
+                # x1..x30, sp, pc
+                32 * "0000000000000000",
+                # cpsr
+                "00000000",
+            ]
+        )
 
 
 class TestExprNoAlloc(GDBRemoteTestBase):
@@ -37,4 +46,4 @@ def test(self):
             self, self.dbg.GetListener(), process, [lldb.eStateStopped]
         )
 
-        self.expect_expr("$x1", result_type="unsigned long", result_value="32")
+        self.expect_expr("$x0", result_type="unsigned long", result_value="32")

>From d072b389e96a16aee22459b3c0a0c833b00e18a3 Mon Sep 17 00:00:00 2001
From: Igor Kudrin <[email protected]>
Date: Thu, 15 Jan 2026 22:03:53 -0800
Subject: [PATCH 6/7] fixup! update the test description

---
 .../functionalities/gdb_remote_client/TestExprNoAlloc.py  | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/lldb/test/API/functionalities/gdb_remote_client/TestExprNoAlloc.py 
b/lldb/test/API/functionalities/gdb_remote_client/TestExprNoAlloc.py
index 254c70ccbb971..caabebb380952 100644
--- a/lldb/test/API/functionalities/gdb_remote_client/TestExprNoAlloc.py
+++ b/lldb/test/API/functionalities/gdb_remote_client/TestExprNoAlloc.py
@@ -30,10 +30,10 @@ class TestExprNoAlloc(GDBRemoteTestBase):
     @skipIfLLVMTargetMissing("AArch64")
     def test(self):
         """
-        Test that a simple expression can be evaluated when the server 
supports the '_M'
-        packet, but memory cannot be allocated, and it returns an error code 
response.
-        In this case, 'CanJIT' used to be set to 'eCanJITYes', so 
'IRMemoryMap' tried to
-        allocated memory in the inferior process and failed.
+        We should be able to evaluate an expression that requires no 
allocations,
+        even if the server responds to '_M' with an error. 'CanJIT' should be 
set
+        to 'eCanJITNo' for this response; otherwise, 'IRMemoryMap' would 
attempt
+        to allocate memory in the inferior process and fail.
         """
 
         self.server.responder = MyResponder()

>From 925c8999f32b6bdfe855ced12e02c1f5ff97f62b Mon Sep 17 00:00:00 2001
From: Igor Kudrin <[email protected]>
Date: Thu, 15 Jan 2026 22:04:34 -0800
Subject: [PATCH 7/7] fixup! add an expression which fails without JIT

---
 .../functionalities/gdb_remote_client/TestExprNoAlloc.py    | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/lldb/test/API/functionalities/gdb_remote_client/TestExprNoAlloc.py 
b/lldb/test/API/functionalities/gdb_remote_client/TestExprNoAlloc.py
index caabebb380952..4fcd7f833c68c 100644
--- a/lldb/test/API/functionalities/gdb_remote_client/TestExprNoAlloc.py
+++ b/lldb/test/API/functionalities/gdb_remote_client/TestExprNoAlloc.py
@@ -47,3 +47,9 @@ def test(self):
         )
 
         self.expect_expr("$x0", result_type="unsigned long", result_value="32")
+        res = self.target.EvaluateExpression("(int)foo()")
+        self.assertFalse(res.GetError().Success())
+        self.assertIn(
+            "Can't evaluate the expression without a running target",
+            res.GetError().GetCString(),
+        )

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

Reply via email to