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 bdb5319..bc9e720 100644 --- a/gdb/python/python.c +++ b/gdb/python/python.c @@ -1032,6 +1032,97 @@ 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 an empty dummy PythonCodeObject. + Copied almost verbatim from (GPL-compatible) + Python-2.6/Modules/pyexpat.c */ +static PyCodeObject * +getcode () +{ + PyObject *code = NULL; + PyObject *name = NULL; + PyObject *nulltuple = NULL; + PyObject *filename = NULL; + PyCodeObject *ret = NULL; + + code = PyString_FromString (""); + if (code == NULL) + goto failed; + name = PyString_FromString ("dummy"); + if (name == NULL) + goto failed; + nulltuple = PyTuple_New (0); + if (nulltuple == NULL) + goto failed; + filename = PyString_FromString (__FILE__); + ret = PyCode_New (0, /* argcount */ + 0, /* nlocals */ + 0, /* stacksize */ + 0, /* flags */ + code, /* code */ + nulltuple, /* consts */ + nulltuple, /* names */ + nulltuple, /* varnames */ +#if PYTHON_API_VERSION >= 1010 + nulltuple, /* freevars */ + nulltuple, /* cellvars */ +#endif + filename, /* filename */ + name, /* name */ + 1, /* firstlineno */ + code /* lnotab */ + ); + if (ret == NULL) + goto failed; + Py_DECREF (code); + Py_DECREF (nulltuple); + Py_DECREF (filename); + Py_DECREF (name); + return ret; + failed: + Py_XDECREF (code); + Py_XDECREF (name); + return NULL; +} + +/* Create a dummy PyFrameObject, needed to work around + a Python-2.4 bug with generators. */ +static PyObject * +push_dummy_python_frame () +{ + PyFrameObject *frame = NULL; + PyCodeObject *code = NULL; + PyObject *globals = NULL; + PyThreadState *tstate = PyThreadState_GET (); + + globals = PyDict_New (); + if (!globals) + goto failed; + code = getcode (); + if (!code) + goto failed; + frame = PyFrame_New (tstate, code, globals, NULL); + if (!frame) + goto failed; + Py_DECREF (globals); + Py_DECREF (code); + + tstate->frame = frame; + make_cleanup (py_restore_tstate, frame->f_back); + return (PyObject *) frame; + failed: + Py_XDECREF (globals); + Py_XDECREF (code); + return NULL; +} + /* Helper for apply_val_pretty_printer that formats children of the printer, if any exist. */ static void @@ -1042,7 +1133,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)) @@ -1075,6 +1166,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) {