Home | History | Annotate | Download | only in thread
      1 """
      2 Test SBThread APIs.
      3 """
      4 
      5 import os, time
      6 import unittest2
      7 import lldb
      8 from lldbutil import get_stopped_thread, get_caller_symbol
      9 from lldbtest import *
     10 
     11 class ThreadAPITestCase(TestBase):
     12 
     13     mydir = os.path.join("python_api", "thread")
     14 
     15     @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
     16     @python_api_test
     17     @dsym_test
     18     def test_get_process_with_dsym(self):
     19         """Test Python SBThread.GetProcess() API."""
     20         self.buildDsym()
     21         self.get_process()
     22 
     23     @python_api_test
     24     @dwarf_test
     25     def test_get_process_with_dwarf(self):
     26         """Test Python SBThread.GetProcess() API."""
     27         self.buildDwarf()
     28         self.get_process()
     29 
     30     @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
     31     @python_api_test
     32     @dsym_test
     33     def test_get_stop_description_with_dsym(self):
     34         """Test Python SBThread.GetStopDescription() API."""
     35         self.buildDsym()
     36         self.get_stop_description()
     37 
     38     @python_api_test
     39     @dwarf_test
     40     def test_get_stop_description_with_dwarf(self):
     41         """Test Python SBThread.GetStopDescription() API."""
     42         self.buildDwarf()
     43         self.get_stop_description()
     44 
     45     @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
     46     @python_api_test
     47     @dsym_test
     48     def test_run_to_address_with_dsym(self):
     49         """Test Python SBThread.RunToAddress() API."""
     50         # We build a different executable than the default buildDwarf() does.
     51         d = {'CXX_SOURCES': 'main2.cpp', 'EXE': self.exe_name}
     52         self.buildDsym(dictionary=d)
     53         self.setTearDownCleanup(dictionary=d)
     54         self.run_to_address(self.exe_name)
     55 
     56     @python_api_test
     57     @dwarf_test
     58     def test_run_to_address_with_dwarf(self):
     59         """Test Python SBThread.RunToAddress() API."""
     60         # We build a different executable than the default buildDwarf() does.
     61         d = {'CXX_SOURCES': 'main2.cpp', 'EXE': self.exe_name}
     62         self.buildDwarf(dictionary=d)
     63         self.setTearDownCleanup(dictionary=d)
     64         self.run_to_address(self.exe_name)
     65 
     66     @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
     67     @python_api_test
     68     @dsym_test
     69     def test_step_out_of_malloc_into_function_b_with_dsym(self):
     70         """Test Python SBThread.StepOut() API to step out of a malloc call where the call site is at function b()."""
     71         # We build a different executable than the default buildDsym() does.
     72         d = {'CXX_SOURCES': 'main2.cpp', 'EXE': self.exe_name}
     73         self.buildDsym(dictionary=d)
     74         self.setTearDownCleanup(dictionary=d)
     75         self.step_out_of_malloc_into_function_b(self.exe_name)
     76 
     77     @expectedFailureLinux # llvm.org/pr14416
     78     @python_api_test
     79     @dwarf_test
     80     def test_step_out_of_malloc_into_function_b_with_dwarf(self):
     81         """Test Python SBThread.StepOut() API to step out of a malloc call where the call site is at function b()."""
     82         # We build a different executable than the default buildDwarf() does.
     83         d = {'CXX_SOURCES': 'main2.cpp', 'EXE': self.exe_name}
     84         self.buildDwarf(dictionary=d)
     85         self.setTearDownCleanup(dictionary=d)
     86         self.step_out_of_malloc_into_function_b(self.exe_name)
     87 
     88     @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
     89     @python_api_test
     90     @dsym_test
     91     def test_step_over_3_times_with_dsym(self):
     92         """Test Python SBThread.StepOver() API."""
     93         # We build a different executable than the default buildDsym() does.
     94         d = {'CXX_SOURCES': 'main2.cpp', 'EXE': self.exe_name}
     95         self.buildDsym(dictionary=d)
     96         self.setTearDownCleanup(dictionary=d)
     97         self.step_over_3_times(self.exe_name)
     98 
     99     @python_api_test
    100     @dwarf_test
    101     def test_step_over_3_times_with_dwarf(self):
    102         """Test Python SBThread.StepOver() API."""
    103         # We build a different executable than the default buildDwarf() does.
    104         d = {'CXX_SOURCES': 'main2.cpp', 'EXE': self.exe_name}
    105         self.buildDwarf(dictionary=d)
    106         self.setTearDownCleanup(dictionary=d)
    107         self.step_over_3_times(self.exe_name)
    108 
    109     def setUp(self):
    110         # Call super's setUp().
    111         TestBase.setUp(self)
    112         # Find the line number within main.cpp to break inside main().
    113         self.break_line = line_number("main.cpp", "// Set break point at this line and check variable 'my_char'.")
    114         # Find the line numbers within main2.cpp for step_out_of_malloc_into_function_b() and step_over_3_times().
    115         self.step_out_of_malloc = line_number("main2.cpp", "// thread step-out of malloc into function b.")
    116         self.after_3_step_overs = line_number("main2.cpp", "// we should reach here after 3 step-over's.")
    117 
    118         # We'll use the test method name as the exe_name for executable comppiled from main2.cpp.
    119         self.exe_name = self.testMethodName
    120 
    121     def get_process(self):
    122         """Test Python SBThread.GetProcess() API."""
    123         exe = os.path.join(os.getcwd(), "a.out")
    124 
    125         target = self.dbg.CreateTarget(exe)
    126         self.assertTrue(target, VALID_TARGET)
    127 
    128         breakpoint = target.BreakpointCreateByLocation("main.cpp", self.break_line)
    129         self.assertTrue(breakpoint, VALID_BREAKPOINT)
    130         self.runCmd("breakpoint list")
    131 
    132         # Launch the process, and do not stop at the entry point.
    133         process = target.LaunchSimple(None, None, os.getcwd())
    134 
    135         thread = get_stopped_thread(process, lldb.eStopReasonBreakpoint)
    136         self.assertTrue(thread.IsValid(), "There should be a thread stopped due to breakpoint")
    137         self.runCmd("process status")
    138 
    139         proc_of_thread = thread.GetProcess()
    140         #print "proc_of_thread:", proc_of_thread
    141         self.assertTrue(proc_of_thread.GetProcessID() == process.GetProcessID())
    142 
    143     def get_stop_description(self):
    144         """Test Python SBThread.GetStopDescription() API."""
    145         exe = os.path.join(os.getcwd(), "a.out")
    146 
    147         target = self.dbg.CreateTarget(exe)
    148         self.assertTrue(target, VALID_TARGET)
    149 
    150         breakpoint = target.BreakpointCreateByLocation("main.cpp", self.break_line)
    151         self.assertTrue(breakpoint, VALID_BREAKPOINT)
    152         #self.runCmd("breakpoint list")
    153 
    154         # Launch the process, and do not stop at the entry point.
    155         process = target.LaunchSimple(None, None, os.getcwd())
    156 
    157         thread = get_stopped_thread(process, lldb.eStopReasonBreakpoint)
    158         self.assertTrue(thread.IsValid(), "There should be a thread stopped due to breakpoint")
    159         #self.runCmd("process status")
    160 
    161         # Due to the typemap magic (see lldb.swig), we pass in an (int)length to GetStopDescription
    162         # and expect to get a Python string as the return object!
    163         # The 100 is just an arbitrary number specifying the buffer size.
    164         stop_description = thread.GetStopDescription(100)
    165         self.expect(stop_description, exe=False,
    166             startstr = 'breakpoint')
    167 
    168     def step_out_of_malloc_into_function_b(self, exe_name):
    169         """Test Python SBThread.StepOut() API to step out of a malloc call where the call site is at function b()."""
    170         exe = os.path.join(os.getcwd(), exe_name)
    171 
    172         target = self.dbg.CreateTarget(exe)
    173         self.assertTrue(target, VALID_TARGET)
    174 
    175         breakpoint = target.BreakpointCreateByName('malloc')
    176         self.assertTrue(breakpoint, VALID_BREAKPOINT)
    177         self.runCmd("breakpoint list")
    178 
    179         # Launch the process, and do not stop at the entry point.
    180         process = target.LaunchSimple(None, None, os.getcwd())
    181 
    182         while True:
    183             thread = get_stopped_thread(process, lldb.eStopReasonBreakpoint)
    184             self.assertTrue(thread.IsValid(), "There should be a thread stopped due to breakpoint")
    185             caller_symbol = get_caller_symbol(thread)
    186             #print "caller symbol of malloc:", caller_symbol
    187             if not caller_symbol:
    188                 self.fail("Test failed: could not locate the caller symbol of malloc")
    189             if caller_symbol == "b(int)":
    190                 break
    191             #self.runCmd("thread backtrace")
    192             #self.runCmd("process status")           
    193             process.Continue()
    194 
    195         thread.StepOut()
    196         self.runCmd("thread backtrace")
    197         #self.runCmd("process status")           
    198         self.assertTrue(thread.GetFrameAtIndex(0).GetLineEntry().GetLine() == self.step_out_of_malloc,
    199                         "step out of malloc into function b is successful")
    200 
    201     def step_over_3_times(self, exe_name):
    202         """Test Python SBThread.StepOver() API."""
    203         exe = os.path.join(os.getcwd(), exe_name)
    204 
    205         target = self.dbg.CreateTarget(exe)
    206         self.assertTrue(target, VALID_TARGET)
    207 
    208         breakpoint = target.BreakpointCreateByLocation('main2.cpp', self.step_out_of_malloc)
    209         self.assertTrue(breakpoint, VALID_BREAKPOINT)
    210         self.runCmd("breakpoint list")
    211 
    212         # Launch the process, and do not stop at the entry point.
    213         process = target.LaunchSimple(None, None, os.getcwd())
    214 
    215         self.assertTrue(process, PROCESS_IS_VALID)
    216 
    217         # Frame #0 should be on self.step_out_of_malloc.
    218         self.assertTrue(process.GetState() == lldb.eStateStopped)
    219         thread = get_stopped_thread(process, lldb.eStopReasonBreakpoint)
    220         self.assertTrue(thread.IsValid(), "There should be a thread stopped due to breakpoint condition")
    221         self.runCmd("thread backtrace")
    222         frame0 = thread.GetFrameAtIndex(0)
    223         lineEntry = frame0.GetLineEntry()
    224         self.assertTrue(lineEntry.GetLine() == self.step_out_of_malloc)
    225 
    226         thread.StepOver()
    227         thread.StepOver()
    228         thread.StepOver()
    229         self.runCmd("thread backtrace")
    230 
    231         # Verify that we are stopped at the correct source line number in main2.cpp.
    232         frame0 = thread.GetFrameAtIndex(0)
    233         lineEntry = frame0.GetLineEntry()
    234         self.assertTrue(thread.GetStopReason() == lldb.eStopReasonPlanComplete)
    235         # Expected failure with clang as the compiler.
    236         # rdar://problem/9223880
    237         #
    238         # Which has been fixed on the lldb by compensating for inaccurate line
    239         # table information with r140416.
    240         self.assertTrue(lineEntry.GetLine() == self.after_3_step_overs)
    241 
    242     def run_to_address(self, exe_name):
    243         """Test Python SBThread.RunToAddress() API."""
    244         exe = os.path.join(os.getcwd(), exe_name)
    245 
    246         target = self.dbg.CreateTarget(exe)
    247         self.assertTrue(target, VALID_TARGET)
    248 
    249         breakpoint = target.BreakpointCreateByLocation('main2.cpp', self.step_out_of_malloc)
    250         self.assertTrue(breakpoint, VALID_BREAKPOINT)
    251         self.runCmd("breakpoint list")
    252 
    253         # Launch the process, and do not stop at the entry point.
    254         process = target.LaunchSimple(None, None, os.getcwd())
    255 
    256         self.assertTrue(process, PROCESS_IS_VALID)
    257 
    258         # Frame #0 should be on self.step_out_of_malloc.
    259         self.assertTrue(process.GetState() == lldb.eStateStopped)
    260         thread = get_stopped_thread(process, lldb.eStopReasonBreakpoint)
    261         self.assertTrue(thread.IsValid(), "There should be a thread stopped due to breakpoint condition")
    262         self.runCmd("thread backtrace")
    263         frame0 = thread.GetFrameAtIndex(0)
    264         lineEntry = frame0.GetLineEntry()
    265         self.assertTrue(lineEntry.GetLine() == self.step_out_of_malloc)
    266 
    267         # Get the start/end addresses for this line entry.
    268         start_addr = lineEntry.GetStartAddress().GetLoadAddress(target)
    269         end_addr = lineEntry.GetEndAddress().GetLoadAddress(target)
    270         if self.TraceOn():
    271             print "start addr:", hex(start_addr)
    272             print "end addr:", hex(end_addr)
    273 
    274         # Disable the breakpoint.
    275         self.assertTrue(target.DisableAllBreakpoints())
    276         self.runCmd("breakpoint list")
    277         
    278         thread.StepOver()
    279         thread.StepOver()
    280         thread.StepOver()
    281         self.runCmd("thread backtrace")
    282 
    283         # Now ask SBThread to run to the address 'start_addr' we got earlier, which
    284         # corresponds to self.step_out_of_malloc line entry's start address.
    285         thread.RunToAddress(start_addr)
    286         self.runCmd("process status")
    287         #self.runCmd("thread backtrace")
    288 
    289 
    290 if __name__ == '__main__':
    291     import atexit
    292     lldb.SBDebugger.Initialize()
    293     atexit.register(lambda: lldb.SBDebugger.Terminate())
    294     unittest2.main()
    295