Skip to content

Commit 838e9ec

Browse files
authored
Support FinishBreakpoint for GDB API (Gallopsled#2114)
* Support FinishBreakpoint for GDB API * Evaluate args outside FinishBreakpoint callbacks
1 parent 826f4f3 commit 838e9ec

File tree

2 files changed

+57
-0
lines changed

2 files changed

+57
-0
lines changed

pwnlib/gdb.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -665,6 +665,48 @@ def exposed_stop(self):
665665
# Handle stop() call from the server.
666666
return self.stop()
667667

668+
class FinishBreakpoint:
669+
"""Mirror of ``gdb.FinishBreakpoint`` class.
670+
671+
See https://sourceware.org/gdb/onlinedocs/gdb/Finish-Breakpoints-in-Python.html
672+
for more information.
673+
"""
674+
675+
def __init__(self, conn, *args, **kwargs):
676+
"""Do not create instances of this class directly.
677+
678+
Use ``pwnlib.gdb.Gdb.FinishBreakpoint`` instead.
679+
"""
680+
# Creates a real finish breakpoint and connects it with this mirror
681+
self.conn = conn
682+
self.server_breakpoint = conn.root.set_finish_breakpoint(
683+
self, hasattr(self, 'stop'), hasattr(self, 'out_of_scope'),
684+
*args, **kwargs)
685+
686+
def __getattr__(self, item):
687+
"""Return attributes of the real breakpoint."""
688+
if item in (
689+
'____id_pack__',
690+
'__name__',
691+
'____conn__',
692+
'stop',
693+
'out_of_scope',
694+
):
695+
# Ignore RPyC netref attributes.
696+
# Also, if stop() or out_of_scope() are not defined, hasattr() call
697+
# in our __init__() will bring us here. Don't contact the
698+
# server in this case either.
699+
raise AttributeError()
700+
return getattr(self.server_breakpoint, item)
701+
702+
def exposed_stop(self):
703+
# Handle stop() call from the server.
704+
return self.stop()
705+
706+
def exposed_out_of_scope(self):
707+
# Handle out_of_scope() call from the server.
708+
return self.out_of_scope()
709+
668710
class Gdb:
669711
"""Mirror of ``gdb`` module.
670712
@@ -682,8 +724,12 @@ def __init__(self, conn):
682724
class _Breakpoint(Breakpoint):
683725
def __init__(self, *args, **kwargs):
684726
super().__init__(conn, *args, **kwargs)
727+
class _FinishBreakpoint(FinishBreakpoint):
728+
def __init__(self, *args, **kwargs):
729+
super().__init__(conn, *args, **kwargs)
685730

686731
self.Breakpoint = _Breakpoint
732+
self.FinishBreakpoint = _FinishBreakpoint
687733
self.stopped = Event()
688734

689735
def stop_handler(event):

pwnlib/gdb_api_bridge.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,17 @@ def stop(self):
8989
return Breakpoint(*args, **kwargs)
9090
return gdb.Breakpoint(*args, **kwargs)
9191

92+
def exposed_set_finish_breakpoint(self, client, has_stop, has_out_of_scope, *args, **kwargs):
93+
"""Create a finish breakpoint and connect it with the client-side mirror."""
94+
class FinishBreakpoint(gdb.FinishBreakpoint):
95+
if has_stop:
96+
def stop(self):
97+
return client.stop()
98+
if has_out_of_scope:
99+
def out_of_scope(self):
100+
client.out_of_scope()
101+
return FinishBreakpoint(*args, **kwargs)
102+
92103
def exposed_quit(self):
93104
"""Terminate GDB."""
94105
gdb.post_event(lambda: gdb.execute('quit'))

0 commit comments

Comments
 (0)