Jim's answer is probably the "correct" way of doing this so all cases are covered. However, after spending quite some time struggling with LLDB's Python APIs for event handling I stumbled across LLDB's target stop-hook ...
command. This can run a Python callback whenever execution pauses, and so covers most of what I want.
Unfortunately, target stop-hook
doesn't cover the need for updates as the user manually navigates the stack e.g. using commands like up
, down
, etc. To deal with this I re-implemented the commands I regularly use: up
, down
, and f
.
My implementation looks roughly like this:
class LLDBStopHandler:
def __init__(self, _target, _extra_args, _dict):
pass
def handle_stop(self, _exe_ctx, _stream):
MY_STOP_HOOK()
return True
def lldb_f_command(debugger, command, result, dict):
debugger.HandleCommand(f'frame select {args}')
MY_STOP_HOOK()
def lldb_down_command(debugger, command, result, dict):
frame_id = lldb.debugger.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame().GetFrameID()
debugger.HandleCommand(f'frame select {frame_id - 1}')
MY_STOP_HOOK()
def lldb_up_command(debugger, command, result, dict):
frame_id = lldb.debugger.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame().GetFrameID()
debugger.HandleCommand(f'frame select {frame_id + 1}')
MY_STOP_HOOK()
def __lldb_init_module(debugger, _dict):
debugger.HandleCommand(f'target stop-hook add -P {__name__}.LLDBStopHandler')
debugger.HandleCommand(f'command script add -f {__name__}.lldb_f_command f')
debugger.HandleCommand(f'command script add -f {__name__}.lldb_down_command down')
debugger.HandleCommand(f'command script add -f {__name__}.lldb_up_command up')
Note the frame
command cannot be overridden directly as it's a built-in. I don't tend to use it though. Also the above is missing anything to cover switching threads, and probably some other things I haven't had to worry about yet.