diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h index 4563597..afdf821 100644 --- a/gdb/python/python-internal.h +++ b/gdb/python/python-internal.h @@ -33,6 +33,7 @@ #if HAVE_LIBPYTHON2_4 #include "python2.4/Python.h" +#include "python2.4/frameobject.h" /* Py_ssize_t is not defined until 2.5. Logical type for Py_ssize_t is Py_intptr_t, but that fails in 64-bit compilation due to several apparent mistakes in python2.4 API, so we @@ -40,8 +41,10 @@ typedef int Py_ssize_t; #elif HAVE_LIBPYTHON2_5 #include "python2.5/Python.h" +#include "python2.5/frameobject.h" #elif HAVE_LIBPYTHON2_6 #include "python2.6/Python.h" +#include "python2.6/frameobject.h" #else #error "Unable to find usable Python.h" #endif diff --git a/gdb/python/python.c b/gdb/python/python.c index 8fdf1fb..b97fbea 100644 --- a/gdb/python/python.c +++ b/gdb/python/python.c @@ -1038,6 +1038,79 @@ print_string_repr (PyObject *printer, const char *hint, gdbpy_print_stack (); } +static void +py_restore_tstate (void *p) +{ + PyFrameObject *frame = p; + PyThreadState *tstate = PyThreadState_GET (); + tstate->frame = frame; +} + +/* Create a dummy PyFrameObject, needed to work around + a Python-2.4 bug with generators. */ +static PyObject * +push_dummy_python_frame () +{ + PyObject *empty_string, *null_tuple; + PyCodeObject *code; + + empty_string = PyString_FromString (""); + null_tuple = PyTuple_New (0); + + if (!empty_string || !null_tuple) + goto failed; + + code = PyCode_New (0, /* argcount */ + 0, /* nlocals */ + 0, /* stacksize */ + 0, /* flags */ + empty_string, /* code */ + null_tuple, /* consts */ + null_tuple, /* names */ + null_tuple, /* varnames */ +#if PYTHON_API_VERSION >= 1010 + null_tuple, /* freevars */ + null_tuple, /* cellvars */ +#endif + empty_string, /* filename */ + empty_string, /* name */ + 1, /* firstlineno */ + empty_string /* lnotab */ + ); + + if (code) + { + PyObject *globals; + PyThreadState *tstate = PyThreadState_GET (); + + Py_DECREF (empty_string); + Py_DECREF (null_tuple); + + globals = PyDict_New (); + if (globals) + { + PyFrameObject *frame; + + frame = PyFrame_New (tstate, code, globals, NULL); + if (frame) + { + Py_DECREF (globals); + Py_DECREF (code); + + tstate->frame = frame; + make_cleanup (py_restore_tstate, frame->f_back); + return (PyObject *) frame; + } + Py_DECREF (globals); + } + Py_DECREF (code); + } + failed: + Py_XDECREF (empty_string); + Py_XDECREF (null_tuple); + return NULL; +} + /* Helper for apply_val_pretty_printer that formats children of the printer, if any exist. */ static void @@ -1048,7 +1121,7 @@ print_children (PyObject *printer, const char *hint, { int is_map, is_array, done_flag, pretty; unsigned int i; - PyObject *children, *iter; + PyObject *children, *iter, *frame; struct cleanup *cleanups; if (! PyObject_HasAttr (printer, gdbpy_children_cst)) @@ -1081,6 +1154,17 @@ print_children (PyObject *printer, const char *hint, and the pretty option otherwise. */ pretty = is_array ? options->prettyprint_arrays : options->pretty; + /* Manufacture a dummy Python frame to work around Python 2.4 bug, + where it insists on having a non-NULL tstate->frame when + a generator is called. */ + frame = push_dummy_python_frame (); + if (!frame) + { + gdbpy_print_stack (); + goto done; + } + make_cleanup_py_decref (frame); + done_flag = 0; for (i = 0; i < options->print_max; ++i) {