diff options
author | Tom Tromey <tromey@redhat.com> | 2012-11-12 17:41:59 +0000 |
---|---|---|
committer | Tom Tromey <tromey@redhat.com> | 2012-11-12 17:41:59 +0000 |
commit | 18a9fc1261b8a654fe6db7eea7e60b0c59296d96 (patch) | |
tree | 50b1290ab9827f259ea103cf50367d7ac6c0e878 /gdb/python | |
parent | bd69fc683f383772bb8fab43c5d4af8d0cd4a8b4 (diff) | |
download | gdb-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__.py | 3 | ||||
-rw-r--r-- | gdb/python/lib/gdb/command/type_printers.py | 125 | ||||
-rw-r--r-- | gdb/python/lib/gdb/types.py | 65 | ||||
-rw-r--r-- | gdb/python/py-objfile.c | 62 | ||||
-rw-r--r-- | gdb/python/py-progspace.c | 62 | ||||
-rw-r--r-- | gdb/python/python.c | 136 | ||||
-rw-r--r-- | gdb/python/python.h | 6 |
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 */ |