summaryrefslogtreecommitdiffstats
path: root/lldb/packages/Python/lldbsuite/test/functionalities/breakpoint
diff options
context:
space:
mode:
authorJim Ingham <jingham@apple.com>2019-10-25 14:05:07 -0700
committerJim Ingham <jingham@apple.com>2019-10-25 14:05:07 -0700
commit738af7a6241c98164625b9cd1ba9f8af4e36f197 (patch)
tree35ecaeb5e79f0fe728c25e82157831b26c3f7158 /lldb/packages/Python/lldbsuite/test/functionalities/breakpoint
parenta6b0219fc4a78e96ff268d101b911466dedbbf2c (diff)
downloadbcm5719-llvm-738af7a6241c98164625b9cd1ba9f8af4e36f197.tar.gz
bcm5719-llvm-738af7a6241c98164625b9cd1ba9f8af4e36f197.zip
Add the ability to pass extra args to a Python breakpoint callback.
For example, it is pretty easy to write a breakpoint command that implements "stop when my caller is Foo", and it is pretty easy to write a breakpoint command that implements "stop when my caller is Bar". But there's no way to write a generic "stop when my caller is..." function, and then specify the caller when you add the command to a breakpoint. With this patch, you can pass this data in a SBStructuredData dictionary. That will get stored in the PythonCommandBaton for the breakpoint, and passed to the implementation function (if it has the right signature) when the breakpoint is hit. Then in lldb, you can say: (lldb) break com add -F caller_is -k caller_name -v Foo More generally this will allow us to write reusable Python breakpoint commands. Differential Revision: https://reviews.llvm.org/D68671
Diffstat (limited to 'lldb/packages/Python/lldbsuite/test/functionalities/breakpoint')
-rw-r--r--lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_command/TestBreakpointCommand.py8
-rw-r--r--lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_command/TestBreakpointCommandsFromPython.py83
-rw-r--r--lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_command/bktptcmd.py18
3 files changed, 102 insertions, 7 deletions
diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_command/TestBreakpointCommand.py b/lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_command/TestBreakpointCommand.py
index b75a6db6e80..af8ece16564 100644
--- a/lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_command/TestBreakpointCommand.py
+++ b/lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_command/TestBreakpointCommand.py
@@ -18,7 +18,7 @@ class BreakpointCommandTestCase(TestBase):
mydir = TestBase.compute_mydir(__file__)
@expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24528")
- def test_breakpoint_command_sequence(self):
+ def not_test_breakpoint_command_sequence(self):
"""Test a sequence of breakpoint command add, list, and delete."""
self.build()
self.breakpoint_command_sequence()
@@ -107,6 +107,10 @@ class BreakpointCommandTestCase(TestBase):
"breakpoint command add -s command -o 'frame variable --show-types --scope' 1 4")
self.runCmd(
"breakpoint command add -s python -o 'import side_effect; side_effect.one_liner = \"one liner was here\"' 2")
+
+ import side_effect
+ self.runCmd("command script import --allow-reload ./bktptcmd.py")
+
self.runCmd(
"breakpoint command add --python-function bktptcmd.function 3")
@@ -151,8 +155,6 @@ class BreakpointCommandTestCase(TestBase):
self.runCmd("breakpoint delete 4")
- self.runCmd("command script import --allow-reload ./bktptcmd.py")
-
# Next lets try some other breakpoint kinds. First break with a regular expression
# and then specify only one file. The first time we should get two locations,
# the second time only one:
diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_command/TestBreakpointCommandsFromPython.py b/lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_command/TestBreakpointCommandsFromPython.py
index 962728a324e..ccb61d79c40 100644
--- a/lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_command/TestBreakpointCommandsFromPython.py
+++ b/lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_command/TestBreakpointCommandsFromPython.py
@@ -19,10 +19,15 @@ class PythonBreakpointCommandSettingTestCase(TestBase):
@add_test_categories(['pyapi'])
def test_step_out_python(self):
- """Test stepping out using avoid-no-debug with dsyms."""
+ """Test stepping out using a python breakpoint command."""
self.build()
self.do_set_python_command_from_python()
+ def test_bkpt_cmd_bad_arguments(self):
+ """Test what happens when pass structured data to a command:"""
+ self.build()
+ self.do_bad_args_to_python_command()
+
def setUp(self):
TestBase.setUp(self)
self.main_source = "main.c"
@@ -43,6 +48,18 @@ class PythonBreakpointCommandSettingTestCase(TestBase):
"Set break point at this line.", self.main_source_spec)
self.assertTrue(func_bkpt, VALID_BREAKPOINT)
+ fancy_bkpt = self.target.BreakpointCreateBySourceRegex(
+ "Set break point at this line.", self.main_source_spec)
+ self.assertTrue(fancy_bkpt, VALID_BREAKPOINT)
+
+ fancier_bkpt = self.target.BreakpointCreateBySourceRegex(
+ "Set break point at this line.", self.main_source_spec)
+ self.assertTrue(fancier_bkpt, VALID_BREAKPOINT)
+
+ not_so_fancy_bkpt = self.target.BreakpointCreateBySourceRegex(
+ "Set break point at this line.", self.main_source_spec)
+ self.assertTrue(not_so_fancy_bkpt, VALID_BREAKPOINT)
+
# Also test that setting a source regex breakpoint with an empty file
# spec list sets it on all files:
no_files_bkpt = self.target.BreakpointCreateBySourceRegex(
@@ -75,14 +92,37 @@ class PythonBreakpointCommandSettingTestCase(TestBase):
"Failed to set the script callback body: %s." %
(error.GetCString()))
- self.dbg.HandleCommand(
- "command script import --allow-reload ./bktptcmd.py")
+ self.expect("command script import --allow-reload ./bktptcmd.py")
+
func_bkpt.SetScriptCallbackFunction("bktptcmd.function")
+ extra_args = lldb.SBStructuredData()
+ stream = lldb.SBStream()
+ stream.Print('{"side_effect" : "I am fancy"}')
+ extra_args.SetFromJSON(stream)
+ error = fancy_bkpt.SetScriptCallbackFunction("bktptcmd.another_function", extra_args)
+ self.assertTrue(error.Success(), "Failed to add callback %s"%(error.GetCString()))
+
+ stream.Clear()
+ stream.Print('{"side_effect" : "I am so much fancier"}')
+ extra_args.SetFromJSON(stream)
+
+ # Fancier's callback is set up from the command line
+ id = fancier_bkpt.GetID()
+ self.expect("breakpoint command add -F bktptcmd.a_third_function -k side_effect -v 'I am fancier' %d"%(id))
+
+ # Not so fancy gets an empty extra_args:
+ empty_args = lldb.SBStructuredData()
+ error = not_so_fancy_bkpt.SetScriptCallbackFunction("bktptcmd.empty_extra_args", empty_args)
+ self.assertTrue(error.Success(), "Failed to add callback %s"%(error.GetCString()))
+
# Clear out canary variables
side_effect.bktptcmd = None
side_effect.callback = None
-
+ side_effect.fancy = None
+ side_effect.fancier = None
+ side_effect.not_so_fancy = None
+
# Now launch the process, and do not stop at entry point.
self.process = self.target.LaunchSimple(
None, None, self.get_process_working_directory())
@@ -97,3 +137,38 @@ class PythonBreakpointCommandSettingTestCase(TestBase):
self.assertEquals("callback was here", side_effect.callback)
self.assertEquals("function was here", side_effect.bktptcmd)
+ self.assertEquals("I am fancy", side_effect.fancy)
+ self.assertEquals("I am fancier", side_effect.fancier)
+ self.assertEquals("Not so fancy", side_effect.not_so_fancy)
+
+ def do_bad_args_to_python_command(self):
+ exe = self.getBuildArtifact("a.out")
+ error = lldb.SBError()
+
+ self.target = self.dbg.CreateTarget(exe)
+ self.assertTrue(self.target, VALID_TARGET)
+
+
+ self.expect("command script import --allow-reload ./bktptcmd.py")
+
+ bkpt = self.target.BreakpointCreateBySourceRegex(
+ "Set break point at this line.", self.main_source_spec)
+ self.assertTrue(bkpt, VALID_BREAKPOINT)
+
+ # Pass a breakpoint command function that doesn't take extra_args,
+ # but pass it extra args:
+
+ extra_args = lldb.SBStructuredData()
+ stream = lldb.SBStream()
+ stream.Print('{"side_effect" : "I am fancy"}')
+ extra_args.SetFromJSON(stream)
+
+ error = bkpt.SetScriptCallbackFunction("bktptcmd.function", extra_args)
+ self.assertTrue(error.Fail(), "Can't pass extra args if the function doesn't take them")
+
+ error = bkpt.SetScriptCallbackFunction("bktptcmd.useless_function", extra_args)
+ self.assertTrue(error.Fail(), "Can't pass extra args if the function has wrong number of args.")
+
+ error = bkpt.SetScriptCallbackFunction("bktptcmd.nosuch_function", extra_args)
+ self.assertTrue(error.Fail(), "Can't pass extra args if the function doesn't exist.")
+
diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_command/bktptcmd.py b/lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_command/bktptcmd.py
index ac0f753ccd8..e839de57fb7 100644
--- a/lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_command/bktptcmd.py
+++ b/lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_command/bktptcmd.py
@@ -1,5 +1,23 @@
from __future__ import print_function
import side_effect
+def useless_function(first, second):
+ print("I have the wrong number of arguments.")
+
def function(frame, bp_loc, dict):
side_effect.bktptcmd = "function was here"
+
+def another_function(frame, bp_loc, extra_args, dict):
+ se_value = extra_args.GetValueForKey("side_effect")
+ se_string = se_value.GetStringValue(100)
+ side_effect.fancy = se_string
+
+def a_third_function(frame, bp_loc, extra_args, dict):
+ se_value = extra_args.GetValueForKey("side_effect")
+ se_string = se_value.GetStringValue(100)
+ side_effect.fancier = se_string
+
+def empty_extra_args(frame, bp_loc, extra_args, dict):
+ if extra_args.IsValid():
+ side_effect.not_so_fancy = "Extra args should not be valid"
+ side_effect.not_so_fancy = "Not so fancy"
OpenPOWER on IntegriCloud