1""" 2Test conditionally break on a function and inspect its variables. 3""" 4 5import os, time 6import re 7import unittest2 8import lldb, lldbutil 9from 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 16class 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 147if __name__ == '__main__': 148 import atexit 149 lldb.SBDebugger.Initialize() 150 atexit.register(lambda: lldb.SBDebugger.Terminate()) 151 unittest2.main() 152