Home | History | Annotate | Download | only in conditional_break
      1 """
      2 Test conditionally break on a function and inspect its variables.
      3 """
      4 
      5 import os, time
      6 import re
      7 import unittest2
      8 import lldb, lldbutil
      9 from lldbtest import *
     10 
     11 # rdar://problem/8532131
     12 # lldb not able to digest the clang-generated debug info correctly with respect to function name
     13 #
     14 # This class currently fails for clang as well as llvm-gcc.
     15 
     16 class ConditionalBreakTestCase(TestBase):
     17 
     18     mydir = os.path.join("functionalities", "conditional_break")
     19 
     20     @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
     21     @python_api_test
     22     @dsym_test
     23     def test_with_dsym_python(self):
     24         """Exercise some thread and frame APIs to break if c() is called by a()."""
     25         self.buildDsym()
     26         self.do_conditional_break()
     27 
     28     @python_api_test
     29     @dwarf_test
     30     def test_with_dwarf_python(self):
     31         """Exercise some thread and frame APIs to break if c() is called by a()."""
     32         self.buildDwarf()
     33         self.do_conditional_break()
     34 
     35     @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
     36     @dsym_test
     37     def test_with_dsym_command(self):
     38         """Simulate a user using lldb commands to break on c() if called from a()."""
     39         self.buildDsym()
     40         self.simulate_conditional_break_by_user()
     41 
     42     @dwarf_test
     43     @skipIfLinux # due to two assertion failures introduced by r174793: ProcessPOSIX.cpp:223 (assertion 'state == eStateStopped || state == eStateCrashed') and POSIXThread.cpp:254 (assertion 'bp_site')
     44     def test_with_dwarf_command(self):
     45         """Simulate a user using lldb commands to break on c() if called from a()."""
     46         self.buildDwarf()
     47         self.simulate_conditional_break_by_user()
     48 
     49     def do_conditional_break(self):
     50         """Exercise some thread and frame APIs to break if c() is called by a()."""
     51         exe = os.path.join(os.getcwd(), "a.out")
     52 
     53         target = self.dbg.CreateTarget(exe)
     54         self.assertTrue(target, VALID_TARGET)
     55 
     56         breakpoint = target.BreakpointCreateByName("c", exe)
     57         self.assertTrue(breakpoint, VALID_BREAKPOINT)
     58 
     59         # Now launch the process, and do not stop at entry point.
     60         process = target.LaunchSimple(None, None, os.getcwd())
     61 
     62         self.assertTrue(process, PROCESS_IS_VALID)
     63 
     64         # The stop reason of the thread should be breakpoint.
     65         self.assertTrue(process.GetState() == lldb.eStateStopped,
     66                         STOPPED_DUE_TO_BREAKPOINT)
     67 
     68         # Find the line number where a's parent frame function is c.
     69         line = line_number('main.c',
     70             "// Find the line number where c's parent frame is a here.")
     71 
     72         # Suppose we are only interested in the call scenario where c()'s
     73         # immediate caller is a() and we want to find out the value passed from
     74         # a().
     75         #
     76         # The 10 in range(10) is just an arbitrary number, which means we would
     77         # like to try for at most 10 times.
     78         for j in range(10):
     79             if self.TraceOn():
     80                 print "j is: ", j
     81             thread = process.GetThreadAtIndex(0)
     82             
     83             if thread.GetNumFrames() >= 2:
     84                 frame0 = thread.GetFrameAtIndex(0)
     85                 name0 = frame0.GetFunction().GetName()
     86                 frame1 = thread.GetFrameAtIndex(1)
     87                 name1 = frame1.GetFunction().GetName()
     88                 #lldbutil.print_stacktrace(thread)
     89                 self.assertTrue(name0 == "c", "Break on function c()")
     90                 if (name1 == "a"):
     91                     # By design, we know that a() calls c() only from main.c:27.
     92                     # In reality, similar logic can be used to find out the call
     93                     # site.
     94                     self.assertTrue(frame1.GetLineEntry().GetLine() == line,
     95                                     "Immediate caller a() at main.c:%d" % line)
     96 
     97                     # And the local variable 'val' should have a value of (int) 3.
     98                     val = frame1.FindVariable("val")
     99                     self.assertTrue(val.GetTypeName() == "int", "'val' has int type")
    100                     self.assertTrue(val.GetValue() == "3", "'val' has a value of 3")
    101                     break
    102 
    103             process.Continue()
    104 
    105     def simulate_conditional_break_by_user(self):
    106         """Simulate a user using lldb commands to break on c() if called from a()."""
    107 
    108         # Sourcing .lldb in the current working directory, which sets the main
    109         # executable, sets the breakpoint on c(), and adds the callback for the
    110         # breakpoint such that lldb only stops when the caller of c() is a().
    111         # the "my" package that defines the date() function.
    112         if self.TraceOn():
    113             print "About to source .lldb"
    114 
    115         if not self.TraceOn():
    116             self.HideStdout()
    117         self.runCmd("command source .lldb")
    118 
    119         self.runCmd ("break list")
    120 
    121         if self.TraceOn():
    122             print "About to run."
    123         self.runCmd("run", RUN_SUCCEEDED)
    124 
    125         self.runCmd ("break list")
    126 
    127         if self.TraceOn():
    128             print "Done running"
    129 
    130         # The stop reason of the thread should be breakpoint.
    131         self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
    132             substrs = ['stopped', 'stop reason = breakpoint'])
    133 
    134         # The frame info for frame #0 points to a.out`c and its immediate caller
    135         # (frame #1) points to a.out`a.
    136 
    137         self.expect("frame info", "We should stop at c()",
    138             substrs = ["a.out`c"])
    139 
    140         # Select our parent frame as the current frame.
    141         self.runCmd("frame select 1")
    142         self.expect("frame info", "The immediate caller should be a()",
    143             substrs = ["a.out`a"])
    144 
    145 
    146 
    147 if __name__ == '__main__':
    148     import atexit
    149     lldb.SBDebugger.Initialize()
    150     atexit.register(lambda: lldb.SBDebugger.Terminate())
    151     unittest2.main()
    152