xref: /llvm-project/lldb/test/API/functionalities/gdb_remote_client/TestGDBRemoteClient.py (revision 7dbbd2b251412b7b0809aabe672f3f57f0805dbb)
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