Forked from kouk/debugging python object fields with gdb
Last active
February 3, 2020 05:52
-
-
Save fake-name/9ea90ec8551ee2dc3a758921c3853bec to your computer and use it in GitHub Desktop.
pyfields.py
This file contains hidden or 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
## Now with python3k support! | |
$ python foo.py & | |
[1] 21377 | |
$ gdb -p 21377 | |
GNU gdb (GDB) Fedora 7.7.1-17.fc20 | |
[... gdb loading messages ...] | |
0x00007f9a09af46e3 in __select_nocancel () at ../sysdeps/unix/syscall-template.S:81 | |
81 T_PSEUDO (SYSCALL_SYMBOL, SYSCALL_NAME, SYSCALL_NARGS) | |
(gdb) py-bt | |
#4 Frame 0x22d9c70, for file foo.py, line 12, in forever () | |
sleep(1) | |
#7 Frame 0x224f830, for file foo.py, line 14, in <module> () | |
forever() | |
(gdb) py-print f | |
global 'f' = <Foo(foo=1) at remote 0x7f9a0abba830> | |
(gdb) py-print f.foo | |
'f.foo' not found | |
(gdb) source pyfields.py | |
(gdb) py-fields f.foo | |
global 'foo' = 1 | |
(gdb) quit | |
A debugging session is active. | |
Inferior 1 [process 21377] will be detached. | |
Quit anyway? (y or n) y | |
Detaching from program: /usr/bin/python2.7, process 21377 | |
$ exit | |
This file contains hidden or 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
from time import sleep | |
class Foo: | |
def __init__(self): | |
self.foo = 1 | |
f = Foo() | |
def forever(): | |
while f.foo == 1: | |
sleep(1) | |
forever() |
This file contains hidden or 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
class PyPrintFields(gdb.Command): | |
'Look up the given python variable name, and print it' | |
def __init__(self): | |
gdb.Command.__init__ (self, | |
"py-fields", | |
gdb.COMMAND_DATA, | |
gdb.COMPLETE_NONE) | |
def invoke(self, args, from_tty): | |
name = str(args) | |
frame = Frame.get_selected_python_frame() | |
if not frame: | |
print('Unable to locate python frame') | |
return | |
pyop_frame = frame.get_pyop() | |
if not pyop_frame: | |
print('Unable to read information on python frame') | |
return | |
def get_var_dict(v): | |
print("V: ", v) | |
if isinstance(v, HeapTypeObjectPtr): | |
return v.get_attr_dict() | |
elif isinstance(v, PyInstanceObjectPtr): | |
return v.pyop_field('in_dict') | |
else: | |
return {} | |
parent = None | |
fields = name.split('.') | |
for name in fields: | |
if parent is None: | |
pyop_var, scope = pyop_frame.get_var_by_name(name) | |
else: | |
for k, pyop_var in get_var_dict(parent).iteritems(): | |
# Assuming x is a PyUnicodeObjectPtr object here. | |
if k.proxyval(False) == name: | |
break | |
else: | |
print("Can't find field %s of %s" % (name, parent)) | |
return | |
parent = pyop_var | |
if pyop_var: | |
print(('%s %r = %s') | |
% (scope, | |
name, | |
pyop_var.get_truncated_repr(MAX_OUTPUT_LEN))) | |
else: | |
print('%r not found' % name) | |
PyPrintFields() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment