From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 10057 invoked by alias); 29 Apr 2008 15:59:35 -0000 Received: (qmail 9763 invoked by uid 22791); 29 Apr 2008 15:59:28 -0000 X-Spam-Check-By: sourceware.org Received: from igw2.br.ibm.com (HELO igw2.br.ibm.com) (32.104.18.25) by sourceware.org (qpsmtpd/0.31) with ESMTP; Tue, 29 Apr 2008 15:59:00 +0000 Received: from mailhub1.br.ibm.com (mailhub1 [9.18.232.109]) by igw2.br.ibm.com (Postfix) with ESMTP id B7B2717F493 for ; Tue, 29 Apr 2008 12:48:57 -0300 (BRST) Received: from d24av01.br.ibm.com (d24av01.br.ibm.com [9.18.232.46]) by mailhub1.br.ibm.com (8.13.8/8.13.8/NCO v8.7) with ESMTP id m3TFwvSU2408458 for ; Tue, 29 Apr 2008 12:58:57 -0300 Received: from d24av01.br.ibm.com (loopback [127.0.0.1]) by d24av01.br.ibm.com (8.12.11.20060308/8.13.3) with ESMTP id m3TFwknc020176 for ; Tue, 29 Apr 2008 12:58:46 -0300 Received: from [9.18.238.95] (dyn531828.br.ibm.com [9.18.238.95]) by d24av01.br.ibm.com (8.12.11.20060308/8.12.11) with ESMTP id m3TFwkRm019823 for ; Tue, 29 Apr 2008 12:58:46 -0300 Message-Id: <20080429155304.816981949@br.ibm.com> References: <20080429155212.444237503@br.ibm.com> User-Agent: quilt/0.46-1 Date: Tue, 29 Apr 2008 18:11:00 -0000 From: Thiago Jung Bauermann To: gdb-patches@sourceware.org Subject: [RFC][patch 4/9] export breakpoints to Python Content-Disposition: inline; filename=python-breakpoints.diff Mime-Version: 1.0 X-Mailer: Evolution 2.12.3 Content-Transfer-Encoding: 7bit X-IsSubscribed: yes Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2008-04/txt/msg00664.txt.bz2 2008-04-29 Tom Tromey * Makefile.in (SUBDIR_PYTHON_OBS): Add python-breakpoint.o. (SUBDIR_PYTHON_SRCS): Add python/breakpoint.c. (python-breakpoint.o): New target. * python/breakpoint.c: New file. * python/hooks.c (gdbpy_initialize_hooks): Register breakpoint event callback functions. * python/python-internal.h (gdbpy_get_breakpoints, gdbpy_initialize_breakpoints, gdbpy_breakpoint_created, gdbpy_breakpoint_deleted): Declare. * python/python.c (demand_python): Add "get_breakpoints" function. Call gdbpy_initialize_breakpoints. Index: tromey.git/gdb/Makefile.in =================================================================== --- tromey.git.orig/gdb/Makefile.in 2008-04-29 11:05:09.000000000 -0300 +++ tromey.git/gdb/Makefile.in 2008-04-29 11:05:15.000000000 -0300 @@ -262,10 +262,12 @@ SUBDIR_TUI_CFLAGS= \ # SUBDIR_PYTHON_OBS = \ python.o \ + python-breakpoint.o \ python-hooks.o \ python-value.o SUBDIR_PYTHON_SRCS = \ python/python.c \ + python/breakpoint.c \ python/hooks.c \ python/value.c SUBDIR_PYTHON_DEPS = @@ -3415,6 +3417,11 @@ python.o: $(srcdir)/python/python.c $(de $(command_h) $(libiberty_h) $(cli_decode_h) $(charset_h) $(top_h) \ $(exceptions_h) $(python_internal_h) $(version_h) $(CC) -c $(INTERNAL_CFLAGS) $(PYTHON_CFLAGS) $(srcdir)/python/python.c +python-breakpoint.o: $(srcdir)/python/breakpoint.c $(defs_h) $(python_h) \ + $(value_h) $(exceptions_h) $(python_internal_h) $(charset_h) \ + $(breakpoint_h) $(gdbcmd_h) + $(CC) -c $(INTERNAL_CFLAGS) $(PYTHON_CFLAGS) \ + $(srcdir)/python/breakpoint.c -o python-breakpoint.o python-hooks.o: $(srcdir)/python/hooks.c $(defs_h) $(cli_decode_h) \ $(charset_h) $(gdb_events_h) $(python_h) $(python_internal_h) $(CC) -c $(INTERNAL_CFLAGS) $(PYTHON_CFLAGS) \ Index: tromey.git/gdb/python/breakpoint.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ tromey.git/gdb/python/breakpoint.c 2008-04-29 11:05:15.000000000 -0300 @@ -0,0 +1,408 @@ +/* Python interface to breakpoints + + Copyright (C) 2008 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include "defs.h" +#include "value.h" +#include "exceptions.h" +#include "python-internal.h" +#include "charset.h" +#include "breakpoint.h" +#include "gdbcmd.h" + + +/* From breakpoint.c. */ +extern struct breakpoint *breakpoint_chain; + + +typedef struct breakpoint_object breakpoint_object; + +static PyObject *bppy_is_valid (PyObject *, PyObject *); +static PyObject *bppy_is_enabled (PyObject *, PyObject *); +static PyObject *bppy_is_silent (PyObject *, PyObject *); +static PyObject *bppy_set_enabled (PyObject *, PyObject *); +static PyObject *bppy_set_silent (PyObject *, PyObject *); +static PyObject *bppy_get_location (PyObject *, PyObject *); +static PyObject *bppy_get_condition (PyObject *, PyObject *); +static PyObject *bppy_get_commands (PyObject *, PyObject *); + + +/* A dynamically allocated vector of breakpoint objects. Each + breakpoint has a number. A breakpoint is valid if its slot in this + vector is non-null. When a breakpoint is deleted, we drop our + reference to it and zero its slot; this is how we let the Python + object have a lifetime which is independent from that of the gdb + breakpoint. */ +static breakpoint_object **bppy_breakpoints; + +/* Number of slots in bppy_breakpoints. */ +static int bppy_slots; + +/* Number of live breakpoints. */ +static int bppy_live; + +/* Variables used to pass information between the Breakpoint + constructor and the breakpoint-created hook function. */ +static breakpoint_object *bppy_pending_object; + +struct breakpoint_object +{ + PyObject_HEAD + + /* The breakpoint number according to gdb. */ + int number; + + /* The gdb breakpoint object, or NULL if the breakpoint has been + deleted. */ + struct breakpoint *bp; +}; + +#define BPPY_VALID_P(Num) \ + ((Num) >= 0 \ + && (Num) < bppy_slots \ + && bppy_breakpoints[Num] != NULL) + +#define BPPY_REQUIRE_VALID(Breakpoint) \ + do { \ + if (! BPPY_VALID_P ((Breakpoint)->number)) \ + return PyErr_Format (PyExc_RuntimeError, "breakpoint %d is invalid", \ + (Breakpoint)->number); \ + } while (0) + +static PyMethodDef breakpoint_object_methods[] = +{ + { "is_valid", bppy_is_valid, METH_NOARGS, + "Return true if this breakpoint is valid, false if not." }, + { "is_enabled", bppy_is_enabled, METH_NOARGS, + "Return true if this breakpoint is enabled, false if disabled." }, + { "is_silent", bppy_is_silent, METH_NOARGS, + "Return true if this breakpoint is silent, false if verbose." }, + + { "set_enabled", bppy_set_enabled, METH_O, + "Enable or disable this breakpoint" }, + { "set_silent", bppy_set_silent, METH_O, + "Make this breakpoint quiet or verbose" }, + + { "get_location", bppy_get_location, METH_NOARGS, + "Return the location of this breakpoint, as specified by the user"}, + { "get_condition", bppy_get_condition, METH_NOARGS, + "Return the condition of this breakpoint, as specified by the user.\n\ +Returns None if no condition set."}, + { "get_commands", bppy_get_commands, METH_NOARGS, + "Return the commands of this breakpoint, as specified by the user"}, + + { 0 } +}; + +static PyTypeObject breakpoint_object_type = +{ + PyObject_HEAD_INIT (NULL) + 0, /*ob_size*/ + "gdb.Breakpoint", /*tp_name*/ + sizeof (breakpoint_object), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + 0, /*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 breakpoint object", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + breakpoint_object_methods /* tp_methods */ +}; + +static PyObject * +bppy_is_valid (PyObject *self, PyObject *args) +{ + if (((breakpoint_object *) self)->bp) + Py_RETURN_TRUE; + Py_RETURN_FALSE; +} + +static PyObject * +bppy_is_enabled (PyObject *self, PyObject *args) +{ + if (! ((breakpoint_object *) self)->bp) + Py_RETURN_FALSE; + /* Not clear what we really want here. */ + if (((breakpoint_object *) self)->bp->enable_state == bp_enabled) + Py_RETURN_TRUE; + Py_RETURN_FALSE; +} + +static PyObject * +bppy_is_silent (PyObject *self, PyObject *args) +{ + BPPY_REQUIRE_VALID ((breakpoint_object *) self); + if (((breakpoint_object *) self)->bp->silent) + Py_RETURN_TRUE; + Py_RETURN_FALSE; +} + +static PyObject * +bppy_set_enabled (PyObject *self, PyObject *newvalue) +{ + breakpoint_object *self_bp = (breakpoint_object *) self; + + BPPY_REQUIRE_VALID (self_bp); + if (! PyBool_Check (newvalue)) + return PyErr_Format (PyExc_RuntimeError, "argument must be boolean"); + + if (newvalue == Py_True) + enable_breakpoint (self_bp->bp); + else + disable_breakpoint (self_bp->bp); + + Py_RETURN_NONE; +} + +static PyObject * +bppy_set_silent (PyObject *self, PyObject *newvalue) +{ + breakpoint_object *self_bp = (breakpoint_object *) self; + + BPPY_REQUIRE_VALID (self_bp); + if (! PyBool_Check (newvalue)) + return PyErr_Format (PyExc_RuntimeError, "argument must be boolean"); + + self_bp->bp->silent = (newvalue == Py_True); + + Py_RETURN_NONE; +} + +static PyObject * +bppy_get_location (PyObject *self, PyObject *args) +{ + char *str; + + BPPY_REQUIRE_VALID ((breakpoint_object *) self); + str = ((breakpoint_object *) self)->bp->addr_string; + /* FIXME: watchpoints? tracepoints? */ + if (! str) + str = ""; + return PyString_Decode (str, strlen (str), host_charset (), + NULL /* FIXME */); +} + +static PyObject * +bppy_get_condition (PyObject *self, PyObject *args) +{ + char *str; + BPPY_REQUIRE_VALID ((breakpoint_object *) self); + + str = ((breakpoint_object *) self)->bp->cond_string; + if (! str) + Py_RETURN_NONE; + return PyString_Decode (str, strlen (str), host_charset (), + NULL /* FIXME */); +} + +static PyObject * +bppy_get_commands (PyObject *self, PyObject *args) +{ + breakpoint_object *self_bp = (breakpoint_object *) self; + long length; + volatile struct gdb_exception except; + struct ui_file *string_file; + struct cleanup *chain; + PyObject *result; + char *cmdstr; + + BPPY_REQUIRE_VALID (self_bp); + + if (! self_bp->bp->commands) + Py_RETURN_NONE; + + string_file = mem_fileopen (); + chain = make_cleanup_ui_file_delete (string_file); + + TRY_CATCH (except, RETURN_MASK_ALL) + { + /* FIXME: this can fail. Maybe we need to be making a new + ui_out object here? */ + ui_out_redirect (uiout, string_file); + print_command_lines (uiout, self_bp->bp->commands, 0); + ui_out_redirect (uiout, NULL); + } + cmdstr = ui_file_xstrdup (string_file, &length); + GDB_PY_HANDLE_EXCEPTION (except); + + result = PyString_Decode (cmdstr, strlen (cmdstr), host_charset (), + NULL /* FIXME */); + do_cleanups (chain); + xfree (cmdstr); + return result; +} + +static PyObject * +bppy_new (PyTypeObject *subtype, PyObject *args, PyObject *kwargs) +{ + PyObject *result; + char *spec; + volatile struct gdb_exception except; + + /* FIXME: allow condition, thread, temporary, ... ? */ + if (! PyArg_ParseTuple (args, "s", &spec)) + return NULL; + result = subtype->tp_alloc (subtype, 0); + if (! result) + return NULL; + bppy_pending_object = (breakpoint_object *) result; + bppy_pending_object->number = -1; + bppy_pending_object->bp = NULL; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + set_breakpoint (spec, NULL, 0, 0, -1, 0, AUTO_BOOLEAN_TRUE); + } + GDB_PY_HANDLE_EXCEPTION (except); + + BPPY_REQUIRE_VALID ((breakpoint_object *) result); + return result; +} + + + +/* Static function to return a tuple holding all breakpoints. */ + +PyObject * +gdbpy_get_breakpoints (PyObject *self, PyObject *args) +{ + PyObject *result; + + if (bppy_live == 0) + Py_RETURN_NONE; + + result = PyTuple_New (bppy_live); + if (result) + { + int i, out = 0; + for (i = 0; out < bppy_live; ++i) + { + if (! bppy_breakpoints[i]) + continue; + Py_INCREF (bppy_breakpoints[i]); + PyTuple_SetItem (result, out, (PyObject *) bppy_breakpoints[i]); + ++out; + } + } + return result; +} + + + +/* Event callback functions. */ + +void +gdbpy_breakpoint_created (int num) +{ + breakpoint_object *newbp; + struct breakpoint *bp; + + if (num < 0) + return; + + for (bp = breakpoint_chain; bp; bp = bp->next) + if (bp->number == num) + break; + if (! bp) + return; + + if (num >= bppy_slots) + { + int old = bppy_slots; + bppy_slots = bppy_slots * 2 + 10; + bppy_breakpoints + = (breakpoint_object **) xrealloc (bppy_breakpoints, + (bppy_slots + * sizeof (breakpoint_object *))); + memset (&bppy_breakpoints[old], 0, + (bppy_slots - old) * sizeof (PyObject *)); + } + + ++bppy_live; + + if (bppy_pending_object) + { + newbp = bppy_pending_object; + bppy_pending_object = NULL; + } + else + newbp = PyObject_New (breakpoint_object, &breakpoint_object_type); + if (newbp) + { + PyObject *hookfn; + + newbp->number = num; + newbp->bp = bp; + bppy_breakpoints[num] = newbp; + + hookfn = gdbpy_get_hook_function ("new_breakpoint"); + if (hookfn) + { + /* FIXME: refc? */ + PyObject_CallFunctionObjArgs (hookfn, newbp, NULL); + } + } + + if (PyErr_Occurred ()) + { + /* FIXME -- what to do? */ + PyErr_Print (); + } +} + +void +gdbpy_breakpoint_deleted (int num) +{ + if (BPPY_VALID_P (num)) + { + bppy_breakpoints[num]->bp = NULL; + Py_DECREF (bppy_breakpoints[num]); + bppy_breakpoints[num] = NULL; + --bppy_live; + } +} + +void +gdbpy_initialize_breakpoints (void) +{ + breakpoint_object_type.tp_new = bppy_new; + if (PyType_Ready (&breakpoint_object_type) < 0) + return; + + Py_INCREF (&breakpoint_object_type); + PyModule_AddObject (gdb_module, "Breakpoint", + (PyObject *) &breakpoint_object_type); +} Index: tromey.git/gdb/python/hooks.c =================================================================== --- tromey.git.orig/gdb/python/hooks.c 2008-04-29 11:05:09.000000000 -0300 +++ tromey.git/gdb/python/hooks.c 2008-04-29 11:05:15.000000000 -0300 @@ -112,6 +112,8 @@ void gdbpy_initialize_hooks (void) { handlers.architecture_changed = gdbpy_architecture_changed; + handlers.breakpoint_create = gdbpy_breakpoint_created; + handlers.breakpoint_delete = gdbpy_breakpoint_deleted; deprecated_set_gdb_event_hooks (&handlers); deprecated_set_hook = gdbpy_set_hook; Index: tromey.git/gdb/python/python-internal.h =================================================================== --- tromey.git.orig/gdb/python/python-internal.h 2008-04-29 11:05:09.000000000 -0300 +++ tromey.git/gdb/python/python-internal.h 2008-04-29 11:05:15.000000000 -0300 @@ -31,6 +31,7 @@ extern PyTypeObject value_object_type; PyObject *gdbpy_make_value_from_int (PyObject *self, PyObject *args); PyObject *gdbpy_get_value_from_history (PyObject *self, PyObject *args); +PyObject *gdbpy_get_breakpoints (PyObject *, PyObject *); PyObject *variable_to_python (struct cmd_list_element *); PyObject *value_to_value_object (struct value *v); @@ -42,6 +43,7 @@ PyObject *gdbpy_get_hook_function (const void gdbpy_initialize_values (void); void gdbpy_initialize_hooks (void); +void gdbpy_initialize_breakpoints (void); /* Use this after a TRY_EXCEPT to throw the appropriate Python exception. FIXME: throw different errors depending on @@ -54,4 +56,8 @@ void gdbpy_initialize_hooks (void); "%s", Exception.message); \ } while (0) +/* Breakpoint hook functions. */ +void gdbpy_breakpoint_created (int); +void gdbpy_breakpoint_deleted (int); + #endif /* GDB_PYTHON_INTERNAL_H */ Index: tromey.git/gdb/python/python.c =================================================================== --- tromey.git.orig/gdb/python/python.c 2008-04-29 11:05:09.000000000 -0300 +++ tromey.git/gdb/python/python.c 2008-04-29 11:05:15.000000000 -0300 @@ -53,6 +53,9 @@ demand_python () { "show", get_show_variable, METH_VARARGS, "Return a gdb setting's value" }, + { "get_breakpoints", gdbpy_get_breakpoints, METH_NOARGS, + "Return a tuple of all breakpoint objects" }, + {NULL, NULL, 0, NULL} }; @@ -66,6 +69,7 @@ demand_python () gdbpy_initialize_hooks (); gdbpy_initialize_values (); + gdbpy_initialize_breakpoints (); PyRun_SimpleString ("import gdb"); -- -- []'s Thiago Jung Bauermann Software Engineer IBM Linux Technology Center