This is the mail archive of the archer@sourceware.org mailing list for the Archer project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

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,


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]