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