199451b44SJordan Rupprecht"""
299451b44SJordan RupprechtTest SBThread APIs.
399451b44SJordan Rupprecht"""
499451b44SJordan Rupprecht
599451b44SJordan Rupprechtfrom __future__ import print_function
699451b44SJordan Rupprecht
799451b44SJordan Rupprecht
899451b44SJordan Rupprechtimport lldb
999451b44SJordan Rupprechtfrom lldbsuite.test.decorators import *
1099451b44SJordan Rupprechtfrom lldbsuite.test.lldbtest import *
1199451b44SJordan Rupprechtfrom lldbsuite.test import lldbutil
1299451b44SJordan Rupprechtfrom lldbsuite.test.lldbutil import get_stopped_thread, get_caller_symbol
1399451b44SJordan Rupprecht
1499451b44SJordan Rupprecht
1599451b44SJordan Rupprechtclass ThreadAPITestCase(TestBase):
1699451b44SJordan Rupprecht
1799451b44SJordan Rupprecht    mydir = TestBase.compute_mydir(__file__)
1899451b44SJordan Rupprecht
1999451b44SJordan Rupprecht    @add_test_categories(['pyapi'])
2099451b44SJordan Rupprecht    def test_get_process(self):
2199451b44SJordan Rupprecht        """Test Python SBThread.GetProcess() API."""
2299451b44SJordan Rupprecht        self.build()
2399451b44SJordan Rupprecht        self.get_process()
2499451b44SJordan Rupprecht
2599451b44SJordan Rupprecht    @add_test_categories(['pyapi'])
2699451b44SJordan Rupprecht    def test_get_stop_description(self):
2799451b44SJordan Rupprecht        """Test Python SBThread.GetStopDescription() API."""
2899451b44SJordan Rupprecht        self.build()
2999451b44SJordan Rupprecht        self.get_stop_description()
3099451b44SJordan Rupprecht
3199451b44SJordan Rupprecht    @add_test_categories(['pyapi'])
3299451b44SJordan Rupprecht    def test_run_to_address(self):
3399451b44SJordan Rupprecht        """Test Python SBThread.RunToAddress() API."""
3499451b44SJordan Rupprecht        # We build a different executable than the default build() does.
3599451b44SJordan Rupprecht        d = {'CXX_SOURCES': 'main2.cpp', 'EXE': self.exe_name}
3699451b44SJordan Rupprecht        self.build(dictionary=d)
3799451b44SJordan Rupprecht        self.setTearDownCleanup(dictionary=d)
3899451b44SJordan Rupprecht        self.run_to_address(self.exe_name)
3999451b44SJordan Rupprecht
4099451b44SJordan Rupprecht    @add_test_categories(['pyapi'])
4199451b44SJordan Rupprecht    @expectedFailureAll(oslist=['freebsd'], bugnumber='llvm.org/pr20476')
4299451b44SJordan Rupprecht    @expectedFailureAll(oslist=["windows"])
4399451b44SJordan Rupprecht    @expectedFailureNetBSD
4499451b44SJordan Rupprecht    def test_step_out_of_malloc_into_function_b(self):
4599451b44SJordan Rupprecht        """Test Python SBThread.StepOut() API to step out of a malloc call where the call site is at function b()."""
4699451b44SJordan Rupprecht        # We build a different executable than the default build() does.
4799451b44SJordan Rupprecht        d = {'CXX_SOURCES': 'main2.cpp', 'EXE': self.exe_name}
4899451b44SJordan Rupprecht        self.build(dictionary=d)
4999451b44SJordan Rupprecht        self.setTearDownCleanup(dictionary=d)
5099451b44SJordan Rupprecht        self.step_out_of_malloc_into_function_b(self.exe_name)
5199451b44SJordan Rupprecht
5299451b44SJordan Rupprecht    @add_test_categories(['pyapi'])
5399451b44SJordan Rupprecht    def test_step_over_3_times(self):
5499451b44SJordan Rupprecht        """Test Python SBThread.StepOver() API."""
5599451b44SJordan Rupprecht        # We build a different executable than the default build() does.
5699451b44SJordan Rupprecht        d = {'CXX_SOURCES': 'main2.cpp', 'EXE': self.exe_name}
5799451b44SJordan Rupprecht        self.build(dictionary=d)
5899451b44SJordan Rupprecht        self.setTearDownCleanup(dictionary=d)
5999451b44SJordan Rupprecht        self.step_over_3_times(self.exe_name)
6099451b44SJordan Rupprecht
6199451b44SJordan Rupprecht    def setUp(self):
6299451b44SJordan Rupprecht        # Call super's setUp().
6399451b44SJordan Rupprecht        TestBase.setUp(self)
6499451b44SJordan Rupprecht        # Find the line number within main.cpp to break inside main().
6599451b44SJordan Rupprecht        self.break_line = line_number(
6699451b44SJordan Rupprecht            "main.cpp", "// Set break point at this line and check variable 'my_char'.")
6799451b44SJordan Rupprecht        # Find the line numbers within main2.cpp for
6899451b44SJordan Rupprecht        # step_out_of_malloc_into_function_b() and step_over_3_times().
6999451b44SJordan Rupprecht        self.step_out_of_malloc = line_number(
7099451b44SJordan Rupprecht            "main2.cpp", "// thread step-out of malloc into function b.")
7199451b44SJordan Rupprecht        self.after_3_step_overs = line_number(
7299451b44SJordan Rupprecht            "main2.cpp", "// we should reach here after 3 step-over's.")
7399451b44SJordan Rupprecht
7499451b44SJordan Rupprecht        # We'll use the test method name as the exe_name for executable
75*e9264b74SKazuaki Ishizaki        # compiled from main2.cpp.
7699451b44SJordan Rupprecht        self.exe_name = self.testMethodName
7799451b44SJordan Rupprecht
7899451b44SJordan Rupprecht    def get_process(self):
7999451b44SJordan Rupprecht        """Test Python SBThread.GetProcess() API."""
8099451b44SJordan Rupprecht        exe = self.getBuildArtifact("a.out")
8199451b44SJordan Rupprecht
8299451b44SJordan Rupprecht        target = self.dbg.CreateTarget(exe)
8399451b44SJordan Rupprecht        self.assertTrue(target, VALID_TARGET)
8499451b44SJordan Rupprecht
8599451b44SJordan Rupprecht        breakpoint = target.BreakpointCreateByLocation(
8699451b44SJordan Rupprecht            "main.cpp", self.break_line)
8799451b44SJordan Rupprecht        self.assertTrue(breakpoint, VALID_BREAKPOINT)
8899451b44SJordan Rupprecht        self.runCmd("breakpoint list")
8999451b44SJordan Rupprecht
9099451b44SJordan Rupprecht        # Launch the process, and do not stop at the entry point.
9199451b44SJordan Rupprecht        process = target.LaunchSimple(
9299451b44SJordan Rupprecht            None, None, self.get_process_working_directory())
9399451b44SJordan Rupprecht
9499451b44SJordan Rupprecht        thread = get_stopped_thread(process, lldb.eStopReasonBreakpoint)
9599451b44SJordan Rupprecht        self.assertTrue(
9699451b44SJordan Rupprecht            thread.IsValid(),
9799451b44SJordan Rupprecht            "There should be a thread stopped due to breakpoint")
9899451b44SJordan Rupprecht        self.runCmd("process status")
9999451b44SJordan Rupprecht
10099451b44SJordan Rupprecht        proc_of_thread = thread.GetProcess()
10199451b44SJordan Rupprecht        #print("proc_of_thread:", proc_of_thread)
10299451b44SJordan Rupprecht        self.assertTrue(proc_of_thread.GetProcessID()
10399451b44SJordan Rupprecht                        == process.GetProcessID())
10499451b44SJordan Rupprecht
10599451b44SJordan Rupprecht    def get_stop_description(self):
10699451b44SJordan Rupprecht        """Test Python SBThread.GetStopDescription() API."""
10799451b44SJordan Rupprecht        exe = self.getBuildArtifact("a.out")
10899451b44SJordan Rupprecht
10999451b44SJordan Rupprecht        target = self.dbg.CreateTarget(exe)
11099451b44SJordan Rupprecht        self.assertTrue(target, VALID_TARGET)
11199451b44SJordan Rupprecht
11299451b44SJordan Rupprecht        breakpoint = target.BreakpointCreateByLocation(
11399451b44SJordan Rupprecht            "main.cpp", self.break_line)
11499451b44SJordan Rupprecht        self.assertTrue(breakpoint, VALID_BREAKPOINT)
11599451b44SJordan Rupprecht        #self.runCmd("breakpoint list")
11699451b44SJordan Rupprecht
11799451b44SJordan Rupprecht        # Launch the process, and do not stop at the entry point.
11899451b44SJordan Rupprecht        process = target.LaunchSimple(
11999451b44SJordan Rupprecht            None, None, self.get_process_working_directory())
12099451b44SJordan Rupprecht
12199451b44SJordan Rupprecht        thread = get_stopped_thread(process, lldb.eStopReasonBreakpoint)
12299451b44SJordan Rupprecht        self.assertTrue(
12399451b44SJordan Rupprecht            thread.IsValid(),
12499451b44SJordan Rupprecht            "There should be a thread stopped due to breakpoint")
12599451b44SJordan Rupprecht
12699451b44SJordan Rupprecht        # Get the stop reason. GetStopDescription expects that we pass in the size of the description
12799451b44SJordan Rupprecht        # we expect plus an additional byte for the null terminator.
12899451b44SJordan Rupprecht
12999451b44SJordan Rupprecht        # Test with a buffer that is exactly as large as the expected stop reason.
13099451b44SJordan Rupprecht        self.assertEqual("breakpoint 1.1", thread.GetStopDescription(len('breakpoint 1.1') + 1))
13199451b44SJordan Rupprecht
13299451b44SJordan Rupprecht        # Test some smaller buffer sizes.
13399451b44SJordan Rupprecht        self.assertEqual("breakpoint", thread.GetStopDescription(len('breakpoint') + 1))
13499451b44SJordan Rupprecht        self.assertEqual("break", thread.GetStopDescription(len('break') + 1))
13599451b44SJordan Rupprecht        self.assertEqual("b", thread.GetStopDescription(len('b') + 1))
13699451b44SJordan Rupprecht
13799451b44SJordan Rupprecht        # Test that we can pass in a much larger size and still get the right output.
13899451b44SJordan Rupprecht        self.assertEqual("breakpoint 1.1", thread.GetStopDescription(len('breakpoint 1.1') + 100))
13999451b44SJordan Rupprecht
14099451b44SJordan Rupprecht    def step_out_of_malloc_into_function_b(self, exe_name):
14199451b44SJordan Rupprecht        """Test Python SBThread.StepOut() API to step out of a malloc call where the call site is at function b()."""
14299451b44SJordan Rupprecht        exe = self.getBuildArtifact(exe_name)
14399451b44SJordan Rupprecht
14499451b44SJordan Rupprecht        target = self.dbg.CreateTarget(exe)
14599451b44SJordan Rupprecht        self.assertTrue(target, VALID_TARGET)
14699451b44SJordan Rupprecht
14799451b44SJordan Rupprecht        breakpoint = target.BreakpointCreateByName('malloc')
14899451b44SJordan Rupprecht        self.assertTrue(breakpoint, VALID_BREAKPOINT)
14999451b44SJordan Rupprecht
15099451b44SJordan Rupprecht        # Launch the process, and do not stop at the entry point.
15199451b44SJordan Rupprecht        process = target.LaunchSimple(
15299451b44SJordan Rupprecht            None, None, self.get_process_working_directory())
15399451b44SJordan Rupprecht
15499451b44SJordan Rupprecht        while True:
15599451b44SJordan Rupprecht            thread = get_stopped_thread(process, lldb.eStopReasonBreakpoint)
15699451b44SJordan Rupprecht            self.assertTrue(
15799451b44SJordan Rupprecht                thread.IsValid(),
15899451b44SJordan Rupprecht                "There should be a thread stopped due to breakpoint")
15999451b44SJordan Rupprecht            caller_symbol = get_caller_symbol(thread)
16099451b44SJordan Rupprecht            if not caller_symbol:
16199451b44SJordan Rupprecht                self.fail(
16299451b44SJordan Rupprecht                    "Test failed: could not locate the caller symbol of malloc")
16399451b44SJordan Rupprecht
16499451b44SJordan Rupprecht            # Our top frame may be an inlined function in malloc() (e.g., on
16599451b44SJordan Rupprecht            # FreeBSD).  Apply a simple heuristic of stepping out until we find
16699451b44SJordan Rupprecht            # a non-malloc caller
16799451b44SJordan Rupprecht            while caller_symbol.startswith("malloc"):
16899451b44SJordan Rupprecht                thread.StepOut()
16999451b44SJordan Rupprecht                self.assertTrue(thread.IsValid(),
17099451b44SJordan Rupprecht                                "Thread valid after stepping to outer malloc")
17199451b44SJordan Rupprecht                caller_symbol = get_caller_symbol(thread)
17299451b44SJordan Rupprecht
17399451b44SJordan Rupprecht            if caller_symbol == "b(int)":
17499451b44SJordan Rupprecht                break
17599451b44SJordan Rupprecht            process.Continue()
17699451b44SJordan Rupprecht
17799451b44SJordan Rupprecht        # On Linux malloc calls itself in some case. Remove the breakpoint because we don't want
17899451b44SJordan Rupprecht        # to hit it during step-out.
17999451b44SJordan Rupprecht        target.BreakpointDelete(breakpoint.GetID())
18099451b44SJordan Rupprecht
18199451b44SJordan Rupprecht        thread.StepOut()
18299451b44SJordan Rupprecht        self.runCmd("thread backtrace")
18399451b44SJordan Rupprecht        self.assertTrue(
18499451b44SJordan Rupprecht            thread.GetFrameAtIndex(0).GetLineEntry().GetLine() == self.step_out_of_malloc,
18599451b44SJordan Rupprecht            "step out of malloc into function b is successful")
18699451b44SJordan Rupprecht
18799451b44SJordan Rupprecht    def step_over_3_times(self, exe_name):
18899451b44SJordan Rupprecht        """Test Python SBThread.StepOver() API."""
18999451b44SJordan Rupprecht        exe = self.getBuildArtifact(exe_name)
19099451b44SJordan Rupprecht
19199451b44SJordan Rupprecht        target = self.dbg.CreateTarget(exe)
19299451b44SJordan Rupprecht        self.assertTrue(target, VALID_TARGET)
19399451b44SJordan Rupprecht
19499451b44SJordan Rupprecht        breakpoint = target.BreakpointCreateByLocation(
19599451b44SJordan Rupprecht            'main2.cpp', self.step_out_of_malloc)
19699451b44SJordan Rupprecht        self.assertTrue(breakpoint, VALID_BREAKPOINT)
19799451b44SJordan Rupprecht        self.runCmd("breakpoint list")
19899451b44SJordan Rupprecht
19999451b44SJordan Rupprecht        # Launch the process, and do not stop at the entry point.
20099451b44SJordan Rupprecht        process = target.LaunchSimple(
20199451b44SJordan Rupprecht            None, None, self.get_process_working_directory())
20299451b44SJordan Rupprecht
20399451b44SJordan Rupprecht        self.assertTrue(process, PROCESS_IS_VALID)
20499451b44SJordan Rupprecht
20599451b44SJordan Rupprecht        # Frame #0 should be on self.step_out_of_malloc.
20699451b44SJordan Rupprecht        self.assertTrue(process.GetState() == lldb.eStateStopped)
20799451b44SJordan Rupprecht        thread = get_stopped_thread(process, lldb.eStopReasonBreakpoint)
20899451b44SJordan Rupprecht        self.assertTrue(
20999451b44SJordan Rupprecht            thread.IsValid(),
21099451b44SJordan Rupprecht            "There should be a thread stopped due to breakpoint condition")
21199451b44SJordan Rupprecht        self.runCmd("thread backtrace")
21299451b44SJordan Rupprecht        frame0 = thread.GetFrameAtIndex(0)
21399451b44SJordan Rupprecht        lineEntry = frame0.GetLineEntry()
21499451b44SJordan Rupprecht        self.assertTrue(lineEntry.GetLine() == self.step_out_of_malloc)
21599451b44SJordan Rupprecht
21699451b44SJordan Rupprecht        thread.StepOver()
21799451b44SJordan Rupprecht        thread.StepOver()
21899451b44SJordan Rupprecht        thread.StepOver()
21999451b44SJordan Rupprecht        self.runCmd("thread backtrace")
22099451b44SJordan Rupprecht
22199451b44SJordan Rupprecht        # Verify that we are stopped at the correct source line number in
22299451b44SJordan Rupprecht        # main2.cpp.
22399451b44SJordan Rupprecht        frame0 = thread.GetFrameAtIndex(0)
22499451b44SJordan Rupprecht        lineEntry = frame0.GetLineEntry()
22599451b44SJordan Rupprecht        self.assertTrue(thread.GetStopReason() == lldb.eStopReasonPlanComplete)
22699451b44SJordan Rupprecht        # Expected failure with clang as the compiler.
22799451b44SJordan Rupprecht        # rdar://problem/9223880
22899451b44SJordan Rupprecht        #
22999451b44SJordan Rupprecht        # Which has been fixed on the lldb by compensating for inaccurate line
23099451b44SJordan Rupprecht        # table information with r140416.
23199451b44SJordan Rupprecht        self.assertTrue(lineEntry.GetLine() == self.after_3_step_overs)
23299451b44SJordan Rupprecht
23399451b44SJordan Rupprecht    def run_to_address(self, exe_name):
23499451b44SJordan Rupprecht        """Test Python SBThread.RunToAddress() API."""
23599451b44SJordan Rupprecht        exe = self.getBuildArtifact(exe_name)
23699451b44SJordan Rupprecht
23799451b44SJordan Rupprecht        target = self.dbg.CreateTarget(exe)
23899451b44SJordan Rupprecht        self.assertTrue(target, VALID_TARGET)
23999451b44SJordan Rupprecht
24099451b44SJordan Rupprecht        breakpoint = target.BreakpointCreateByLocation(
24199451b44SJordan Rupprecht            'main2.cpp', self.step_out_of_malloc)
24299451b44SJordan Rupprecht        self.assertTrue(breakpoint, VALID_BREAKPOINT)
24399451b44SJordan Rupprecht        self.runCmd("breakpoint list")
24499451b44SJordan Rupprecht
24599451b44SJordan Rupprecht        # Launch the process, and do not stop at the entry point.
24699451b44SJordan Rupprecht        process = target.LaunchSimple(
24799451b44SJordan Rupprecht            None, None, self.get_process_working_directory())
24899451b44SJordan Rupprecht
24999451b44SJordan Rupprecht        self.assertTrue(process, PROCESS_IS_VALID)
25099451b44SJordan Rupprecht
25199451b44SJordan Rupprecht        # Frame #0 should be on self.step_out_of_malloc.
25299451b44SJordan Rupprecht        self.assertTrue(process.GetState() == lldb.eStateStopped)
25399451b44SJordan Rupprecht        thread = get_stopped_thread(process, lldb.eStopReasonBreakpoint)
25499451b44SJordan Rupprecht        self.assertTrue(
25599451b44SJordan Rupprecht            thread.IsValid(),
25699451b44SJordan Rupprecht            "There should be a thread stopped due to breakpoint condition")
25799451b44SJordan Rupprecht        self.runCmd("thread backtrace")
25899451b44SJordan Rupprecht        frame0 = thread.GetFrameAtIndex(0)
25999451b44SJordan Rupprecht        lineEntry = frame0.GetLineEntry()
26099451b44SJordan Rupprecht        self.assertTrue(lineEntry.GetLine() == self.step_out_of_malloc)
26199451b44SJordan Rupprecht
26299451b44SJordan Rupprecht        # Get the start/end addresses for this line entry.
26399451b44SJordan Rupprecht        start_addr = lineEntry.GetStartAddress().GetLoadAddress(target)
26499451b44SJordan Rupprecht        end_addr = lineEntry.GetEndAddress().GetLoadAddress(target)
26599451b44SJordan Rupprecht        if self.TraceOn():
26699451b44SJordan Rupprecht            print("start addr:", hex(start_addr))
26799451b44SJordan Rupprecht            print("end addr:", hex(end_addr))
26899451b44SJordan Rupprecht
26999451b44SJordan Rupprecht        # Disable the breakpoint.
27099451b44SJordan Rupprecht        self.assertTrue(target.DisableAllBreakpoints())
27199451b44SJordan Rupprecht        self.runCmd("breakpoint list")
27299451b44SJordan Rupprecht
27399451b44SJordan Rupprecht        thread.StepOver()
27499451b44SJordan Rupprecht        thread.StepOver()
27599451b44SJordan Rupprecht        thread.StepOver()
27699451b44SJordan Rupprecht        self.runCmd("thread backtrace")
27799451b44SJordan Rupprecht
27899451b44SJordan Rupprecht        # Now ask SBThread to run to the address 'start_addr' we got earlier, which
27999451b44SJordan Rupprecht        # corresponds to self.step_out_of_malloc line entry's start address.
28099451b44SJordan Rupprecht        thread.RunToAddress(start_addr)
28199451b44SJordan Rupprecht        self.runCmd("process status")
28299451b44SJordan Rupprecht        #self.runCmd("thread backtrace")
283