1import lldb 2import binascii 3from lldbsuite.test.lldbtest import * 4from lldbsuite.test.decorators import * 5from gdbclientutils import * 6 7 8class TestGDBRemoteClient(GDBRemoteTestBase): 9 10 class gPacketResponder(MockGDBServerResponder): 11 def readRegisters(self): 12 return '0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' 13 14 def test_connect(self): 15 """Test connecting to a remote gdb server""" 16 target = self.createTarget("a.yaml") 17 process = self.connect(target) 18 self.assertPacketLogContains(["qProcessInfo", "qfThreadInfo"]) 19 20 def test_attach_fail(self): 21 error_msg = "mock-error-msg" 22 23 class MyResponder(MockGDBServerResponder): 24 # Pretend we don't have any process during the initial queries. 25 def qC(self): 26 return "E42" 27 28 def qfThreadInfo(self): 29 return "OK" # No threads. 30 31 # Then, when we are asked to attach, error out. 32 def vAttach(self, pid): 33 return "E42;" + binascii.hexlify(error_msg.encode()).decode() 34 35 self.server.responder = MyResponder() 36 37 target = self.dbg.CreateTarget("") 38 process = self.connect(target) 39 lldbutil.expect_state_changes(self, self.dbg.GetListener(), process, [lldb.eStateConnected]) 40 41 error = lldb.SBError() 42 target.AttachToProcessWithID(lldb.SBListener(), 47, error) 43 self.assertEquals(error_msg, error.GetCString()) 44 45 def test_launch_fail(self): 46 class MyResponder(MockGDBServerResponder): 47 # Pretend we don't have any process during the initial queries. 48 def qC(self): 49 return "E42" 50 51 def qfThreadInfo(self): 52 return "OK" # No threads. 53 54 # Then, when we are asked to attach, error out. 55 def A(self, packet): 56 return "E47" 57 58 self.runCmd("log enable gdb-remote packets") 59 self.server.responder = MyResponder() 60 61 target = self.createTarget("a.yaml") 62 process = self.connect(target) 63 lldbutil.expect_state_changes(self, self.dbg.GetListener(), process, [lldb.eStateConnected]) 64 65 error = lldb.SBError() 66 target.Launch(lldb.SBListener(), None, None, None, None, None, 67 None, 0, True, error) 68 self.assertEquals("'A' packet returned an error: 71", error.GetCString()) 69 70 def test_read_registers_using_g_packets(self): 71 """Test reading registers using 'g' packets (default behavior)""" 72 self.dbg.HandleCommand( 73 "settings set plugin.process.gdb-remote.use-g-packet-for-reading true") 74 self.addTearDownHook(lambda: 75 self.runCmd("settings set plugin.process.gdb-remote.use-g-packet-for-reading false")) 76 self.server.responder = self.gPacketResponder() 77 target = self.createTarget("a.yaml") 78 process = self.connect(target) 79 80 self.assertEquals(1, self.server.responder.packetLog.count("g")) 81 self.server.responder.packetLog = [] 82 self.read_registers(process) 83 # Reading registers should not cause any 'p' packets to be exchanged. 84 self.assertEquals( 85 0, len([p for p in self.server.responder.packetLog if p.startswith("p")])) 86 87 def test_read_registers_using_p_packets(self): 88 """Test reading registers using 'p' packets""" 89 self.dbg.HandleCommand( 90 "settings set plugin.process.gdb-remote.use-g-packet-for-reading false") 91 target = self.createTarget("a.yaml") 92 process = self.connect(target) 93 94 self.read_registers(process) 95 self.assertFalse("g" in self.server.responder.packetLog) 96 self.assertGreater( 97 len([p for p in self.server.responder.packetLog if p.startswith("p")]), 0) 98 99 def test_write_registers_using_P_packets(self): 100 """Test writing registers using 'P' packets (default behavior)""" 101 self.server.responder = self.gPacketResponder() 102 target = self.createTarget("a.yaml") 103 process = self.connect(target) 104 105 self.write_registers(process) 106 self.assertEquals(0, len( 107 [p for p in self.server.responder.packetLog if p.startswith("G")])) 108 self.assertGreater( 109 len([p for p in self.server.responder.packetLog if p.startswith("P")]), 0) 110 111 def test_write_registers_using_G_packets(self): 112 """Test writing registers using 'G' packets""" 113 114 class MyResponder(self.gPacketResponder): 115 def readRegister(self, register): 116 # empty string means unsupported 117 return "" 118 119 self.server.responder = MyResponder() 120 target = self.createTarget("a.yaml") 121 process = self.connect(target) 122 123 self.write_registers(process) 124 self.assertEquals(0, len( 125 [p for p in self.server.responder.packetLog if p.startswith("P")])) 126 self.assertGreater(len( 127 [p for p in self.server.responder.packetLog if p.startswith("G")]), 0) 128 129 def read_registers(self, process): 130 self.for_each_gpr( 131 process, lambda r: self.assertEquals("0x00000000", r.GetValue())) 132 133 def write_registers(self, process): 134 self.for_each_gpr( 135 process, lambda r: r.SetValueFromCString("0x00000000")) 136 137 def for_each_gpr(self, process, operation): 138 registers = process.GetThreadAtIndex(0).GetFrameAtIndex(0).GetRegisters() 139 self.assertGreater(registers.GetSize(), 0) 140 regSet = registers[0] 141 numChildren = regSet.GetNumChildren() 142 self.assertGreater(numChildren, 0) 143 for i in range(numChildren): 144 operation(regSet.GetChildAtIndex(i)) 145