Code was added to Target::RunStopHook to make sure that we don't run stop hooks when you stop after an expression evaluation. But the way it was done was to check that we hadn't run an expression since the last natural stop. That failed in the case where you stopped for a breakpoint which had run an expression, because the stop-hooks get run after the breakpoint actions, and so by the time we got to running the stop-hooks, we had already run a user expression. I fixed this by adding a target ivar tracking the last natural stop ID at which we had run a stop-hook. Then we keep track of this and make sure we run the stop-hooks only once per natural stop. Differential Revision: https://reviews.llvm.org/D106514
91 lines
3.4 KiB
Python
91 lines
3.4 KiB
Python
"""
|
|
Test stop hook functionality
|
|
"""
|
|
|
|
|
|
|
|
import lldb
|
|
import lldbsuite.test.lldbutil as lldbutil
|
|
from lldbsuite.test.lldbtest import *
|
|
|
|
|
|
class TestStopHooks(TestBase):
|
|
|
|
mydir = TestBase.compute_mydir(__file__)
|
|
|
|
# If your test case doesn't stress debug info, the
|
|
# set this to true. That way it won't be run once for
|
|
# each debug info format.
|
|
NO_DEBUG_INFO_TESTCASE = True
|
|
|
|
def setUp(self):
|
|
TestBase.setUp(self)
|
|
self.build()
|
|
self.main_source_file = lldb.SBFileSpec("main.c")
|
|
full_path = os.path.join(self.getSourceDir(), "main.c")
|
|
self.main_start_line = line_number(full_path, "main()")
|
|
|
|
def test_stop_hooks_step_out(self):
|
|
"""Test that stop hooks fire on step-out."""
|
|
self.step_out_test()
|
|
|
|
def test_stop_hooks_after_expr(self):
|
|
"""Test that a stop hook fires when hitting a breakpoint
|
|
that runs an expression"""
|
|
self.after_expr_test()
|
|
|
|
def step_out_test(self):
|
|
(target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(self,
|
|
"Set a breakpoint here", self.main_source_file)
|
|
|
|
interp = self.dbg.GetCommandInterpreter()
|
|
result = lldb.SBCommandReturnObject()
|
|
interp.HandleCommand("target stop-hook add -o 'expr g_var++'", result)
|
|
self.assertTrue(result.Succeeded, "Set the target stop hook")
|
|
thread.StepOut()
|
|
var = target.FindFirstGlobalVariable("g_var")
|
|
self.assertTrue(var.IsValid())
|
|
self.assertEqual(var.GetValueAsUnsigned(), 1, "Updated g_var")
|
|
|
|
def after_expr_test(self):
|
|
interp = self.dbg.GetCommandInterpreter()
|
|
result = lldb.SBCommandReturnObject()
|
|
interp.HandleCommand("target stop-hook add -o 'expr g_var++'", result)
|
|
self.assertTrue(result.Succeeded, "Set the target stop hook")
|
|
|
|
(target, process, thread, first_bkpt) = lldbutil.run_to_source_breakpoint(self,
|
|
"Set a breakpoint here", self.main_source_file)
|
|
|
|
var = target.FindFirstGlobalVariable("g_var")
|
|
self.assertTrue(var.IsValid())
|
|
self.assertEqual(var.GetValueAsUnsigned(), 1, "Updated g_var")
|
|
|
|
bkpt = target.BreakpointCreateBySourceRegex("Continue to here", self.main_source_file)
|
|
self.assertNotEqual(bkpt.GetNumLocations(), 0, "Set the second breakpoint")
|
|
commands = lldb.SBStringList()
|
|
commands.AppendString("expr increment_gvar()")
|
|
bkpt.SetCommandLineCommands(commands);
|
|
|
|
threads = lldbutil.continue_to_breakpoint(process, bkpt)
|
|
self.assertEqual(len(threads), 1, "Hit my breakpoint")
|
|
|
|
self.assertTrue(var.IsValid())
|
|
self.assertEqual(var.GetValueAsUnsigned(), 3, "Updated g_var")
|
|
|
|
# Make sure running an expression does NOT run the stop hook.
|
|
# Our expression will increment it by one, but the stop shouldn't
|
|
# have gotten it to 5.
|
|
threads[0].frames[0].EvaluateExpression("increment_gvar()")
|
|
self.assertTrue(var.IsValid())
|
|
self.assertEqual(var.GetValueAsUnsigned(), 4, "Updated g_var")
|
|
|
|
|
|
# Make sure a rerun doesn't upset the state we've set up:
|
|
process.Kill()
|
|
lldbutil.run_to_breakpoint_do_run(self, target, first_bkpt)
|
|
var = target.FindFirstGlobalVariable("g_var")
|
|
self.assertTrue(var.IsValid())
|
|
self.assertEqual(var.GetValueAsUnsigned(), 1, "Updated g_var")
|
|
|
|
|