diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2016-01-06 20:12:03 +0000 | 
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2016-01-06 20:12:03 +0000 | 
| commit | 9e6d35490a6542f9c97607f93c2ef8ca8e03cbcc (patch) | |
| tree | dd2a1ddf0476664c2b823409c36cbccd52662ca7 /packages/Python/lldbsuite/test/functionalities/conditional_break | |
| parent | 3bd2e91faeb9eeec1aae82c64a3253afff551cfd (diff) | |
Notes
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 000000000000..4be90efee23b --- /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 000000000000..0d70f2595019 --- /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 000000000000..3ae7a20b4c7d --- /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 000000000000..b30a34e56b14 --- /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 000000000000..1329fd69a2e1 --- /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; +} | 
