Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions lldb/source/Commands/CommandObjectTarget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5121,6 +5121,15 @@ class CommandObjectTargetStopHookDelete : public CommandObjectParsed {
: CommandObjectParsed(interpreter, "target stop-hook delete",
"Delete a stop-hook.",
"target stop-hook delete [<idx>]") {
SetHelpLong(
R"(
Deletes the stop hook by index.

At any given stop, all enabled stop hooks that pass the stop filter will
get a chance to run. That means if one stop-hook deletes another stop hook
while executing, the deleted stop hook will still fire for the stop at which
it was deleted.
)");
AddSimpleArgumentList(eArgTypeStopHookID, eArgRepeatStar);
}

Expand Down
5 changes: 5 additions & 0 deletions lldb/source/Target/Target.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3207,6 +3207,11 @@ bool Target::RunStopHooks(bool at_initial_stop) {
bool should_stop = false;
bool requested_continue = false;

// A stop hook might get deleted while running stop hooks.
// We have to decide what that means. We will follow the rule that deleting
// a stop hook while processing these stop hooks will delete it for FUTURE
// stops but not this stop. Fortunately, copying the m_stop_hooks to the
// active_hooks list before iterating over the hooks has this effect.
for (auto cur_hook_sp : active_hooks) {
bool any_thread_matched = false;
for (auto exc_ctx : exc_ctx_with_reasons) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,39 @@ def test_bad_handler(self):
"Got the right error",
)

def test_self_deleting(self):
"""Test that we can handle a stop hook that deletes itself"""
self.script_setup()
# Run to the first breakpoint before setting the stop hook
# so we don't have to figure out where it showed up in the new
# target.
(target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(
self, "Stop here first", self.main_source_file
)

# Now add our stop hook and register it:
result = lldb.SBCommandReturnObject()
command = "target stop-hook add -P stop_hook.self_deleting_stop"
self.interp.HandleCommand(command, result)
self.assertCommandReturn(result, f"Added my stop hook: {result.GetError()}")

result_str = result.GetOutput()
p = re.compile("Stop hook #([0-9]+) added.")
m = p.match(result_str)
current_stop_hook_id = m.group(1)
command = "command script add -o -f stop_hook.handle_stop_hook_id handle_id"
self.interp.HandleCommand(command, result)
self.assertCommandReturn(result, "Added my command")

command = f"handle_id {current_stop_hook_id}"
self.interp.HandleCommand(command, result)
self.assertCommandReturn(result, "Registered my stop ID")

# Now step the process and make sure the stop hook was deleted.
thread.StepOver()
self.interp.HandleCommand("target stop-hook list", result)
self.assertEqual(result.GetOutput().rstrip(), "No stop hooks.", "Deleted hook")

def test_stop_hooks_scripted(self):
"""Test that a scripted stop hook works with no specifiers"""
self.stop_hooks_scripted(5, "-I false")
Expand Down
25 changes: 25 additions & 0 deletions lldb/test/API/commands/target/stop-hooks/stop_hook.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,28 @@ def handle_stop(self):
class no_handle_stop:
def __init__(self, target, extra_args, dict):
print("I am okay")


class self_deleting_stop:
def __init__(self, target, extra_args, dict):
self.target = target

def handle_stop(self, exe_ctx, stream):
interp = exe_ctx.target.debugger.GetCommandInterpreter()
result = lldb.SBCommandReturnObject()
interp.HandleCommand("handle_id", result)
id_str = result.GetOutput().rstrip()

command = f"target stop-hook delete {id_str}"
interp.HandleCommand(command, result)


stop_hook_id = 0


def handle_stop_hook_id(debugger, command, exe_ctx, result, extra_args):
global stop_hook_id
if command == "":
result.AppendMessage(str(stop_hook_id))
else:
stop_hook_id = int(command)
Loading