1
2import os
3from time import sleep
4
5import gdbremote_testcase
6import lldbgdbserverutils
7from lldbsuite.test.decorators import *
8from lldbsuite.test.lldbtest import *
9from lldbsuite.test import lldbutil
10
11
12class TestGdbRemoteAttachWait(gdbremote_testcase.GdbRemoteTestCaseBase):
13
14    @skipIfWindows # This test is flaky on Windows
15    def test_attach_with_vAttachWait(self):
16        exe = '%s_%d' % (self.testMethodName, os.getpid())
17        exe_to_attach = exe
18        sync_file_path = lldbutil.append_to_process_working_directory(self, "process_ready")
19        args = [sync_file_path]
20
21        def launch_inferior():
22            inferior = self.launch_process_for_attach(
23                inferior_args=args,
24                exe_path=self.getBuildArtifact(exe))
25            self.assertIsNotNone(inferior)
26            self.assertTrue(inferior.pid > 0)
27            self.assertTrue(
28                lldbgdbserverutils.process_is_running(
29                    inferior.pid, True))
30            return inferior
31
32        self.build(dictionary={'EXE': exe, 'CXX_SOURCES': 'main.cpp'})
33        if self.getPlatform() != "windows":
34            # Use a shim to ensure that the process is ready to be attached from
35            # the get-go.
36            args = [self.getBuildArtifact(exe)] + args
37            exe = "shim"
38            self.build(dictionary={'EXE': exe, 'CXX_SOURCES': 'shim.cpp'})
39
40        self.set_inferior_startup_attach_manually()
41
42        server = self.connect_to_debug_monitor()
43        self.assertIsNotNone(server)
44
45        # Launch the first inferior (we shouldn't attach to this one).
46        launch_inferior()
47
48        lldbutil.wait_for_file_on_target(self, sync_file_path)
49
50        self.do_handshake()
51        self.test_sequence.add_log_lines([
52            # Do the attach.
53            "read packet: $vAttachWait;{}#00".format(
54                lldbgdbserverutils.gdbremote_hex_encode_string(exe_to_attach)),
55        ], True)
56        # Run the stream until attachWait.
57        context = self.expect_gdbremote_sequence()
58        self.assertIsNotNone(context)
59
60        # Sleep so we're sure that the inferior is launched after we ask for the attach.
61        sleep(1)
62
63        # Launch the second inferior (we SHOULD attach to this one).
64        inferior_to_attach = launch_inferior()
65
66        # Make sure the attach succeeded.
67        self.test_sequence.add_log_lines([
68            {"direction": "send",
69             "regex": r"^\$T([0-9a-fA-F]{2})[^#]*#[0-9a-fA-F]{2}$",
70             "capture": {1: "stop_signal_hex"}},
71        ], True)
72        self.add_process_info_collection_packets()
73
74
75        # Run the stream sending the response..
76        context = self.expect_gdbremote_sequence()
77        self.assertIsNotNone(context)
78
79        # Gather process info response.
80        process_info = self.parse_process_info_response(context)
81        self.assertIsNotNone(process_info)
82
83        # Ensure the process id matches what we expected.
84        pid_text = process_info.get('pid', None)
85        self.assertIsNotNone(pid_text)
86        reported_pid = int(pid_text, base=16)
87        self.assertEqual(reported_pid, inferior_to_attach.pid)
88