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
1299451b44SJordan Rupprecht    class gPacketResponder(MockGDBServerResponder):
13270c989fSMichał Górny        registers = [
14270c989fSMichał Górny            "name:rax;bitsize:64;offset:0;encoding:uint;format:hex;set:General Purpose Registers;ehframe:0;dwarf:0;",
15270c989fSMichał Górny            "name:rbx;bitsize:64;offset:8;encoding:uint;format:hex;set:General Purpose Registers;ehframe:3;dwarf:3;",
16270c989fSMichał Górny            "name:rcx;bitsize:64;offset:16;encoding:uint;format:hex;set:General Purpose Registers;ehframe:2;dwarf:2;generic:arg4;",
17270c989fSMichał Górny            "name:rdx;bitsize:64;offset:24;encoding:uint;format:hex;set:General Purpose Registers;ehframe:1;dwarf:1;generic:arg3;",
18270c989fSMichał Górny            "name:rdi;bitsize:64;offset:32;encoding:uint;format:hex;set:General Purpose Registers;ehframe:5;dwarf:5;generic:arg1;",
19270c989fSMichał Górny            "name:rsi;bitsize:64;offset:40;encoding:uint;format:hex;set:General Purpose Registers;ehframe:4;dwarf:4;generic:arg2;",
20270c989fSMichał Górny            "name:rbp;bitsize:64;offset:48;encoding:uint;format:hex;set:General Purpose Registers;ehframe:6;dwarf:6;generic:fp;",
21270c989fSMichał Górny            "name:rsp;bitsize:64;offset:56;encoding:uint;format:hex;set:General Purpose Registers;ehframe:7;dwarf:7;generic:sp;",
22270c989fSMichał Górny        ]
23270c989fSMichał Górny
24270c989fSMichał Górny        def qRegisterInfo(self, num):
25270c989fSMichał Górny            try:
26270c989fSMichał Górny                return self.registers[num]
27270c989fSMichał Górny            except IndexError:
28270c989fSMichał Górny                return "E45"
29270c989fSMichał Górny
3099451b44SJordan Rupprecht        def readRegisters(self):
31270c989fSMichał Górny            return len(self.registers) * 16 * '0'
32270c989fSMichał Górny
33270c989fSMichał Górny        def readRegister(self, register):
34270c989fSMichał Górny            return "0000000000000000"
3599451b44SJordan Rupprecht
3699451b44SJordan Rupprecht    def test_connect(self):
3799451b44SJordan Rupprecht        """Test connecting to a remote gdb server"""
3899451b44SJordan Rupprecht        target = self.createTarget("a.yaml")
3999451b44SJordan Rupprecht        process = self.connect(target)
4099451b44SJordan Rupprecht        self.assertPacketLogContains(["qProcessInfo", "qfThreadInfo"])
4199451b44SJordan Rupprecht
4299451b44SJordan Rupprecht    def test_attach_fail(self):
4399451b44SJordan Rupprecht        error_msg = "mock-error-msg"
4499451b44SJordan Rupprecht
4599451b44SJordan Rupprecht        class MyResponder(MockGDBServerResponder):
4699451b44SJordan Rupprecht            # Pretend we don't have any process during the initial queries.
4799451b44SJordan Rupprecht            def qC(self):
4899451b44SJordan Rupprecht                return "E42"
4999451b44SJordan Rupprecht
5099451b44SJordan Rupprecht            def qfThreadInfo(self):
5199451b44SJordan Rupprecht                return "OK" # No threads.
5299451b44SJordan Rupprecht
5399451b44SJordan Rupprecht            # Then, when we are asked to attach, error out.
5499451b44SJordan Rupprecht            def vAttach(self, pid):
5599451b44SJordan Rupprecht                return "E42;" + binascii.hexlify(error_msg.encode()).decode()
5699451b44SJordan Rupprecht
5799451b44SJordan Rupprecht        self.server.responder = MyResponder()
5899451b44SJordan Rupprecht
5999451b44SJordan Rupprecht        target = self.dbg.CreateTarget("")
6099451b44SJordan Rupprecht        process = self.connect(target)
6199451b44SJordan Rupprecht        lldbutil.expect_state_changes(self, self.dbg.GetListener(), process, [lldb.eStateConnected])
6299451b44SJordan Rupprecht
6399451b44SJordan Rupprecht        error = lldb.SBError()
6499451b44SJordan Rupprecht        target.AttachToProcessWithID(lldb.SBListener(), 47, error)
6599451b44SJordan Rupprecht        self.assertEquals(error_msg, error.GetCString())
6699451b44SJordan Rupprecht
6765e843c9SPavel Labath    def test_launch_fail(self):
6865e843c9SPavel Labath        class MyResponder(MockGDBServerResponder):
6965e843c9SPavel Labath            # Pretend we don't have any process during the initial queries.
7065e843c9SPavel Labath            def qC(self):
7165e843c9SPavel Labath                return "E42"
7265e843c9SPavel Labath
7365e843c9SPavel Labath            def qfThreadInfo(self):
7465e843c9SPavel Labath                return "OK" # No threads.
7565e843c9SPavel Labath
7665e843c9SPavel Labath            # Then, when we are asked to attach, error out.
7765e843c9SPavel Labath            def A(self, packet):
7865e843c9SPavel Labath                return "E47"
7965e843c9SPavel Labath
8065e843c9SPavel Labath        self.server.responder = MyResponder()
8165e843c9SPavel Labath
8265e843c9SPavel Labath        target = self.createTarget("a.yaml")
8365e843c9SPavel Labath        process = self.connect(target)
8465e843c9SPavel Labath        lldbutil.expect_state_changes(self, self.dbg.GetListener(), process, [lldb.eStateConnected])
8565e843c9SPavel Labath
8665e843c9SPavel Labath        error = lldb.SBError()
8765e843c9SPavel Labath        target.Launch(lldb.SBListener(), None, None, None, None, None,
8865e843c9SPavel Labath                None, 0, True, error)
8983bea6d9SJason Molenda        self.assertEquals("'A' packet returned an error: 71", error.GetCString())
9065e843c9SPavel Labath
9199451b44SJordan Rupprecht    def test_read_registers_using_g_packets(self):
9299451b44SJordan Rupprecht        """Test reading registers using 'g' packets (default behavior)"""
9399451b44SJordan Rupprecht        self.dbg.HandleCommand(
9499451b44SJordan Rupprecht                "settings set plugin.process.gdb-remote.use-g-packet-for-reading true")
9599451b44SJordan Rupprecht        self.addTearDownHook(lambda:
9699451b44SJordan Rupprecht                self.runCmd("settings set plugin.process.gdb-remote.use-g-packet-for-reading false"))
9799451b44SJordan Rupprecht        self.server.responder = self.gPacketResponder()
9899451b44SJordan Rupprecht        target = self.createTarget("a.yaml")
9999451b44SJordan Rupprecht        process = self.connect(target)
10099451b44SJordan Rupprecht
10199451b44SJordan Rupprecht        self.assertEquals(1, self.server.responder.packetLog.count("g"))
10299451b44SJordan Rupprecht        self.server.responder.packetLog = []
10399451b44SJordan Rupprecht        self.read_registers(process)
10499451b44SJordan Rupprecht        # Reading registers should not cause any 'p' packets to be exchanged.
10599451b44SJordan Rupprecht        self.assertEquals(
10699451b44SJordan Rupprecht                0, len([p for p in self.server.responder.packetLog if p.startswith("p")]))
10799451b44SJordan Rupprecht
10899451b44SJordan Rupprecht    def test_read_registers_using_p_packets(self):
10999451b44SJordan Rupprecht        """Test reading registers using 'p' packets"""
11099451b44SJordan Rupprecht        self.dbg.HandleCommand(
11199451b44SJordan Rupprecht                "settings set plugin.process.gdb-remote.use-g-packet-for-reading false")
112270c989fSMichał Górny        self.server.responder = self.gPacketResponder()
11399451b44SJordan Rupprecht        target = self.createTarget("a.yaml")
11499451b44SJordan Rupprecht        process = self.connect(target)
11599451b44SJordan Rupprecht
11699451b44SJordan Rupprecht        self.read_registers(process)
1173cc37622SDave Lee        self.assertNotIn("g", self.server.responder.packetLog)
11899451b44SJordan Rupprecht        self.assertGreater(
11999451b44SJordan Rupprecht                len([p for p in self.server.responder.packetLog if p.startswith("p")]), 0)
12099451b44SJordan Rupprecht
12199451b44SJordan Rupprecht    def test_write_registers_using_P_packets(self):
12299451b44SJordan Rupprecht        """Test writing registers using 'P' packets (default behavior)"""
12399451b44SJordan Rupprecht        self.server.responder = self.gPacketResponder()
12499451b44SJordan Rupprecht        target = self.createTarget("a.yaml")
12599451b44SJordan Rupprecht        process = self.connect(target)
12699451b44SJordan Rupprecht
12799451b44SJordan Rupprecht        self.write_registers(process)
12899451b44SJordan Rupprecht        self.assertEquals(0, len(
12999451b44SJordan Rupprecht                [p for p in self.server.responder.packetLog if p.startswith("G")]))
13099451b44SJordan Rupprecht        self.assertGreater(
13199451b44SJordan Rupprecht                len([p for p in self.server.responder.packetLog if p.startswith("P")]), 0)
13299451b44SJordan Rupprecht
13399451b44SJordan Rupprecht    def test_write_registers_using_G_packets(self):
13499451b44SJordan Rupprecht        """Test writing registers using 'G' packets"""
13599451b44SJordan Rupprecht
13699451b44SJordan Rupprecht        class MyResponder(self.gPacketResponder):
13799451b44SJordan Rupprecht            def readRegister(self, register):
13899451b44SJordan Rupprecht                # empty string means unsupported
13999451b44SJordan Rupprecht                return ""
14099451b44SJordan Rupprecht
14199451b44SJordan Rupprecht        self.server.responder = MyResponder()
14299451b44SJordan Rupprecht        target = self.createTarget("a.yaml")
14399451b44SJordan Rupprecht        process = self.connect(target)
14499451b44SJordan Rupprecht
14599451b44SJordan Rupprecht        self.write_registers(process)
14699451b44SJordan Rupprecht        self.assertEquals(0, len(
14799451b44SJordan Rupprecht                [p for p in self.server.responder.packetLog if p.startswith("P")]))
14899451b44SJordan Rupprecht        self.assertGreater(len(
14999451b44SJordan Rupprecht                [p for p in self.server.responder.packetLog if p.startswith("G")]), 0)
15099451b44SJordan Rupprecht
15199451b44SJordan Rupprecht    def read_registers(self, process):
15299451b44SJordan Rupprecht        self.for_each_gpr(
153270c989fSMichał Górny                process, lambda r: self.assertEquals("0x0000000000000000", r.GetValue()))
15499451b44SJordan Rupprecht
15599451b44SJordan Rupprecht    def write_registers(self, process):
15699451b44SJordan Rupprecht        self.for_each_gpr(
157270c989fSMichał Górny                process, lambda r: r.SetValueFromCString("0x0000000000000000"))
15899451b44SJordan Rupprecht
15999451b44SJordan Rupprecht    def for_each_gpr(self, process, operation):
16099451b44SJordan Rupprecht        registers = process.GetThreadAtIndex(0).GetFrameAtIndex(0).GetRegisters()
16199451b44SJordan Rupprecht        self.assertGreater(registers.GetSize(), 0)
16299451b44SJordan Rupprecht        regSet = registers[0]
16399451b44SJordan Rupprecht        numChildren = regSet.GetNumChildren()
16499451b44SJordan Rupprecht        self.assertGreater(numChildren, 0)
16599451b44SJordan Rupprecht        for i in range(numChildren):
16699451b44SJordan Rupprecht            operation(regSet.GetChildAtIndex(i))
1676ba3f723SMichał Górny
1686ba3f723SMichał Górny    def test_launch_A(self):
1696ba3f723SMichał Górny        class MyResponder(MockGDBServerResponder):
1706ba3f723SMichał Górny            def __init__(self, *args, **kwargs):
1716ba3f723SMichał Górny                self.started = False
1726ba3f723SMichał Górny                return super().__init__(*args, **kwargs)
1736ba3f723SMichał Górny
1746ba3f723SMichał Górny            def qC(self):
1756ba3f723SMichał Górny                if self.started:
1766ba3f723SMichał Górny                    return "QCp10.10"
1776ba3f723SMichał Górny                else:
1786ba3f723SMichał Górny                    return "E42"
1796ba3f723SMichał Górny
1806ba3f723SMichał Górny            def qfThreadInfo(self):
1816ba3f723SMichał Górny                if self.started:
1826ba3f723SMichał Górny                    return "mp10.10"
1836ba3f723SMichał Górny                else:
1846ba3f723SMichał Górny                   return "E42"
1856ba3f723SMichał Górny
1866ba3f723SMichał Górny            def qsThreadInfo(self):
1876ba3f723SMichał Górny                return "l"
1886ba3f723SMichał Górny
1896ba3f723SMichał Górny            def A(self, packet):
1906ba3f723SMichał Górny                self.started = True
1916ba3f723SMichał Górny                return "OK"
1926ba3f723SMichał Górny
1936ba3f723SMichał Górny            def qLaunchSuccess(self):
1946ba3f723SMichał Górny                if self.started:
1956ba3f723SMichał Górny                    return "OK"
1966ba3f723SMichał Górny                return "E42"
1976ba3f723SMichał Górny
1986ba3f723SMichał Górny        self.server.responder = MyResponder()
1996ba3f723SMichał Górny
2006ba3f723SMichał Górny        target = self.createTarget("a.yaml")
201784281d3SMichał Górny        # NB: apparently GDB packets are using "/" on Windows too
202784281d3SMichał Górny        exe_path = self.getBuildArtifact("a").replace(os.path.sep, '/')
2036ba3f723SMichał Górny        exe_hex = binascii.b2a_hex(exe_path.encode()).decode()
2046ba3f723SMichał Górny        process = self.connect(target)
2056ba3f723SMichał Górny        lldbutil.expect_state_changes(self, self.dbg.GetListener(), process,
2066ba3f723SMichał Górny                                      [lldb.eStateConnected])
2076ba3f723SMichał Górny
2086ba3f723SMichał Górny        target.Launch(lldb.SBListener(),
2096ba3f723SMichał Górny                      ["arg1", "arg2", "arg3"],  # argv
2106ba3f723SMichał Górny                      [],  # envp
2116ba3f723SMichał Górny                      None,  # stdin_path
2126ba3f723SMichał Górny                      None,  # stdout_path
2136ba3f723SMichał Górny                      None,  # stderr_path
2146ba3f723SMichał Górny                      None,  # working_directory
2156ba3f723SMichał Górny                      0,  # launch_flags
2166ba3f723SMichał Górny                      True,  # stop_at_entry
2176ba3f723SMichał Górny                      lldb.SBError())  # error
2186ba3f723SMichał Górny        self.assertTrue(process, PROCESS_IS_VALID)
2196ba3f723SMichał Górny        self.assertEqual(process.GetProcessID(), 16)
2206ba3f723SMichał Górny
2216ba3f723SMichał Górny        self.assertPacketLogContains([
2226ba3f723SMichał Górny          "A%d,0,%s,8,1,61726731,8,2,61726732,8,3,61726733" % (
2236ba3f723SMichał Górny              len(exe_hex), exe_hex),
2246ba3f723SMichał Górny        ])
2256ba3f723SMichał Górny
2266ba3f723SMichał Górny    def test_launch_vRun(self):
2276ba3f723SMichał Górny        class MyResponder(MockGDBServerResponder):
2286ba3f723SMichał Górny            def __init__(self, *args, **kwargs):
2296ba3f723SMichał Górny                self.started = False
2306ba3f723SMichał Górny                return super().__init__(*args, **kwargs)
2316ba3f723SMichał Górny
2326ba3f723SMichał Górny            def qC(self):
2336ba3f723SMichał Górny                if self.started:
2346ba3f723SMichał Górny                    return "QCp10.10"
2356ba3f723SMichał Górny                else:
2366ba3f723SMichał Górny                    return "E42"
2376ba3f723SMichał Górny
2386ba3f723SMichał Górny            def qfThreadInfo(self):
2396ba3f723SMichał Górny                if self.started:
2406ba3f723SMichał Górny                    return "mp10.10"
2416ba3f723SMichał Górny                else:
2426ba3f723SMichał Górny                   return "E42"
2436ba3f723SMichał Górny
2446ba3f723SMichał Górny            def qsThreadInfo(self):
2456ba3f723SMichał Górny                return "l"
2466ba3f723SMichał Górny
2476ba3f723SMichał Górny            def vRun(self, packet):
2486ba3f723SMichał Górny                self.started = True
2496ba3f723SMichał Górny                return "T13"
2506ba3f723SMichał Górny
2516ba3f723SMichał Górny            def A(self, packet):
2526ba3f723SMichał Górny                return "E28"
2536ba3f723SMichał Górny
2546ba3f723SMichał Górny        self.server.responder = MyResponder()
2556ba3f723SMichał Górny
2566ba3f723SMichał Górny        target = self.createTarget("a.yaml")
257784281d3SMichał Górny        # NB: apparently GDB packets are using "/" on Windows too
258784281d3SMichał Górny        exe_path = self.getBuildArtifact("a").replace(os.path.sep, '/')
2596ba3f723SMichał Górny        exe_hex = binascii.b2a_hex(exe_path.encode()).decode()
2606ba3f723SMichał Górny        process = self.connect(target)
2616ba3f723SMichał Górny        lldbutil.expect_state_changes(self, self.dbg.GetListener(), process,
2626ba3f723SMichał Górny                                      [lldb.eStateConnected])
2636ba3f723SMichał Górny
2646ba3f723SMichał Górny        process = target.Launch(lldb.SBListener(),
2656ba3f723SMichał Górny                                ["arg1", "arg2", "arg3"],  # argv
2666ba3f723SMichał Górny                                [],  # envp
2676ba3f723SMichał Górny                                None,  # stdin_path
2686ba3f723SMichał Górny                                None,  # stdout_path
2696ba3f723SMichał Górny                                None,  # stderr_path
2706ba3f723SMichał Górny                                None,  # working_directory
2716ba3f723SMichał Górny                                0,  # launch_flags
2726ba3f723SMichał Górny                                True,  # stop_at_entry
2736ba3f723SMichał Górny                                lldb.SBError())  # error
2746ba3f723SMichał Górny        self.assertTrue(process, PROCESS_IS_VALID)
2756ba3f723SMichał Górny        self.assertEqual(process.GetProcessID(), 16)
2766ba3f723SMichał Górny
2776ba3f723SMichał Górny        self.assertPacketLogContains([
2786ba3f723SMichał Górny          "vRun;%s;61726731;61726732;61726733" % (exe_hex,)
2796ba3f723SMichał Górny        ])
2803fade954SMichał Górny
2813fade954SMichał Górny    def test_launch_QEnvironment(self):
2823fade954SMichał Górny        class MyResponder(MockGDBServerResponder):
2833fade954SMichał Górny            def qC(self):
2843fade954SMichał Górny                return "E42"
2853fade954SMichał Górny
2863fade954SMichał Górny            def qfThreadInfo(self):
2873fade954SMichał Górny               return "E42"
2883fade954SMichał Górny
2893fade954SMichał Górny            def vRun(self, packet):
2903fade954SMichał Górny                self.started = True
2913fade954SMichał Górny                return "E28"
2923fade954SMichał Górny
2933fade954SMichał Górny        self.server.responder = MyResponder()
2943fade954SMichał Górny
2953fade954SMichał Górny        target = self.createTarget("a.yaml")
2963fade954SMichał Górny        process = self.connect(target)
2973fade954SMichał Górny        lldbutil.expect_state_changes(self, self.dbg.GetListener(), process,
2983fade954SMichał Górny                                      [lldb.eStateConnected])
2993fade954SMichał Górny
3003fade954SMichał Górny        target.Launch(lldb.SBListener(),
3013fade954SMichał Górny                      [],  # argv
3023fade954SMichał Górny                      ["PLAIN=foo",
3033fade954SMichał Górny                       "NEEDSENC=frob$",
3043fade954SMichał Górny                       "NEEDSENC2=fr*ob",
3053fade954SMichał Górny                       "NEEDSENC3=fro}b",
3063fade954SMichał Górny                       "NEEDSENC4=f#rob",
3073fade954SMichał Górny                       "EQUALS=foo=bar",
3083fade954SMichał Górny                       ],  # envp
3093fade954SMichał Górny                      None,  # stdin_path
3103fade954SMichał Górny                      None,  # stdout_path
3113fade954SMichał Górny                      None,  # stderr_path
3123fade954SMichał Górny                      None,  # working_directory
3133fade954SMichał Górny                      0,  # launch_flags
3143fade954SMichał Górny                      True,  # stop_at_entry
3153fade954SMichał Górny                      lldb.SBError())  # error
3163fade954SMichał Górny
3173fade954SMichał Górny        self.assertPacketLogContains([
3183fade954SMichał Górny          "QEnvironment:PLAIN=foo",
3193fade954SMichał Górny          "QEnvironmentHexEncoded:4e45454453454e433d66726f6224",
3203fade954SMichał Górny          "QEnvironmentHexEncoded:4e45454453454e43323d66722a6f62",
3213fade954SMichał Górny          "QEnvironmentHexEncoded:4e45454453454e43333d66726f7d62",
3223fade954SMichał Górny          "QEnvironmentHexEncoded:4e45454453454e43343d6623726f62",
3233fade954SMichał Górny          "QEnvironment:EQUALS=foo=bar",
3243fade954SMichał Górny        ])
3253fade954SMichał Górny
3263fade954SMichał Górny    def test_launch_QEnvironmentHexEncoded_only(self):
3273fade954SMichał Górny        class MyResponder(MockGDBServerResponder):
3283fade954SMichał Górny            def qC(self):
3293fade954SMichał Górny                return "E42"
3303fade954SMichał Górny
3313fade954SMichał Górny            def qfThreadInfo(self):
3323fade954SMichał Górny               return "E42"
3333fade954SMichał Górny
3343fade954SMichał Górny            def vRun(self, packet):
3353fade954SMichał Górny                self.started = True
3363fade954SMichał Górny                return "E28"
3373fade954SMichał Górny
3383fade954SMichał Górny            def QEnvironment(self, packet):
3393fade954SMichał Górny                return ""
3403fade954SMichał Górny
3413fade954SMichał Górny        self.server.responder = MyResponder()
3423fade954SMichał Górny
3433fade954SMichał Górny        target = self.createTarget("a.yaml")
3443fade954SMichał Górny        process = self.connect(target)
3453fade954SMichał Górny        lldbutil.expect_state_changes(self, self.dbg.GetListener(), process,
3463fade954SMichał Górny                                      [lldb.eStateConnected])
3473fade954SMichał Górny
3483fade954SMichał Górny        target.Launch(lldb.SBListener(),
3493fade954SMichał Górny                      [],  # argv
3503fade954SMichał Górny                      ["PLAIN=foo",
3513fade954SMichał Górny                       "NEEDSENC=frob$",
3523fade954SMichał Górny                       "NEEDSENC2=fr*ob",
3533fade954SMichał Górny                       "NEEDSENC3=fro}b",
3543fade954SMichał Górny                       "NEEDSENC4=f#rob",
3553fade954SMichał Górny                       "EQUALS=foo=bar",
3563fade954SMichał Górny                       ],  # envp
3573fade954SMichał Górny                      None,  # stdin_path
3583fade954SMichał Górny                      None,  # stdout_path
3593fade954SMichał Górny                      None,  # stderr_path
3603fade954SMichał Górny                      None,  # working_directory
3613fade954SMichał Górny                      0,  # launch_flags
3623fade954SMichał Górny                      True,  # stop_at_entry
3633fade954SMichał Górny                      lldb.SBError())  # error
3643fade954SMichał Górny
3653fade954SMichał Górny        self.assertPacketLogContains([
3663fade954SMichał Górny          "QEnvironmentHexEncoded:504c41494e3d666f6f",
3673fade954SMichał Górny          "QEnvironmentHexEncoded:4e45454453454e433d66726f6224",
3683fade954SMichał Górny          "QEnvironmentHexEncoded:4e45454453454e43323d66722a6f62",
3693fade954SMichał Górny          "QEnvironmentHexEncoded:4e45454453454e43333d66726f7d62",
3703fade954SMichał Górny          "QEnvironmentHexEncoded:4e45454453454e43343d6623726f62",
3713fade954SMichał Górny          "QEnvironmentHexEncoded:455155414c533d666f6f3d626172",
3723fade954SMichał Górny        ])
373b1099120SMichał Górny
374b1099120SMichał Górny    def test_detach_no_multiprocess(self):
375b1099120SMichał Górny        class MyResponder(MockGDBServerResponder):
376b1099120SMichał Górny            def __init__(self):
377b1099120SMichał Górny                super().__init__()
378b1099120SMichał Górny                self.detached = None
379b1099120SMichał Górny
380b1099120SMichał Górny            def qfThreadInfo(self):
381b1099120SMichał Górny                return "10200"
382b1099120SMichał Górny
383b1099120SMichał Górny            def D(self, packet):
384b1099120SMichał Górny                self.detached = packet
385b1099120SMichał Górny                return "OK"
386b1099120SMichał Górny
387b1099120SMichał Górny        self.server.responder = MyResponder()
388b1099120SMichał Górny        target = self.dbg.CreateTarget('')
389b1099120SMichał Górny        process = self.connect(target)
390b1099120SMichał Górny        process.Detach()
391b1099120SMichał Górny        self.assertEqual(self.server.responder.detached, "D")
392b1099120SMichał Górny
393b1099120SMichał Górny    def test_detach_pid(self):
394b1099120SMichał Górny        class MyResponder(MockGDBServerResponder):
395b1099120SMichał Górny            def __init__(self, test_case):
396b1099120SMichał Górny                super().__init__()
397b1099120SMichał Górny                self.test_case = test_case
398b1099120SMichał Górny                self.detached = None
399b1099120SMichał Górny
400b1099120SMichał Górny            def qSupported(self, client_supported):
401b1099120SMichał Górny                self.test_case.assertIn("multiprocess+", client_supported)
402b1099120SMichał Górny                return "multiprocess+;" + super().qSupported(client_supported)
403b1099120SMichał Górny
404b1099120SMichał Górny            def qfThreadInfo(self):
405b1099120SMichał Górny                return "mp400.10200"
406b1099120SMichał Górny
407b1099120SMichał Górny            def D(self, packet):
408b1099120SMichał Górny                self.detached = packet
409b1099120SMichał Górny                return "OK"
410b1099120SMichał Górny
411b1099120SMichał Górny        self.server.responder = MyResponder(self)
412b1099120SMichał Górny        target = self.dbg.CreateTarget('')
413b1099120SMichał Górny        process = self.connect(target)
414b1099120SMichał Górny        process.Detach()
415b1099120SMichał Górny        self.assertRegex(self.server.responder.detached, r"D;0*400")
4163f137236SMichał Górny
4173f137236SMichał Górny    def test_signal_gdb(self):
4183f137236SMichał Górny        class MyResponder(MockGDBServerResponder):
4193f137236SMichał Górny            def qSupported(self, client_supported):
4203f137236SMichał Górny                return "PacketSize=3fff;QStartNoAckMode+"
4213f137236SMichał Górny
4223f137236SMichał Górny            def haltReason(self):
4233f137236SMichał Górny                return "S0a"
4243f137236SMichał Górny
4253f137236SMichał Górny            def cont(self):
4263f137236SMichał Górny                return self.haltReason()
4273f137236SMichał Górny
4283f137236SMichał Górny        self.server.responder = MyResponder()
4293f137236SMichał Górny
430d96656caSMichał Górny        self.runCmd("platform select remote-linux")
4313f137236SMichał Górny        target = self.createTarget("a.yaml")
4323f137236SMichał Górny        process = self.connect(target)
4333f137236SMichał Górny
4343f137236SMichał Górny        self.assertEqual(process.threads[0].GetStopReason(),
4353f137236SMichał Górny                         lldb.eStopReasonSignal)
4363f137236SMichał Górny        self.assertEqual(process.threads[0].GetStopDescription(100),
4373f137236SMichał Górny                         'signal SIGBUS')
4383f137236SMichał Górny
4393f137236SMichał Górny    def test_signal_lldb_old(self):
4403f137236SMichał Górny        class MyResponder(MockGDBServerResponder):
4413f137236SMichał Górny            def qSupported(self, client_supported):
4423f137236SMichał Górny                return "PacketSize=3fff;QStartNoAckMode+"
4433f137236SMichał Górny
4443f137236SMichał Górny            def qHostInfo(self):
4453f137236SMichał Górny                return "triple:61726d76372d756e6b6e6f776e2d6c696e75782d676e75;"
4463f137236SMichał Górny
4473f137236SMichał Górny            def QThreadSuffixSupported(self):
4483f137236SMichał Górny                return "OK"
4493f137236SMichał Górny
4503f137236SMichał Górny            def haltReason(self):
4513f137236SMichał Górny                return "S0a"
4523f137236SMichał Górny
4533f137236SMichał Górny            def cont(self):
4543f137236SMichał Górny                return self.haltReason()
4553f137236SMichał Górny
4563f137236SMichał Górny        self.server.responder = MyResponder()
4573f137236SMichał Górny
458d96656caSMichał Górny        self.runCmd("platform select remote-linux")
4593f137236SMichał Górny        target = self.createTarget("a.yaml")
4603f137236SMichał Górny        process = self.connect(target)
4613f137236SMichał Górny
4623f137236SMichał Górny        self.assertEqual(process.threads[0].GetStopReason(),
4633f137236SMichał Górny                         lldb.eStopReasonSignal)
4643f137236SMichał Górny        self.assertEqual(process.threads[0].GetStopDescription(100),
4653f137236SMichał Górny                         'signal SIGUSR1')
4663f137236SMichał Górny
4673f137236SMichał Górny    def test_signal_lldb(self):
4683f137236SMichał Górny        class MyResponder(MockGDBServerResponder):
4693f137236SMichał Górny            def qSupported(self, client_supported):
4703f137236SMichał Górny                return "PacketSize=3fff;QStartNoAckMode+;native-signals+"
4713f137236SMichał Górny
4723f137236SMichał Górny            def qHostInfo(self):
4733f137236SMichał Górny                return "triple:61726d76372d756e6b6e6f776e2d6c696e75782d676e75;"
4743f137236SMichał Górny
4753f137236SMichał Górny            def haltReason(self):
4763f137236SMichał Górny                return "S0a"
4773f137236SMichał Górny
4783f137236SMichał Górny            def cont(self):
4793f137236SMichał Górny                return self.haltReason()
4803f137236SMichał Górny
4813f137236SMichał Górny        self.server.responder = MyResponder()
4823f137236SMichał Górny
483d96656caSMichał Górny        self.runCmd("platform select remote-linux")
4843f137236SMichał Górny        target = self.createTarget("a.yaml")
4853f137236SMichał Górny        process = self.connect(target)
4863f137236SMichał Górny
4873f137236SMichał Górny        self.assertEqual(process.threads[0].GetStopReason(),
4883f137236SMichał Górny                         lldb.eStopReasonSignal)
4893f137236SMichał Górny        self.assertEqual(process.threads[0].GetStopDescription(100),
4903f137236SMichał Górny                         'signal SIGUSR1')
491ac666d17SMichał Górny
492ac666d17SMichał Górny    def do_siginfo_test(self, platform, target_yaml, raw_data, expected):
493ac666d17SMichał Górny        class MyResponder(MockGDBServerResponder):
494ac666d17SMichał Górny            def qSupported(self, client_supported):
495ac666d17SMichał Górny                return "PacketSize=3fff;QStartNoAckMode+;qXfer:siginfo:read+"
496ac666d17SMichał Górny
497ac666d17SMichał Górny            def qXferRead(self, obj, annex, offset, length):
498ac666d17SMichał Górny                if obj == "siginfo":
499ac666d17SMichał Górny                    return raw_data, False
500ac666d17SMichał Górny                else:
501ac666d17SMichał Górny                    return None, False
502ac666d17SMichał Górny
503ac666d17SMichał Górny            def haltReason(self):
504ac666d17SMichał Górny                return "T02"
505ac666d17SMichał Górny
506ac666d17SMichał Górny            def cont(self):
507ac666d17SMichał Górny                return self.haltReason()
508ac666d17SMichał Górny
509ac666d17SMichał Górny        self.server.responder = MyResponder()
510ac666d17SMichał Górny
511ac666d17SMichał Górny        self.runCmd("platform select " + platform)
512ac666d17SMichał Górny        target = self.createTarget(target_yaml)
513ac666d17SMichał Górny        process = self.connect(target)
514ac666d17SMichał Górny
515ac666d17SMichał Górny        siginfo = process.threads[0].GetSiginfo()
516*779bbbf2SDave Lee        self.assertSuccess(siginfo.GetError())
517ac666d17SMichał Górny
518ac666d17SMichał Górny        for key, value in expected.items():
519ac666d17SMichał Górny            self.assertEqual(siginfo.GetValueForExpressionPath("." + key)
520ac666d17SMichał Górny                             .GetValueAsUnsigned(),
521ac666d17SMichał Górny                             value)
522ac666d17SMichał Górny
523ac666d17SMichał Górny
524ac666d17SMichał Górny    def test_siginfo_linux_amd64(self):
525ac666d17SMichał Górny        data = (
526ac666d17SMichał Górny          # si_signo         si_errno        si_code
527ac666d17SMichał Górny            "\x11\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00"
528ac666d17SMichał Górny          # __pad0           si_pid          si_uid
529ac666d17SMichał Górny            "\x00\x00\x00\x00\xbf\xf7\x0b\x00\xe8\x03\x00\x00"
530ac666d17SMichał Górny          # si_status
531ac666d17SMichał Górny            "\x0c\x00\x00\x00" + "\x00" * 100)
532ac666d17SMichał Górny        expected = {
533ac666d17SMichał Górny            "si_signo": 17,  # SIGCHLD
534ac666d17SMichał Górny            "si_errno": 0,
535ac666d17SMichał Górny            "si_code": 1,  # CLD_EXITED
536ac666d17SMichał Górny            "_sifields._sigchld.si_pid": 784319,
537ac666d17SMichał Górny            "_sifields._sigchld.si_uid": 1000,
538ac666d17SMichał Górny            "_sifields._sigchld.si_status": 12,
539ac666d17SMichał Górny            "_sifields._sigchld.si_utime": 0,
540ac666d17SMichał Górny            "_sifields._sigchld.si_stime": 0,
541ac666d17SMichał Górny        }
542ac666d17SMichał Górny        self.do_siginfo_test("remote-linux", "basic_eh_frame.yaml",
543ac666d17SMichał Górny                             data, expected)
544ac666d17SMichał Górny
545ac666d17SMichał Górny    def test_siginfo_linux_i386(self):
546ac666d17SMichał Górny        data = (
547ac666d17SMichał Górny          # si_signo         si_errno        si_code
548ac666d17SMichał Górny            "\x11\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00"
549ac666d17SMichał Górny          # si_pid           si_uid          si_status
550ac666d17SMichał Górny            "\x49\x43\x07\x00\xe8\x03\x00\x00\x0c\x00\x00\x00"
551ac666d17SMichał Górny            + "\x00" * 104)
552ac666d17SMichał Górny        expected = {
553ac666d17SMichał Górny            "si_signo": 17,  # SIGCHLD
554ac666d17SMichał Górny            "si_errno": 0,
555ac666d17SMichał Górny            "si_code": 1,  # CLD_EXITED
556ac666d17SMichał Górny            "_sifields._sigchld.si_pid": 475977,
557ac666d17SMichał Górny            "_sifields._sigchld.si_uid": 1000,
558ac666d17SMichał Górny            "_sifields._sigchld.si_status": 12,
559ac666d17SMichał Górny            "_sifields._sigchld.si_utime": 0,
560ac666d17SMichał Górny            "_sifields._sigchld.si_stime": 0,
561ac666d17SMichał Górny        }
562ac666d17SMichał Górny        self.do_siginfo_test("remote-linux", "basic_eh_frame-i386.yaml",
563ac666d17SMichał Górny                             data, expected)
564ac666d17SMichał Górny
565ac666d17SMichał Górny    def test_siginfo_freebsd_amd64(self):
566ac666d17SMichał Górny        data = (
567ac666d17SMichał Górny          # si_signo         si_errno        si_code
568ac666d17SMichał Górny            "\x0b\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00"
569ac666d17SMichał Górny          # si_pid           si_uid          si_status
570ac666d17SMichał Górny            "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
571ac666d17SMichał Górny          # si_addr
572ac666d17SMichał Górny            "\x76\x98\xba\xdc\xfe\x00\x00\x00"
573ac666d17SMichał Górny          # si_status                        si_trapno
574ac666d17SMichał Górny            "\x00\x00\x00\x00\x00\x00\x00\x00\x0c\x00\x00\x00"
575ac666d17SMichał Górny            + "\x00" * 36)
576ac666d17SMichał Górny
577ac666d17SMichał Górny        expected = {
578ac666d17SMichał Górny            "si_signo": 11,  # SIGSEGV
579ac666d17SMichał Górny            "si_errno": 0,
580ac666d17SMichał Górny            "si_code": 1,  # SEGV_MAPERR
581ac666d17SMichał Górny            "si_addr": 0xfedcba9876,
582ac666d17SMichał Górny            "_reason._fault._trapno": 12,
583ac666d17SMichał Górny        }
584ac666d17SMichał Górny        self.do_siginfo_test("remote-freebsd", "basic_eh_frame.yaml",
585ac666d17SMichał Górny                             data, expected)
586