199451b44SJordan Rupprecht""" 299451b44SJordan RupprechtTest conditionally break on a function and inspect its variables. 399451b44SJordan Rupprecht""" 499451b44SJordan Rupprecht 599451b44SJordan Rupprechtimport lldb 699451b44SJordan Rupprechtfrom lldbsuite.test.decorators import * 799451b44SJordan Rupprechtfrom lldbsuite.test.lldbtest import * 899451b44SJordan Rupprechtfrom lldbsuite.test import lldbutil 999451b44SJordan Rupprecht 1099451b44SJordan Rupprecht# rdar://problem/8532131 1199451b44SJordan Rupprecht# lldb not able to digest the clang-generated debug info correctly with respect to function name 1299451b44SJordan Rupprecht# 13*e0a79eecSMichael Buch# This class currently fails for clang. 1499451b44SJordan Rupprecht 1599451b44SJordan Rupprecht 1699451b44SJordan Rupprechtclass ConditionalBreakTestCase(TestBase): 172238dcc3SJonas Devlieghere @add_test_categories(["pyapi"]) 1899451b44SJordan Rupprecht def test_with_python(self): 1999451b44SJordan Rupprecht """Exercise some thread and frame APIs to break if c() is called by a().""" 2099451b44SJordan Rupprecht self.build() 2199451b44SJordan Rupprecht self.do_conditional_break() 2299451b44SJordan Rupprecht 2399451b44SJordan Rupprecht def test_with_command(self): 2499451b44SJordan Rupprecht """Simulate a user using lldb commands to break on c() if called from a().""" 2599451b44SJordan Rupprecht self.build() 2699451b44SJordan Rupprecht self.simulate_conditional_break_by_user() 2799451b44SJordan Rupprecht 2899451b44SJordan Rupprecht def do_conditional_break(self): 2999451b44SJordan Rupprecht """Exercise some thread and frame APIs to break if c() is called by a().""" 3099451b44SJordan Rupprecht exe = self.getBuildArtifact("a.out") 3199451b44SJordan Rupprecht 3299451b44SJordan Rupprecht target = self.dbg.CreateTarget(exe) 3399451b44SJordan Rupprecht self.assertTrue(target, VALID_TARGET) 3499451b44SJordan Rupprecht 3599451b44SJordan Rupprecht breakpoint = target.BreakpointCreateByName("c", exe) 3699451b44SJordan Rupprecht self.assertTrue(breakpoint, VALID_BREAKPOINT) 3799451b44SJordan Rupprecht 3899451b44SJordan Rupprecht # Now launch the process, and do not stop at entry point. 392238dcc3SJonas Devlieghere process = target.LaunchSimple(None, None, self.get_process_working_directory()) 4099451b44SJordan Rupprecht 4199451b44SJordan Rupprecht self.assertTrue(process, PROCESS_IS_VALID) 4299451b44SJordan Rupprecht 4399451b44SJordan Rupprecht # The stop reason of the thread should be breakpoint. 442238dcc3SJonas Devlieghere self.assertState( 452238dcc3SJonas Devlieghere process.GetState(), lldb.eStateStopped, STOPPED_DUE_TO_BREAKPOINT 462238dcc3SJonas Devlieghere ) 4799451b44SJordan Rupprecht 4899451b44SJordan Rupprecht # Find the line number where a's parent frame function is c. 4999451b44SJordan Rupprecht line = line_number( 502238dcc3SJonas Devlieghere "main.c", "// Find the line number where c's parent frame is a here." 512238dcc3SJonas Devlieghere ) 5299451b44SJordan Rupprecht 5399451b44SJordan Rupprecht # Suppose we are only interested in the call scenario where c()'s 5499451b44SJordan Rupprecht # immediate caller is a() and we want to find out the value passed from 5599451b44SJordan Rupprecht # a(). 5699451b44SJordan Rupprecht # 5799451b44SJordan Rupprecht # The 10 in range(10) is just an arbitrary number, which means we would 5899451b44SJordan Rupprecht # like to try for at most 10 times. 5999451b44SJordan Rupprecht for j in range(10): 6099451b44SJordan Rupprecht if self.TraceOn(): 6199451b44SJordan Rupprecht print("j is: ", j) 622238dcc3SJonas Devlieghere thread = lldbutil.get_one_thread_stopped_at_breakpoint(process, breakpoint) 6399451b44SJordan Rupprecht self.assertIsNotNone( 642238dcc3SJonas Devlieghere thread, "Expected one thread to be stopped at the breakpoint" 652238dcc3SJonas Devlieghere ) 6699451b44SJordan Rupprecht 6799451b44SJordan Rupprecht if thread.GetNumFrames() >= 2: 6899451b44SJordan Rupprecht frame0 = thread.GetFrameAtIndex(0) 6999451b44SJordan Rupprecht name0 = frame0.GetFunction().GetName() 7099451b44SJordan Rupprecht frame1 = thread.GetFrameAtIndex(1) 7199451b44SJordan Rupprecht name1 = frame1.GetFunction().GetName() 7299451b44SJordan Rupprecht # lldbutil.print_stacktrace(thread) 73619e2e09SDave Lee self.assertEqual(name0, "c", "Break on function c()") 742238dcc3SJonas Devlieghere if name1 == "a": 7599451b44SJordan Rupprecht # By design, we know that a() calls c() only from main.c:27. 7699451b44SJordan Rupprecht # In reality, similar logic can be used to find out the call 7799451b44SJordan Rupprecht # site. 782238dcc3SJonas Devlieghere self.assertEqual( 792238dcc3SJonas Devlieghere frame1.GetLineEntry().GetLine(), 802238dcc3SJonas Devlieghere line, 812238dcc3SJonas Devlieghere "Immediate caller a() at main.c:%d" % line, 822238dcc3SJonas Devlieghere ) 8399451b44SJordan Rupprecht 8499451b44SJordan Rupprecht # And the local variable 'val' should have a value of (int) 8599451b44SJordan Rupprecht # 3. 8699451b44SJordan Rupprecht val = frame1.FindVariable("val") 8799451b44SJordan Rupprecht self.assertEqual("int", val.GetTypeName()) 8899451b44SJordan Rupprecht self.assertEqual("3", val.GetValue()) 8999451b44SJordan Rupprecht break 9099451b44SJordan Rupprecht 9199451b44SJordan Rupprecht process.Continue() 9299451b44SJordan Rupprecht 9399451b44SJordan Rupprecht def simulate_conditional_break_by_user(self): 9499451b44SJordan Rupprecht """Simulate a user using lldb commands to break on c() if called from a().""" 9599451b44SJordan Rupprecht 9699451b44SJordan Rupprecht # Sourcing .lldb in the current working directory, which sets the main 9799451b44SJordan Rupprecht # executable, sets the breakpoint on c(), and adds the callback for the 9899451b44SJordan Rupprecht # breakpoint such that lldb only stops when the caller of c() is a(). 9999451b44SJordan Rupprecht # the "my" package that defines the date() function. 10099451b44SJordan Rupprecht if self.TraceOn(): 10199451b44SJordan Rupprecht print("About to source .lldb") 10299451b44SJordan Rupprecht 10399451b44SJordan Rupprecht if not self.TraceOn(): 10499451b44SJordan Rupprecht self.HideStdout() 10599451b44SJordan Rupprecht 10699451b44SJordan Rupprecht # Separate out the "file " + self.getBuildArtifact("a.out") command from .lldb file, for the sake of 10799451b44SJordan Rupprecht # remote testsuite. 10899451b44SJordan Rupprecht self.runCmd("file " + self.getBuildArtifact("a.out")) 10999451b44SJordan Rupprecht self.runCmd("command source .lldb") 11099451b44SJordan Rupprecht 11199451b44SJordan Rupprecht self.runCmd("break list") 11299451b44SJordan Rupprecht 11399451b44SJordan Rupprecht if self.TraceOn(): 11499451b44SJordan Rupprecht print("About to run.") 11599451b44SJordan Rupprecht self.runCmd("run", RUN_SUCCEEDED) 11699451b44SJordan Rupprecht 11799451b44SJordan Rupprecht self.runCmd("break list") 11899451b44SJordan Rupprecht 11999451b44SJordan Rupprecht if self.TraceOn(): 12099451b44SJordan Rupprecht print("Done running") 12199451b44SJordan Rupprecht 12299451b44SJordan Rupprecht # The stop reason of the thread should be breakpoint. 1232238dcc3SJonas Devlieghere self.expect( 1242238dcc3SJonas Devlieghere "thread list", 1252238dcc3SJonas Devlieghere STOPPED_DUE_TO_BREAKPOINT, 1262238dcc3SJonas Devlieghere substrs=["stopped", "stop reason = breakpoint"], 1272238dcc3SJonas Devlieghere ) 12899451b44SJordan Rupprecht 12999451b44SJordan Rupprecht # The frame info for frame #0 points to a.out`c and its immediate caller 13099451b44SJordan Rupprecht # (frame #1) points to a.out`a. 13199451b44SJordan Rupprecht 1322238dcc3SJonas Devlieghere self.expect("frame info", "We should stop at c()", substrs=["a.out`c"]) 13399451b44SJordan Rupprecht 13499451b44SJordan Rupprecht # Select our parent frame as the current frame. 13599451b44SJordan Rupprecht self.runCmd("frame select 1") 1362238dcc3SJonas Devlieghere self.expect( 1372238dcc3SJonas Devlieghere "frame info", "The immediate caller should be a()", substrs=["a.out`a"] 1382238dcc3SJonas Devlieghere ) 139