This is the mail archive of the
archer@sourceware.org
mailing list for the Archer project.
Re: [patch] Fix glitches with libstdc++ pretty printers
Here's a patch that changes how pretty printers are found.
The python code is now found based on the objfile's real path. gdb
appends "-gdb.py" to this and tries to eval it. So, instead of
.gdb.py, I now have libstdc++.so.6.0.10-gdb.py.
When this file is being evalled, a new global is set to the "current"
objfile. This can be retrieved using gdb.get_current_objfile. This
adds a new Objfile class which represents an objfile. An Objfile has
printer map properties.
So, I changed the end of my libstdc++ .py file to read:
obj = gdb.get_current_objfile()
obj.cli_pretty_printers['^std::basic_string<char.*>$'] = StdStringPrinter()
obj.mi_pretty_printers['^std::basic_string<char.*>$'] = StdStringPrinter
...
This is how printers are associated with a particular objfile.
Then we just iterate over all the objfiles when trying to find a
printer. Presumably this will handle the multi-process case nicely,
by having some caller set the current inferior first.
Let me know what you think. I think I will check this in now; we can
always revert it if we prefer a different approach. If we agree on
this direction, I'll write the documentation.
Tom
2008-10-31 Tom Tromey <tromey@redhat.com>
* python/python.c (_initialize_python): Call
gdbpy_initialize_objfile.
(gdbpy_current_objfile): New global.
(gdbpy_get_current_objfile): New function.
(gdbpy_new_objfile): Set gdbpy_current_objfile. Use real path to
objfile. Change filename computation.
(GdbMethods): Add get_current_objfile, get_objfiles.
(gdbpy_get_objfiles): New function.
(find_pretty_printer): Remove dict_name argument, add is_mi.
Search objfile printers first.
(search_pp_dictionary): New function.
(apply_pretty_printer): Update.
(apply_val_pretty_printer): Likewise.
(gdbpy_get_varobj_pretty_printer): Likewise.
(GDBPY_AUTO_FILENAME): Change value.
* python/python-objfile.c: New file.
* python/python-internal.h (objfile_to_objfile_object): Declare.
(gdbpy_initialize_objfile): Declare.
(objfpy_get_mi_printers, objfpy_get_cli_printers): Declare.
* Makefile.in (SUBDIR_PYTHON_OBS): Add python-objfile.o.
(SUBDIR_PYTHON_SRCS): Add python-objfile.c.
(python-objfile.o): New target.
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 1706b6b..a0716af 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -277,6 +277,7 @@ SUBDIR_PYTHON_OBS = \
python-frame.o \
python-function.o \
python-hooks.o \
+ python-objfile.o \
python-param.o \
python-symbol.o \
python-symtab.o \
@@ -291,6 +292,7 @@ SUBDIR_PYTHON_SRCS = \
python/python-frame.c \
python/python-function.c \
python/python-hooks.c \
+ python/python-objfile.c \
python/python-param.c \
python/python-symbol.c \
python/python-symtab.c \
@@ -1891,6 +1893,10 @@ python-hooks.o: $(srcdir)/python/python-hooks.c
$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-hooks.c
$(POSTCOMPILE)
+python-objfile.o: $(srcdir)/python/python-objfile.c
+ $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-objfile.c
+ $(POSTCOMPILE)
+
python-param.o: $(srcdir)/python/python-param.c
$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-param.c
$(POSTCOMPILE)
diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h
index 12b9917..6dff805 100644
--- a/gdb/python/python-internal.h
+++ b/gdb/python/python-internal.h
@@ -73,6 +73,10 @@ PyObject *block_to_block_object (struct block *block);
PyObject *value_to_value_object (struct value *v);
PyObject *gdb_owned_value_to_value_object (struct value *v);
PyObject *type_to_type_object (struct type *);
+PyObject *objfile_to_objfile_object (struct objfile *);
+
+PyObject *objfpy_get_mi_printers (PyObject *, void *);
+PyObject *objfpy_get_cli_printers (PyObject *, void *);
struct block *block_object_to_block (PyObject *obj);
struct symbol *symbol_object_to_symbol (PyObject *obj);
@@ -91,6 +95,7 @@ void gdbpy_initialize_symbols (void);
void gdbpy_initialize_types (void);
void gdbpy_initialize_blocks (void);
void gdbpy_initialize_functions (void);
+void gdbpy_initialize_objfile (void);
void gdbpy_initialize_parameters (void);
struct cleanup *make_cleanup_py_decref (PyObject *py);
diff --git a/gdb/python/python-objfile.c b/gdb/python/python-objfile.c
new file mode 100644
index 0000000..6b5a7c3
--- /dev/null
+++ b/gdb/python/python-objfile.c
@@ -0,0 +1,281 @@
+/* Python interface to objfiles.
+
+ Copyright (C) 2008 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "defs.h"
+#include "python-internal.h"
+#include "charset.h"
+#include "objfiles.h"
+
+typedef struct
+{
+ PyObject_HEAD
+
+ /* The corresponding objfile. */
+ struct objfile *objfile;
+
+ /* The pretty-printer dictionaries. */
+ PyObject *mi_printers;
+ PyObject *cli_printers;
+} objfile_object;
+
+static PyTypeObject objfile_object_type;
+
+static const struct objfile_data *objfpy_objfile_data_key;
+
+
+
+/* An Objfile method which returns the objfile's file name, or None. */
+static PyObject *
+objfpy_filename (PyObject *self, PyObject *args)
+{
+ objfile_object *obj = (objfile_object *) self;
+ if (obj->objfile && obj->objfile->name)
+ return PyString_Decode (obj->objfile->name, strlen (obj->objfile->name),
+ host_charset (), NULL);
+ Py_RETURN_NONE;
+}
+
+static void
+objfpy_dealloc (PyObject *o)
+{
+ objfile_object *self = (objfile_object *) o;
+ Py_XDECREF (self->mi_printers);
+ Py_XDECREF (self->cli_printers);
+ self->ob_type->tp_free ((PyObject *) self);
+}
+
+static PyObject *
+objfpy_new (PyTypeObject *type, PyObject *args, PyObject *keywords)
+{
+ objfile_object *self = (objfile_object *) type->tp_alloc (type, 0);
+ if (self)
+ {
+ self->objfile = NULL;
+ /* Initialize in case of early return. */
+ self->cli_printers = NULL;
+
+ self->mi_printers = PyDict_New ();
+ if (!self->mi_printers)
+ {
+ Py_DECREF (self);
+ return NULL;
+ }
+ self->cli_printers = PyDict_New ();
+ if (!self->cli_printers)
+ {
+ Py_DECREF (self);
+ return NULL;
+ }
+ }
+ return (PyObject *) self;
+}
+
+PyObject *
+objfpy_get_mi_printers (PyObject *o, void *ignore)
+{
+ objfile_object *self = (objfile_object *) o;
+ Py_INCREF (self->mi_printers);
+ return self->mi_printers;
+}
+
+static int
+objfpy_set_mi_printers (PyObject *o, PyObject *value, void *ignore)
+{
+ objfile_object *self = (objfile_object *) o;
+ if (! value)
+ {
+ PyErr_SetString (PyExc_TypeError,
+ "cannot delete the mi_pretty_printers attribute");
+ return -1;
+ }
+
+ if (! PyDict_Check (value))
+ {
+ PyErr_SetString (PyExc_TypeError,
+ "the mi_pretty_printers attribute must be a dictionary");
+ return -1;
+ }
+
+ Py_XDECREF (self->mi_printers);
+ Py_INCREF (value);
+ self->mi_printers = value;
+
+ return 0;
+}
+
+PyObject *
+objfpy_get_cli_printers (PyObject *o, void *ignore)
+{
+ objfile_object *self = (objfile_object *) o;
+ Py_INCREF (self->cli_printers);
+ return self->cli_printers;
+}
+
+static int
+objfpy_set_cli_printers (PyObject *o, PyObject *value, void *ignore)
+{
+ objfile_object *self = (objfile_object *) o;
+ if (! value)
+ {
+ PyErr_SetString (PyExc_TypeError,
+ "cannot delete the cli_pretty_printers attribute");
+ return -1;
+ }
+
+ if (! PyDict_Check (value))
+ {
+ PyErr_SetString (PyExc_TypeError,
+ "the cli_pretty_printers attribute must be a dictionary");
+ return -1;
+ }
+
+ Py_XDECREF (self->cli_printers);
+ Py_INCREF (value);
+ self->cli_printers = value;
+
+ return 0;
+}
+
+
+
+/* Clear the OBJFILE pointer in an Objfile object and remove the
+ reference. */
+static void
+clean_up_objfile (struct objfile *objfile, void *datum)
+{
+ objfile_object *object = datum;
+ object->objfile = NULL;
+ Py_DECREF ((PyObject *) object);
+}
+
+/* Return the Python object of type Objfile representing OBJFILE. If
+ the object has already been created, return it. Otherwise, create
+ it. Return NULL and set the Python error on failure. */
+PyObject *
+objfile_to_objfile_object (struct objfile *objfile)
+{
+ objfile_object *object;
+
+ object = objfile_data (objfile, objfpy_objfile_data_key);
+ if (!object)
+ {
+ object = PyObject_New (objfile_object, &objfile_object_type);
+ if (object)
+ {
+ PyObject *dict;
+
+ object->objfile = objfile;
+ /* Initialize in case of early return. */
+ object->cli_printers = NULL;
+
+ object->mi_printers = PyDict_New ();
+ if (!object->mi_printers)
+ {
+ Py_DECREF (object);
+ return NULL;
+ }
+
+ object->cli_printers = PyDict_New ();
+ if (!object->cli_printers)
+ {
+ Py_DECREF (object);
+ return NULL;
+ }
+
+ set_objfile_data (objfile, objfpy_objfile_data_key, object);
+ }
+ }
+
+ return (PyObject *) object;
+}
+
+void
+gdbpy_initialize_objfile (void)
+{
+ objfpy_objfile_data_key
+ = register_objfile_data_with_cleanup (clean_up_objfile);
+
+ objfile_object_type.tp_new = PyType_GenericNew;
+ if (PyType_Ready (&objfile_object_type) < 0)
+ return;
+
+ Py_INCREF (&objfile_object_type);
+ PyModule_AddObject (gdb_module, "Objfile", (PyObject *) &objfile_object_type);
+}
+
+
+
+static PyGetSetDef objfile_getset[] =
+{
+ { "mi_pretty_printers", objfpy_get_mi_printers, objfpy_set_mi_printers,
+ "MI pretty printers", NULL },
+ { "cli_pretty_printers", objfpy_get_cli_printers, objfpy_set_cli_printers,
+ "CLI pretty printers", NULL },
+ { NULL }
+};
+
+static PyMethodDef objfile_object_methods[] =
+{
+ { "get_filename", objfpy_filename, METH_NOARGS,
+ "Return the objfile's filename, or None." },
+ {NULL} /* Sentinel */
+};
+
+static PyTypeObject objfile_object_type =
+{
+ PyObject_HEAD_INIT (NULL)
+ 0, /*ob_size*/
+ "gdb.Objfile", /*tp_name*/
+ sizeof (objfile_object), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ objfpy_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT, /*tp_flags*/
+ "GDB objfile object", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ objfile_object_methods, /* tp_methods */
+ 0, /* tp_members */
+ objfile_getset, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ objfpy_new, /* tp_new */
+};
diff --git a/gdb/python/python.c b/gdb/python/python.c
index 22f85ba..af50c4c 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -545,15 +545,20 @@ run_python_script (int argc, char **argv)
+/* The "current" objfile. This is set when gdb detects that a new
+ objfile has been loaded. It is only set for the duration of a call
+ to gdbpy_new_objfile; it is NULL at other times. */
+static struct objfile *gdbpy_current_objfile;
+
/* The file name we attempt to read. */
-#define GDBPY_AUTO_FILENAME ".gdb.py"
+#define GDBPY_AUTO_FILENAME "-gdb.py"
/* This is a new_objfile observer callback which loads python code
based on the path to the objfile. */
static void
gdbpy_new_objfile (struct objfile *objfile)
{
- char *p;
+ char *realname;
char *filename;
int len;
FILE *input;
@@ -561,10 +566,12 @@ gdbpy_new_objfile (struct objfile *objfile)
if (!gdbpy_auto_load || !objfile || !objfile->name)
return;
- p = (char *) lbasename (objfile->name);
- len = p - objfile->name;
+ gdbpy_current_objfile = objfile;
+
+ realname = gdb_realpath (objfile->name);
+ len = strlen (realname);
filename = xmalloc (len + sizeof (GDBPY_AUTO_FILENAME));
- memcpy (filename, objfile->name, len);
+ memcpy (filename, realname, len);
strcpy (filename + len, GDBPY_AUTO_FILENAME);
input = fopen (filename, "r");
@@ -578,7 +585,48 @@ gdbpy_new_objfile (struct objfile *objfile)
fclose (input);
}
+ xfree (realname);
xfree (filename);
+ gdbpy_current_objfile = NULL;
+}
+
+/* Return the current Objfile, or None if there isn't one. */
+static PyObject *
+gdbpy_get_current_objfile (PyObject *unused1, PyObject *unused2)
+{
+ PyObject *result;
+
+ if (! gdbpy_current_objfile)
+ Py_RETURN_NONE;
+
+ result = objfile_to_objfile_object (gdbpy_current_objfile);
+ if (result)
+ Py_INCREF (result);
+ return result;
+}
+
+/* Return a sequence holding all the Objfiles. */
+static PyObject *
+gdbpy_get_objfiles (PyObject *unused1, PyObject *unused2)
+{
+ struct objfile *objf;
+ PyObject *list;
+
+ list = PyList_New (0);
+ if (!list)
+ return NULL;
+
+ ALL_OBJFILES (objf)
+ {
+ PyObject *item = objfile_to_objfile_object (objf);
+ if (!item || PyList_Append (list, item) == -1)
+ {
+ Py_DECREF (list);
+ return NULL;
+ }
+ }
+
+ return list;
}
@@ -604,31 +652,44 @@ get_type (struct type *type)
return thetype;
}
+/* Helper function for find_pretty_printer which iterates over a
+ dictionary and tries to find a match. */
+static PyObject *
+search_pp_dictionary (PyObject *dict, char *type_name)
+{
+ Py_ssize_t iter;
+ PyObject *key, *func, *found = NULL;
+
+ /* See if the type matches a pretty-printer regexp. */
+ iter = 0;
+ while (! found && PyDict_Next (dict, &iter, &key, &func))
+ {
+ char *rx_str;
+
+ if (! PyString_Check (key))
+ continue;
+ rx_str = PyString_AsString (key);
+ if (re_comp (rx_str) == NULL && re_exec (type_name) == 1)
+ found = func;
+ }
+
+ return found;
+}
+
/* Find the pretty-printing function for TYPE. If no pretty-printer
exists, return NULL. If one exists, return a borrowed reference.
If a printer is found, *DICTP is set to a reference to the
dictionary object; it must be derefed by the caller. DICT_NAME is
the name of the dictionary to search for types. */
static PyObject *
-find_pretty_printer (struct type *type, PyObject **dictp, char *dict_name)
+find_pretty_printer (struct type *type, PyObject **dictp, int is_mi)
{
- PyObject *dict, *key, *func, *found = NULL;
- Py_ssize_t iter;
+ PyObject *dict, *found;
char *type_name = NULL;
+ char *dict_name;
+ struct objfile *obj;
volatile struct gdb_exception except;
- /* Fetch the pretty printer dictionary. */
- if (! PyObject_HasAttrString (gdb_module, dict_name))
- return NULL;
- dict = PyObject_GetAttrString (gdb_module, dict_name);
- if (! dict)
- return NULL;
- if (! PyDict_Check (dict) || ! PyDict_Size (dict))
- {
- Py_DECREF (dict);
- return NULL;
- }
-
/* Get the name of the type. */
TRY_CATCH (except, RETURN_MASK_ALL)
{
@@ -645,25 +706,45 @@ find_pretty_printer (struct type *type, PyObject **dictp, char *dict_name)
return NULL;
}
- /* See if the type matches a pretty-printer regexp. */
- iter = 0;
- while (! found && PyDict_Next (dict, &iter, &key, &func))
- {
- char *rx_str;
+ /* Look at the pretty-printer dictionary for each objfile. */
+ ALL_OBJFILES (obj)
+ {
+ PyObject *objf = objfile_to_objfile_object (obj);
+ if (!objf)
+ continue;
- if (! PyString_Check (key))
- continue;
- rx_str = PyString_AsString (key);
- if (re_comp (rx_str) == NULL && re_exec (type_name) == 1)
- found = func;
- }
+ if (is_mi)
+ dict = objfpy_get_mi_printers (objf, NULL);
+ else
+ dict = objfpy_get_cli_printers (objf, NULL);
+ found = search_pp_dictionary (dict, type_name);
+ if (found)
+ goto done;
+
+ Py_DECREF (dict);
+ }
+
+ /* Fetch the global pretty printer dictionary. */
+ dict_name = is_mi ? "mi_pretty_printers" : "cli_pretty_printers";
+ dict = NULL;
+ if (! PyObject_HasAttrString (gdb_module, dict_name))
+ goto done;
+ dict = PyObject_GetAttrString (gdb_module, dict_name);
+ if (! dict)
+ goto done;
+ if (! PyDict_Check (dict) || ! PyDict_Size (dict))
+ goto done;
+
+ found = search_pp_dictionary (dict, type_name);
+
+ done:
xfree (type_name);
if (found)
*dictp = dict;
else
- Py_DECREF (dict);
+ Py_XDECREF (dict);
return found;
}
@@ -751,7 +832,7 @@ apply_pretty_printer (struct value *value, struct value **out_value)
*out_value = NULL;
- func = find_pretty_printer (value_type (value), &dict, "cli_pretty_printers");
+ func = find_pretty_printer (value_type (value), &dict, 0);
if (! func)
return NULL;
@@ -778,7 +859,7 @@ apply_val_pretty_printer (struct type *type, const gdb_byte *valaddr,
struct value *value, *replacement = NULL;
char *output;
- func = find_pretty_printer (type, &dict, "cli_pretty_printers");
+ func = find_pretty_printer (type, &dict, 0);
if (! func)
return NULL;
@@ -828,7 +909,7 @@ PyObject *
gdbpy_get_varobj_pretty_printer (struct type *type)
{
PyObject *dict = NULL;
- PyObject *printer = find_pretty_printer (type, &dict, "mi_pretty_printers");
+ PyObject *printer = find_pretty_printer (type, &dict, 1);
if (dict)
{
Py_DECREF (dict);
@@ -1015,6 +1096,7 @@ Enables or disables auto-loading of Python code when an object is opened."),
gdbpy_initialize_functions ();
gdbpy_initialize_types ();
gdbpy_initialize_parameters ();
+ gdbpy_initialize_objfile ();
PyRun_SimpleString ("import gdb");
PyRun_SimpleString ("gdb.cli_pretty_printers = {}");
@@ -1102,6 +1184,11 @@ static PyMethodDef GdbMethods[] =
{ "get_default_visualizer", gdbpy_get_default_visualizer, METH_VARARGS,
"Find the default visualizer for a Value." },
+ { "get_current_objfile", gdbpy_get_current_objfile, METH_NOARGS,
+ "Return the current Objfile being loaded, or None." },
+ { "get_objfiles", gdbpy_get_objfiles, METH_NOARGS,
+ "Return a sequence of all loaded objfiles." },
+
{ "get_frames", gdbpy_get_frames, METH_NOARGS,
"Return a tuple of all frame objects" },
{ "get_current_frame", gdbpy_get_current_frame, METH_NOARGS,