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/packages/Python/lldbsuite/test/lldbgdbclient.py b/lldb/packages/Python/lldbsuite/test/lldbgdbclient.py index 9b2a89e934132..6a56f57964b93 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,7 @@ 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) + return self.dbg.CreateTargetWithFileAndTargetTriple(obj_path, triple) 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..4fcd7f833c68c --- /dev/null +++ b/lldb/test/API/functionalities/gdb_remote_client/TestExprNoAlloc.py @@ -0,0 +1,55 @@ +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 _M(self, size, permissions) -> str: + return "E04" + + def readRegister(self, regnum): + return "E01" + + def readRegisters(self): + return "".join( + [ + # x0 + "2000000000000000", + # x1..x30, sp, pc + 32 * "0000000000000000", + # cpsr + "00000000", + ] + ) + + +class TestExprNoAlloc(GDBRemoteTestBase): + @skipIfRemote + @skipIfLLVMTargetMissing("AArch64") + def test(self): + """ + 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() + # 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("$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(), + )