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.

gdb/doc

2009-04-01  Tom Tromey  <tromey@redhat.com>
	    Thiago Jung Bauermann  <bauerman@br.ibm.com>

	* gdb.texinfo (Python API): Update.
	(Auto-loading): New node.
	(Objfiles In Python): New node.

gdb/testsuite

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.
This commit is contained in:
Tom Tromey 2009-05-28 00:40:24 +00:00
parent 58683880f5
commit 89c73adef9
10 changed files with 530 additions and 0 deletions

View file

@ -68,6 +68,9 @@ PyObject *gdbpy_frame_stop_reason_string (PyObject *, PyObject *);
PyObject *gdbpy_selected_frame (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);
@ -75,6 +78,7 @@ void gdbpy_initialize_values (void);
void gdbpy_initialize_frames (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);

229
gdb/python/python-objfile.c Normal file
View file

@ -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;
/* 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;
}
/* 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);
}
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 */
};

View file

@ -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 ();
}
/* 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 ();
@ -414,9 +552,12 @@ Enables or disables printing of Python stack traces."),
gdbpy_initialize_frames ();
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
@ -465,6 +606,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." },
{ "selected_frame", gdbpy_selected_frame, METH_NOARGS,
"selected_frame () -> gdb.Frame.\n\
Return the selected frame object." },