From c04aedec7f8cd3b4355ea937440ac8a8b1bcc5e2 Mon Sep 17 00:00:00 2001 From: patryk4815 Date: Mon, 26 May 2025 22:16:35 +0200 Subject: [PATCH] Add ability to suspend all events via SUSPEND_ALL (#3019) * Add ability to suspend all events via SUSPEND_ALL * fix mypy --- pwndbg/dbg/__init__.py | 14 ++++++++++++++ pwndbg/dbg/gdb/__init__.py | 7 +++++++ pwndbg/dbg/lldb/__init__.py | 6 +++--- pwndbg/gdblib/events.py | 3 ++- 4 files changed, 26 insertions(+), 4 deletions(-) diff --git a/pwndbg/dbg/__init__.py b/pwndbg/dbg/__init__.py index 99655eabb..0908fa660 100644 --- a/pwndbg/dbg/__init__.py +++ b/pwndbg/dbg/__init__.py @@ -1001,6 +1001,7 @@ class EventType(Enum): debugged. In GDB terminology, these are called `objfile`s. """ + SUSPEND_ALL = -1 START = 0 STOP = 1 EXIT = 2 @@ -1098,6 +1099,19 @@ class Debugger: """ raise NotImplementedError() + @contextlib.contextmanager + def ctx_suspend_events(self, ty: EventType) -> Iterator[None]: + """ + Context manager for temporarily suspending and resuming the delivery of events + of a given type. + """ + + self.suspend_events(ty) + try: + yield + finally: + self.resume_events(ty) + def suspend_events(self, ty: EventType) -> None: """ Suspend delivery of all events of the given type until it is resumed diff --git a/pwndbg/dbg/gdb/__init__.py b/pwndbg/dbg/gdb/__init__.py index c033ab0d3..980bc028a 100644 --- a/pwndbg/dbg/gdb/__init__.py +++ b/pwndbg/dbg/gdb/__init__.py @@ -1298,6 +1298,11 @@ def _gdb_event_class_from_event_type(ty: pwndbg.dbg_mod.EventType) -> Any: return gdb.events.memory_changed elif ty == pwndbg.dbg_mod.EventType.REGISTER_CHANGED: return gdb.events.register_changed + elif ty == pwndbg.dbg_mod.EventType.SUSPEND_ALL: + assert hasattr( + gdb.events, "suspend_all" + ), "gdb.events.suspend_all is missing. Did the Pwndbg GDB event code not get loaded?" + return gdb.events.suspend_all raise NotImplementedError(f"unknown event type {ty}") @@ -1652,6 +1657,8 @@ class GDB(pwndbg.dbg_mod.Debugger): return pwndbg.gdblib.events.mem_changed elif ty == pwndbg.dbg_mod.EventType.REGISTER_CHANGED: return pwndbg.gdblib.events.reg_changed + elif ty == pwndbg.dbg_mod.EventType.SUSPEND_ALL: + raise RuntimeError("invalid usage, this event is not supported") @override def suspend_events(self, ty: pwndbg.dbg_mod.EventType) -> None: diff --git a/pwndbg/dbg/lldb/__init__.py b/pwndbg/dbg/lldb/__init__.py index 70fd2aa01..4004aec12 100644 --- a/pwndbg/dbg/lldb/__init__.py +++ b/pwndbg/dbg/lldb/__init__.py @@ -1986,7 +1986,7 @@ class LLDB(pwndbg.dbg_mod.Debugger): if ty not in self.event_handlers: # No one cares about this event type. return - if self.suspended_events[ty]: + if self.suspended_events[ty] or self.suspended_events[pwndbg.dbg_mod.EventType.SUSPEND_ALL]: # This event has been suspended. return @@ -1994,9 +1994,9 @@ class LLDB(pwndbg.dbg_mod.Debugger): try: handler() except Exception as e: - import pwndbg.exception + from pwndbg.exception import handle as pwndbg_exception - pwndbg.exception.handle() + pwndbg_exception() raise e @override diff --git a/pwndbg/gdblib/events.py b/pwndbg/gdblib/events.py index 0a8a23b3a..61f9e57aa 100644 --- a/pwndbg/gdblib/events.py +++ b/pwndbg/gdblib/events.py @@ -97,6 +97,7 @@ class StartEvent: gdb.events.start = StartEvent() +gdb.events.suspend_all = object() def _is_safe_event_packet(): @@ -283,7 +284,7 @@ def connect( @wraps(func) def caller(*a: P.args, **kw: P.kwargs) -> None: - if paused[event_handler]: + if paused[event_handler] or paused[gdb.events.suspend_all]: return None if debug: