Normally, the "finish" command will interrupt any script you're in the middle of executing, so we have to do a bit of an ugly hack to make sure our script keeps running:
b PyEval_EvalFrameEx if strcmp(PyString_AsString(f->f_code->co_name), "handle_uncaught_exception") == 0
commands
disable
frame 3
python
gdb.execute('finish')
gdb.execute('shell git stash pop')
gdb.execute('call PyImport_ReloadModule(PyImport_AddModule("monospace.views"))')
gdb.execute('call PyImport_ReloadModule(PyImport_AddModule("monospace.urls"))')
gdb.execute('set $self = PyDict_GetItemString(f->f_locals, "self")')
gdb.execute('set $request = PyDict_GetItemString(f->f_locals, "request")')
gdb.execute('set $get_response = PyObject_GetAttrString($self, "get_response")')
gdb.execute('set $args = Py_BuildValue("(O)", $request)')
gdb.execute('set $rax PyObject_Call($get_response, $args, 0)')
gdb.execute('enable')
gdb.execute('c')
end
c
end
(Bah. Edited because I couldn't get monospace text working)
You could put those commands into a file and run "gdb -p <my django process> -x <my commands file>"
Of course, instead of shelling out to git stash pop, you'd probably want to pause so you could update the code. And you may need to reload more modules than just monospace.views and monospace.urls, depending on the change.
If you start each line with a few spaces, HN will format it as source code:
b PyEval_EvalFrameEx if strcmp(PyString_AsString(f->f_code->co_name), "handle_uncaught_exception") == 0
commands
disable
frame 3
python
gdb.execute('finish')
gdb.execute('shell git stash pop')
gdb.execute('call PyImport_ReloadModule(PyImport_AddModule("monospace.views"))')
gdb.execute('call PyImport_ReloadModule(PyImport_AddModule("monospace.urls"))')
gdb.execute('set $self = PyDict_GetItemString(f->f_locals, "self")')
gdb.execute('set $request = PyDict_GetItemString(f->f_locals, "request")')
gdb.execute('set $get_response = PyObject_GetAttrString($self, "get_response")')
gdb.execute('set $args = Py_BuildValue("(O)", $request)')
gdb.execute('set $rax PyObject_Call($get_response, $args, 0)')
gdb.execute('enable')
gdb.execute('c')
end
c
endI've done this manually a few times, but with foresight attaching signal handlers that open up a port or dump stack (a la `jstack`) is usually less finicky.