xref: /llvm-project/lldb/test/API/functionalities/thread/create_after_attach/TestCreateAfterAttach.py (revision 99451b4453688a94c6014cac233d371ab4cc342d)
1"""
2Test thread creation after process attach.
3"""
4
5
6
7import lldb
8from lldbsuite.test.decorators import *
9from lldbsuite.test.lldbtest import *
10from lldbsuite.test import lldbutil
11
12
13class CreateAfterAttachTestCase(TestBase):
14
15    mydir = TestBase.compute_mydir(__file__)
16
17    @skipIfFreeBSD  # Hangs.  May be the same as Linux issue llvm.org/pr16229 but
18    # not yet investigated.  Revisit once required functionality
19    # is implemented for FreeBSD.
20    # Occasionally hangs on Windows, may be same as other issues.
21    @skipIfWindows
22    @skipIfiOSSimulator
23    @expectedFailureNetBSD
24    def test_create_after_attach_with_popen(self):
25        """Test thread creation after process attach."""
26        self.build(dictionary=self.getBuildFlags(use_cpp11=False))
27        self.create_after_attach(use_fork=False)
28
29    @skipIfFreeBSD  # Hangs. Revisit once required functionality is implemented
30    # for FreeBSD.
31    @skipIfRemote
32    @skipIfWindows  # Windows doesn't have fork.
33    @skipIfiOSSimulator
34    @expectedFailureNetBSD
35    def test_create_after_attach_with_fork(self):
36        """Test thread creation after process attach."""
37        self.build(dictionary=self.getBuildFlags(use_cpp11=False))
38        self.create_after_attach(use_fork=True)
39
40    def setUp(self):
41        # Call super's setUp().
42        TestBase.setUp(self)
43        # Find the line numbers for our breakpoints.
44        self.break_1 = line_number('main.cpp', '// Set first breakpoint here')
45        self.break_2 = line_number('main.cpp', '// Set second breakpoint here')
46        self.break_3 = line_number('main.cpp', '// Set third breakpoint here')
47
48    def create_after_attach(self, use_fork):
49        """Test thread creation after process attach."""
50
51        exe = self.getBuildArtifact("a.out")
52
53        # Spawn a new process
54        if use_fork:
55            pid = self.forkSubprocess(exe)
56        else:
57            popen = self.spawnSubprocess(exe)
58            pid = popen.pid
59        self.addTearDownHook(self.cleanupSubprocesses)
60
61        # Attach to the spawned process
62        self.runCmd("process attach -p " + str(pid))
63
64        target = self.dbg.GetSelectedTarget()
65
66        process = target.GetProcess()
67        self.assertTrue(process, PROCESS_IS_VALID)
68
69        # This should create a breakpoint in the main thread.
70        lldbutil.run_break_set_by_file_and_line(
71            self, "main.cpp", self.break_1, num_expected_locations=1)
72
73        # This should create a breakpoint in the second child thread.
74        lldbutil.run_break_set_by_file_and_line(
75            self, "main.cpp", self.break_2, num_expected_locations=1)
76
77        # This should create a breakpoint in the first child thread.
78        lldbutil.run_break_set_by_file_and_line(
79            self, "main.cpp", self.break_3, num_expected_locations=1)
80
81        # Note:  With std::thread, we cannot rely on particular thread numbers.  Using
82        # std::thread may cause the program to spin up a thread pool (and it does on
83        # Windows), so the thread numbers are non-deterministic.
84
85        # Run to the first breakpoint
86        self.runCmd("continue")
87
88        # The stop reason of the thread should be breakpoint.
89        self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
90                    substrs=['stopped',
91                             '* thread #',
92                             'main',
93                             'stop reason = breakpoint'])
94
95        # Change a variable to escape the loop
96        self.runCmd("expression main_thread_continue = 1")
97
98        # Run to the second breakpoint
99        self.runCmd("continue")
100
101        # The stop reason of the thread should be breakpoint.
102        self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
103                    substrs=['stopped',
104                             '* thread #',
105                             'thread_2_func',
106                             'stop reason = breakpoint'])
107
108        # Change a variable to escape the loop
109        self.runCmd("expression child_thread_continue = 1")
110
111        # Run to the third breakpoint
112        self.runCmd("continue")
113
114        # The stop reason of the thread should be breakpoint.
115        # Thread 3 may or may not have already exited.
116        self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
117                    substrs=['stopped',
118                             '* thread #',
119                             'thread_1_func',
120                             'stop reason = breakpoint'])
121
122        # Run to completion
123        self.runCmd("continue")
124
125        # At this point, the inferior process should have exited.
126        self.assertTrue(
127            process.GetState() == lldb.eStateExited,
128            PROCESS_EXITED)
129