* Python pretty-printing [2/6] @ 2009-04-02 20:55 Tom Tromey 2009-04-02 22:29 ` Thiago Jung Bauermann 0 siblings, 1 reply; 8+ messages in thread From: Tom Tromey @ 2009-04-02 20:55 UTC (permalink / raw) To: gdb-patches This patch adds a minimal Python wrapper for struct objfile, and arranges to auto-load Python code when an objfile is created. This auto-loading makes the pretty-printing feature convenient for users. For example, we have a patch with a full suite of printers for libstdc++. libstdc++ will install these printers in a place visible to gdb (see patch #1); gdb will automatically load them and so the user will not have to do anything to see the benefits. There was some disagreement about this feature on the Archer list. In particular, Daniel did not want to tie pretty-printing to objfiles. However, I think this is still ok because this is just one method for loading such code -- it need not be the only method. That is, the printers are separate from the method chosen to read them into gdb. Tom 2009-04-01 Tom Tromey <tromey@redhat.com> Thiago Jung Bauermann <bauerman@br.ibm.com> Phil Muldoon <pmuldoon@redhat.com> * python/python.c: Include objfiles.h, observer.h. (gdbpy_auto_load): New global. (gdbpy_current_objfile): Likewise. (GDBPY_AUTO_FILENAME): New define. (gdbpy_new_objfile): New function. (gdbpy_get_current_objfile): Likewise. (gdbpy_objfiles): Likewise. (_initialize_python): Add "maint set auto-load". Call gdbpy_initialize_objfile. Attach objfile observer. (GdbMethods): New methods current_objfile, objfiles. * python/python-objfile.c: New file. * python/python-internal.h (objfile_to_objfile_object): Declare. (objfpy_get_printers): Likewise. (gdbpy_initialize_objfile): Likewise. * Makefile.in (SUBDIR_PYTHON_OBS): Add python-objfile.o. (SUBDIR_PYTHON_SRCS): Add python-objfile.c. (python-objfile.o): New target. 2009-04-01 Tom Tromey <tromey@redhat.com> Thiago Jung Bauermann <bauerman@br.ibm.com> Phil Muldoon <pmuldoon@redhat.com> * gdb.texinfo (Python API): Update. (Basic Python): Document current_objfile, objfiles. (Auto-loading): New node. (Objfiles In Python): New node. gdb/ChangeLog | 22 ++++ gdb/Makefile.in | 6 + gdb/doc/ChangeLog | 9 ++ gdb/doc/gdb.texinfo | 80 +++++++++++++++ gdb/python/python-internal.h | 4 + gdb/python/python-objfile.c | 225 ++++++++++++++++++++++++++++++++++++++++++ gdb/python/python.c | 146 +++++++++++++++++++++++++++ 7 files changed, 492 insertions(+), 0 deletions(-) create mode 100644 gdb/python/python-objfile.c diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 6b69881..dbd2126 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -267,12 +267,14 @@ SUBDIR_PYTHON_OBS = \ python.o \ python-cmd.o \ python-function.o \ + python-objfile.o \ python-utils.o \ python-value.o SUBDIR_PYTHON_SRCS = \ python/python.c \ python/python-cmd.c \ python/python-function.c \ + python/python-objfile.c \ python/python-utils.c \ python/python-value.c SUBDIR_PYTHON_DEPS = @@ -1851,6 +1853,10 @@ python-function.o: $(srcdir)/python/python-function.c $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-function.c $(POSTCOMPILE) +python-objfile.o: $(srcdir)/python/python-objfile.c + $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-objfile.c + $(POSTCOMPILE) + python-utils.o: $(srcdir)/python/python-utils.c $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-utils.c $(POSTCOMPILE) diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 0dff6e0..bcfc9bf 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -18191,9 +18191,11 @@ situation, a Python @code{KeyboardInterrupt} exception is thrown. @menu * Basic Python:: Basic Python Functions. * Exception Handling:: +* Auto-loading:: Automatically loading Python code. * Values From Inferior:: * Commands In Python:: Implementing new commands in Python. * Functions In Python:: Writing new convenience functions. +* Objfiles In Python:: Object files. @end menu @node Basic Python @@ -18219,6 +18221,20 @@ command as having originated from the user invoking it interactively. It must be a boolean value. If omitted, it defaults to @code{False}. @end defun +@findex gdb.current_objfile +@defun current_objfile +When auto-loading a Python script (@pxref{Auto-loading}), @value{GDBN} +sets the ``current objfile'' to the corresponding objfile. This +function returns the current objfile. If there is no current objfile, +this function returns @code{None}. +@end defun + +@findex gdb.objfiles +@defun objfiles +Return a sequence of all the objfiles current known to @value{GDBN}. +@xref{Objfiles In Python}. +@end defun + @findex gdb.get_parameter @defun get_parameter parameter Return the value of a @value{GDBN} parameter. @var{parameter} is a @@ -18291,6 +18307,44 @@ message as its value, and the Python call stack backtrace at the Python statement closest to where the @value{GDBN} error occured as the traceback. +@node Auto-loading +@subsubsection Auto-loading + +When a new object file (@pxref{Objfiles In Python}) is read (for +example, due to the @code{file} command, or because the inferior has +loaded a shared library), @value{GDBN} will look for a file named by +adding @samp{-gdb.py} to the object file's real name (the name formed +after following all symlinks and resolving @code{.} and @code{..} +components). If this file exists and is readable, @value{GDBN} will +evaluate it as a Python script. + +If this file does not exist, and if the parameter +@code{debug-file-directory} is set, then @value{GDBN} will append the +object file's real name to the value of this parameter, and try again. + +Finally, if this file does not exist, then @value{GDBN} will look in +subdirectory of @code{gdb_datadir} (whose value is available from +@code{maint show gdb_datadir}). Specifically, @value{GDBN} will take +the value of @code{gdb_datadir}, append @samp{python/auto-load}, and +then append the object file's real name. + +Also, if a separate debug file is used, @value{GDBN} will look for the +@samp{-gdb.py} file both in the directory associated with the +application and the directory associated with the separate debug file. + +When reading a @samp{-gdb.py} file, @value{GDBN} sets the ``current +objfile''. This is available via the @code{gdb.current_objfile} +function. This can be useful for registering objfile-specific +pretty-printers. + +This feature is useful for supplying application-specific debugging +commands and scripts. It can be disabled using @code{maint set python +auto-load}. + +@value{GDBN} does not track which files it has already auto-loaded. +So, your @samp{-gdb.py} file should take care to ensure that it may be +evaluated multiple times without error. + @node Values From Inferior @subsubsection Values From Inferior @cindex values from inferior, with Python @@ -18704,6 +18758,32 @@ registration of the function with @value{GDBN}. Depending on how the Python code is read into @value{GDBN}, you may need to import the @code{gdb} module explicitly. +@node Objfiles In Python +@subsubsection Objfiles In Python + +@cindex objfiles in python +@cindex python objfiles +@tindex gdb.Objfile +@tindex Objfile +@value{GDBN} loads symbols for an inferior from various +symbol-containing files. These include the primary executable file, +any shared libraries used by the inferior, and any separate debug info +files. @value{GDBN} calls these symbol-containing files +@dfn{objfiles}. + +Each objfile is represented by an instance of the @code{gdb.Objfile} +class. + +@defivar Objfile filename +The file name of the objfile as a string. +@end defivar + +@defivar Objfile pretty_printers +The @code{pretty_printers} attribute is used to look up +pretty-printers by type. This is a dictionary which maps regular +expressions (strings) to pretty-printing objects. +@end defivar + @node Interpreters @chapter Command Interpreters @cindex command interpreters diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h index 463f08e..9764f4f 100644 --- a/gdb/python/python-internal.h +++ b/gdb/python/python-internal.h @@ -66,12 +66,16 @@ extern PyTypeObject value_object_type; PyObject *gdbpy_history (PyObject *self, PyObject *args); PyObject *value_to_value_object (struct value *v); +PyObject *objfile_to_objfile_object (struct objfile *); + +PyObject *objfpy_get_printers (PyObject *, void *); struct value *convert_value_from_python (PyObject *obj); void gdbpy_initialize_values (void); void gdbpy_initialize_commands (void); void gdbpy_initialize_functions (void); +void gdbpy_initialize_objfile (void); struct cleanup *make_cleanup_py_decref (PyObject *py); struct cleanup *make_cleanup_py_restore_gil (PyGILState_STATE *state); diff --git a/gdb/python/python-objfile.c b/gdb/python/python-objfile.c new file mode 100644 index 0000000..f5db084 --- /dev/null +++ b/gdb/python/python-objfile.c @@ -0,0 +1,225 @@ +/* Python interface to objfiles. + + Copyright (C) 2008, 2009 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 list of functions. */ + PyObject *printers; +} objfile_object; + +static PyTypeObject objfile_object_type; + +static const struct objfile_data *objfpy_objfile_data_key; + +\f + +/* An Objfile method which returns the objfile's file name, or None. */ +static PyObject * +objfpy_get_filename (PyObject *self, void *closure) +{ + 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->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; + + self->printers = PyList_New (0); + if (!self->printers) + { + Py_DECREF (self); + return NULL; + } + } + return (PyObject *) self; +} + +PyObject * +objfpy_get_printers (PyObject *o, void *ignore) +{ + objfile_object *self = (objfile_object *) o; + Py_INCREF (self->printers); + return self->printers; +} + +static int +objfpy_set_printers (PyObject *o, PyObject *value, void *ignore) +{ + objfile_object *self = (objfile_object *) o; + if (! value) + { + PyErr_SetString (PyExc_TypeError, + "cannot delete the pretty_printers attribute"); + return -1; + } + + if (! PyList_Check (value)) + { + PyErr_SetString (PyExc_TypeError, + "the pretty_printers attribute must be a list"); + return -1; + } + + Py_XDECREF (self->printers); + Py_INCREF (value); + self->printers = value; + + return 0; +} + +\f + +/* Clear the OBJFILE pointer in an Objfile object and remove the + reference. */ +static void +clean_up_objfile (struct objfile *objfile, void *datum) +{ + PyGILState_STATE state; + objfile_object *object = datum; + + state = PyGILState_Ensure (); + object->objfile = NULL; + Py_DECREF ((PyObject *) object); + PyGILState_Release (state); +} + +/* 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; + + object->printers = PyList_New (0); + if (!object->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); + + if (PyType_Ready (&objfile_object_type) < 0) + return; + + Py_INCREF (&objfile_object_type); + PyModule_AddObject (gdb_module, "Objfile", (PyObject *) &objfile_object_type); +} + +\f + +static PyGetSetDef objfile_getset[] = +{ + { "filename", objfpy_get_filename, NULL, + "The objfile's filename, or None.", NULL }, + { "pretty_printers", objfpy_get_printers, objfpy_set_printers, + "Pretty printers.", NULL }, + { NULL } +}; + +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 */ + 0, /* 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 1762c46..5044b8a 100644 --- a/gdb/python/python.c +++ b/gdb/python/python.c @@ -22,6 +22,8 @@ #include "ui-out.h" #include "cli/cli-script.h" #include "gdbcmd.h" +#include "objfiles.h" +#include "observer.h" #include <ctype.h> @@ -29,6 +31,10 @@ false otherwise. */ static int gdbpy_should_print_stack = 1; +/* This is true if we should auto-load python code when an objfile is + opened, false otherwise. */ +static int gdbpy_auto_load = 1; + #ifdef HAVE_PYTHON #include "python.h" @@ -301,6 +307,129 @@ gdbpy_print_stack (void) PyErr_Clear (); } +\f + +/* 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" + +/* 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 *realname; + char *filename, *debugfile; + int len; + FILE *input; + PyGILState_STATE state; + struct cleanup *cleanups; + + if (!gdbpy_auto_load || !objfile || !objfile->name) + return; + + state = PyGILState_Ensure (); + + gdbpy_current_objfile = objfile; + + realname = gdb_realpath (objfile->name); + len = strlen (realname); + filename = xmalloc (len + sizeof (GDBPY_AUTO_FILENAME)); + memcpy (filename, realname, len); + strcpy (filename + len, GDBPY_AUTO_FILENAME); + + input = fopen (filename, "r"); + debugfile = filename; + + cleanups = make_cleanup (xfree, filename); + make_cleanup (xfree, realname); + + if (!input && debug_file_directory) + { + /* Also try the same file in the separate debug info directory. */ + debugfile = xmalloc (strlen (filename) + + strlen (debug_file_directory) + 1); + strcpy (debugfile, debug_file_directory); + /* FILENAME is absolute, so we don't need a "/" here. */ + strcat (debugfile, filename); + + make_cleanup (xfree, debugfile); + input = fopen (debugfile, "r"); + } + + if (!input && gdb_datadir) + { + /* Also try the same file in a subdirectory of gdb's data + directory. */ + debugfile = xmalloc (strlen (gdb_datadir) + strlen (filename) + + strlen ("/auto-load") + 1); + strcpy (debugfile, gdb_datadir); + strcat (debugfile, "/auto-load"); + /* FILENAME is absolute, so we don't need a "/" here. */ + strcat (debugfile, filename); + + make_cleanup (xfree, debugfile); + input = fopen (debugfile, "r"); + } + + if (input) + { + /* We don't want to throw an exception here -- but the user + would like to know that something went wrong. */ + if (PyRun_SimpleFile (input, debugfile)) + gdbpy_print_stack (); + fclose (input); + } + + do_cleanups (cleanups); + gdbpy_current_objfile = NULL; + + PyGILState_Release (state); +} + +/* 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_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; +} + #else /* HAVE_PYTHON */ /* Dummy implementation of the gdb "python" command. */ @@ -399,6 +528,15 @@ Enables or disables printing of Python stack traces."), &set_python_list, &show_python_list); + add_setshow_boolean_cmd ("auto-load", class_maintenance, + &gdbpy_auto_load, _("\ +Enable or disable auto-loading of Python code when an object is opened."), _("\ +Show whether Python code will be auto-loaded when an object is opened."), _("\ +Enables or disables auto-loading of Python code when an object is opened."), + NULL, NULL, + &set_python_list, + &show_python_list); + #ifdef HAVE_PYTHON Py_Initialize (); PyEval_InitThreads (); @@ -419,9 +557,12 @@ Enables or disables printing of Python stack traces."), gdbpy_initialize_values (); gdbpy_initialize_commands (); gdbpy_initialize_functions (); + gdbpy_initialize_objfile (); PyRun_SimpleString ("import gdb"); + observer_attach_new_objfile (gdbpy_new_objfile); + gdbpy_doc_cst = PyString_FromString ("__doc__"); /* Create a couple objects which are used for Python's stdout and @@ -479,6 +620,11 @@ static PyMethodDef GdbMethods[] = { "get_parameter", get_parameter, METH_VARARGS, "Return a gdb parameter's value" }, + { "current_objfile", gdbpy_get_current_objfile, METH_NOARGS, + "Return the current Objfile being loaded, or None." }, + { "objfiles", gdbpy_objfiles, METH_NOARGS, + "Return a sequence of all loaded objfiles." }, + { "write", gdbpy_write, METH_VARARGS, "Write a string using gdb's filtered stream." }, { "flush", gdbpy_flush, METH_NOARGS, -- 1.6.0.6 ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: Python pretty-printing [2/6] 2009-04-02 20:55 Python pretty-printing [2/6] Tom Tromey @ 2009-04-02 22:29 ` Thiago Jung Bauermann 2009-04-03 0:23 ` Tom Tromey 0 siblings, 1 reply; 8+ messages in thread From: Thiago Jung Bauermann @ 2009-04-02 22:29 UTC (permalink / raw) To: Tom Tromey; +Cc: gdb-patches El jue, 02-04-2009 a las 14:55 -0600, Tom Tromey escribió: > This patch adds a minimal Python wrapper for struct objfile, > and arranges to auto-load Python code when an objfile is created. Hooray. Just a few comments... > +@findex gdb.current_objfile > +@defun current_objfile > +When auto-loading a Python script (@pxref{Auto-loading}), @value{GDBN} > +sets the ``current objfile'' to the corresponding objfile. This > +function returns the current objfile. If there is no current objfile, > +this function returns @code{None}. > +@end defun > + > +@findex gdb.objfiles > +@defun objfiles > +Return a sequence of all the objfiles current known to @value{GDBN}. > +@xref{Objfiles In Python}. > +@end defun IMHO these should go in the "Objfiles In Python" section, like e.g. gdb.selected_frame goes in the "Frames In Python" section. > +static int > +objfpy_set_printers (PyObject *o, PyObject *value, void *ignore) <snip> > + Py_XDECREF (self->printers); > + Py_INCREF (value); > + self->printers = value; I'm trying to decide if the sequence above is ok or not. Python docs say[1] in a warning box: "... any object that is reachable from a global variable should be in a consistent state before Py_DECREF is invoked. For example, code to delete an object from a list should copy a reference to the deleted object in a temporary variable, update the list data structure, and then call Py_DECREF for the temporary variable." So perhaps you should: tmp = self->printers; Py_INCREF (value); self->printers = value; Py_XDECREF (tmp); You certainly have more experience in this area than me though. WDYT? > +/* 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) Perhaps it would be useful to mention that this function returns a borrowed reference to the object? Also, just to check: the lack of testcases is because you believe this code is tested enough with python-prettyprint.exp in a later patch? [1] - http://docs.python.org/c-api/refcounting.html#Py_DECREF -- []'s Thiago Jung Bauermann IBM Linux Technology Center ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: Python pretty-printing [2/6] 2009-04-02 22:29 ` Thiago Jung Bauermann @ 2009-04-03 0:23 ` Tom Tromey 2009-04-03 0:47 ` Tom Tromey 2009-04-03 20:36 ` Thiago Jung Bauermann 0 siblings, 2 replies; 8+ messages in thread From: Tom Tromey @ 2009-04-03 0:23 UTC (permalink / raw) To: Thiago Jung Bauermann; +Cc: gdb-patches >>>>> "Thiago" == Thiago Jung Bauermann <bauerman@br.ibm.com> writes: Tom> This patch adds a minimal Python wrapper for struct objfile, Tom> and arranges to auto-load Python code when an objfile is created. Thiago> Hooray. Just a few comments... Thanks for looking at this. I've found that seeing the Python patches again, out of context, helps me look at them anew. Apparently this works for you too :-) Thiago> IMHO these should go in the "Objfiles In Python" section, like e.g. Thiago> gdb.selected_frame goes in the "Frames In Python" section. Thanks, will do. Thiago> So perhaps you should: > tmp = self->printers; > Py_INCREF (value); > self->printers = value; > Py_XDECREF (tmp); Thiago> You certainly have more experience in this area than me though. WDYT? Good catch. I will make this change. I think one failing case is just: objfile.pretty_printers = objfile.pretty_printers Tom> +/* Return the Python object of type Objfile representing OBJFILE. If Tom> + the object has already been created, return it. Otherwise, create Tom> + it. Return NULL and set the Python error on failure. */ Tom> +PyObject * Tom> +objfile_to_objfile_object (struct objfile *objfile) Thiago> Perhaps it would be useful to mention that this function returns a Thiago> borrowed reference to the object? Will do. Thiago> Also, just to check: the lack of testcases is because you believe this Thiago> code is tested enough with python-prettyprint.exp in a later patch? You know, I am not sure. This class doesn't provide much behavior yet. And, the most important bits are tested by the pretty-printer. I'm inclined not to bother, but if you (or anybody) thinks it is important, I suppose I can whip something up. Tom ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: Python pretty-printing [2/6] 2009-04-03 0:23 ` Tom Tromey @ 2009-04-03 0:47 ` Tom Tromey 2009-04-03 15:06 ` Eli Zaretskii 2009-04-03 20:36 ` Thiago Jung Bauermann 1 sibling, 1 reply; 8+ messages in thread From: Tom Tromey @ 2009-04-03 0:47 UTC (permalink / raw) To: Thiago Jung Bauermann; +Cc: gdb-patches Here is the updated patch. Thank goodness for git rebase. Tom 2009-04-01 Tom Tromey <tromey@redhat.com> Thiago Jung Bauermann <bauerman@br.ibm.com> Phil Muldoon <pmuldoon@redhat.com> * python/python.c: Include objfiles.h, observer.h. (gdbpy_auto_load): New global. (gdbpy_current_objfile): Likewise. (GDBPY_AUTO_FILENAME): New define. (gdbpy_new_objfile): New function. (gdbpy_get_current_objfile): Likewise. (gdbpy_objfiles): Likewise. (_initialize_python): Add "maint set auto-load". Call gdbpy_initialize_objfile. Attach objfile observer. (GdbMethods): New methods current_objfile, objfiles. * python/python-objfile.c: New file. * python/python-internal.h (objfile_to_objfile_object): Declare. (objfpy_get_printers): Likewise. (gdbpy_initialize_objfile): Likewise. * Makefile.in (SUBDIR_PYTHON_OBS): Add python-objfile.o. (SUBDIR_PYTHON_SRCS): Add python-objfile.c. (python-objfile.o): New target. 2009-04-01 Tom Tromey <tromey@redhat.com> Thiago Jung Bauermann <bauerman@br.ibm.com> Phil Muldoon <pmuldoon@redhat.com> * gdb.texinfo (Python API): Update. (Auto-loading): New node. (Objfiles In Python): New node. gdb/ChangeLog | 22 ++++ gdb/Makefile.in | 6 + gdb/doc/ChangeLog | 8 ++ gdb/doc/gdb.texinfo | 83 +++++++++++++++ gdb/python/python-internal.h | 4 + gdb/python/python-objfile.c | 229 ++++++++++++++++++++++++++++++++++++++++++ gdb/python/python.c | 146 +++++++++++++++++++++++++++ 7 files changed, 498 insertions(+), 0 deletions(-) create mode 100644 gdb/python/python-objfile.c diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 6b69881..dbd2126 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -267,12 +267,14 @@ SUBDIR_PYTHON_OBS = \ python.o \ python-cmd.o \ python-function.o \ + python-objfile.o \ python-utils.o \ python-value.o SUBDIR_PYTHON_SRCS = \ python/python.c \ python/python-cmd.c \ python/python-function.c \ + python/python-objfile.c \ python/python-utils.c \ python/python-value.c SUBDIR_PYTHON_DEPS = @@ -1851,6 +1853,10 @@ python-function.o: $(srcdir)/python/python-function.c $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-function.c $(POSTCOMPILE) +python-objfile.o: $(srcdir)/python/python-objfile.c + $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-objfile.c + $(POSTCOMPILE) + python-utils.o: $(srcdir)/python/python-utils.c $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-utils.c $(POSTCOMPILE) diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 0dff6e0..70f2a40 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -18191,9 +18191,11 @@ situation, a Python @code{KeyboardInterrupt} exception is thrown. @menu * Basic Python:: Basic Python Functions. * Exception Handling:: +* Auto-loading:: Automatically loading Python code. * Values From Inferior:: * Commands In Python:: Implementing new commands in Python. * Functions In Python:: Writing new convenience functions. +* Objfiles In Python:: Object files. @end menu @node Basic Python @@ -18291,6 +18293,44 @@ message as its value, and the Python call stack backtrace at the Python statement closest to where the @value{GDBN} error occured as the traceback. +@node Auto-loading +@subsubsection Auto-loading + +When a new object file (@pxref{Objfiles In Python}) is read (for +example, due to the @code{file} command, or because the inferior has +loaded a shared library), @value{GDBN} will look for a file named by +adding @samp{-gdb.py} to the object file's real name (the name formed +after following all symlinks and resolving @code{.} and @code{..} +components). If this file exists and is readable, @value{GDBN} will +evaluate it as a Python script. + +If this file does not exist, and if the parameter +@code{debug-file-directory} is set, then @value{GDBN} will append the +object file's real name to the value of this parameter, and try again. + +Finally, if this file does not exist, then @value{GDBN} will look in +subdirectory of @code{gdb_datadir} (whose value is available from +@code{maint show gdb_datadir}). Specifically, @value{GDBN} will take +the value of @code{gdb_datadir}, append @samp{python/auto-load}, and +then append the object file's real name. + +Also, if a separate debug file is used, @value{GDBN} will look for the +@samp{-gdb.py} file both in the directory associated with the +application and the directory associated with the separate debug file. + +When reading a @samp{-gdb.py} file, @value{GDBN} sets the ``current +objfile''. This is available via the @code{gdb.current_objfile} +function. This can be useful for registering objfile-specific +pretty-printers. + +This feature is useful for supplying application-specific debugging +commands and scripts. It can be disabled using @code{maint set python +auto-load}. + +@value{GDBN} does not track which files it has already auto-loaded. +So, your @samp{-gdb.py} file should take care to ensure that it may be +evaluated multiple times without error. + @node Values From Inferior @subsubsection Values From Inferior @cindex values from inferior, with Python @@ -18704,6 +18744,49 @@ registration of the function with @value{GDBN}. Depending on how the Python code is read into @value{GDBN}, you may need to import the @code{gdb} module explicitly. +@node Objfiles In Python +@subsubsection Objfiles In Python + +@cindex objfiles in python +@cindex python objfiles +@tindex gdb.Objfile +@tindex Objfile +@value{GDBN} loads symbols for an inferior from various +symbol-containing files. These include the primary executable file, +any shared libraries used by the inferior, and any separate debug info +files. @value{GDBN} calls these symbol-containing files +@dfn{objfiles}. + +The following objfile-related functions are available in the +@code{gdb} module: + +@findex gdb.current_objfile +@defun current_objfile +When auto-loading a Python script (@pxref{Auto-loading}), @value{GDBN} +sets the ``current objfile'' to the corresponding objfile. This +function returns the current objfile. If there is no current objfile, +this function returns @code{None}. +@end defun + +@findex gdb.objfiles +@defun objfiles +Return a sequence of all the objfiles current known to @value{GDBN}. +@xref{Objfiles In Python}. +@end defun + +Each objfile is represented by an instance of the @code{gdb.Objfile} +class. + +@defivar Objfile filename +The file name of the objfile as a string. +@end defivar + +@defivar Objfile pretty_printers +The @code{pretty_printers} attribute is used to look up +pretty-printers by type. This is a dictionary which maps regular +expressions (strings) to pretty-printing objects. +@end defivar + @node Interpreters @chapter Command Interpreters @cindex command interpreters diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h index 463f08e..9764f4f 100644 --- a/gdb/python/python-internal.h +++ b/gdb/python/python-internal.h @@ -66,12 +66,16 @@ extern PyTypeObject value_object_type; PyObject *gdbpy_history (PyObject *self, PyObject *args); PyObject *value_to_value_object (struct value *v); +PyObject *objfile_to_objfile_object (struct objfile *); + +PyObject *objfpy_get_printers (PyObject *, void *); struct value *convert_value_from_python (PyObject *obj); void gdbpy_initialize_values (void); void gdbpy_initialize_commands (void); void gdbpy_initialize_functions (void); +void gdbpy_initialize_objfile (void); struct cleanup *make_cleanup_py_decref (PyObject *py); struct cleanup *make_cleanup_py_restore_gil (PyGILState_STATE *state); diff --git a/gdb/python/python-objfile.c b/gdb/python/python-objfile.c new file mode 100644 index 0000000..b70a006 --- /dev/null +++ b/gdb/python/python-objfile.c @@ -0,0 +1,229 @@ +/* Python interface to objfiles. + + Copyright (C) 2008, 2009 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 list of functions. */ + PyObject *printers; +} objfile_object; + +static PyTypeObject objfile_object_type; + +static const struct objfile_data *objfpy_objfile_data_key; + +\f + +/* An Objfile method which returns the objfile's file name, or None. */ +static PyObject * +objfpy_get_filename (PyObject *self, void *closure) +{ + 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->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; + + self->printers = PyList_New (0); + if (!self->printers) + { + Py_DECREF (self); + return NULL; + } + } + return (PyObject *) self; +} + +PyObject * +objfpy_get_printers (PyObject *o, void *ignore) +{ + objfile_object *self = (objfile_object *) o; + Py_INCREF (self->printers); + return self->printers; +} + +static int +objfpy_set_printers (PyObject *o, PyObject *value, void *ignore) +{ + PyObject *tmp; + objfile_object *self = (objfile_object *) o; + if (! value) + { + PyErr_SetString (PyExc_TypeError, + "cannot delete the pretty_printers attribute"); + return -1; + } + + if (! PyList_Check (value)) + { + PyErr_SetString (PyExc_TypeError, + "the pretty_printers attribute must be a list"); + return -1; + } + + /* Take care in case the LHS and RHS are related somehow. */ + tmp = self->printers; + Py_INCREF (value); + self->printers = value; + Py_XDECREF (tmp); + + return 0; +} + +\f + +/* Clear the OBJFILE pointer in an Objfile object and remove the + reference. */ +static void +clean_up_objfile (struct objfile *objfile, void *datum) +{ + PyGILState_STATE state; + objfile_object *object = datum; + + state = PyGILState_Ensure (); + object->objfile = NULL; + Py_DECREF ((PyObject *) object); + PyGILState_Release (state); +} + +/* Return a borrowed reference to 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; + + object->printers = PyList_New (0); + if (!object->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); + + if (PyType_Ready (&objfile_object_type) < 0) + return; + + Py_INCREF (&objfile_object_type); + PyModule_AddObject (gdb_module, "Objfile", (PyObject *) &objfile_object_type); +} + +\f + +static PyGetSetDef objfile_getset[] = +{ + { "filename", objfpy_get_filename, NULL, + "The objfile's filename, or None.", NULL }, + { "pretty_printers", objfpy_get_printers, objfpy_set_printers, + "Pretty printers.", NULL }, + { NULL } +}; + +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 */ + 0, /* 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 1762c46..5044b8a 100644 --- a/gdb/python/python.c +++ b/gdb/python/python.c @@ -22,6 +22,8 @@ #include "ui-out.h" #include "cli/cli-script.h" #include "gdbcmd.h" +#include "objfiles.h" +#include "observer.h" #include <ctype.h> @@ -29,6 +31,10 @@ false otherwise. */ static int gdbpy_should_print_stack = 1; +/* This is true if we should auto-load python code when an objfile is + opened, false otherwise. */ +static int gdbpy_auto_load = 1; + #ifdef HAVE_PYTHON #include "python.h" @@ -301,6 +307,129 @@ gdbpy_print_stack (void) PyErr_Clear (); } +\f + +/* 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" + +/* 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 *realname; + char *filename, *debugfile; + int len; + FILE *input; + PyGILState_STATE state; + struct cleanup *cleanups; + + if (!gdbpy_auto_load || !objfile || !objfile->name) + return; + + state = PyGILState_Ensure (); + + gdbpy_current_objfile = objfile; + + realname = gdb_realpath (objfile->name); + len = strlen (realname); + filename = xmalloc (len + sizeof (GDBPY_AUTO_FILENAME)); + memcpy (filename, realname, len); + strcpy (filename + len, GDBPY_AUTO_FILENAME); + + input = fopen (filename, "r"); + debugfile = filename; + + cleanups = make_cleanup (xfree, filename); + make_cleanup (xfree, realname); + + if (!input && debug_file_directory) + { + /* Also try the same file in the separate debug info directory. */ + debugfile = xmalloc (strlen (filename) + + strlen (debug_file_directory) + 1); + strcpy (debugfile, debug_file_directory); + /* FILENAME is absolute, so we don't need a "/" here. */ + strcat (debugfile, filename); + + make_cleanup (xfree, debugfile); + input = fopen (debugfile, "r"); + } + + if (!input && gdb_datadir) + { + /* Also try the same file in a subdirectory of gdb's data + directory. */ + debugfile = xmalloc (strlen (gdb_datadir) + strlen (filename) + + strlen ("/auto-load") + 1); + strcpy (debugfile, gdb_datadir); + strcat (debugfile, "/auto-load"); + /* FILENAME is absolute, so we don't need a "/" here. */ + strcat (debugfile, filename); + + make_cleanup (xfree, debugfile); + input = fopen (debugfile, "r"); + } + + if (input) + { + /* We don't want to throw an exception here -- but the user + would like to know that something went wrong. */ + if (PyRun_SimpleFile (input, debugfile)) + gdbpy_print_stack (); + fclose (input); + } + + do_cleanups (cleanups); + gdbpy_current_objfile = NULL; + + PyGILState_Release (state); +} + +/* 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_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; +} + #else /* HAVE_PYTHON */ /* Dummy implementation of the gdb "python" command. */ @@ -399,6 +528,15 @@ Enables or disables printing of Python stack traces."), &set_python_list, &show_python_list); + add_setshow_boolean_cmd ("auto-load", class_maintenance, + &gdbpy_auto_load, _("\ +Enable or disable auto-loading of Python code when an object is opened."), _("\ +Show whether Python code will be auto-loaded when an object is opened."), _("\ +Enables or disables auto-loading of Python code when an object is opened."), + NULL, NULL, + &set_python_list, + &show_python_list); + #ifdef HAVE_PYTHON Py_Initialize (); PyEval_InitThreads (); @@ -419,9 +557,12 @@ Enables or disables printing of Python stack traces."), gdbpy_initialize_values (); gdbpy_initialize_commands (); gdbpy_initialize_functions (); + gdbpy_initialize_objfile (); PyRun_SimpleString ("import gdb"); + observer_attach_new_objfile (gdbpy_new_objfile); + gdbpy_doc_cst = PyString_FromString ("__doc__"); /* Create a couple objects which are used for Python's stdout and @@ -479,6 +620,11 @@ static PyMethodDef GdbMethods[] = { "get_parameter", get_parameter, METH_VARARGS, "Return a gdb parameter's value" }, + { "current_objfile", gdbpy_get_current_objfile, METH_NOARGS, + "Return the current Objfile being loaded, or None." }, + { "objfiles", gdbpy_objfiles, METH_NOARGS, + "Return a sequence of all loaded objfiles." }, + { "write", gdbpy_write, METH_VARARGS, "Write a string using gdb's filtered stream." }, { "flush", gdbpy_flush, METH_NOARGS, -- 1.6.0.6 ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: Python pretty-printing [2/6] 2009-04-03 0:47 ` Tom Tromey @ 2009-04-03 15:06 ` Eli Zaretskii 2009-04-06 19:25 ` Tom Tromey 0 siblings, 1 reply; 8+ messages in thread From: Eli Zaretskii @ 2009-04-03 15:06 UTC (permalink / raw) To: Tom Tromey; +Cc: bauerman, gdb-patches > Cc: gdb-patches@sourceware.org > From: Tom Tromey <tromey@redhat.com> > Date: Thu, 02 Apr 2009 18:47:16 -0600 > > 2009-04-01 Tom Tromey <tromey@redhat.com> > Thiago Jung Bauermann <bauerman@br.ibm.com> > Phil Muldoon <pmuldoon@redhat.com> > > * gdb.texinfo (Python API): Update. > (Auto-loading): New node. > (Objfiles In Python): New node. Thanks. I have several comments about the docs part: > +@node Auto-loading > +@subsubsection Auto-loading Suggest a @cindex entry here, something like "auto-loading, Python". > +When a new object file (@pxref{Objfiles In Python}) is read (for Is the cross-reference to "Objfiles in Python" really useful here? Loading object files has nothing to do with Python; the section you refer to describes Python-specific features related to object files, but those features seem to have nothing to do with auto-loading. Did I miss something? If there no real relation between these two sections, I'd prefer to remove the xref. When I read a manual and it gives me a cross-reference, I always assume that the cross-reference is important, and go there to see what it says. If it says nothing appropriate, my time and attention are lost. > + @value{GDBN} will look for a file named by > +adding @samp{-gdb.py} to the object file's real name (the name formed > +after following all symlinks and resolving @code{.} and @code{..} > +components). I suggest to rephrase this as follows: @value{GDBN} will look for a file named @file{@var{objfile}-gdb.py}, where @var{objfile} is the object file's real name, formed by following all symlinks and resolving @file{.} and @file{..} components. This tells the reader what the file name is, instead of explaining how it is constructed. I think the result is more clear. Btw, the above description of what ``real name'' is seems inaccurate, because the code actually calls `gdb_realpath', so the result is actually an absolute file name, right? > +If this file does not exist, and if the parameter > +@code{debug-file-directory} is set, then @value{GDBN} will append the > +object file's real name to the value of this parameter, and try again. Again, I think it's better not to explain how the file's name is created, but give its form and tell what are the components. There's another instance of that below. Could you rephrase them all along the above lines? Also, what is debug-file-directory? If it is documented somewhere, a cross-reference here would be beneficial. > +Finally, if this file does not exist, then @value{GDBN} will look in > +subdirectory of @code{gdb_datadir} (whose value is available from > +@code{maint show gdb_datadir}). ^^^^^^^^^^^^^^^^^^^^^^ Please add a cross-reference to where you describe this command. > Specifically, @value{GDBN} will take > +the value of @code{gdb_datadir}, append @samp{python/auto-load}, and > +then append the object file's real name. Please use @file for files, not @samp. > +Also, if a separate debug file is used, Please add another cross-reference, to where we describe separate debug file. > @value{GDBN} will look for the > +@samp{-gdb.py} file both in the directory associated with the > +application and the directory associated with the separate debug file. Is this true for all 3 file names GDB tries, or only for some (the first one?)? Either way, I think we should tell that explicitly. > +When reading a @samp{-gdb.py} file, @value{GDBN} sets the ``current > +objfile''. This is available via the @code{gdb.current_objfile} > +function. This can be useful for registering objfile-specific > +pretty-printers. Now, _this_ is where the cross-reference to "Objfiles in Python" would be handy. Also, you use "@samp{-gdb.py} file" quite a lot, so I think we should invent a special term for it. How about "autoloaded Python file"? > +This feature is useful for supplying application-specific debugging > +commands and scripts. It can be disabled using @code{maint set python > +auto-load}. A cross-reference here, to where the command is documented would be good. Or maybe just document it here ('cause I don't think it's documented anywhere else in your patches). > +@cindex python objfiles There are no "python objfiles", right? I think it's better to use something like "objfiles, access from Python". > +@tindex gdb.Objfile > +@tindex Objfile We still don't have a @syncodeindex for @tindex, so if you want to use it, please add that directive. > +@value{GDBN} loads symbols for an inferior from various > +symbol-containing files. These include the primary executable file, > +any shared libraries used by the inferior, and any separate debug info > +files. @value{GDBN} calls these symbol-containing files > +@dfn{objfiles}. It would be good to have cross-reference here to where the related GDB features are described. > +@defivar Objfile pretty_printers > +The @code{pretty_printers} attribute is used to look up > +pretty-printers by type. This is a dictionary which maps regular > +expressions (strings) to pretty-printing objects. I think we want a cross-reference here to where pretty-printing is described. ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: Python pretty-printing [2/6] 2009-04-03 15:06 ` Eli Zaretskii @ 2009-04-06 19:25 ` Tom Tromey 2009-04-06 20:41 ` Eli Zaretskii 0 siblings, 1 reply; 8+ messages in thread From: Tom Tromey @ 2009-04-06 19:25 UTC (permalink / raw) To: Eli Zaretskii; +Cc: bauerman, gdb-patches >>>>> "Eli" == Eli Zaretskii <eliz@gnu.org> writes: I didn't answer most of your questions, I just made the implied changes. Most of the questions read as rhetorical to me. If they weren't, and you really wanted answers, let me know and I will reply again. >> +@defivar Objfile pretty_printers >> +The @code{pretty_printers} attribute is used to look up >> +pretty-printers by type. This is a dictionary which maps regular >> +expressions (strings) to pretty-printing objects. Eli> I think we want a cross-reference here to where pretty-printing is Eli> described. This comes in a later patch. Here's the updated patch. I've tried to address all the comments that anybody raised. Also, I fixed the documentation for Objfile.pretty_printers to reflect reality. Tom 2009-04-01 Tom Tromey <tromey@redhat.com> Thiago Jung Bauermann <bauerman@br.ibm.com> Phil Muldoon <pmuldoon@redhat.com> * python/python.c: Include objfiles.h, observer.h. (gdbpy_auto_load): New global. (gdbpy_current_objfile): Likewise. (GDBPY_AUTO_FILENAME): New define. (gdbpy_new_objfile): New function. (gdbpy_get_current_objfile): Likewise. (gdbpy_objfiles): Likewise. (_initialize_python): Add "maint set auto-load". Call gdbpy_initialize_objfile. Attach objfile observer. (GdbMethods): New methods current_objfile, objfiles. * python/python-objfile.c: New file. * python/python-internal.h (objfile_to_objfile_object): Declare. (objfpy_get_printers): Likewise. (gdbpy_initialize_objfile): Likewise. * Makefile.in (SUBDIR_PYTHON_OBS): Add python-objfile.o. (SUBDIR_PYTHON_SRCS): Add python-objfile.c. (python-objfile.o): New target. 2009-04-01 Tom Tromey <tromey@redhat.com> Thiago Jung Bauermann <bauerman@br.ibm.com> Phil Muldoon <pmuldoon@redhat.com> * gdb.texinfo: Add @syncodeindex for `tp'. (Python API): Update. (Auto-loading): New node. (Objfiles In Python): New node. 2009-04-06 Tom Tromey <tromey@redhat.com> * gdb.python/python.exp (gdb_py_test_multiple): Add two objfile tests. * gdb.python/python-value.exp (py_objfile_tests): New proc. Call it. --- gdb/ChangeLog | 22 +++ gdb/Makefile.in | 6 + gdb/doc/ChangeLog | 9 + gdb/doc/gdb.texinfo | 94 ++++++++++++ gdb/python/python-internal.h | 4 + gdb/python/python-objfile.c | 229 +++++++++++++++++++++++++++++ gdb/python/python.c | 146 ++++++++++++++++++ gdb/testsuite/ChangeLog | 7 + gdb/testsuite/gdb.python/python-value.exp | 10 ++ gdb/testsuite/gdb.python/python.exp | 3 + 10 files changed, 530 insertions(+), 0 deletions(-) create mode 100644 gdb/python/python-objfile.c diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 6b69881..dbd2126 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -267,12 +267,14 @@ SUBDIR_PYTHON_OBS = \ python.o \ python-cmd.o \ python-function.o \ + python-objfile.o \ python-utils.o \ python-value.o SUBDIR_PYTHON_SRCS = \ python/python.c \ python/python-cmd.c \ python/python-function.c \ + python/python-objfile.c \ python/python-utils.c \ python/python-value.c SUBDIR_PYTHON_DEPS = @@ -1851,6 +1853,10 @@ python-function.o: $(srcdir)/python/python-function.c $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-function.c $(POSTCOMPILE) +python-objfile.o: $(srcdir)/python/python-objfile.c + $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-objfile.c + $(POSTCOMPILE) + python-utils.o: $(srcdir)/python/python-utils.c $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-utils.c $(POSTCOMPILE) diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index dd26db8..ca3c99b 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -21,6 +21,7 @@ @finalout @syncodeindex ky cp +@syncodeindex tp cp @c readline appendices use @vindex, @findex and @ftable, @c annotate.texi and gdbmi use @findex. @@ -18222,9 +18223,11 @@ situation, a Python @code{KeyboardInterrupt} exception is thrown. @menu * Basic Python:: Basic Python Functions. * Exception Handling:: +* Auto-loading:: Automatically loading Python code. * Values From Inferior:: * Commands In Python:: Implementing new commands in Python. * Functions In Python:: Writing new convenience functions. +* Objfiles In Python:: Object files. @end menu @node Basic Python @@ -18322,6 +18325,53 @@ message as its value, and the Python call stack backtrace at the Python statement closest to where the @value{GDBN} error occured as the traceback. +@node Auto-loading +@subsubsection Auto-loading +@cindex auto-loading, Python + +When a new object file is read (for example, due to the @code{file} +command, or because the inferior has loaded a shared library), +@value{GDBN} will look for a file named @file{@var{objfile}-gdb.py}, +where @var{objfile} is the object file's real name, formed by ensuring +that the file name is absolute, following all symlinks, and resolving +@code{.} and @code{..} components. If this file exists and is +readable, @value{GDBN} will evaluate it as a Python script. + +If this file does not exist, and if the parameter +@code{debug-file-directory} is set (@pxref{Separate Debug Files}), +then @value{GDBN} will use the file named +@file{@var{debug-file-directory}/@var{real-name}}, where +@var{real-name} is the object file's real name, as described above. + +Finally, if this file does not exist, then @value{GDBN} will look for +a file named @file{@var{data-directory}/python/auto-load/@var{real-name}}, where +@var{data-directory} is @value{GDBN}'s data directory (available via +@code{show data-directory}, @pxref{Data Files}), and @var{real-name} +is the object file's real name, as described above. + +When reading an auto-loaded file, @value{GDBN} sets the ``current +objfile''. This is available via the @code{gdb.current_objfile} +function (@pxref{Objfiles In Python}). This can be useful for +registering objfile-specific pretty-printers. + +The auto-loading feature is useful for supplying application-specific +debugging commands and scripts. You can enable or disable this +feature, and view its current state. + +@table @code +@kindex maint set python auto-load +@item maint set python auto-load [yes|no] +Enable or disable the Python auto-loading feature. + +@kindex show python auto-load +@item show python auto-load +Show whether Python auto-loading is enabled or disabled. +@end table + +@value{GDBN} does not track which files it has already auto-loaded. +So, your @samp{-gdb.py} file should take care to ensure that it may be +evaluated multiple times without error. + @node Values From Inferior @subsubsection Values From Inferior @cindex values from inferior, with Python @@ -18735,6 +18785,50 @@ registration of the function with @value{GDBN}. Depending on how the Python code is read into @value{GDBN}, you may need to import the @code{gdb} module explicitly. +@node Objfiles In Python +@subsubsection Objfiles In Python + +@cindex objfiles in python +@tindex gdb.Objfile +@tindex Objfile +@value{GDBN} loads symbols for an inferior from various +symbol-containing files (@pxref{Files}). These include the primary +executable file, any shared libraries used by the inferior, and any +separate debug info files (@pxref{Separate Debug Files}). +@value{GDBN} calls these symbol-containing files @dfn{objfiles}. + +The following objfile-related functions are available in the +@code{gdb} module: + +@findex gdb.current_objfile +@defun current_objfile +When auto-loading a Python script (@pxref{Auto-loading}), @value{GDBN} +sets the ``current objfile'' to the corresponding objfile. This +function returns the current objfile. If there is no current objfile, +this function returns @code{None}. +@end defun + +@findex gdb.objfiles +@defun objfiles +Return a sequence of all the objfiles current known to @value{GDBN}. +@xref{Objfiles In Python}. +@end defun + +Each objfile is represented by an instance of the @code{gdb.Objfile} +class. + +@defivar Objfile filename +The file name of the objfile as a string. +@end defivar + +@defivar Objfile pretty_printers +The @code{pretty_printers} attribute is a list of functions. It is +used to look up pretty-printers. A @code{Value} is passed to each +function in order; if the function returns @code{None}, then the +search continues. Otherwise, the return value should be an object +which is used to format the value. +@end defivar + @node Interpreters @chapter Command Interpreters @cindex command interpreters diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h index 463f08e..9764f4f 100644 --- a/gdb/python/python-internal.h +++ b/gdb/python/python-internal.h @@ -66,12 +66,16 @@ extern PyTypeObject value_object_type; PyObject *gdbpy_history (PyObject *self, PyObject *args); PyObject *value_to_value_object (struct value *v); +PyObject *objfile_to_objfile_object (struct objfile *); + +PyObject *objfpy_get_printers (PyObject *, void *); struct value *convert_value_from_python (PyObject *obj); void gdbpy_initialize_values (void); void gdbpy_initialize_commands (void); void gdbpy_initialize_functions (void); +void gdbpy_initialize_objfile (void); struct cleanup *make_cleanup_py_decref (PyObject *py); struct cleanup *make_cleanup_py_restore_gil (PyGILState_STATE *state); diff --git a/gdb/python/python-objfile.c b/gdb/python/python-objfile.c new file mode 100644 index 0000000..b70a006 --- /dev/null +++ b/gdb/python/python-objfile.c @@ -0,0 +1,229 @@ +/* Python interface to objfiles. + + Copyright (C) 2008, 2009 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 list of functions. */ + PyObject *printers; +} objfile_object; + +static PyTypeObject objfile_object_type; + +static const struct objfile_data *objfpy_objfile_data_key; + +\f + +/* An Objfile method which returns the objfile's file name, or None. */ +static PyObject * +objfpy_get_filename (PyObject *self, void *closure) +{ + 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->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; + + self->printers = PyList_New (0); + if (!self->printers) + { + Py_DECREF (self); + return NULL; + } + } + return (PyObject *) self; +} + +PyObject * +objfpy_get_printers (PyObject *o, void *ignore) +{ + objfile_object *self = (objfile_object *) o; + Py_INCREF (self->printers); + return self->printers; +} + +static int +objfpy_set_printers (PyObject *o, PyObject *value, void *ignore) +{ + PyObject *tmp; + objfile_object *self = (objfile_object *) o; + if (! value) + { + PyErr_SetString (PyExc_TypeError, + "cannot delete the pretty_printers attribute"); + return -1; + } + + if (! PyList_Check (value)) + { + PyErr_SetString (PyExc_TypeError, + "the pretty_printers attribute must be a list"); + return -1; + } + + /* Take care in case the LHS and RHS are related somehow. */ + tmp = self->printers; + Py_INCREF (value); + self->printers = value; + Py_XDECREF (tmp); + + return 0; +} + +\f + +/* Clear the OBJFILE pointer in an Objfile object and remove the + reference. */ +static void +clean_up_objfile (struct objfile *objfile, void *datum) +{ + PyGILState_STATE state; + objfile_object *object = datum; + + state = PyGILState_Ensure (); + object->objfile = NULL; + Py_DECREF ((PyObject *) object); + PyGILState_Release (state); +} + +/* Return a borrowed reference to 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; + + object->printers = PyList_New (0); + if (!object->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); + + if (PyType_Ready (&objfile_object_type) < 0) + return; + + Py_INCREF (&objfile_object_type); + PyModule_AddObject (gdb_module, "Objfile", (PyObject *) &objfile_object_type); +} + +\f + +static PyGetSetDef objfile_getset[] = +{ + { "filename", objfpy_get_filename, NULL, + "The objfile's filename, or None.", NULL }, + { "pretty_printers", objfpy_get_printers, objfpy_set_printers, + "Pretty printers.", NULL }, + { NULL } +}; + +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 */ + 0, /* 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 b48cf05..fcf351f 100644 --- a/gdb/python/python.c +++ b/gdb/python/python.c @@ -22,6 +22,8 @@ #include "ui-out.h" #include "cli/cli-script.h" #include "gdbcmd.h" +#include "objfiles.h" +#include "observer.h" #include <ctype.h> @@ -29,6 +31,10 @@ false otherwise. */ static int gdbpy_should_print_stack = 1; +/* This is true if we should auto-load python code when an objfile is + opened, false otherwise. */ +static int gdbpy_auto_load = 1; + #ifdef HAVE_PYTHON #include "python.h" @@ -301,6 +307,129 @@ gdbpy_print_stack (void) PyErr_Clear (); } +\f + +/* 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" + +/* 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 *realname; + char *filename, *debugfile; + int len; + FILE *input; + PyGILState_STATE state; + struct cleanup *cleanups; + + if (!gdbpy_auto_load || !objfile || !objfile->name) + return; + + state = PyGILState_Ensure (); + + gdbpy_current_objfile = objfile; + + realname = gdb_realpath (objfile->name); + len = strlen (realname); + filename = xmalloc (len + sizeof (GDBPY_AUTO_FILENAME)); + memcpy (filename, realname, len); + strcpy (filename + len, GDBPY_AUTO_FILENAME); + + input = fopen (filename, "r"); + debugfile = filename; + + cleanups = make_cleanup (xfree, filename); + make_cleanup (xfree, realname); + + if (!input && debug_file_directory) + { + /* Also try the same file in the separate debug info directory. */ + debugfile = xmalloc (strlen (filename) + + strlen (debug_file_directory) + 1); + strcpy (debugfile, debug_file_directory); + /* FILENAME is absolute, so we don't need a "/" here. */ + strcat (debugfile, filename); + + make_cleanup (xfree, debugfile); + input = fopen (debugfile, "r"); + } + + if (!input && gdb_datadir) + { + /* Also try the same file in a subdirectory of gdb's data + directory. */ + debugfile = xmalloc (strlen (gdb_datadir) + strlen (filename) + + strlen ("/auto-load") + 1); + strcpy (debugfile, gdb_datadir); + strcat (debugfile, "/auto-load"); + /* FILENAME is absolute, so we don't need a "/" here. */ + strcat (debugfile, filename); + + make_cleanup (xfree, debugfile); + input = fopen (debugfile, "r"); + } + + if (input) + { + /* We don't want to throw an exception here -- but the user + would like to know that something went wrong. */ + if (PyRun_SimpleFile (input, debugfile)) + gdbpy_print_stack (); + fclose (input); + } + + do_cleanups (cleanups); + gdbpy_current_objfile = NULL; + + PyGILState_Release (state); +} + +/* 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_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; +} + #else /* HAVE_PYTHON */ /* Dummy implementation of the gdb "python" command. */ @@ -399,6 +528,15 @@ Enables or disables printing of Python stack traces."), &set_python_list, &show_python_list); + add_setshow_boolean_cmd ("auto-load", class_maintenance, + &gdbpy_auto_load, _("\ +Enable or disable auto-loading of Python code when an object is opened."), _("\ +Show whether Python code will be auto-loaded when an object is opened."), _("\ +Enables or disables auto-loading of Python code when an object is opened."), + NULL, NULL, + &set_python_list, + &show_python_list); + #ifdef HAVE_PYTHON Py_Initialize (); PyEval_InitThreads (); @@ -413,9 +551,12 @@ Enables or disables printing of Python stack traces."), gdbpy_initialize_values (); gdbpy_initialize_commands (); gdbpy_initialize_functions (); + gdbpy_initialize_objfile (); PyRun_SimpleString ("import gdb"); + observer_attach_new_objfile (gdbpy_new_objfile); + gdbpy_doc_cst = PyString_FromString ("__doc__"); /* Create a couple objects which are used for Python's stdout and @@ -464,6 +605,11 @@ static PyMethodDef GdbMethods[] = { "get_parameter", get_parameter, METH_VARARGS, "Return a gdb parameter's value" }, + { "current_objfile", gdbpy_get_current_objfile, METH_NOARGS, + "Return the current Objfile being loaded, or None." }, + { "objfiles", gdbpy_objfiles, METH_NOARGS, + "Return a sequence of all loaded objfiles." }, + { "write", gdbpy_write, METH_VARARGS, "Write a string using gdb's filtered stream." }, { "flush", gdbpy_flush, METH_NOARGS, diff --git a/gdb/testsuite/gdb.python/python-value.exp b/gdb/testsuite/gdb.python/python-value.exp index b3b5746..93e9d89 100644 --- a/gdb/testsuite/gdb.python/python-value.exp +++ b/gdb/testsuite/gdb.python/python-value.exp @@ -236,6 +236,15 @@ proc test_value_in_inferior {} { gdb_test "python print 'result =', arg0.address" "= 0x\[\[:xdigit:\]\]+" "Test address attribute" } +# A few objfile tests. +proc test_objfiles {} { + gdb_test "python\nok=False\nfor file in gdb.objfiles():\n if 'python-value' in file.filename:\n ok=True\nprint ok\nend" "True" + + gdb_test "python print gdb.objfiles()\[0\].pretty_printers" "\\\[\\\]" + + gdb_test "python gdb.objfiles()\[0\].pretty_printers = 0" \ + "pretty_printers attribute must be a list.*Error while executing Python code." +} # Start with a fresh gdb. @@ -256,6 +265,7 @@ test_value_creation test_value_numeric_ops test_value_boolean test_value_compare +test_objfiles # The following tests require execution. diff --git a/gdb/testsuite/gdb.python/python.exp b/gdb/testsuite/gdb.python/python.exp index a0c9b39..5223fc8 100644 --- a/gdb/testsuite/gdb.python/python.exp +++ b/gdb/testsuite/gdb.python/python.exp @@ -71,3 +71,6 @@ gdb_py_test_multiple "indented multi-line python command" \ " print 'hello, world!'" "" \ "foo ()" "" \ "end" "hello, world!" + +gdb_test "python print gdb.current_objfile()" "None" +gdb_test "python print gdb.objfiles()" "\\\[\\\]" -- 1.6.0.6 ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: Python pretty-printing [2/6] 2009-04-06 19:25 ` Tom Tromey @ 2009-04-06 20:41 ` Eli Zaretskii 0 siblings, 0 replies; 8+ messages in thread From: Eli Zaretskii @ 2009-04-06 20:41 UTC (permalink / raw) To: Tom Tromey; +Cc: bauerman, gdb-patches > Cc: bauerman@br.ibm.com, gdb-patches@sourceware.org > From: Tom Tromey <tromey@redhat.com> > Date: Mon, 06 Apr 2009 13:24:33 -0600 > > Here's the updated patch. I've tried to address all the comments that > anybody raised. Also, I fixed the documentation for > Objfile.pretty_printers to reflect reality. Thanks, the doco part is OK with me. ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: Python pretty-printing [2/6] 2009-04-03 0:23 ` Tom Tromey 2009-04-03 0:47 ` Tom Tromey @ 2009-04-03 20:36 ` Thiago Jung Bauermann 1 sibling, 0 replies; 8+ messages in thread From: Thiago Jung Bauermann @ 2009-04-03 20:36 UTC (permalink / raw) To: Tom Tromey; +Cc: gdb-patches El jue, 02-04-2009 a las 18:23 -0600, Tom Tromey escribió: > >>>>> "Thiago" == Thiago Jung Bauermann <bauerman@br.ibm.com> writes: > Thiago> Also, just to check: the lack of testcases is because you believe this > Thiago> code is tested enough with python-prettyprint.exp in a later patch? > > You know, I am not sure. This class doesn't provide much behavior > yet. And, the most important bits are tested by the pretty-printer. > I'm inclined not to bother, but if you (or anybody) thinks it is > important, I suppose I can whip something up. Well, my policy with python testcases has been to at least smoke-test all of the API supported by GDB. That way, if we make an API-breaking change, at least one testcase will fail. I won't insist that it is important to do this, since I believe it's not hard to spot API changes by looking at a patch. -- []'s Thiago Jung Bauermann IBM Linux Technology Center ^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2009-04-06 20:41 UTC | newest] Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2009-04-02 20:55 Python pretty-printing [2/6] Tom Tromey 2009-04-02 22:29 ` Thiago Jung Bauermann 2009-04-03 0:23 ` Tom Tromey 2009-04-03 0:47 ` Tom Tromey 2009-04-03 15:06 ` Eli Zaretskii 2009-04-06 19:25 ` Tom Tromey 2009-04-06 20:41 ` Eli Zaretskii 2009-04-03 20:36 ` Thiago Jung Bauermann
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox