aboutsummaryrefslogtreecommitdiff
path: root/gdb/python
diff options
context:
space:
mode:
authorTom Tromey <tromey@redhat.com>2012-11-12 17:41:59 +0000
committerTom Tromey <tromey@redhat.com>2012-11-12 17:41:59 +0000
commit18a9fc1261b8a654fe6db7eea7e60b0c59296d96 (patch)
tree50b1290ab9827f259ea103cf50367d7ac6c0e878 /gdb/python
parentbd69fc683f383772bb8fab43c5d4af8d0cd4a8b4 (diff)
downloadgdb-18a9fc1261b8a654fe6db7eea7e60b0c59296d96.zip
gdb-18a9fc1261b8a654fe6db7eea7e60b0c59296d96.tar.gz
gdb-18a9fc1261b8a654fe6db7eea7e60b0c59296d96.tar.bz2
* NEWS: Update.
* data-directory/Makefile.in (PYTHON_FILES): Add type_printers.py. * python/lib/gdb/command/type_printers.py: New file. * python/lib/gdb/command/types.py (TypePrinter): New class. (_get_some_type_recognizers, get_type_recognizers, apply_type_recognizers, register_type_printer): New functions. * python/py-objfile.c (objfile_object) <type_printers>: New field. (objfpy_dealloc): Decref new field. (objfpy_new): Set new field. (objfpy_get_type_printers, objfpy_set_type_printers): New functions. (objfile_to_objfile_object): Set new field. (objfile_getset): Add "type_printers". * python/py-progspace.c (pspace_object) <type_printers>: New field. (pspy_dealloc): Decref new field. (pspy_new): Set new field. (pspy_get_type_printers, pspy_set_type_printers): New functions. (pspace_to_pspace_object): Set new field. (pspace_getset): Add "type_printers". * python/python.c (start_type_printers, apply_type_printers, free_type_printers): New functions. (_initialize_python): Set gdb.type_printers. * python/python.h (start_type_printers, apply_type_printers, free_type_printers): Declare. * typeprint.c (type_print_raw_options, default_ptype_flags): Update for new fields. (do_free_global_table, create_global_typedef_table, find_global_typedef): New functions. (find_typedef_in_hash): Use find_global_typedef. (whatis_exp): Use create_global_typedef_table. Change cleanup handling. * typeprint.h (struct type_print_options) <global_typedefs, global_printers>: New fields. doc * gdb.texinfo (Symbols): Document "info type-printers", "enable type-printer" and "disable type-printer". (Python API): Add new node to menu. (Type Printing API): New node. (Progspaces In Python): Document type_printers field. (Objfiles In Python): Likewise. (gdb.types) <get_type_recognizers, apply_type_recognizers, register_type_printer, TypePrinter>: Document. testsuite * gdb.base/completion.exp: Update for "info type-printers". * gdb.python/py-typeprint.cc: New file. * gdb.python/py-typeprint.exp: New file. * gdb.python/py-typeprint.py: New file.
Diffstat (limited to 'gdb/python')
-rw-r--r--gdb/python/lib/gdb/__init__.py3
-rw-r--r--gdb/python/lib/gdb/command/type_printers.py125
-rw-r--r--gdb/python/lib/gdb/types.py65
-rw-r--r--gdb/python/py-objfile.c62
-rw-r--r--gdb/python/py-progspace.c62
-rw-r--r--gdb/python/python.c136
-rw-r--r--gdb/python/python.h6
7 files changed, 459 insertions, 0 deletions
diff --git a/gdb/python/lib/gdb/__init__.py b/gdb/python/lib/gdb/__init__.py
index 0e020fe..0671526 100644
--- a/gdb/python/lib/gdb/__init__.py
+++ b/gdb/python/lib/gdb/__init__.py
@@ -70,6 +70,9 @@ sys.argv = ['']
# Initial pretty printers.
pretty_printers = []
+# Initial type printers.
+type_printers = []
+
# Convenience variable to GDB's python directory
PYTHONDIR = os.path.dirname(os.path.dirname(__file__))
diff --git a/gdb/python/lib/gdb/command/type_printers.py b/gdb/python/lib/gdb/command/type_printers.py
new file mode 100644
index 0000000..b7d6930
--- /dev/null
+++ b/gdb/python/lib/gdb/command/type_printers.py
@@ -0,0 +1,125 @@
+# Type printer commands.
+# Copyright (C) 2010-2012 Free Software Foundation, Inc.
+
+# 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/>.
+
+import copy
+import gdb
+
+"""GDB commands for working with type-printers."""
+
+class InfoTypePrinter(gdb.Command):
+ """GDB command to list all registered type-printers.
+
+ Usage: info type-printers
+ """
+
+ def __init__ (self):
+ super(InfoTypePrinter, self).__init__("info type-printers",
+ gdb.COMMAND_DATA)
+
+ def list_type_printers(self, type_printers):
+ """Print a list of type printers."""
+ # A potential enhancement is to provide an option to list printers in
+ # "lookup order" (i.e. unsorted).
+ sorted_type_printers = copy.copy(type_printers)
+ sorted_type_printers.sort(lambda x, y: cmp(x.name, y.name))
+ for printer in sorted_type_printers:
+ if printer.enabled:
+ enabled = ''
+ else:
+ enabled = " [disabled]"
+ print " %s%s" % (printer.name, enabled)
+
+ def invoke(self, arg, from_tty):
+ """GDB calls this to perform the command."""
+ sep = ''
+ for objfile in gdb.objfiles():
+ if objfile.type_printers:
+ print "%sType printers for %s:" % (sep, objfile.name)
+ self.list_type_printers(objfile.type_printers)
+ sep = '\n'
+ if gdb.current_progspace().type_printers:
+ print "%sType printers for program space:" % sep
+ self.list_type_printers(gdb.current_progspace().type_printers)
+ sep = '\n'
+ if gdb.type_printers:
+ print "%sGlobal type printers:" % sep
+ self.list_type_printers(gdb.type_printers)
+
+class _EnableOrDisableCommand(gdb.Command):
+ def __init__(self, setting, name):
+ super(_EnableOrDisableCommand, self).__init__(name, gdb.COMMAND_DATA)
+ self.setting = setting
+
+ def set_some(self, name, printers):
+ result = False
+ for p in printers:
+ if name == p.name:
+ p.enabled = self.setting
+ result = True
+ return result
+
+ def invoke(self, arg, from_tty):
+ """GDB calls this to perform the command."""
+ for name in arg.split():
+ ok = False
+ for objfile in gdb.objfiles():
+ if self.set_some(name, objfile.type_printers):
+ ok = True
+ if self.set_some(name, gdb.current_progspace().type_printers):
+ ok = True
+ if self.set_some(name, gdb.type_printers):
+ ok = True
+ if not ok:
+ print "No type printer named '%s'" % name
+
+ def add_some(self, result, word, printers):
+ for p in printers:
+ if p.name.startswith(word):
+ result.append(p.name)
+
+ def complete(self, text, word):
+ result = []
+ for objfile in gdb.objfiles():
+ self.add_some(result, word, objfile.type_printers)
+ self.add_some(result, word, gdb.current_progspace().type_printers)
+ self.add_some(result, word, gdb.type_printers)
+ return result
+
+class EnableTypePrinter(_EnableOrDisableCommand):
+ """GDB command to enable the specified type printer.
+
+ Usage: enable type-printer NAME
+
+ NAME is the name of the type-printer.
+ """
+
+ def __init__(self):
+ super(EnableTypePrinter, self).__init__(True, "enable type-printer")
+
+class DisableTypePrinter(_EnableOrDisableCommand):
+ """GDB command to disable the specified type-printer.
+
+ Usage: disable type-printer NAME
+
+ NAME is the name of the type-printer.
+ """
+
+ def __init__(self):
+ super(DisableTypePrinter, self).__init__(False, "disable type-printer")
+
+InfoTypePrinter()
+EnableTypePrinter()
+DisableTypePrinter()
diff --git a/gdb/python/lib/gdb/types.py b/gdb/python/lib/gdb/types.py
index 66c9528..3745383 100644
--- a/gdb/python/lib/gdb/types.py
+++ b/gdb/python/lib/gdb/types.py
@@ -109,3 +109,68 @@ def deep_items (type_):
else:
for i in deep_items (v.type):
yield i
+
+class TypePrinter(object):
+ """The base class for type printers.
+
+ Instances of this type can be used to substitute type names during
+ 'ptype'.
+
+ A type printer must have at least 'name' and 'enabled' attributes,
+ and supply an 'instantiate' method.
+
+ The 'instantiate' method must either return None, or return an
+ object which has a 'recognize' method. This method must accept a
+ gdb.Type argument and either return None, meaning that the type
+ was not recognized, or a string naming the type.
+ """
+
+ def __init__(self, name):
+ self.name = name
+ self.enabled = True
+
+ def instantiate(self):
+ return None
+
+# Helper function for computing the list of type recognizers.
+def _get_some_type_recognizers(result, plist):
+ for printer in plist:
+ if printer.enabled:
+ inst = printer.instantiate()
+ if inst is not None:
+ result.append(inst)
+ return None
+
+def get_type_recognizers():
+ "Return a list of the enabled type recognizers for the current context."
+ result = []
+
+ # First try the objfiles.
+ for objfile in gdb.objfiles():
+ _get_some_type_recognizers(result, objfile.type_printers)
+ # Now try the program space.
+ _get_some_type_recognizers(result, gdb.current_progspace().type_printers)
+ # Finally, globals.
+ _get_some_type_recognizers(result, gdb.type_printers)
+
+ return result
+
+def apply_type_recognizers(recognizers, type_obj):
+ """Apply the given list of type recognizers to the type TYPE_OBJ.
+ If any recognizer in the list recognizes TYPE_OBJ, returns the name
+ given by the recognizer. Otherwise, this returns None."""
+ for r in recognizers:
+ result = r.recognize(type_obj)
+ if result is not None:
+ return result
+ return None
+
+def register_type_printer(locus, printer):
+ """Register a type printer.
+ PRINTER is the type printer instance.
+ LOCUS is either an objfile, a program space, or None, indicating
+ global registration."""
+
+ if locus is None:
+ locus = gdb
+ locus.type_printers.insert(0, printer)
diff --git a/gdb/python/py-objfile.c b/gdb/python/py-objfile.c
index 9fa6813..5d2398f 100644
--- a/gdb/python/py-objfile.c
+++ b/gdb/python/py-objfile.c
@@ -32,6 +32,9 @@ typedef struct
/* The pretty-printer list of functions. */
PyObject *printers;
+
+ /* The type-printer list. */
+ PyObject *type_printers;
} objfile_object;
static PyTypeObject objfile_object_type;
@@ -58,6 +61,7 @@ objfpy_dealloc (PyObject *o)
objfile_object *self = (objfile_object *) o;
Py_XDECREF (self->printers);
+ Py_XDECREF (self->type_printers);
self->ob_type->tp_free ((PyObject *) self);
}
@@ -76,6 +80,13 @@ objfpy_new (PyTypeObject *type, PyObject *args, PyObject *keywords)
Py_DECREF (self);
return NULL;
}
+
+ self->type_printers = PyList_New (0);
+ if (!self->type_printers)
+ {
+ Py_DECREF (self);
+ return NULL;
+ }
}
return (PyObject *) self;
}
@@ -118,6 +129,48 @@ objfpy_set_printers (PyObject *o, PyObject *value, void *ignore)
return 0;
}
+/* Get the 'type_printers' attribute. */
+
+static PyObject *
+objfpy_get_type_printers (PyObject *o, void *ignore)
+{
+ objfile_object *self = (objfile_object *) o;
+
+ Py_INCREF (self->type_printers);
+ return self->type_printers;
+}
+
+/* Set the 'type_printers' attribute. */
+
+static int
+objfpy_set_type_printers (PyObject *o, PyObject *value, void *ignore)
+{
+ PyObject *tmp;
+ objfile_object *self = (objfile_object *) o;
+
+ if (! value)
+ {
+ PyErr_SetString (PyExc_TypeError,
+ _("Cannot delete the type_printers attribute."));
+ return -1;
+ }
+
+ if (! PyList_Check (value))
+ {
+ PyErr_SetString (PyExc_TypeError,
+ _("The type_printers attribute must be a list."));
+ return -1;
+ }
+
+ /* Take care in case the LHS and RHS are related somehow. */
+ tmp = self->type_printers;
+ Py_INCREF (value);
+ self->type_printers = value;
+ Py_XDECREF (tmp);
+
+ return 0;
+}
+
/* Implementation of gdb.Objfile.is_valid (self) -> Boolean.
Returns True if this object file still exists in GDB. */
@@ -172,6 +225,13 @@ objfile_to_objfile_object (struct objfile *objfile)
return NULL;
}
+ object->type_printers = PyList_New (0);
+ if (!object->type_printers)
+ {
+ Py_DECREF (object);
+ return NULL;
+ }
+
set_objfile_data (objfile, objfpy_objfile_data_key, object);
}
}
@@ -210,6 +270,8 @@ static PyGetSetDef objfile_getset[] =
"The objfile's filename, or None.", NULL },
{ "pretty_printers", objfpy_get_printers, objfpy_set_printers,
"Pretty printers.", NULL },
+ { "type_printers", objfpy_get_type_printers, objfpy_set_type_printers,
+ "Type printers.", NULL },
{ NULL }
};
diff --git a/gdb/python/py-progspace.c b/gdb/python/py-progspace.c
index e4b029b..c1b1cac 100644
--- a/gdb/python/py-progspace.c
+++ b/gdb/python/py-progspace.c
@@ -34,6 +34,9 @@ typedef struct
/* The pretty-printer list of functions. */
PyObject *printers;
+
+ /* The type-printer list. */
+ PyObject *type_printers;
} pspace_object;
static PyTypeObject pspace_object_type;
@@ -66,6 +69,7 @@ pspy_dealloc (PyObject *self)
pspace_object *ps_self = (pspace_object *) self;
Py_XDECREF (ps_self->printers);
+ Py_XDECREF (ps_self->type_printers);
self->ob_type->tp_free (self);
}
@@ -84,6 +88,13 @@ pspy_new (PyTypeObject *type, PyObject *args, PyObject *keywords)
Py_DECREF (self);
return NULL;
}
+
+ self->type_printers = PyList_New (0);
+ if (!self->type_printers)
+ {
+ Py_DECREF (self);
+ return NULL;
+ }
}
return (PyObject *) self;
}
@@ -126,6 +137,48 @@ pspy_set_printers (PyObject *o, PyObject *value, void *ignore)
return 0;
}
+/* Get the 'type_printers' attribute. */
+
+static PyObject *
+pspy_get_type_printers (PyObject *o, void *ignore)
+{
+ pspace_object *self = (pspace_object *) o;
+
+ Py_INCREF (self->type_printers);
+ return self->type_printers;
+}
+
+/* Set the 'type_printers' attribute. */
+
+static int
+pspy_set_type_printers (PyObject *o, PyObject *value, void *ignore)
+{
+ PyObject *tmp;
+ pspace_object *self = (pspace_object *) o;
+
+ if (! value)
+ {
+ PyErr_SetString (PyExc_TypeError,
+ "cannot delete the type_printers attribute");
+ return -1;
+ }
+
+ if (! PyList_Check (value))
+ {
+ PyErr_SetString (PyExc_TypeError,
+ "the type_printers attribute must be a list");
+ return -1;
+ }
+
+ /* Take care in case the LHS and RHS are related somehow. */
+ tmp = self->type_printers;
+ Py_INCREF (value);
+ self->type_printers = value;
+ Py_XDECREF (tmp);
+
+ return 0;
+}
+
/* Clear the PSPACE pointer in a Pspace object and remove the reference. */
@@ -168,6 +221,13 @@ pspace_to_pspace_object (struct program_space *pspace)
return NULL;
}
+ object->type_printers = PyList_New (0);
+ if (!object->type_printers)
+ {
+ Py_DECREF (object);
+ return NULL;
+ }
+
set_program_space_data (pspace, pspy_pspace_data_key, object);
}
}
@@ -197,6 +257,8 @@ static PyGetSetDef pspace_getset[] =
"The progspace's main filename, or None.", NULL },
{ "pretty_printers", pspy_get_printers, pspy_set_printers,
"Pretty printers.", NULL },
+ { "type_printers", pspy_get_type_printers, pspy_set_type_printers,
+ "Type printers.", NULL },
{ NULL }
};
diff --git a/gdb/python/python.c b/gdb/python/python.c
index cd50e50..359d238 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -1181,6 +1181,125 @@ gdbpy_objfiles (PyObject *unused1, PyObject *unused2)
return list;
}
+/* Compute the list of active type printers and return it. The result
+ of this function can be passed to apply_type_printers, and should
+ be freed by free_type_printers. */
+
+void *
+start_type_printers (void)
+{
+ struct cleanup *cleanups;
+ PyObject *type_module, *func, *result_obj;
+
+ cleanups = ensure_python_env (get_current_arch (), current_language);
+
+ type_module = PyImport_ImportModule ("gdb.types");
+ if (type_module == NULL)
+ {
+ gdbpy_print_stack ();
+ goto done;
+ }
+ make_cleanup_py_decref (type_module);
+
+ func = PyObject_GetAttrString (type_module, "get_type_recognizers");
+ if (func == NULL)
+ {
+ gdbpy_print_stack ();
+ goto done;
+ }
+ make_cleanup_py_decref (func);
+
+ result_obj = PyObject_CallFunctionObjArgs (func, (char *) NULL);
+ if (result_obj == NULL)
+ gdbpy_print_stack ();
+
+ done:
+ do_cleanups (cleanups);
+ return result_obj;
+}
+
+/* If TYPE is recognized by some type printer, return a newly
+ allocated string holding the type's replacement name. The caller
+ is responsible for freeing the string. Otherwise, return NULL.
+
+ This function has a bit of a funny name, since it actually applies
+ recognizers, but this seemed clearer given the start_type_printers
+ and free_type_printers functions. */
+
+char *
+apply_type_printers (void *printers, struct type *type)
+{
+ struct cleanup *cleanups;
+ PyObject *type_obj, *type_module, *func, *result_obj;
+ PyObject *printers_obj = printers;
+ char *result = NULL;
+
+ if (printers_obj == NULL)
+ return NULL;
+
+ cleanups = ensure_python_env (get_current_arch (), current_language);
+
+ type_obj = type_to_type_object (type);
+ if (type_obj == NULL)
+ {
+ gdbpy_print_stack ();
+ goto done;
+ }
+ make_cleanup_py_decref (type_obj);
+
+ type_module = PyImport_ImportModule ("gdb.types");
+ if (type_module == NULL)
+ {
+ gdbpy_print_stack ();
+ goto done;
+ }
+ make_cleanup_py_decref (type_module);
+
+ func = PyObject_GetAttrString (type_module, "apply_type_recognizers");
+ if (func == NULL)
+ {
+ gdbpy_print_stack ();
+ goto done;
+ }
+ make_cleanup_py_decref (func);
+
+ result_obj = PyObject_CallFunctionObjArgs (func, printers_obj,
+ type_obj, (char *) NULL);
+ if (result_obj == NULL)
+ {
+ gdbpy_print_stack ();
+ goto done;
+ }
+ make_cleanup_py_decref (result_obj);
+
+ if (result_obj != Py_None)
+ {
+ result = python_string_to_host_string (result_obj);
+ if (result == NULL)
+ gdbpy_print_stack ();
+ }
+
+ done:
+ do_cleanups (cleanups);
+ return result;
+}
+
+/* Free the result of start_type_printers. */
+
+void
+free_type_printers (void *arg)
+{
+ struct cleanup *cleanups;
+ PyObject *printers = arg;
+
+ if (printers == NULL)
+ return;
+
+ cleanups = ensure_python_env (get_current_arch (), current_language);
+ Py_DECREF (printers);
+ do_cleanups (cleanups);
+}
+
#else /* HAVE_PYTHON */
/* Dummy implementation of the gdb "python-interactive" and "python"
@@ -1238,6 +1357,23 @@ gdbpy_breakpoint_has_py_cond (struct breakpoint_object *bp_obj)
"scripting is not supported."));
}
+void *
+start_type_printers (void)
+{
+ return NULL;
+}
+
+char *
+apply_type_printers (void *ignore, struct type *type)
+{
+ return NULL;
+}
+
+void
+free_type_printers (void *arg)
+{
+}
+
#endif /* HAVE_PYTHON */
diff --git a/gdb/python/python.h b/gdb/python/python.h
index 0d07271..72872b0 100644
--- a/gdb/python/python.h
+++ b/gdb/python/python.h
@@ -49,4 +49,10 @@ int gdbpy_should_stop (struct breakpoint_object *bp_obj);
int gdbpy_breakpoint_has_py_cond (struct breakpoint_object *bp_obj);
+void *start_type_printers (void);
+
+char *apply_type_printers (void *, struct type *type);
+
+void free_type_printers (void *arg);
+
#endif /* GDB_PYTHON_H */