Last active
August 29, 2015 14:24
-
-
Save scottt/411b59e84e64de0607c4 to your computer and use it in GitHub Desktop.
until-breakpoint: A GDB command that waits for a specific breakpoint to hit
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
volatile int n; | |
int main() | |
{ | |
n = 29; | |
while (n != 1) | |
if (n % 2 == 1) | |
n = 3*n + 1; | |
else | |
n = n/2; | |
return 0; | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
set python print-stack full | |
source until-breakpoint.py | |
file ./3n1 | |
break 3n1.c:5 | |
until-breakpoint $bpnum | |
step | |
set var n=3 | |
printf "n: %d\n", n | |
while 1 | |
if n % 2 == 1 | |
break 3n1.c:8 | |
else | |
break 3n1.c:10 | |
end | |
until-breakpoint $bpnum | |
step | |
printf "n: %d\n", n | |
if n == 2 | |
loop_break | |
end | |
#info breakpoints | |
delete $bpnum | |
end | |
quit |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$ cc -Og -Wall -g3 -I. 3n1.c -o 3n1 | |
$ gdb -x 3n1.gdb | |
Breakpoint 1 at 0x4004f6: file 3n1.c, line 5. | |
Breakpoint 1, main () at 3n1.c:5 | |
5 n = 29; | |
6 while (n != 1) | |
n: 3 | |
Breakpoint 2 at 0x400519: file 3n1.c, line 8. | |
Breakpoint 2, main () at 3n1.c:8 | |
8 n = 3*n + 1; | |
6 while (n != 1) | |
n: 10 | |
Breakpoint 3 at 0x40052b: file 3n1.c, line 10. | |
Breakpoint 3, main () at 3n1.c:10 | |
10 n = n/2; | |
6 while (n != 1) | |
n: 5 | |
Breakpoint 4 at 0x400519: file 3n1.c, line 8. | |
Breakpoint 4, main () at 3n1.c:8 | |
8 n = 3*n + 1; | |
6 while (n != 1) | |
n: 16 | |
Breakpoint 5 at 0x40052b: file 3n1.c, line 10. | |
Breakpoint 5, main () at 3n1.c:10 | |
10 n = n/2; | |
6 while (n != 1) | |
n: 8 | |
Breakpoint 6 at 0x40052b: file 3n1.c, line 10. | |
Breakpoint 6, main () at 3n1.c:10 | |
10 n = n/2; | |
6 while (n != 1) | |
n: 4 | |
Breakpoint 7 at 0x40052b: file 3n1.c, line 10. | |
Breakpoint 7, main () at 3n1.c:10 | |
10 n = n/2; | |
6 while (n != 1) | |
n: 2 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import gdb | |
class UntilBreakpointContext: | |
(STATE_NOT_WAITING, # initial state | |
STATE_WAIT_INITED, # post wait_init | |
STATE_STOPPED_SHOULD_CONTINUE, # stopped, but not by a breakpoints we want | |
STATE_INFERIOR_EXITED, # the process being debugged ('inferior') exited | |
STATE_STOPPED_BP_HIT # stopped by a breakpoint we're waiting for | |
) = range(5) | |
def __init__(self): | |
self.bpnums = [] | |
self.state = self.STATE_NOT_WAITING | |
self.stopped_by_bpnum = None | |
def stop_handler(self, e): | |
if not isinstance(e, gdb.BreakpointEvent): | |
self.state = self.STATE_STOPPED_SHOULD_CONTINUE | |
return | |
for i in e.breakpoints: | |
if i.number in self.bpnums: | |
(self.state, self.stopped_by_bpnum) = (self.STATE_STOPPED_BP_HIT, i.number) | |
return | |
else: | |
self.state = self.STATE_STOPPED_SHOULD_CONTINUE | |
def exited_handler(self, e): | |
self.state = self.STATE_INFERIOR_EXITED | |
return | |
def wait_init(self): | |
if self.state != self.STATE_NOT_WAITING: | |
return | |
gdb.events.stop.connect(self.stop_handler) | |
gdb.events.exited.connect(self.exited_handler) | |
self.state = self.STATE_WAIT_INITED | |
def wait_end(self): | |
if self.state == self.STATE_NOT_WAITING: | |
return | |
gdb.events.stop.disconnect(self.stop_handler) | |
gdb.events.exited.disconnect(self.exited_handler) | |
self.state = self.STATE_NOT_WAITING | |
def wait(self, bpnums): | |
assert(self.state == self.STATE_NOT_WAITING) | |
self.bpnums = bpnums | |
self.wait_init() | |
while 1: | |
if gdb.selected_inferior().pid == 0: | |
gdb.execute('run') | |
else: | |
gdb.execute('continue') | |
# 'run' or 'continue' returned, state changed | |
if self.state == self.STATE_STOPPED_SHOULD_CONTINUE: | |
gdb.execute('continue') | |
elif self.state == self.STATE_INFERIOR_EXITED: | |
self.wait_end() | |
raise gdb.GdbError('until-breakpoint: ' | |
'inferior exited while waiting for breakpoints %r' % (self.bpnums,)) | |
elif self.state == self.STATE_STOPPED_BP_HIT: | |
self.wait_end() | |
return | |
else: | |
assert(0) | |
until_breakpoint_cxt = UntilBreakpointContext() | |
class UntilBreakpoint(gdb.Command): | |
'''until-breakpoint BPNUM. Run until BPNUM is hit''' | |
def __init__(self): | |
super(UntilBreakpoint, self).__init__('until-breakpoint', | |
gdb.COMMAND_RUNNING, gdb.COMPLETE_EXPRESSION) | |
def invoke(self, args, from_tty): | |
global until_breakpoint_cxt | |
bpnum = int(gdb.parse_and_eval(args)) | |
until_breakpoint_cxt.wait([bpnum]) | |
UntilBreakpoint() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment