199451b44SJordan Rupprechtimport lldb 299451b44SJordan Rupprechtimport binascii 3784281d3SMichał Górnyimport os.path 499451b44SJordan Rupprechtfrom lldbsuite.test.lldbtest import * 599451b44SJordan Rupprechtfrom lldbsuite.test.decorators import * 633c0f93fSPavel Labathfrom lldbsuite.test.gdbclientutils import * 733c0f93fSPavel Labathfrom lldbsuite.test.lldbgdbclient import GDBRemoteTestBase 899451b44SJordan Rupprecht 999451b44SJordan Rupprecht 1099451b44SJordan Rupprechtclass TestGDBRemoteClient(GDBRemoteTestBase): 1199451b44SJordan Rupprecht class gPacketResponder(MockGDBServerResponder): 12270c989fSMichał Górny registers = [ 13270c989fSMichał Górny "name:rax;bitsize:64;offset:0;encoding:uint;format:hex;set:General Purpose Registers;ehframe:0;dwarf:0;", 14270c989fSMichał Górny "name:rbx;bitsize:64;offset:8;encoding:uint;format:hex;set:General Purpose Registers;ehframe:3;dwarf:3;", 15270c989fSMichał Górny "name:rcx;bitsize:64;offset:16;encoding:uint;format:hex;set:General Purpose Registers;ehframe:2;dwarf:2;generic:arg4;", 16270c989fSMichał Górny "name:rdx;bitsize:64;offset:24;encoding:uint;format:hex;set:General Purpose Registers;ehframe:1;dwarf:1;generic:arg3;", 17270c989fSMichał Górny "name:rdi;bitsize:64;offset:32;encoding:uint;format:hex;set:General Purpose Registers;ehframe:5;dwarf:5;generic:arg1;", 18270c989fSMichał Górny "name:rsi;bitsize:64;offset:40;encoding:uint;format:hex;set:General Purpose Registers;ehframe:4;dwarf:4;generic:arg2;", 19270c989fSMichał Górny "name:rbp;bitsize:64;offset:48;encoding:uint;format:hex;set:General Purpose Registers;ehframe:6;dwarf:6;generic:fp;", 20270c989fSMichał Górny "name:rsp;bitsize:64;offset:56;encoding:uint;format:hex;set:General Purpose Registers;ehframe:7;dwarf:7;generic:sp;", 21270c989fSMichał Górny ] 22270c989fSMichał Górny 23270c989fSMichał Górny def qRegisterInfo(self, num): 24270c989fSMichał Górny try: 25270c989fSMichał Górny return self.registers[num] 26270c989fSMichał Górny except IndexError: 27270c989fSMichał Górny return "E45" 28270c989fSMichał Górny 2999451b44SJordan Rupprecht def readRegisters(self): 302238dcc3SJonas Devlieghere return len(self.registers) * 16 * "0" 31270c989fSMichał Górny 32270c989fSMichał Górny def readRegister(self, register): 33270c989fSMichał Górny return "0000000000000000" 3499451b44SJordan Rupprecht 3599451b44SJordan Rupprecht def test_connect(self): 3699451b44SJordan Rupprecht """Test connecting to a remote gdb server""" 3799451b44SJordan Rupprecht target = self.createTarget("a.yaml") 3899451b44SJordan Rupprecht process = self.connect(target) 3999451b44SJordan Rupprecht self.assertPacketLogContains(["qProcessInfo", "qfThreadInfo"]) 4099451b44SJordan Rupprecht 4199451b44SJordan Rupprecht def test_attach_fail(self): 4299451b44SJordan Rupprecht error_msg = "mock-error-msg" 4399451b44SJordan Rupprecht 4499451b44SJordan Rupprecht class MyResponder(MockGDBServerResponder): 4599451b44SJordan Rupprecht # Pretend we don't have any process during the initial queries. 4699451b44SJordan Rupprecht def qC(self): 4799451b44SJordan Rupprecht return "E42" 4899451b44SJordan Rupprecht 4999451b44SJordan Rupprecht def qfThreadInfo(self): 5099451b44SJordan Rupprecht return "OK" # No threads. 5199451b44SJordan Rupprecht 5299451b44SJordan Rupprecht # Then, when we are asked to attach, error out. 5399451b44SJordan Rupprecht def vAttach(self, pid): 5499451b44SJordan Rupprecht return "E42;" + binascii.hexlify(error_msg.encode()).decode() 5599451b44SJordan Rupprecht 5699451b44SJordan Rupprecht self.server.responder = MyResponder() 5799451b44SJordan Rupprecht 5899451b44SJordan Rupprecht target = self.dbg.CreateTarget("") 5999451b44SJordan Rupprecht process = self.connect(target) 602238dcc3SJonas Devlieghere lldbutil.expect_state_changes( 612238dcc3SJonas Devlieghere self, self.dbg.GetListener(), process, [lldb.eStateConnected] 622238dcc3SJonas Devlieghere ) 6399451b44SJordan Rupprecht 6499451b44SJordan Rupprecht error = lldb.SBError() 6599451b44SJordan Rupprecht target.AttachToProcessWithID(lldb.SBListener(), 47, error) 6680fcecb1SJonas Devlieghere self.assertEqual(error_msg, error.GetCString()) 6799451b44SJordan Rupprecht 6865e843c9SPavel Labath def test_launch_fail(self): 6965e843c9SPavel Labath class MyResponder(MockGDBServerResponder): 7065e843c9SPavel Labath # Pretend we don't have any process during the initial queries. 7165e843c9SPavel Labath def qC(self): 7265e843c9SPavel Labath return "E42" 7365e843c9SPavel Labath 7465e843c9SPavel Labath def qfThreadInfo(self): 7565e843c9SPavel Labath return "OK" # No threads. 7665e843c9SPavel Labath 7765e843c9SPavel Labath # Then, when we are asked to attach, error out. 7865e843c9SPavel Labath def A(self, packet): 7965e843c9SPavel Labath return "E47" 8065e843c9SPavel Labath 8165e843c9SPavel Labath self.server.responder = MyResponder() 8265e843c9SPavel Labath 8365e843c9SPavel Labath target = self.createTarget("a.yaml") 8465e843c9SPavel Labath process = self.connect(target) 852238dcc3SJonas Devlieghere lldbutil.expect_state_changes( 862238dcc3SJonas Devlieghere self, self.dbg.GetListener(), process, [lldb.eStateConnected] 872238dcc3SJonas Devlieghere ) 8865e843c9SPavel Labath 8965e843c9SPavel Labath error = lldb.SBError() 902238dcc3SJonas Devlieghere target.Launch( 912238dcc3SJonas Devlieghere lldb.SBListener(), None, None, None, None, None, None, 0, True, error 922238dcc3SJonas Devlieghere ) 938d1de7b3SPavel Labath self.assertRegex(error.GetCString(), "Cannot launch '.*a': Error 71") 948d1de7b3SPavel Labath 958d1de7b3SPavel Labath def test_launch_rich_error(self): 968d1de7b3SPavel Labath class MyResponder(MockGDBServerResponder): 978d1de7b3SPavel Labath def qC(self): 988d1de7b3SPavel Labath return "E42" 998d1de7b3SPavel Labath 1008d1de7b3SPavel Labath def qfThreadInfo(self): 1018d1de7b3SPavel Labath return "OK" # No threads. 1028d1de7b3SPavel Labath 1038d1de7b3SPavel Labath # Then, when we are asked to attach, error out. 1048d1de7b3SPavel Labath def vRun(self, packet): 1058d1de7b3SPavel Labath return "Eff;" + seven.hexlify("I'm a teapot") 1068d1de7b3SPavel Labath 1078d1de7b3SPavel Labath self.server.responder = MyResponder() 1088d1de7b3SPavel Labath 1098d1de7b3SPavel Labath target = self.createTarget("a.yaml") 1108d1de7b3SPavel Labath process = self.connect(target) 1112238dcc3SJonas Devlieghere lldbutil.expect_state_changes( 1122238dcc3SJonas Devlieghere self, self.dbg.GetListener(), process, [lldb.eStateConnected] 1132238dcc3SJonas Devlieghere ) 1148d1de7b3SPavel Labath 1158d1de7b3SPavel Labath error = lldb.SBError() 1162238dcc3SJonas Devlieghere target.Launch( 1172238dcc3SJonas Devlieghere lldb.SBListener(), None, None, None, None, None, None, 0, True, error 1182238dcc3SJonas Devlieghere ) 1198d1de7b3SPavel Labath self.assertRegex(error.GetCString(), "Cannot launch '.*a': I'm a teapot") 12065e843c9SPavel Labath 12199451b44SJordan Rupprecht def test_read_registers_using_g_packets(self): 12299451b44SJordan Rupprecht """Test reading registers using 'g' packets (default behavior)""" 12399451b44SJordan Rupprecht self.dbg.HandleCommand( 1242238dcc3SJonas Devlieghere "settings set plugin.process.gdb-remote.use-g-packet-for-reading true" 1252238dcc3SJonas Devlieghere ) 1262238dcc3SJonas Devlieghere self.addTearDownHook( 1272238dcc3SJonas Devlieghere lambda: self.runCmd( 1282238dcc3SJonas Devlieghere "settings set plugin.process.gdb-remote.use-g-packet-for-reading false" 1292238dcc3SJonas Devlieghere ) 1302238dcc3SJonas Devlieghere ) 13199451b44SJordan Rupprecht self.server.responder = self.gPacketResponder() 13299451b44SJordan Rupprecht target = self.createTarget("a.yaml") 13399451b44SJordan Rupprecht process = self.connect(target) 13499451b44SJordan Rupprecht 135*7dbbd2b2Sjimingham # We want to make sure that the process is using the g packet, but it's 136*7dbbd2b2Sjimingham # not required the "connect" should read all registers. However, it might 137*7dbbd2b2Sjimingham # have... So we need to wait till we explicitly 'read_registers' to do 138*7dbbd2b2Sjimingham # test. 139*7dbbd2b2Sjimingham # Also, even with the use-g-packet-for-reading lldb will sometimes send p0 140*7dbbd2b2Sjimingham # early on to see if the packet is supported. So we can't say that there 141*7dbbd2b2Sjimingham # will be NO p packets. 142*7dbbd2b2Sjimingham # But there certainly should be no p packets after the g packet. 143*7dbbd2b2Sjimingham 14499451b44SJordan Rupprecht self.read_registers(process) 145*7dbbd2b2Sjimingham print(f"\nPACKET LOG:\n{self.server.responder.packetLog}\n") 146*7dbbd2b2Sjimingham g_pos = 0 147*7dbbd2b2Sjimingham try: 148*7dbbd2b2Sjimingham g_pos = self.server.responder.packetLog.index("g") 149*7dbbd2b2Sjimingham except err: 150*7dbbd2b2Sjimingham self.fail("'g' packet not found after fetching registers") 151*7dbbd2b2Sjimingham 152*7dbbd2b2Sjimingham try: 153*7dbbd2b2Sjimingham second_g = self.server.responder.packetLog.index("g", g_pos) 154*7dbbd2b2Sjimingham self.fail("Found more than one 'g' packet") 155*7dbbd2b2Sjimingham except: 156*7dbbd2b2Sjimingham pass 157*7dbbd2b2Sjimingham 158*7dbbd2b2Sjimingham # Make sure there aren't any `p` packets after the `g` packet: 15980fcecb1SJonas Devlieghere self.assertEqual( 160*7dbbd2b2Sjimingham 0, 161*7dbbd2b2Sjimingham len( 162*7dbbd2b2Sjimingham [ 163*7dbbd2b2Sjimingham p 164*7dbbd2b2Sjimingham for p in self.server.responder.packetLog[g_pos:] 165*7dbbd2b2Sjimingham if p.startswith("p") 166*7dbbd2b2Sjimingham ] 167*7dbbd2b2Sjimingham ), 1682238dcc3SJonas Devlieghere ) 16999451b44SJordan Rupprecht 17099451b44SJordan Rupprecht def test_read_registers_using_p_packets(self): 17199451b44SJordan Rupprecht """Test reading registers using 'p' packets""" 17299451b44SJordan Rupprecht self.dbg.HandleCommand( 1732238dcc3SJonas Devlieghere "settings set plugin.process.gdb-remote.use-g-packet-for-reading false" 1742238dcc3SJonas Devlieghere ) 175270c989fSMichał Górny self.server.responder = self.gPacketResponder() 17699451b44SJordan Rupprecht target = self.createTarget("a.yaml") 17799451b44SJordan Rupprecht process = self.connect(target) 17899451b44SJordan Rupprecht 17999451b44SJordan Rupprecht self.read_registers(process) 1803cc37622SDave Lee self.assertNotIn("g", self.server.responder.packetLog) 18199451b44SJordan Rupprecht self.assertGreater( 1822238dcc3SJonas Devlieghere len([p for p in self.server.responder.packetLog if p.startswith("p")]), 0 1832238dcc3SJonas Devlieghere ) 18499451b44SJordan Rupprecht 18599451b44SJordan Rupprecht def test_write_registers_using_P_packets(self): 18699451b44SJordan Rupprecht """Test writing registers using 'P' packets (default behavior)""" 18799451b44SJordan Rupprecht self.server.responder = self.gPacketResponder() 18899451b44SJordan Rupprecht target = self.createTarget("a.yaml") 18999451b44SJordan Rupprecht process = self.connect(target) 19099451b44SJordan Rupprecht 19199451b44SJordan Rupprecht self.write_registers(process) 19280fcecb1SJonas Devlieghere self.assertEqual( 1932238dcc3SJonas Devlieghere 0, len([p for p in self.server.responder.packetLog if p.startswith("G")]) 1942238dcc3SJonas Devlieghere ) 19599451b44SJordan Rupprecht self.assertGreater( 1962238dcc3SJonas Devlieghere len([p for p in self.server.responder.packetLog if p.startswith("P")]), 0 1972238dcc3SJonas Devlieghere ) 19899451b44SJordan Rupprecht 19999451b44SJordan Rupprecht def test_write_registers_using_G_packets(self): 20099451b44SJordan Rupprecht """Test writing registers using 'G' packets""" 20199451b44SJordan Rupprecht 20299451b44SJordan Rupprecht class MyResponder(self.gPacketResponder): 20399451b44SJordan Rupprecht def readRegister(self, register): 20499451b44SJordan Rupprecht # empty string means unsupported 20599451b44SJordan Rupprecht return "" 20699451b44SJordan Rupprecht 20799451b44SJordan Rupprecht self.server.responder = MyResponder() 20899451b44SJordan Rupprecht target = self.createTarget("a.yaml") 20999451b44SJordan Rupprecht process = self.connect(target) 21099451b44SJordan Rupprecht 21199451b44SJordan Rupprecht self.write_registers(process) 21280fcecb1SJonas Devlieghere self.assertEqual( 2132238dcc3SJonas Devlieghere 0, len([p for p in self.server.responder.packetLog if p.startswith("P")]) 2142238dcc3SJonas Devlieghere ) 2152238dcc3SJonas Devlieghere self.assertGreater( 2162238dcc3SJonas Devlieghere len([p for p in self.server.responder.packetLog if p.startswith("G")]), 0 2172238dcc3SJonas Devlieghere ) 21899451b44SJordan Rupprecht 21999451b44SJordan Rupprecht def read_registers(self, process): 22099451b44SJordan Rupprecht self.for_each_gpr( 22180fcecb1SJonas Devlieghere process, lambda r: self.assertEqual("0x0000000000000000", r.GetValue()) 2222238dcc3SJonas Devlieghere ) 22399451b44SJordan Rupprecht 22499451b44SJordan Rupprecht def write_registers(self, process): 22599451b44SJordan Rupprecht self.for_each_gpr( 2262238dcc3SJonas Devlieghere process, lambda r: r.SetValueFromCString("0x0000000000000000") 2272238dcc3SJonas Devlieghere ) 22899451b44SJordan Rupprecht 22999451b44SJordan Rupprecht def for_each_gpr(self, process, operation): 23099451b44SJordan Rupprecht registers = process.GetThreadAtIndex(0).GetFrameAtIndex(0).GetRegisters() 23199451b44SJordan Rupprecht self.assertGreater(registers.GetSize(), 0) 23299451b44SJordan Rupprecht regSet = registers[0] 23399451b44SJordan Rupprecht numChildren = regSet.GetNumChildren() 23499451b44SJordan Rupprecht self.assertGreater(numChildren, 0) 23599451b44SJordan Rupprecht for i in range(numChildren): 23699451b44SJordan Rupprecht operation(regSet.GetChildAtIndex(i)) 2376ba3f723SMichał Górny 2386ba3f723SMichał Górny def test_launch_A(self): 2396ba3f723SMichał Górny class MyResponder(MockGDBServerResponder): 2406ba3f723SMichał Górny def __init__(self, *args, **kwargs): 2416ba3f723SMichał Górny self.started = False 2426ba3f723SMichał Górny return super().__init__(*args, **kwargs) 2436ba3f723SMichał Górny 2446ba3f723SMichał Górny def qC(self): 2456ba3f723SMichał Górny if self.started: 2466ba3f723SMichał Górny return "QCp10.10" 2476ba3f723SMichał Górny else: 2486ba3f723SMichał Górny return "E42" 2496ba3f723SMichał Górny 2506ba3f723SMichał Górny def qfThreadInfo(self): 2516ba3f723SMichał Górny if self.started: 2526ba3f723SMichał Górny return "mp10.10" 2536ba3f723SMichał Górny else: 2546ba3f723SMichał Górny return "E42" 2556ba3f723SMichał Górny 2566ba3f723SMichał Górny def qsThreadInfo(self): 2576ba3f723SMichał Górny return "l" 2586ba3f723SMichał Górny 2596ba3f723SMichał Górny def A(self, packet): 2606ba3f723SMichał Górny self.started = True 2616ba3f723SMichał Górny return "OK" 2626ba3f723SMichał Górny 2636ba3f723SMichał Górny def qLaunchSuccess(self): 2646ba3f723SMichał Górny if self.started: 2656ba3f723SMichał Górny return "OK" 2666ba3f723SMichał Górny return "E42" 2676ba3f723SMichał Górny 2686ba3f723SMichał Górny self.server.responder = MyResponder() 2696ba3f723SMichał Górny 2706ba3f723SMichał Górny target = self.createTarget("a.yaml") 271784281d3SMichał Górny # NB: apparently GDB packets are using "/" on Windows too 2722238dcc3SJonas Devlieghere exe_path = self.getBuildArtifact("a").replace(os.path.sep, "/") 2736ba3f723SMichał Górny exe_hex = binascii.b2a_hex(exe_path.encode()).decode() 2746ba3f723SMichał Górny process = self.connect(target) 2752238dcc3SJonas Devlieghere lldbutil.expect_state_changes( 2762238dcc3SJonas Devlieghere self, self.dbg.GetListener(), process, [lldb.eStateConnected] 2772238dcc3SJonas Devlieghere ) 2786ba3f723SMichał Górny 2792238dcc3SJonas Devlieghere target.Launch( 2802238dcc3SJonas Devlieghere lldb.SBListener(), 2816ba3f723SMichał Górny ["arg1", "arg2", "arg3"], # argv 2826ba3f723SMichał Górny [], # envp 2836ba3f723SMichał Górny None, # stdin_path 2846ba3f723SMichał Górny None, # stdout_path 2856ba3f723SMichał Górny None, # stderr_path 2866ba3f723SMichał Górny None, # working_directory 2876ba3f723SMichał Górny 0, # launch_flags 2886ba3f723SMichał Górny True, # stop_at_entry 2892238dcc3SJonas Devlieghere lldb.SBError(), 2902238dcc3SJonas Devlieghere ) # error 2916ba3f723SMichał Górny self.assertTrue(process, PROCESS_IS_VALID) 2926ba3f723SMichał Górny self.assertEqual(process.GetProcessID(), 16) 2936ba3f723SMichał Górny 2942238dcc3SJonas Devlieghere self.assertPacketLogContains( 2952238dcc3SJonas Devlieghere [ 2962238dcc3SJonas Devlieghere "A%d,0,%s,8,1,61726731,8,2,61726732,8,3,61726733" 2972238dcc3SJonas Devlieghere % (len(exe_hex), exe_hex), 2982238dcc3SJonas Devlieghere ] 2992238dcc3SJonas Devlieghere ) 3006ba3f723SMichał Górny 3016ba3f723SMichał Górny def test_launch_vRun(self): 3026ba3f723SMichał Górny class MyResponder(MockGDBServerResponder): 3036ba3f723SMichał Górny def __init__(self, *args, **kwargs): 3046ba3f723SMichał Górny self.started = False 3056ba3f723SMichał Górny return super().__init__(*args, **kwargs) 3066ba3f723SMichał Górny 3076ba3f723SMichał Górny def qC(self): 3086ba3f723SMichał Górny if self.started: 3096ba3f723SMichał Górny return "QCp10.10" 3106ba3f723SMichał Górny else: 3116ba3f723SMichał Górny return "E42" 3126ba3f723SMichał Górny 3136ba3f723SMichał Górny def qfThreadInfo(self): 3146ba3f723SMichał Górny if self.started: 3156ba3f723SMichał Górny return "mp10.10" 3166ba3f723SMichał Górny else: 3176ba3f723SMichał Górny return "E42" 3186ba3f723SMichał Górny 3196ba3f723SMichał Górny def qsThreadInfo(self): 3206ba3f723SMichał Górny return "l" 3216ba3f723SMichał Górny 3226ba3f723SMichał Górny def vRun(self, packet): 3236ba3f723SMichał Górny self.started = True 3246ba3f723SMichał Górny return "T13" 3256ba3f723SMichał Górny 3266ba3f723SMichał Górny def A(self, packet): 3276ba3f723SMichał Górny return "E28" 3286ba3f723SMichał Górny 3296ba3f723SMichał Górny self.server.responder = MyResponder() 3306ba3f723SMichał Górny 3316ba3f723SMichał Górny target = self.createTarget("a.yaml") 332784281d3SMichał Górny # NB: apparently GDB packets are using "/" on Windows too 3332238dcc3SJonas Devlieghere exe_path = self.getBuildArtifact("a").replace(os.path.sep, "/") 3346ba3f723SMichał Górny exe_hex = binascii.b2a_hex(exe_path.encode()).decode() 3356ba3f723SMichał Górny process = self.connect(target) 3362238dcc3SJonas Devlieghere lldbutil.expect_state_changes( 3372238dcc3SJonas Devlieghere self, self.dbg.GetListener(), process, [lldb.eStateConnected] 3382238dcc3SJonas Devlieghere ) 3396ba3f723SMichał Górny 3402238dcc3SJonas Devlieghere process = target.Launch( 3412238dcc3SJonas Devlieghere lldb.SBListener(), 3426ba3f723SMichał Górny ["arg1", "arg2", "arg3"], # argv 3436ba3f723SMichał Górny [], # envp 3446ba3f723SMichał Górny None, # stdin_path 3456ba3f723SMichał Górny None, # stdout_path 3466ba3f723SMichał Górny None, # stderr_path 3476ba3f723SMichał Górny None, # working_directory 3486ba3f723SMichał Górny 0, # launch_flags 3496ba3f723SMichał Górny True, # stop_at_entry 3502238dcc3SJonas Devlieghere lldb.SBError(), 3512238dcc3SJonas Devlieghere ) # error 3526ba3f723SMichał Górny self.assertTrue(process, PROCESS_IS_VALID) 3536ba3f723SMichał Górny self.assertEqual(process.GetProcessID(), 16) 3546ba3f723SMichał Górny 3552238dcc3SJonas Devlieghere self.assertPacketLogContains( 3562238dcc3SJonas Devlieghere ["vRun;%s;61726731;61726732;61726733" % (exe_hex,)] 3572238dcc3SJonas Devlieghere ) 3583fade954SMichał Górny 3593fade954SMichał Górny def test_launch_QEnvironment(self): 3603fade954SMichał Górny class MyResponder(MockGDBServerResponder): 3613fade954SMichał Górny def qC(self): 3623fade954SMichał Górny return "E42" 3633fade954SMichał Górny 3643fade954SMichał Górny def qfThreadInfo(self): 3653fade954SMichał Górny return "E42" 3663fade954SMichał Górny 3673fade954SMichał Górny def vRun(self, packet): 3683fade954SMichał Górny self.started = True 3693fade954SMichał Górny return "E28" 3703fade954SMichał Górny 3713fade954SMichał Górny self.server.responder = MyResponder() 3723fade954SMichał Górny 3733fade954SMichał Górny target = self.createTarget("a.yaml") 3743fade954SMichał Górny process = self.connect(target) 3752238dcc3SJonas Devlieghere lldbutil.expect_state_changes( 3762238dcc3SJonas Devlieghere self, self.dbg.GetListener(), process, [lldb.eStateConnected] 3772238dcc3SJonas Devlieghere ) 3783fade954SMichał Górny 3792238dcc3SJonas Devlieghere target.Launch( 3802238dcc3SJonas Devlieghere lldb.SBListener(), 3813fade954SMichał Górny [], # argv 3822238dcc3SJonas Devlieghere [ 3832238dcc3SJonas Devlieghere "PLAIN=foo", 3843fade954SMichał Górny "NEEDSENC=frob$", 3853fade954SMichał Górny "NEEDSENC2=fr*ob", 3863fade954SMichał Górny "NEEDSENC3=fro}b", 3873fade954SMichał Górny "NEEDSENC4=f#rob", 3883fade954SMichał Górny "EQUALS=foo=bar", 3893fade954SMichał Górny ], # envp 3903fade954SMichał Górny None, # stdin_path 3913fade954SMichał Górny None, # stdout_path 3923fade954SMichał Górny None, # stderr_path 3933fade954SMichał Górny None, # working_directory 3943fade954SMichał Górny 0, # launch_flags 3953fade954SMichał Górny True, # stop_at_entry 3962238dcc3SJonas Devlieghere lldb.SBError(), 3972238dcc3SJonas Devlieghere ) # error 3983fade954SMichał Górny 3992238dcc3SJonas Devlieghere self.assertPacketLogContains( 4002238dcc3SJonas Devlieghere [ 4015d66f9fdSFangrui Song "QEnvironment:EQUALS=foo=bar", 4025d66f9fdSFangrui Song "QEnvironmentHexEncoded:4e45454453454e433d66726f6224", 4035d66f9fdSFangrui Song "QEnvironmentHexEncoded:4e45454453454e43323d66722a6f62", 4043fade954SMichał Górny "QEnvironmentHexEncoded:4e45454453454e43333d66726f7d62", 4053fade954SMichał Górny "QEnvironmentHexEncoded:4e45454453454e43343d6623726f62", 40687d02e0dSErik Desjardins "QEnvironment:PLAIN=foo", 4072238dcc3SJonas Devlieghere ] 4082238dcc3SJonas Devlieghere ) 4093fade954SMichał Górny 4103fade954SMichał Górny def test_launch_QEnvironmentHexEncoded_only(self): 4113fade954SMichał Górny class MyResponder(MockGDBServerResponder): 4123fade954SMichał Górny def qC(self): 4133fade954SMichał Górny return "E42" 4143fade954SMichał Górny 4153fade954SMichał Górny def qfThreadInfo(self): 4163fade954SMichał Górny return "E42" 4173fade954SMichał Górny 4183fade954SMichał Górny def vRun(self, packet): 4193fade954SMichał Górny self.started = True 4203fade954SMichał Górny return "E28" 4213fade954SMichał Górny 4223fade954SMichał Górny def QEnvironment(self, packet): 4233fade954SMichał Górny return "" 4243fade954SMichał Górny 4253fade954SMichał Górny self.server.responder = MyResponder() 4263fade954SMichał Górny 4273fade954SMichał Górny target = self.createTarget("a.yaml") 4283fade954SMichał Górny process = self.connect(target) 4292238dcc3SJonas Devlieghere lldbutil.expect_state_changes( 4302238dcc3SJonas Devlieghere self, self.dbg.GetListener(), process, [lldb.eStateConnected] 4312238dcc3SJonas Devlieghere ) 4323fade954SMichał Górny 4332238dcc3SJonas Devlieghere target.Launch( 4342238dcc3SJonas Devlieghere lldb.SBListener(), 4353fade954SMichał Górny [], # argv 4362238dcc3SJonas Devlieghere [ 4372238dcc3SJonas Devlieghere "PLAIN=foo", 4383fade954SMichał Górny "NEEDSENC=frob$", 4393fade954SMichał Górny "NEEDSENC2=fr*ob", 4403fade954SMichał Górny "NEEDSENC3=fro}b", 4413fade954SMichał Górny "NEEDSENC4=f#rob", 4423fade954SMichał Górny "EQUALS=foo=bar", 4433fade954SMichał Górny ], # envp 4443fade954SMichał Górny None, # stdin_path 4453fade954SMichał Górny None, # stdout_path 4463fade954SMichał Górny None, # stderr_path 4473fade954SMichał Górny None, # working_directory 4483fade954SMichał Górny 0, # launch_flags 4493fade954SMichał Górny True, # stop_at_entry 4502238dcc3SJonas Devlieghere lldb.SBError(), 4512238dcc3SJonas Devlieghere ) # error 4523fade954SMichał Górny 4532238dcc3SJonas Devlieghere self.assertPacketLogContains( 4542238dcc3SJonas Devlieghere [ 4555d66f9fdSFangrui Song "QEnvironmentHexEncoded:455155414c533d666f6f3d626172", 4565d66f9fdSFangrui Song "QEnvironmentHexEncoded:4e45454453454e433d66726f6224", 4575d66f9fdSFangrui Song "QEnvironmentHexEncoded:4e45454453454e43323d66722a6f62", 4583fade954SMichał Górny "QEnvironmentHexEncoded:4e45454453454e43333d66726f7d62", 4593fade954SMichał Górny "QEnvironmentHexEncoded:4e45454453454e43343d6623726f62", 46087d02e0dSErik Desjardins "QEnvironmentHexEncoded:504c41494e3d666f6f", 4612238dcc3SJonas Devlieghere ] 4622238dcc3SJonas Devlieghere ) 463b1099120SMichał Górny 464b1099120SMichał Górny def test_detach_no_multiprocess(self): 465b1099120SMichał Górny class MyResponder(MockGDBServerResponder): 466b1099120SMichał Górny def __init__(self): 467b1099120SMichał Górny super().__init__() 468b1099120SMichał Górny self.detached = None 469b1099120SMichał Górny 470b1099120SMichał Górny def qfThreadInfo(self): 471b1099120SMichał Górny return "10200" 472b1099120SMichał Górny 473b1099120SMichał Górny def D(self, packet): 474b1099120SMichał Górny self.detached = packet 475b1099120SMichał Górny return "OK" 476b1099120SMichał Górny 477b1099120SMichał Górny self.server.responder = MyResponder() 4782238dcc3SJonas Devlieghere target = self.dbg.CreateTarget("") 479b1099120SMichał Górny process = self.connect(target) 480b1099120SMichał Górny process.Detach() 481b1099120SMichał Górny self.assertEqual(self.server.responder.detached, "D") 482b1099120SMichał Górny 483b1099120SMichał Górny def test_detach_pid(self): 484b1099120SMichał Górny class MyResponder(MockGDBServerResponder): 485b1099120SMichał Górny def __init__(self, test_case): 486b1099120SMichał Górny super().__init__() 487b1099120SMichał Górny self.test_case = test_case 488b1099120SMichał Górny self.detached = None 489b1099120SMichał Górny 490b1099120SMichał Górny def qSupported(self, client_supported): 491b1099120SMichał Górny self.test_case.assertIn("multiprocess+", client_supported) 492b1099120SMichał Górny return "multiprocess+;" + super().qSupported(client_supported) 493b1099120SMichał Górny 494b1099120SMichał Górny def qfThreadInfo(self): 495b1099120SMichał Górny return "mp400.10200" 496b1099120SMichał Górny 497b1099120SMichał Górny def D(self, packet): 498b1099120SMichał Górny self.detached = packet 499b1099120SMichał Górny return "OK" 500b1099120SMichał Górny 501b1099120SMichał Górny self.server.responder = MyResponder(self) 5022238dcc3SJonas Devlieghere target = self.dbg.CreateTarget("") 503b1099120SMichał Górny process = self.connect(target) 504b1099120SMichał Górny process.Detach() 505b1099120SMichał Górny self.assertRegex(self.server.responder.detached, r"D;0*400") 5063f137236SMichał Górny 5073f137236SMichał Górny def test_signal_gdb(self): 5083f137236SMichał Górny class MyResponder(MockGDBServerResponder): 5093f137236SMichał Górny def qSupported(self, client_supported): 5103f137236SMichał Górny return "PacketSize=3fff;QStartNoAckMode+" 5113f137236SMichał Górny 5123f137236SMichał Górny def haltReason(self): 5133f137236SMichał Górny return "S0a" 5143f137236SMichał Górny 5153f137236SMichał Górny def cont(self): 5163f137236SMichał Górny return self.haltReason() 5173f137236SMichał Górny 5183f137236SMichał Górny self.server.responder = MyResponder() 5193f137236SMichał Górny 520d96656caSMichał Górny self.runCmd("platform select remote-linux") 5213f137236SMichał Górny target = self.createTarget("a.yaml") 5223f137236SMichał Górny process = self.connect(target) 5233f137236SMichał Górny 5242238dcc3SJonas Devlieghere self.assertEqual(process.threads[0].GetStopReason(), lldb.eStopReasonSignal) 5252238dcc3SJonas Devlieghere self.assertEqual(process.threads[0].GetStopDescription(100), "signal SIGBUS") 5263f137236SMichał Górny 5273f137236SMichał Górny def test_signal_lldb_old(self): 5283f137236SMichał Górny class MyResponder(MockGDBServerResponder): 5293f137236SMichał Górny def qSupported(self, client_supported): 5303f137236SMichał Górny return "PacketSize=3fff;QStartNoAckMode+" 5313f137236SMichał Górny 5323f137236SMichał Górny def qHostInfo(self): 5333f137236SMichał Górny return "triple:61726d76372d756e6b6e6f776e2d6c696e75782d676e75;" 5343f137236SMichał Górny 5353f137236SMichał Górny def QThreadSuffixSupported(self): 5363f137236SMichał Górny return "OK" 5373f137236SMichał Górny 5383f137236SMichał Górny def haltReason(self): 5393f137236SMichał Górny return "S0a" 5403f137236SMichał Górny 5413f137236SMichał Górny def cont(self): 5423f137236SMichał Górny return self.haltReason() 5433f137236SMichał Górny 5443f137236SMichał Górny self.server.responder = MyResponder() 5453f137236SMichał Górny 546d96656caSMichał Górny self.runCmd("platform select remote-linux") 5473f137236SMichał Górny target = self.createTarget("a.yaml") 5483f137236SMichał Górny process = self.connect(target) 5493f137236SMichał Górny 5502238dcc3SJonas Devlieghere self.assertEqual(process.threads[0].GetStopReason(), lldb.eStopReasonSignal) 5512238dcc3SJonas Devlieghere self.assertEqual(process.threads[0].GetStopDescription(100), "signal SIGUSR1") 5523f137236SMichał Górny 5533f137236SMichał Górny def test_signal_lldb(self): 5543f137236SMichał Górny class MyResponder(MockGDBServerResponder): 5553f137236SMichał Górny def qSupported(self, client_supported): 5563f137236SMichał Górny return "PacketSize=3fff;QStartNoAckMode+;native-signals+" 5573f137236SMichał Górny 5583f137236SMichał Górny def qHostInfo(self): 5593f137236SMichał Górny return "triple:61726d76372d756e6b6e6f776e2d6c696e75782d676e75;" 5603f137236SMichał Górny 5613f137236SMichał Górny def haltReason(self): 5623f137236SMichał Górny return "S0a" 5633f137236SMichał Górny 5643f137236SMichał Górny def cont(self): 5653f137236SMichał Górny return self.haltReason() 5663f137236SMichał Górny 5673f137236SMichał Górny self.server.responder = MyResponder() 5683f137236SMichał Górny 569d96656caSMichał Górny self.runCmd("platform select remote-linux") 5703f137236SMichał Górny target = self.createTarget("a.yaml") 5713f137236SMichał Górny process = self.connect(target) 5723f137236SMichał Górny 5732238dcc3SJonas Devlieghere self.assertEqual(process.threads[0].GetStopReason(), lldb.eStopReasonSignal) 5742238dcc3SJonas Devlieghere self.assertEqual(process.threads[0].GetStopDescription(100), "signal SIGUSR1") 575ac666d17SMichał Górny 576ac666d17SMichał Górny def do_siginfo_test(self, platform, target_yaml, raw_data, expected): 577ac666d17SMichał Górny class MyResponder(MockGDBServerResponder): 578ac666d17SMichał Górny def qSupported(self, client_supported): 579ac666d17SMichał Górny return "PacketSize=3fff;QStartNoAckMode+;qXfer:siginfo:read+" 580ac666d17SMichał Górny 581ac666d17SMichał Górny def qXferRead(self, obj, annex, offset, length): 582ac666d17SMichał Górny if obj == "siginfo": 583ac666d17SMichał Górny return raw_data, False 584ac666d17SMichał Górny else: 585ac666d17SMichał Górny return None, False 586ac666d17SMichał Górny 587ac666d17SMichał Górny def haltReason(self): 588ac666d17SMichał Górny return "T02" 589ac666d17SMichał Górny 590ac666d17SMichał Górny def cont(self): 591ac666d17SMichał Górny return self.haltReason() 592ac666d17SMichał Górny 593ac666d17SMichał Górny self.server.responder = MyResponder() 594ac666d17SMichał Górny 595ac666d17SMichał Górny self.runCmd("platform select " + platform) 596ac666d17SMichał Górny target = self.createTarget(target_yaml) 597ac666d17SMichał Górny process = self.connect(target) 598ac666d17SMichał Górny 599ac666d17SMichał Górny siginfo = process.threads[0].GetSiginfo() 600779bbbf2SDave Lee self.assertSuccess(siginfo.GetError()) 601ac666d17SMichał Górny 602ac666d17SMichał Górny for key, value in expected.items(): 6032238dcc3SJonas Devlieghere self.assertEqual( 6042238dcc3SJonas Devlieghere siginfo.GetValueForExpressionPath("." + key).GetValueAsUnsigned(), value 6052238dcc3SJonas Devlieghere ) 606ac666d17SMichał Górny 607ac666d17SMichał Górny def test_siginfo_linux_amd64(self): 608ac666d17SMichał Górny data = ( 609ac666d17SMichał Górny # si_signo si_errno si_code 610ac666d17SMichał Górny "\x11\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00" 611ac666d17SMichał Górny # __pad0 si_pid si_uid 612ac666d17SMichał Górny "\x00\x00\x00\x00\xbf\xf7\x0b\x00\xe8\x03\x00\x00" 613ac666d17SMichał Górny # si_status 6142238dcc3SJonas Devlieghere "\x0c\x00\x00\x00" 6152238dcc3SJonas Devlieghere + "\x00" * 100 6162238dcc3SJonas Devlieghere ) 617ac666d17SMichał Górny expected = { 618ac666d17SMichał Górny "si_signo": 17, # SIGCHLD 619ac666d17SMichał Górny "si_errno": 0, 620ac666d17SMichał Górny "si_code": 1, # CLD_EXITED 621ac666d17SMichał Górny "_sifields._sigchld.si_pid": 784319, 622ac666d17SMichał Górny "_sifields._sigchld.si_uid": 1000, 623ac666d17SMichał Górny "_sifields._sigchld.si_status": 12, 624ac666d17SMichał Górny "_sifields._sigchld.si_utime": 0, 625ac666d17SMichał Górny "_sifields._sigchld.si_stime": 0, 626ac666d17SMichał Górny } 6272238dcc3SJonas Devlieghere self.do_siginfo_test("remote-linux", "basic_eh_frame.yaml", data, expected) 628ac666d17SMichał Górny 629ac666d17SMichał Górny def test_siginfo_linux_i386(self): 630ac666d17SMichał Górny data = ( 631ac666d17SMichał Górny # si_signo si_errno si_code 632ac666d17SMichał Górny "\x11\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00" 633ac666d17SMichał Górny # si_pid si_uid si_status 634ac666d17SMichał Górny "\x49\x43\x07\x00\xe8\x03\x00\x00\x0c\x00\x00\x00" 6352238dcc3SJonas Devlieghere + "\x00" * 104 6362238dcc3SJonas Devlieghere ) 637ac666d17SMichał Górny expected = { 638ac666d17SMichał Górny "si_signo": 17, # SIGCHLD 639ac666d17SMichał Górny "si_errno": 0, 640ac666d17SMichał Górny "si_code": 1, # CLD_EXITED 641ac666d17SMichał Górny "_sifields._sigchld.si_pid": 475977, 642ac666d17SMichał Górny "_sifields._sigchld.si_uid": 1000, 643ac666d17SMichał Górny "_sifields._sigchld.si_status": 12, 644ac666d17SMichał Górny "_sifields._sigchld.si_utime": 0, 645ac666d17SMichał Górny "_sifields._sigchld.si_stime": 0, 646ac666d17SMichał Górny } 6472238dcc3SJonas Devlieghere self.do_siginfo_test("remote-linux", "basic_eh_frame-i386.yaml", data, expected) 648ac666d17SMichał Górny 649ac666d17SMichał Górny def test_siginfo_freebsd_amd64(self): 650ac666d17SMichał Górny data = ( 651ac666d17SMichał Górny # si_signo si_errno si_code 652ac666d17SMichał Górny "\x0b\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00" 653ac666d17SMichał Górny # si_pid si_uid si_status 654ac666d17SMichał Górny "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" 655ac666d17SMichał Górny # si_addr 656ac666d17SMichał Górny "\x76\x98\xba\xdc\xfe\x00\x00\x00" 657ac666d17SMichał Górny # si_status si_trapno 658ac666d17SMichał Górny "\x00\x00\x00\x00\x00\x00\x00\x00\x0c\x00\x00\x00" 6592238dcc3SJonas Devlieghere + "\x00" * 36 6602238dcc3SJonas Devlieghere ) 661ac666d17SMichał Górny 662ac666d17SMichał Górny expected = { 663ac666d17SMichał Górny "si_signo": 11, # SIGSEGV 664ac666d17SMichał Górny "si_errno": 0, 665ac666d17SMichał Górny "si_code": 1, # SEGV_MAPERR 6662238dcc3SJonas Devlieghere "si_addr": 0xFEDCBA9876, 667ac666d17SMichał Górny "_reason._fault._trapno": 12, 668ac666d17SMichał Górny } 6692238dcc3SJonas Devlieghere self.do_siginfo_test("remote-freebsd", "basic_eh_frame.yaml", data, expected) 670