aboutsummaryrefslogtreecommitdiff
path: root/test/functionalities/thread/step_out/TestThreadStepOut.py
blob: 12cbd806c250b53d36ce37813d543161d363b9b7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
"""
Test stepping out from a function in a multi-threaded program.
"""

import os, time
import unittest2
import lldb
from lldbtest import *
import lldbutil

class ThreadStepOutTestCase(TestBase):

    mydir = os.path.join("functionalities", "thread", "step_out")

    @dsym_test
    def test_step_single_thread_with_dsym(self):
        """Test thread step out on one thread via command interpreter. """
        self.buildDsym(dictionary=self.getBuildFlags())
        self.step_out_test(self.step_out_single_thread_with_cmd)

    @expectedFailureFreeBSD("llvm.org/pr16696") # threaded inferior not yet implemented on FreeBSD
    @dwarf_test
    def test_step_single_thread_with_dwarf(self):
        """Test thread step out on one thread via command interpreter. """
        self.buildDwarf(dictionary=self.getBuildFlags())
        self.step_out_test(self.step_out_single_thread_with_cmd)

    @dsym_test
    def test_step_all_threads_with_dsym(self):
        """Test thread step out on all threads via command interpreter. """
        self.buildDsym(dictionary=self.getBuildFlags())
        self.step_out_test(self.step_out_all_threads_with_cmd)

    @expectedFailureFreeBSD("llvm.org/pr16696") # threaded inferior not yet implemented on FreeBSD
    @dwarf_test
    def test_step_all_threads_with_dwarf(self):
        """Test thread step out on all threads via command interpreter. """
        self.buildDwarf(dictionary=self.getBuildFlags())
        self.step_out_test(self.step_out_all_threads_with_cmd)

    @dsym_test
    def test_python_with_dsym(self):
        """Test thread step out on one threads via Python API (dsym)."""
        self.buildDsym(dictionary=self.getBuildFlags())
        self.step_out_test(self.step_out_with_python)

    @expectedFailureFreeBSD("llvm.org/pr16696") # threaded inferior not yet implemented on FreeBSD
    @dwarf_test
    def test_python_with_dwarf(self):
        """Test thread step out on one thread via Python API (dwarf)."""
        self.buildDwarf(dictionary=self.getBuildFlags())
        self.step_out_test(self.step_out_with_python)

    def setUp(self):
        # Call super's setUp().
        TestBase.setUp(self)
        # Find the line number for our breakpoint.
        self.breakpoint = line_number('main.cpp', '// Set breakpoint here')
        if "gcc" in self.getCompiler() or self.isIntelCompiler(): 
            self.step_out_destination = line_number('main.cpp', '// Expect to stop here after step-out (icc and gcc)')
        else:
            self.step_out_destination = line_number('main.cpp', '// Expect to stop here after step-out (clang)')

    def step_out_single_thread_with_cmd(self):
        self.step_out_with_cmd("this-thread")
        self.expect("thread backtrace all", "Thread location after step out is correct",
            substrs = ["main.cpp:%d" % self.step_out_destination,
                       "main.cpp:%d" % self.breakpoint])

    def step_out_all_threads_with_cmd(self):
        self.step_out_with_cmd("all-threads")
        self.expect("thread backtrace all", "Thread location after step out is correct",
            substrs = ["main.cpp:%d" % self.step_out_destination])

    def step_out_with_cmd(self, run_mode):
        self.runCmd("thread select %d" % self.step_out_thread.GetIndexID())
        self.runCmd("thread step-out -m %s" % run_mode)
        self.expect("process status", "Expected stop reason to be step-out",
            substrs = ["stop reason = step out"])

        self.expect("thread list", "Selected thread did not change during step-out",
            substrs = ["* thread #%d" % self.step_out_thread.GetIndexID()])

    def step_out_with_python(self):
        self.step_out_thread.StepOut()

        reason = self.step_out_thread.GetStopReason()
        self.assertEqual(lldb.eStopReasonPlanComplete, reason,
            "Expected thread stop reason 'plancomplete', but got '%s'" % lldbutil.stop_reason_to_str(reason))

        # Verify location after stepping out
        frame = self.step_out_thread.GetFrameAtIndex(0)
        desc = lldbutil.get_description(frame.GetLineEntry())
        expect = "main.cpp:%d" % self.step_out_destination
        self.assertTrue(expect in desc, "Expected %s but thread stopped at %s" % (expect, desc))

    def step_out_test(self, step_out_func):
        """Test single thread step out of a function."""
        exe = os.path.join(os.getcwd(), "a.out")
        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)

        # This should create a breakpoint in the main thread.
        lldbutil.run_break_set_by_file_and_line (self, "main.cpp", self.breakpoint, num_expected_locations=1)

        # The breakpoint list should show 1 location.
        self.expect("breakpoint list -f", "Breakpoint location shown correctly",
            substrs = ["1: file = 'main.cpp', line = %d, locations = 1" % self.breakpoint])

        # Run the program.
        self.runCmd("run", RUN_SUCCEEDED)

        # Get the target process
        self.inferior_target = self.dbg.GetSelectedTarget()
        self.inferior_process = self.inferior_target.GetProcess()

        # Get the number of threads, ensure we see all three.
        num_threads = self.inferior_process.GetNumThreads()
        self.assertEqual(num_threads, 3, 'Number of expected threads and actual threads do not match.')

        (breakpoint_threads, other_threads) = ([], [])
        lldbutil.sort_stopped_threads(self.inferior_process,
                                      breakpoint_threads=breakpoint_threads,
                                      other_threads=other_threads)

        while len(breakpoint_threads) < 2:
            self.runCmd("thread continue %s" % " ".join([str(x.GetIndexID()) for x in other_threads]))
            lldbutil.sort_stopped_threads(self.inferior_process,
                                          breakpoint_threads=breakpoint_threads,
                                          other_threads=other_threads)

        self.step_out_thread = breakpoint_threads[0]

        # Step out of thread stopped at breakpoint
        step_out_func()

        # Run to completion
        self.runCmd("continue")

        # At this point, the inferior process should have exited.
        self.assertTrue(self.inferior_process.GetState() == lldb.eStateExited, PROCESS_EXITED)

if __name__ == '__main__':
    import atexit
    lldb.SBDebugger.Initialize()
    atexit.register(lambda: lldb.SBDebugger.Terminate())
    unittest2.main()