diff options
Diffstat (limited to 'packages/Python/lldbsuite/test/functionalities/conditional_break')
5 files changed, 225 insertions, 0 deletions
diff --git a/packages/Python/lldbsuite/test/functionalities/conditional_break/.lldb b/packages/Python/lldbsuite/test/functionalities/conditional_break/.lldb new file mode 100644 index 0000000..4be90ef --- /dev/null +++ b/packages/Python/lldbsuite/test/functionalities/conditional_break/.lldb @@ -0,0 +1,3 @@ +breakpoint set -n c +command script import -r conditional_break.py +breakpoint command add 1 -F "conditional_break.stop_if_called_from_a" diff --git a/packages/Python/lldbsuite/test/functionalities/conditional_break/Makefile b/packages/Python/lldbsuite/test/functionalities/conditional_break/Makefile new file mode 100644 index 0000000..0d70f25 --- /dev/null +++ b/packages/Python/lldbsuite/test/functionalities/conditional_break/Makefile @@ -0,0 +1,5 @@ +LEVEL = ../../make + +C_SOURCES := main.c + +include $(LEVEL)/Makefile.rules diff --git a/packages/Python/lldbsuite/test/functionalities/conditional_break/TestConditionalBreak.py b/packages/Python/lldbsuite/test/functionalities/conditional_break/TestConditionalBreak.py new file mode 100644 index 0000000..3ae7a20 --- /dev/null +++ b/packages/Python/lldbsuite/test/functionalities/conditional_break/TestConditionalBreak.py @@ -0,0 +1,133 @@ +""" +Test conditionally break on a function and inspect its variables. +""" + +from __future__ import print_function + + + +import os, time +import re +import lldb +import lldbsuite.test.lldbutil as lldbutil +from lldbsuite.test.lldbtest import * + +# rdar://problem/8532131 +# lldb not able to digest the clang-generated debug info correctly with respect to function name +# +# This class currently fails for clang as well as llvm-gcc. + +class ConditionalBreakTestCase(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + @add_test_categories(['pyapi']) + def test_with_python(self): + """Exercise some thread and frame APIs to break if c() is called by a().""" + self.build() + self.do_conditional_break() + + def test_with_command(self): + """Simulate a user using lldb commands to break on c() if called from a().""" + self.build() + self.simulate_conditional_break_by_user() + + def do_conditional_break(self): + """Exercise some thread and frame APIs to break if c() is called by a().""" + exe = os.path.join(os.getcwd(), "a.out") + + target = self.dbg.CreateTarget(exe) + self.assertTrue(target, VALID_TARGET) + + breakpoint = target.BreakpointCreateByName("c", exe) + self.assertTrue(breakpoint, VALID_BREAKPOINT) + + # Now launch the process, and do not stop at entry point. + process = target.LaunchSimple (None, None, self.get_process_working_directory()) + + self.assertTrue(process, PROCESS_IS_VALID) + + # The stop reason of the thread should be breakpoint. + self.assertTrue(process.GetState() == lldb.eStateStopped, + STOPPED_DUE_TO_BREAKPOINT) + + # Find the line number where a's parent frame function is c. + line = line_number('main.c', + "// Find the line number where c's parent frame is a here.") + + # Suppose we are only interested in the call scenario where c()'s + # immediate caller is a() and we want to find out the value passed from + # a(). + # + # The 10 in range(10) is just an arbitrary number, which means we would + # like to try for at most 10 times. + for j in range(10): + if self.TraceOn(): + print("j is: ", j) + thread = process.GetThreadAtIndex(0) + + if thread.GetNumFrames() >= 2: + frame0 = thread.GetFrameAtIndex(0) + name0 = frame0.GetFunction().GetName() + frame1 = thread.GetFrameAtIndex(1) + name1 = frame1.GetFunction().GetName() + #lldbutil.print_stacktrace(thread) + self.assertTrue(name0 == "c", "Break on function c()") + if (name1 == "a"): + # By design, we know that a() calls c() only from main.c:27. + # In reality, similar logic can be used to find out the call + # site. + self.assertTrue(frame1.GetLineEntry().GetLine() == line, + "Immediate caller a() at main.c:%d" % line) + + # And the local variable 'val' should have a value of (int) 3. + val = frame1.FindVariable("val") + self.assertTrue(val.GetTypeName() == "int", "'val' has int type") + self.assertTrue(val.GetValue() == "3", "'val' has a value of 3") + break + + process.Continue() + + def simulate_conditional_break_by_user(self): + """Simulate a user using lldb commands to break on c() if called from a().""" + + # Sourcing .lldb in the current working directory, which sets the main + # executable, sets the breakpoint on c(), and adds the callback for the + # breakpoint such that lldb only stops when the caller of c() is a(). + # the "my" package that defines the date() function. + if self.TraceOn(): + print("About to source .lldb") + + if not self.TraceOn(): + self.HideStdout() + + # Separate out the "file a.out" command from .lldb file, for the sake of + # remote testsuite. + self.runCmd("file a.out") + self.runCmd("command source .lldb") + + self.runCmd ("break list") + + if self.TraceOn(): + print("About to run.") + self.runCmd("run", RUN_SUCCEEDED) + + self.runCmd ("break list") + + if self.TraceOn(): + print("Done running") + + # The stop reason of the thread should be breakpoint. + self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT, + substrs = ['stopped', 'stop reason = breakpoint']) + + # The frame info for frame #0 points to a.out`c and its immediate caller + # (frame #1) points to a.out`a. + + self.expect("frame info", "We should stop at c()", + substrs = ["a.out`c"]) + + # Select our parent frame as the current frame. + self.runCmd("frame select 1") + self.expect("frame info", "The immediate caller should be a()", + substrs = ["a.out`a"]) diff --git a/packages/Python/lldbsuite/test/functionalities/conditional_break/conditional_break.py b/packages/Python/lldbsuite/test/functionalities/conditional_break/conditional_break.py new file mode 100644 index 0000000..b30a34e --- /dev/null +++ b/packages/Python/lldbsuite/test/functionalities/conditional_break/conditional_break.py @@ -0,0 +1,30 @@ +import sys +import lldb + +def stop_if_called_from_a(frame, bp_loc, dict): + + thread = frame.GetThread() + process = thread.GetProcess() + target = process.GetTarget() + dbg = target.GetDebugger() + + # Perform synchronous interaction with the debugger. + old_async = dbg.GetAsync() + dbg.SetAsync(True) + + # We check the call frames in order to stop only when the immediate caller + # of the leaf function c() is a(). If it's not the right caller, we ask the + # command interpreter to continue execution. + + should_stop = True + if thread.GetNumFrames() >= 2: + + if (thread.frames[0].function.name == 'c' and thread.frames[1].function.name == 'a'): + should_stop = True + else: + should_stop = False + + dbg.SetAsync(old_async) + return should_stop + + diff --git a/packages/Python/lldbsuite/test/functionalities/conditional_break/main.c b/packages/Python/lldbsuite/test/functionalities/conditional_break/main.c new file mode 100644 index 0000000..1329fd69 --- /dev/null +++ b/packages/Python/lldbsuite/test/functionalities/conditional_break/main.c @@ -0,0 +1,54 @@ +//===-- main.c --------------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#include <stdio.h> + +// This simple program is to demonstrate the capability of the lldb command +// "breakpoint command add" to add a set of commands to a breakpoint to be +// executed when the breakpoint is hit. +// +// In particular, we want to break within c(), but only if the immediate caller +// is a(). + +int a(int); +int b(int); +int c(int); + +int a(int val) +{ + if (val <= 1) + return b(val); + else if (val >= 3) + return c(val); // Find the line number where c's parent frame is a here. + + return val; +} + +int b(int val) +{ + return c(val); +} + +int c(int val) +{ + return val + 3; +} + +int main (int argc, char const *argv[]) +{ + int A1 = a(1); // a(1) -> b(1) -> c(1) + printf("a(1) returns %d\n", A1); + + int B2 = b(2); // b(2) -> c(2) + printf("b(2) returns %d\n", B2); + + int A3 = a(3); // a(3) -> c(3) + printf("a(3) returns %d\n", A3); + + return 0; +} |