diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/gdb_remote_client/TestJLink6Armv7RegisterDefinition.py b/lldb/packages/Python/lldbsuite/test/functionalities/gdb_remote_client/TestJLink6Armv7RegisterDefinition.py new file mode 100644 --- /dev/null +++ b/lldb/packages/Python/lldbsuite/test/functionalities/gdb_remote_client/TestJLink6Armv7RegisterDefinition.py @@ -0,0 +1,196 @@ +from __future__ import print_function +import lldb +from lldbsuite.test.lldbtest import * +from lldbsuite.test.decorators import * +from gdbclientutils import * + +class TestJLink6Armv7RegisterDefinition(GDBRemoteTestBase): + + @skipIfXmlSupportMissing + @skipIfRemote + def test(self): + """ + Test lldb's parsing of SEGGER J-Link v6.54 register + definition for a Cortex M-4 dev board, and the fact + that the J-Link only supports g/G for reading/writing + register AND the J-Link v6.54 doesn't provide anything + but the general purpose registers.""" + class MyResponder(MockGDBServerResponder): + + def qXferRead(self, obj, annex, offset, length): + if annex == "target.xml": + return """ + + + + + arm + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +""", False + else: + return None, False + + def readRegister(self, regnum): + return "E01" + + # Initial r1 bytes, in little-endian order + r1_bytes = "01000000" + + ## readRegisters only provides reg values up through xpsr (0x61000000) + ## it doesn't send up any of the exception registers or floating point + ## registers that the above register xml describes. + def readRegisters(self): + return "00000000" + self.r1_bytes + "010000000100000001000000000000008c080020a872012000000000a0790120000000008065012041ad0008a0720120692a00089e26000800000061" + + ## the J-Link accepts a register write packet with just the GPRs + ## defined. + def writeRegisters(self, registers_hex): + # Check that lldb returns the full 704 hex-byte register context, + # or the 136 hex-byte general purpose register reg ctx. + if len(registers_hex) != 704 and len(register_hex) != 136: + return "E06" + if registers_hex.startswith("0000000044332211010000000100000001000000000000008c080020a872012000000000a0790120000000008065012041ad0008a0720120692a00089e26000800000061"): + self.r1_bytes = "44332211" + return "OK" + else: + return "E07" + + def haltReason(self): + return "S05" + + def qfThreadInfo(self): + return "mdead" + + def qC(self): + return "" + + def qSupported(self, client_supported): + return "PacketSize=4000;qXfer:memory-map:read-;QStartNoAckMode+;hwbreak+;qXfer:features:read+" + + def QThreadSuffixSupported(self): + return "OK" + + def QListThreadsInStopReply(self): + return "OK" + + self.server.responder = MyResponder() + if self.TraceOn(): + self.runCmd("log enable gdb-remote packets") + self.addTearDownHook( + lambda: self.runCmd("log disable gdb-remote packets")) + + self.dbg.SetDefaultArchitecture("armv7em") + target = self.dbg.CreateTargetWithFileAndArch(None, None) + + process = self.connect(target) + + if self.TraceOn(): + interp = self.dbg.GetCommandInterpreter() + result = lldb.SBCommandReturnObject() + interp.HandleCommand("target list", result) + print(result.GetOutput()) + + r1_valobj = process.GetThreadAtIndex(0).GetFrameAtIndex(0).FindRegister("r1") + self.assertEqual(r1_valobj.GetValueAsUnsigned(), 1) + + pc_valobj = process.GetThreadAtIndex(0).GetFrameAtIndex(0).FindRegister("pc") + self.assertEqual(pc_valobj.GetValueAsUnsigned(), 0x0800269e) + + xpsr_valobj = process.GetThreadAtIndex(0).GetFrameAtIndex(0).FindRegister("xpsr") + self.assertEqual(xpsr_valobj.GetValueAsUnsigned(), 0x61000000) + + msp_valobj = process.GetThreadAtIndex(0).GetFrameAtIndex(0).FindRegister("msp") + err = msp_valobj.GetError() + self.assertTrue(err.Fail(), "lldb should not be able to fetch the msp register") + + val = b'\x11\x22\x33\x44' + error = lldb.SBError() + data = lldb.SBData() + data.SetData(error, val, lldb.eByteOrderBig, 4) + self.assertEqual(r1_valobj.SetData(data, error), True) + self.assertTrue(error.Success()) + + r1_valobj = process.GetThreadAtIndex(0).GetFrameAtIndex(0).FindRegister("r1") + self.assertEqual(r1_valobj.GetValueAsUnsigned(), 0x11223344) + diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/gdb_remote_client/gdbclientutils.py b/lldb/packages/Python/lldbsuite/test/functionalities/gdb_remote_client/gdbclientutils.py --- a/lldb/packages/Python/lldbsuite/test/functionalities/gdb_remote_client/gdbclientutils.py +++ b/lldb/packages/Python/lldbsuite/test/functionalities/gdb_remote_client/gdbclientutils.py @@ -109,7 +109,9 @@ if packet[0] == "g": return self.readRegisters() if packet[0] == "G": - return self.writeRegisters(packet[1:]) + # Gxxxxxxxxxxx + # Gxxxxxxxxxxx;thread:1234; + return self.writeRegisters(packet[1:].split(';')[0]) if packet[0] == "p": regnum = packet[1:].split(';')[0] return self.readRegister(int(regnum, 16)) diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp @@ -89,6 +89,9 @@ RegisterValue &value) { // Read the register if (ReadRegisterBytes(reg_info, m_reg_data)) { + const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; + if (m_reg_valid[reg] == false) + return false; const bool partial_data_ok = false; Status error(value.SetValueFromData( reg_info, m_reg_data, reg_info->byte_offset, partial_data_ok)); @@ -205,6 +208,18 @@ if (buffer_sp->GetByteSize() >= m_reg_data.GetByteSize()) { SetAllRegisterValid(true); return true; + } else if (buffer_sp->GetByteSize() > 0) { + const int regcount = m_reg_info.GetNumRegisters(); + for (int i = 0; i < regcount; i++) { + struct RegisterInfo *reginfo = m_reg_info.GetRegisterInfoAtIndex(i); + if (reginfo->byte_offset + reginfo->byte_size + <= buffer_sp->GetByteSize()) { + m_reg_valid[i] = true; + } else { + m_reg_valid[i] = false; + } + } + return true; } else { Log *log(ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet(GDBR_LOG_THREAD | GDBR_LOG_PACKETS));