From 735ddf1d48e94553d401d39afc3b49fb1b4e898e Mon Sep 17 00:00:00 2001 From: Kevin Pouget Date: Thu, 12 May 2011 15:55:54 -0400 Subject: [PATCH] Python Finish Breakpoints --- gdb/Makefile.in | 6 + gdb/breakpoint.c | 2 +- gdb/breakpoint.h | 10 + gdb/infcmd.c | 20 +- gdb/inferior.h | 3 + gdb/infrun.c | 4 +- gdb/python/py-breakpoint.c | 40 +-- gdb/python/py-finishbreakpoint.c | 447 ++++++++++++++++++++ gdb/python/py-frame.c | 32 +- gdb/python/python-internal.h | 44 ++- gdb/python/python.c | 6 + gdb/python/python.h | 2 + gdb/testsuite/gdb.python/py-breakpoint.exp | 7 +- .../gdb.python/py-finish-breakpoint-cc.cc | 59 +++ .../gdb.python/py-finish-breakpoint-cc.exp | 59 +++ .../gdb.python/py-finish-breakpoint-cc.py | 43 ++ gdb/testsuite/gdb.python/py-finish-breakpoint.c | 82 ++++ gdb/testsuite/gdb.python/py-finish-breakpoint.exp | 183 ++++++++ gdb/testsuite/gdb.python/py-finish-breakpoint.py | 85 ++++ 19 files changed, 1070 insertions(+), 64 deletions(-) create mode 100644 gdb/python/py-finishbreakpoint.c create mode 100644 gdb/testsuite/gdb.python/py-finish-breakpoint-cc.cc create mode 100644 gdb/testsuite/gdb.python/py-finish-breakpoint-cc.exp create mode 100644 gdb/testsuite/gdb.python/py-finish-breakpoint-cc.py create mode 100644 gdb/testsuite/gdb.python/py-finish-breakpoint.c create mode 100644 gdb/testsuite/gdb.python/py-finish-breakpoint.exp create mode 100644 gdb/testsuite/gdb.python/py-finish-breakpoint.py diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 5bab360..2507938 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -285,6 +285,7 @@ SUBDIR_PYTHON_OBS = \ py-evtregistry.o \ py-evts.o \ py-exitedevent.o \ + py-finishbreakpoint.o \ py-frame.o \ py-function.o \ py-inferior.o \ @@ -315,6 +316,7 @@ SUBDIR_PYTHON_SRCS = \ python/py-evtregistry.c \ python/py-evts.c \ python/py-exitedevent.c \ + python/py-finishbreakpoint.c \ python/py-frame.c \ python/py-function.c \ python/py-inferior.c \ @@ -2062,6 +2064,10 @@ py-exitedevent.o: $(srcdir)/python/py-exitedevent.c $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-exitedevent.c $(POSTCOMPILE) +py-finishbreakpoint.o: $(srcdir)/python/py-finishbreakpoint.c + $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-finishbreakpoint.c + $(POSTCOMPILE) + py-frame.o: $(srcdir)/python/py-frame.c $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-frame.c $(POSTCOMPILE) diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c index b5fc448..eff5e23 100644 --- a/gdb/breakpoint.c +++ b/gdb/breakpoint.c @@ -7330,7 +7330,7 @@ bp_loc_is_permanent (struct bp_location *loc) as textual description of the location, and COND_STRING as condition expression. */ -static void +void create_breakpoint_sal (struct gdbarch *gdbarch, struct symtabs_and_lines sals, char *addr_string, char *cond_string, diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h index 7a9c2d4..a003651 100644 --- a/gdb/breakpoint.h +++ b/gdb/breakpoint.h @@ -986,6 +986,16 @@ extern int create_breakpoint (struct gdbarch *gdbarch, char *arg, int enabled, int internal); +extern void create_breakpoint_sal (struct gdbarch *gdbarch, + struct symtabs_and_lines sals, + char *addr_string, + char *cond_string, + enum bptype type, enum bpdisp disposition, + int thread, int task, int ignore_count, + struct breakpoint_ops *ops, int from_tty, + int enabled, int internal, + int display_canonical); + extern void insert_breakpoints (void); extern int remove_breakpoints (void); diff --git a/gdb/infcmd.c b/gdb/infcmd.c index fce1e8f..1b8c612 100644 --- a/gdb/infcmd.c +++ b/gdb/infcmd.c @@ -1378,14 +1378,12 @@ advance_command (char *arg, int from_tty) until_break_command (arg, from_tty, 1); } -/* Print the result of a function at the end of a 'finish' command. */ +/* Returns the value of the result at the end of a 'finish' command/BP. */ -static void -print_return_value (struct type *func_type, struct type *value_type) +struct value * +get_return_value (struct type *func_type, struct type *value_type) { struct gdbarch *gdbarch = get_regcache_arch (stop_registers); - struct cleanup *old_chain; - struct ui_stream *stb; struct value *value; CHECK_TYPEDEF (value_type); @@ -1415,6 +1413,18 @@ print_return_value (struct type *func_type, struct type *value_type) internal_error (__FILE__, __LINE__, _("bad switch")); } + return value; +} + +/* Print the result of a function at the end of a 'finish' command. */ + +static void +print_return_value (struct type *func_type, struct type *value_type) +{ + struct value *value = get_return_value(func_type, value_type); + struct cleanup *old_chain; + struct ui_stream *stb; + if (value) { struct value_print_options opts; diff --git a/gdb/inferior.h b/gdb/inferior.h index f8adb6c..b8d5b13 100644 --- a/gdb/inferior.h +++ b/gdb/inferior.h @@ -285,6 +285,9 @@ extern void detach_command (char *, int); extern void notice_new_inferior (ptid_t, int, int); +extern struct value *get_return_value (struct type *func_type, + struct type *value_type); + /* Address at which inferior stopped. */ extern CORE_ADDR stop_pc; diff --git a/gdb/infrun.c b/gdb/infrun.c index 2d6d523..3cf1cd5 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -54,6 +54,7 @@ #include "inline-frame.h" #include "jit.h" #include "tracepoint.h" +#include "python/python.h" /* Prototypes for local functions */ @@ -5826,7 +5827,8 @@ normal_stop (void) /* Save the function value return registers, if we care. We might be about to restore their previous contents. */ - if (inferior_thread ()->control.proceed_to_finish) + if (gdbpy_is_stopped_at_finish_bp (inferior_thread ()->control.stop_bpstat) + || inferior_thread ()->control.proceed_to_finish) { /* This should not be necessary. */ if (stop_registers) diff --git a/gdb/python/py-breakpoint.c b/gdb/python/py-breakpoint.c index 9c33848..f9a3a8f 100644 --- a/gdb/python/py-breakpoint.c +++ b/gdb/python/py-breakpoint.c @@ -31,52 +31,18 @@ #include "arch-utils.h" #include "language.h" -static PyTypeObject breakpoint_object_type; +PyTypeObject breakpoint_object_type; /* 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; +breakpoint_object *bppy_pending_object; /* Function that is called when a Python condition is evaluated. */ static char * const stop_func = "stop"; -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; -}; - -/* Require that BREAKPOINT be a valid breakpoint ID; throw a Python - exception if it is invalid. */ -#define BPPY_REQUIRE_VALID(Breakpoint) \ - do { \ - if ((Breakpoint)->bp == NULL) \ - return PyErr_Format (PyExc_RuntimeError, \ - _("Breakpoint %d is invalid."), \ - (Breakpoint)->number); \ - } while (0) - -/* Require that BREAKPOINT be a valid breakpoint ID; throw a Python - exception if it is invalid. This macro is for use in setter functions. */ -#define BPPY_SET_REQUIRE_VALID(Breakpoint) \ - do { \ - if ((Breakpoint)->bp == NULL) \ - { \ - PyErr_Format (PyExc_RuntimeError, _("Breakpoint %d is invalid."), \ - (Breakpoint)->number); \ - return -1; \ - } \ - } while (0) - /* This is used to initialize various gdb.bp_* constants. */ struct pybp_code { @@ -971,7 +937,7 @@ static PyMethodDef breakpoint_object_methods[] = { NULL } /* Sentinel. */ }; -static PyTypeObject breakpoint_object_type = +PyTypeObject breakpoint_object_type = { PyObject_HEAD_INIT (NULL) 0, /*ob_size*/ diff --git a/gdb/python/py-finishbreakpoint.c b/gdb/python/py-finishbreakpoint.c new file mode 100644 index 0000000..f69928e --- /dev/null +++ b/gdb/python/py-finishbreakpoint.c @@ -0,0 +1,447 @@ +/* Python interface to finish breakpoints + + Copyright (C) 2011 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 "exceptions.h" +#include "python-internal.h" +#include "breakpoint.h" +#include "frame.h" +#include "gdbthread.h" +#include "arch-utils.h" +#include "language.h" +#include "observer.h" +#include "inferior.h" + +static PyTypeObject finish_breakpoint_object_type; + +/* Function that is called when a Python finish bp is found out of scope. */ +static char * const outofscope_func = "out_of_scope"; + +/* struct implementing the gdb.FinishBreakpoint object by extending + the gdb.Breakpoint class. */ +struct finish_breakpoint_object +{ + /* gdb.Breakpoint base class. */ + struct breakpoint_object py_bp; + /* Flag indicating that the BP is out of the callstack and Python callback + has been triggered. */ + int out_of_scope_notif; + /* The function finished by this breakpoint. */ + struct symbol *function; +}; + +/* Python function to set the 'out_of_scope_notif' attribute of + FinishBreakpoint. */ + +static int +bpfinishpy_set_outofscope_notif (PyObject *self, PyObject *newvalue, + void *closure) +{ + struct finish_breakpoint_object *self_finishbp = + (struct finish_breakpoint_object *) self; + int cmp; + + BPPY_SET_REQUIRE_VALID (&self_finishbp->py_bp); + + if (newvalue == NULL) + { + PyErr_SetString (PyExc_TypeError, + _("Cannot delete `out_of_scope_notif' attribute.")); + return -1; + } + else if (!PyBool_Check (newvalue)) + { + PyErr_SetString (PyExc_TypeError, + _("The value of `out_of_scope_notif' must be a boolean.")); + return -1; + } + + cmp = PyObject_IsTrue (newvalue); + if (cmp < 0) + return -1; + else + self_finishbp->out_of_scope_notif = cmp; + + return 0; +} + +/* Python function to update and get the 'out_of_scope_notif' + attribute of FinishBreakpoint. */ + +static PyObject * +bpfinishpy_get_outofscope_notif (PyObject *self, void *closure) +{ + struct finish_breakpoint_object *self_finishbp = + (struct finish_breakpoint_object *) self; + + BPPY_REQUIRE_VALID (&self_finishbp->py_bp); + + if (self_finishbp->out_of_scope_notif) + Py_RETURN_TRUE; + Py_RETURN_FALSE; +} + +/* Python function to get the 'return_value' attribute of + FinishBreakpoint. */ + +static PyObject * +bpfinishpy_get_returnvalue (PyObject *self, void *closure) +{ + struct finish_breakpoint_object *self_finishbp = + (struct finish_breakpoint_object *) self; + + BPPY_REQUIRE_VALID (&self_finishbp->py_bp); + + if (self_finishbp->function == NULL) + goto return_none; + + /* Ensure that GDB is stopped at this FinishBreakpoint. */ + if (inferior_thread ()->control.stop_bpstat != NULL) + { + bpstat bs; + + for(bs = inferior_thread ()->control.stop_bpstat; + bs; bs = bs->next) + { + struct breakpoint *bp = bs->breakpoint_at; + if (bp != NULL + && (PyObject *) bp->py_bp_object == self) + { + struct type *v_type; + + v_type = TYPE_TARGET_TYPE (SYMBOL_TYPE + (self_finishbp->function)); + if (!v_type) + internal_error (__FILE__, __LINE__, + _("bpfinishpy_get_returnvalue: function has no target type")); + + if (TYPE_CODE (v_type) != TYPE_CODE_VOID) + { + struct value *ret = get_return_value + (SYMBOL_TYPE (self_finishbp->function), v_type); + PyObject *return_value = value_to_value_object (ret); + + Py_INCREF (return_value); + return return_value; + } + else + goto return_none; + } + } + } + +return_none: + Py_RETURN_NONE; +} + +/* Called when GDB notices that the finish breakpoint BP_OBJ is out of + the current callstack. If BP_OBJ has the attribute OUT_OF_SCOPE_NOTIF + and its value is FALSE, trigger the method OUT_OF_SCOPE and set the flag + to TRUE. */ + +static void +gdbpy_out_of_scope (struct finish_breakpoint_object *bpfinish_obj) +{ + breakpoint_object *bp_obj = (breakpoint_object *) bpfinish_obj; + PyObject *py_obj = (PyObject *) bp_obj ; + + bpfinish_obj->out_of_scope_notif = 0; + + if (PyObject_HasAttrString (py_obj, outofscope_func)) + { + struct gdbarch *garch = bp_obj->bp->gdbarch ? + bp_obj->bp->gdbarch : get_current_arch (); + struct cleanup *cleanup = ensure_python_env (garch, current_language); + + if (!PyObject_CallMethod (py_obj, outofscope_func, NULL)) + gdbpy_print_stack (); + + do_cleanups (cleanup); + } +} + +/* Python function to check if the FinishBreakpoint SELF is not anymore + in the callstack. Triggers self->out_of_scope */ +static PyObject * +bpfinishpy_check_scope (PyObject *self, PyObject *args) +{ + struct finish_breakpoint_object *self_finishbp = + (struct finish_breakpoint_object *) self; + + if (self_finishbp->out_of_scope_notif + && frame_find_by_id(self_finishbp->py_bp.bp->frame_id) == NULL) + { + gdbpy_out_of_scope (self_finishbp); + + Py_RETURN_TRUE; + } + Py_RETURN_FALSE; +} + +/* Python function to create a new breakpoint. */ + +static int +bpfinishpy_init (PyObject *self, PyObject *args, PyObject *kwargs) +{ + static char *keywords[] = { "frame", "internal", NULL }; + breakpoint_object *self_bp = (breakpoint_object *) self; + struct finish_breakpoint_object *self_bpfinish = + (struct finish_breakpoint_object *) self; + int type = bp_breakpoint; + PyObject *frame_obj = NULL; + struct frame_info *frame, *prev_frame; + struct frame_id frame_id; + struct symtabs_and_lines sals; + struct symtab_and_line sal; + PyObject *internal = NULL; + int internal_bp = 0; + CORE_ADDR pc ; + volatile struct gdb_exception except; + + if (! PyArg_ParseTupleAndKeywords (args, kwargs, "O|O", keywords, + &frame_obj, &internal)) + return -1; + + if (!frame_obj) + goto invalid_frame; + + frame = frame_object_to_frame_info (frame_obj); + if (frame == NULL) + goto invalid_frame; + + prev_frame = get_prev_frame(frame); + if (prev_frame == 0) + { + PyErr_SetString (PyExc_ValueError, + _("\"FinishBreakpoint\" not meaningful in the outermost frame.")); + return -1; + } + + frame_id = get_frame_id (prev_frame); + if (frame_id_eq(frame_id, null_frame_id)) + goto invalid_frame; + + pc = get_frame_pc (prev_frame); + + sal = find_pc_line (pc, 0); + sal.pc = pc; + sals.sals = &sal; + sals.nelts = 1; + + /* Find the function we will return from. */ + self_bpfinish->function = find_pc_function (get_frame_pc (frame)); + + if (internal) + { + internal_bp = PyObject_IsTrue (internal); + if (internal_bp == -1) + { + PyErr_SetString (PyExc_ValueError, + _("The value of `internal' must be a boolean.")); + return -1; + } + } + + bppy_pending_object = self_bp; + bppy_pending_object->number = -1; + bppy_pending_object->bp = NULL; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + create_breakpoint_sal (python_gdbarch, sals, NULL, NULL, + bp_breakpoint, disp_donttouch, -1, + 0, 0, NULL, 0, 1, internal_bp, 0) ; + } + if (except.reason < 0) + { + PyErr_Format (except.reason == RETURN_QUIT + ? PyExc_KeyboardInterrupt : PyExc_RuntimeError, + "%s", except.message); + return -1; + } + BPPY_SET_REQUIRE_VALID (self_bp); + + self_bp->bp->frame_id = frame_id; + + self_bpfinish->out_of_scope_notif = 1; + + return 0; + +invalid_frame: + PyErr_SetString (PyExc_ValueError, + _("Invalid ID for the `frame' object.")); + return -1; +} + +/* Returns 1 if OBJ is not NULL and references a FinishBreakpoint object. */ + +static int +bpfinishpy_is_finish_bp (PyObject *obj) +{ + return obj != NULL + && PyObject_TypeCheck (obj, &finish_breakpoint_object_type) ; +} + +/* Returns 1 if STOP_BPSTAT contains a FinishBreakpoint, 0 if not. */ + +int +gdbpy_is_stopped_at_finish_bp (bpstat stop_bpstat) +{ + bpstat bs; + + for (bs = stop_bpstat; bs; bs = bs->next) + { + if (bs->breakpoint_at + && bpfinishpy_is_finish_bp((PyObject *) + bs->breakpoint_at->py_bp_object)) + return 1; + } + + return 0; +} + +/* Callback for `bpfinishpy_detect_out_scope'. Triggers Python's + `B->out_of_scope' function if B is a FinishBreakpoint out of its + scope or turn of out_of_scope notification if B has been hit. */ + +static int +bpfinishpy_detect_out_scope_cb (struct breakpoint *b, void *args) +{ + struct breakpoint *bp_stopped = (struct breakpoint *) args; + PyObject *py_bp = (PyObject *) b->py_bp_object; + struct gdbarch *garch = b->gdbarch ? b->gdbarch : get_current_arch (); + struct cleanup *cleanup = ensure_python_env (garch, current_language); + + /* Trigger out_of_scope if this is a FinishBreakpoint its frame is not in the + current callstack and the notification has not been sent yet. */ + if (bpfinishpy_is_finish_bp (py_bp)) + { + struct finish_breakpoint_object *finish_bp = + (struct finish_breakpoint_object *) py_bp; + + if (b == bp_stopped) + finish_bp->out_of_scope_notif = 0; + else if (frame_find_by_id(b->frame_id) == NULL + && finish_bp->out_of_scope_notif) + { + gdbpy_out_of_scope (finish_bp); + } + } + + do_cleanups (cleanup); + + return 0; +} + +/* Attached to `stop' notifications, check if the execution has run out + out of the scope of any FinishBreakpoint before it has been hit. */ + +static void +bpfinishpy_handle_stop (struct bpstats *bs, int print_frame) +{ + iterate_over_breakpoints (bpfinishpy_detect_out_scope_cb, + bs == NULL ? NULL : bs->breakpoint_at); +} + +/* Attached to `exit' notifications, triggers all the necessary out of + scope notifications. */ + +static void +bpfinishpy_handle_exit (struct inferior *inf) +{ + iterate_over_breakpoints (bpfinishpy_detect_out_scope_cb, NULL); +} + +/* Initialize the Python finish breakpoint code. */ + +void +gdbpy_initialize_finishbreakpoints (void) +{ + if (PyType_Ready (&finish_breakpoint_object_type) < 0) + return; + + Py_INCREF (&finish_breakpoint_object_type); + PyModule_AddObject (gdb_module, "FinishBreakpoint", + (PyObject *) &finish_breakpoint_object_type); + + observer_attach_normal_stop (bpfinishpy_handle_stop); + observer_attach_inferior_exit(bpfinishpy_handle_exit); +} + +static PyMethodDef finish_breakpoint_object_methods[] = { + { "check_scope", bpfinishpy_check_scope, METH_NOARGS, + "check_scope () -> Boolean.\n\ +Return true if out_of_scope() has been triggered, false if not." }, + {NULL} /* Sentinel */ +}; + +static PyGetSetDef finish_breakpoint_object_getset[] = { + { "out_of_scope_notif", bpfinishpy_get_outofscope_notif, bpfinishpy_set_outofscope_notif, + "Boolean telling whether the breakpoint is still within the scope \ +of the current callstack.", NULL }, + { "return_value", bpfinishpy_get_returnvalue, NULL, + "gdb.Value object representing the return value, if any. \ +None otherwise.", NULL }, + { NULL } /* Sentinel. */ +}; + +static PyTypeObject finish_breakpoint_object_type = +{ + PyObject_HEAD_INIT (NULL) + 0, /*ob_size*/ + "gdb.FinishBreakpoint", /*tp_name*/ + sizeof (struct finish_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 | Py_TPFLAGS_BASETYPE, /*tp_flags*/ + "GDB finish breakpoint object", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + finish_breakpoint_object_methods, /* tp_methods */ + 0, /* tp_members */ + finish_breakpoint_object_getset,/* tp_getset */ + &breakpoint_object_type, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + bpfinishpy_init, /* tp_init */ + 0, /* tp_alloc */ + 0 /* tp_new */ +}; diff --git a/gdb/python/py-frame.c b/gdb/python/py-frame.c index d7128a9..2109c73 100644 --- a/gdb/python/py-frame.c +++ b/gdb/python/py-frame.c @@ -60,9 +60,10 @@ static PyTypeObject frame_object_type; object. If the frame doesn't exist anymore (the frame id doesn't correspond to any frame in the inferior), returns NULL. */ -static struct frame_info * -frame_object_to_frame_info (frame_object *frame_obj) +struct frame_info * +frame_object_to_frame_info (PyObject *obj) { + frame_object *frame_obj = (frame_object *) obj; struct frame_info *frame; frame = frame_find_by_id (frame_obj->frame_id); @@ -103,7 +104,7 @@ frapy_is_valid (PyObject *self, PyObject *args) { struct frame_info *frame; - frame = frame_object_to_frame_info ((frame_object *) self); + frame = frame_object_to_frame_info (self); if (frame == NULL) Py_RETURN_FALSE; @@ -124,7 +125,7 @@ frapy_name (PyObject *self, PyObject *args) TRY_CATCH (except, RETURN_MASK_ALL) { - FRAPY_REQUIRE_VALID ((frame_object *) self, frame); + FRAPY_REQUIRE_VALID (self, frame); find_frame_funname (frame, &name, &lang, NULL); } @@ -153,7 +154,7 @@ frapy_type (PyObject *self, PyObject *args) TRY_CATCH (except, RETURN_MASK_ALL) { - FRAPY_REQUIRE_VALID ((frame_object *) self, frame); + FRAPY_REQUIRE_VALID (self, frame); type = get_frame_type (frame); } @@ -174,7 +175,7 @@ frapy_unwind_stop_reason (PyObject *self, PyObject *args) TRY_CATCH (except, RETURN_MASK_ALL) { - FRAPY_REQUIRE_VALID ((frame_object *) self, frame); + FRAPY_REQUIRE_VALID (self, frame); } GDB_PY_HANDLE_EXCEPTION (except); @@ -195,7 +196,7 @@ frapy_pc (PyObject *self, PyObject *args) TRY_CATCH (except, RETURN_MASK_ALL) { - FRAPY_REQUIRE_VALID ((frame_object *) self, frame); + FRAPY_REQUIRE_VALID (self, frame); pc = get_frame_pc (frame); } @@ -216,7 +217,7 @@ frapy_block (PyObject *self, PyObject *args) TRY_CATCH (except, RETURN_MASK_ALL) { - FRAPY_REQUIRE_VALID ((frame_object *) self, frame); + FRAPY_REQUIRE_VALID (self, frame); block = get_frame_block (frame, NULL); } GDB_PY_HANDLE_EXCEPTION (except); @@ -257,7 +258,7 @@ frapy_function (PyObject *self, PyObject *args) TRY_CATCH (except, RETURN_MASK_ALL) { - FRAPY_REQUIRE_VALID ((frame_object *) self, frame); + FRAPY_REQUIRE_VALID (self, frame); sym = find_pc_function (get_frame_address_in_block (frame)); } @@ -319,7 +320,7 @@ frapy_older (PyObject *self, PyObject *args) TRY_CATCH (except, RETURN_MASK_ALL) { - FRAPY_REQUIRE_VALID ((frame_object *) self, frame); + FRAPY_REQUIRE_VALID (self, frame); prev = get_prev_frame (frame); if (prev) @@ -348,7 +349,7 @@ frapy_newer (PyObject *self, PyObject *args) TRY_CATCH (except, RETURN_MASK_ALL) { - FRAPY_REQUIRE_VALID ((frame_object *) self, frame); + FRAPY_REQUIRE_VALID (self, frame); next = get_next_frame (frame); if (next) @@ -377,7 +378,7 @@ frapy_find_sal (PyObject *self, PyObject *args) TRY_CATCH (except, RETURN_MASK_ALL) { - FRAPY_REQUIRE_VALID ((frame_object *) self, frame); + FRAPY_REQUIRE_VALID (self, frame); find_frame_sal (frame, &sal); sal_obj = symtab_and_line_to_sal_object (sal); @@ -433,7 +434,7 @@ frapy_read_var (PyObject *self, PyObject *args) TRY_CATCH (except, RETURN_MASK_ALL) { - FRAPY_REQUIRE_VALID ((frame_object *) self, frame); + FRAPY_REQUIRE_VALID (self, frame); if (!block) block = get_frame_block (frame, NULL); @@ -461,7 +462,7 @@ frapy_read_var (PyObject *self, PyObject *args) TRY_CATCH (except, RETURN_MASK_ALL) { - FRAPY_REQUIRE_VALID ((frame_object *) self, frame); + FRAPY_REQUIRE_VALID (self, frame); val = read_var_value (var, frame); } @@ -484,12 +485,11 @@ static PyObject * frapy_select (PyObject *self, PyObject *args) { struct frame_info *fi; - frame_object *frame = (frame_object *) self; volatile struct gdb_exception except; TRY_CATCH (except, RETURN_MASK_ALL) { - FRAPY_REQUIRE_VALID (frame, fi); + FRAPY_REQUIRE_VALID (self, fi); select_frame (fi); } diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h index d3cb788..31ec1b8 100644 --- a/gdb/python/python-internal.h +++ b/gdb/python/python-internal.h @@ -114,9 +114,47 @@ extern PyTypeObject symbol_object_type; extern PyTypeObject event_object_type; extern PyTypeObject events_object_type; extern PyTypeObject stop_event_object_type; +extern PyTypeObject breakpoint_object_type; + +typedef 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; +} breakpoint_object; + +/* Require that BREAKPOINT be a valid breakpoint ID; throw a Python + exception if it is invalid. */ +#define BPPY_REQUIRE_VALID(Breakpoint) \ + do { \ + if ((Breakpoint)->bp == NULL) \ + return PyErr_Format (PyExc_RuntimeError, \ + _("Breakpoint %d is invalid."), \ + (Breakpoint)->number); \ + } while (0) + +/* Require that BREAKPOINT be a valid breakpoint ID; throw a Python + exception if it is invalid. This macro is for use in setter functions. */ +#define BPPY_SET_REQUIRE_VALID(Breakpoint) \ + do { \ + if ((Breakpoint)->bp == NULL) \ + { \ + PyErr_Format (PyExc_RuntimeError, _("Breakpoint %d is invalid."), \ + (Breakpoint)->number); \ + return -1; \ + } \ + } while (0) + + +/* Variables used to pass information between the Breakpoint + constructor and the breakpoint-created hook function. */ +extern breakpoint_object *bppy_pending_object; -/* Defined in py-breakpoint.c */ -typedef struct breakpoint_object breakpoint_object; typedef struct { @@ -161,6 +199,7 @@ PyObject *block_to_block_object (struct block *block, struct objfile *objfile); PyObject *value_to_value_object (struct value *v); PyObject *type_to_type_object (struct type *); PyObject *frame_info_to_frame_object (struct frame_info *frame); +struct frame_info *frame_object_to_frame_info (PyObject *frame_obj); PyObject *pspace_to_pspace_object (struct program_space *); PyObject *pspy_get_printers (PyObject *, void *); @@ -194,6 +233,7 @@ void gdbpy_initialize_functions (void); void gdbpy_initialize_pspace (void); void gdbpy_initialize_objfile (void); void gdbpy_initialize_breakpoints (void); +void gdbpy_initialize_finishbreakpoints (void); void gdbpy_initialize_lazy_string (void); void gdbpy_initialize_parameters (void); void gdbpy_initialize_thread (void); diff --git a/gdb/python/python.c b/gdb/python/python.c index 8a7bc66..97007b3 100644 --- a/gdb/python/python.c +++ b/gdb/python/python.c @@ -926,6 +926,11 @@ gdbpy_breakpoint_has_py_cond (struct breakpoint_object *bp_obj) "scripting is not supported.")); } +int +gdbpy_is_stopped_at_finish_bp (bpstat stop_bpstat) +{ + return 0; +} #endif /* HAVE_PYTHON */ @@ -1060,6 +1065,7 @@ Enables or disables printing of Python stack traces."), gdbpy_initialize_pspace (); gdbpy_initialize_objfile (); gdbpy_initialize_breakpoints (); + gdbpy_initialize_finishbreakpoints (); gdbpy_initialize_lazy_string (); gdbpy_initialize_thread (); gdbpy_initialize_inferior (); diff --git a/gdb/python/python.h b/gdb/python/python.h index ce0eb35..aa2d096 100644 --- a/gdb/python/python.h +++ b/gdb/python/python.h @@ -21,6 +21,7 @@ #define GDB_PYTHON_H #include "value.h" +#include "breakpoint.h" struct breakpoint_object; @@ -47,4 +48,5 @@ int gdbpy_should_stop (struct breakpoint_object *bp_obj); int gdbpy_breakpoint_has_py_cond (struct breakpoint_object *bp_obj); +int gdbpy_is_stopped_at_finish_bp (bpstat stop_bpstat); #endif /* GDB_PYTHON_H */ diff --git a/gdb/testsuite/gdb.python/py-breakpoint.exp b/gdb/testsuite/gdb.python/py-breakpoint.exp index f0a83f1..8755888 100644 --- a/gdb/testsuite/gdb.python/py-breakpoint.exp +++ b/gdb/testsuite/gdb.python/py-breakpoint.exp @@ -44,7 +44,8 @@ gdb_py_test_silent_cmd "python blist = gdb.breakpoints()" "Get Breakpoint List" gdb_test "python print blist\[0\]" "" "Check obj exists" gdb_test "python print blist\[0\].location" "main." "Check breakpoint location" -gdb_breakpoint [gdb_get_line_number "Break at multiply."] +set mult_line [gdb_get_line_number "Break at multiply."] +gdb_breakpoint ${mult_line} gdb_continue_to_breakpoint "Break at multiply." # Check that the Python breakpoint code noted the addition of a @@ -54,7 +55,9 @@ gdb_test "python print len(blist)" "2" "Check for two breakpoints" gdb_test "python print blist\[0\]" "" "Check obj exists" gdb_test "python print blist\[0\].location" "main." "Check breakpoint location" gdb_test "python print blist\[1\]" "" "Check obj exists" -gdb_test "python print blist\[1\].location" "py-breakpoint\.c:41*" "Check breakpoint location" + +gdb_test "python print blist\[1\].location" "py-breakpoint\.c:${mult_line}*" \ + "Check breakpoint location" # Check hit and ignore counts. gdb_test "python print blist\[1\].hit_count" "1" "Check breakpoint hit count" diff --git a/gdb/testsuite/gdb.python/py-finish-breakpoint-cc.cc b/gdb/testsuite/gdb.python/py-finish-breakpoint-cc.cc new file mode 100644 index 0000000..a0eea06 --- /dev/null +++ b/gdb/testsuite/gdb.python/py-finish-breakpoint-cc.cc @@ -0,0 +1,59 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2011 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + + +#include + +void +throw_exception_1 (int e) +{ + throw new int (e); +} + +void +throw_exception (int e) +{ + throw_exception_1 (e); +} + +int +main (void) +{ + int i; + try + { + throw_exception_1 (10); + } + catch (const int *e) + { + std::cerr << "Exception #" << *e << std::endl; + } + i += 1; /* Break after exception 1. */ + + try + { + throw_exception (10); + } + catch (const int *e) + { + std::cerr << "Exception #" << *e << std::endl; + } + i += 1; /* Break after exception 2. */ + + return i; +} diff --git a/gdb/testsuite/gdb.python/py-finish-breakpoint-cc.exp b/gdb/testsuite/gdb.python/py-finish-breakpoint-cc.exp new file mode 100644 index 0000000..e74023d --- /dev/null +++ b/gdb/testsuite/gdb.python/py-finish-breakpoint-cc.exp @@ -0,0 +1,59 @@ +# Copyright (C) 2011 Free Software Foundation, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# This file is part of the GDB testsuite. It tests the mechanism +# exposing values to Python. + +if $tracelevel then { + strace $tracelevel +} + +load_lib gdb-python.exp + +set testfile "py-finish-breakpoint-cc" +set srcfile ${testfile}.cc +set binfile ${objdir}/${subdir}/${testfile} +set pyfile ${srcdir}/${subdir}/${testfile}.py + +# Start with a fresh gdb. +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug c++}] != "" } { + untested "Couldn't compile ${srcfile}" + return -1 +} + +if ![runto_main] then { + fail "Cannot run to main." + return 0 +} + +gdb_test "source $pyfile" ".*Python script imported.*" \ + "import python scripts" + +gdb_test "break [gdb_get_line_number "Break after exception 1."]" "Breakpoint.* at .*" \ + "set watchdog after the exception 1" +gdb_test "break [gdb_get_line_number "Break after exception 2."]" "Breakpoint.* at .*" \ + "set watchdog after the exception 2" + +gdb_test "python ExceptionBreakpoint()" "ExceptionBreakpoint init" "set BP before throwing the exception" +gdb_test "python print len(gdb.breakpoints())" "4" "check number of BPs" +gdb_test "continue" ".*stopped at ExceptionFinishBreakpoint.*" "check FinishBreakpoint in catch()" +gdb_test "python print len(gdb.breakpoints())" "4" "check finish BP removal" + +gdb_test "continue" ".*exception did not finish.*" "FinishBreakpoint with exception thrown not caught" diff --git a/gdb/testsuite/gdb.python/py-finish-breakpoint-cc.py b/gdb/testsuite/gdb.python/py-finish-breakpoint-cc.py new file mode 100644 index 0000000..d0dfe2f --- /dev/null +++ b/gdb/testsuite/gdb.python/py-finish-breakpoint-cc.py @@ -0,0 +1,43 @@ +# Copyright (C) 2011 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# This file is part of the GDB testsuite. It tests python Finish +# Breakpoints. + +class ExceptionBreakpoint(gdb.Breakpoint): + def __init__(self): + gdb.Breakpoint.__init__(self, spec="throw_exception_1", internal=1) + self.silent = True + print "ExceptionBreakpoint init" + + def stop(self): + ExceptionFinishBreakpoint(gdb.newest_frame()) + return False + +class ExceptionFinishBreakpoint(gdb.FinishBreakpoint): + def __init__(self, frame): + gdb.FinishBreakpoint.__init__(self, frame, internal=1) + self.silent = True; + + def stop(self): + print "stopped at ExceptionFinishBreakpoint" + gdb.post_event(self.delete) + return True + + def out_of_scope(self): + print "exception did not finish ..." + + +print "Python script imported" diff --git a/gdb/testsuite/gdb.python/py-finish-breakpoint.c b/gdb/testsuite/gdb.python/py-finish-breakpoint.c new file mode 100644 index 0000000..32b8b38 --- /dev/null +++ b/gdb/testsuite/gdb.python/py-finish-breakpoint.c @@ -0,0 +1,82 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2011 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#include + +int increase_1(int *a) +{ + *a += 1; + return -5; +} + +void increase(int *a) +{ + increase_1(a); +} + +int +test_1(int i, int j) +{ + return i == j; +} + +int +test(int i, int j) +{ + return test_1(i, j); +} + +int +call_longjmp_1 (jmp_buf *buf) +{ + longjmp (*buf, 1); +} + +int +call_longjmp (jmp_buf *buf) +{ + call_longjmp_1 (buf); +} + + +int main (int argc, char *argv[]) +{ + jmp_buf env; + int foo = 5; + int bar = 42; + int i, j; + + i = 0 ; + /* Break at increase. */ + increase (&i) ; + increase (&i) ; + increase (&i) ; + + for (i = 0; i < 10; i++) + { + j += 1; /* Condition Break. */ + } + + if (setjmp (env) == 0) /* longjmp caught */ + { + call_longjmp (&env); + } + else + j += 1; /* after longjmp. */ + + return j; /* Break at end. */ +} diff --git a/gdb/testsuite/gdb.python/py-finish-breakpoint.exp b/gdb/testsuite/gdb.python/py-finish-breakpoint.exp new file mode 100644 index 0000000..65eebc9 --- /dev/null +++ b/gdb/testsuite/gdb.python/py-finish-breakpoint.exp @@ -0,0 +1,183 @@ +# Copyright (C) 2011 Free Software Foundation, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# This file is part of the GDB testsuite. It tests the mechanism +# exposing values to Python. + +if $tracelevel then { + strace $tracelevel +} + +load_lib gdb-python.exp + +set testfile "py-finish-breakpoint" +set srcfile ${testfile}.c + +if { [prepare_for_testing ${testfile}.exp ${testfile} ${srcfile}] } { + return -1 +} + +set remote_python_file [remote_download host ${srcdir}/${subdir}/${testfile}.py] + + +# Skip all tests if Python scripting is not enabled. +if { [skip_python_tests] } { continue } + +# +# Test FinishBreakpoint in function returned by longjmp +# + +clean_restart ${testfile} + +if ![runto call_longjmp_1] then { + perror "couldn't run to breakpoint call_longjmp" + continue +} + +gdb_test "source $remote_python_file" ".*Python script imported.*" \ + "import python scripts" + +gdb_test "python ljmpBP = LongjmpFinishBreakpoint(gdb.newest_frame())" \ + "LongjmpFinishBreakpoint init" \ + "set finish breakpoint" +gdb_test "break [gdb_get_line_number "after longjmp."]" "Breakpoint.* at .*" \ + "set BP after the jump" +gdb_test "continue" ".*Longjmp didn't finish.*" "check FinishBP out of scope notification" + +# +# Test FinishBreakpoint in BP condition evaluation +# (finish in dummy frame) +# + +clean_restart ${testfile} + +set cond_line [gdb_get_line_number "Condition Break."] +if ![runto_main] then { + fail "Cannot run to main." + return 0 +} + +gdb_test "source $remote_python_file" ".*Python script imported.*" \ + "import python scripts" + +gdb_test "break ${cond_line} if test_1(i,8)" ".*Breakpoint .* at .*" "set conditional BP" +gdb_test "python TestBreakpoint()" "TestBreakpoint init" "set BP in condition" + + +set msg "check FinishBreakpoint don't stop in GDB Dummy Frame" +gdb_test_multiple "continue" $msg { + -re ".*test don't stop 2.*test stop.*test don't stop 4.*" { + pass $msg + } + -re ".*test don't stop 2.*test stop.*$gdb_prompt" { + fail $msg + } +} + +gdb_test "print i" "8" "check stopped location" + +# +# Test FinishBreakpoint in BP condition evaluation +# (finish in normal frame) +# + +clean_restart ${testfile} + +gdb_test "source $remote_python_file" ".*Python script imported.*" \ + "import python scripts" + +if ![runto_main] then { + fail "Cannot run to main." + return 0 +} + +gdb_test "break ${cond_line} if test(i,8)" ".*Breakpoint .* at .*" "set conditional BP" +gdb_test "python TestBreakpoint()" "TestBreakpoint init" "set BP in condition" + +gdb_test "continue" ".*test don't stop 1.*test don't stop 2.*test stop.*Error in testing breakpoint condition.*The program being debugged stopped while in a function called from GDB.*" \ + "stop in condition function" + +setup_kfail "normal_stop_notification not triggered during condition evaluation" *-*-* +gdb_test "python print gdb.breakpoints()\[2\].out_of_scope_notif" ".*False.*" "check out_of_scope notification disabled" +gdb_test_no_output "python gdb.breakpoints()\[2\].out_of_scope_notif = False" "reestablish correct value" + +gdb_test "continue" "Continuing.*" "finish condition evaluation" +gdb_test "continue" "Breakpoint.*" "stop at conditional breakpoint" +gdb_test "print i" "8" "check stopped location" + +# +# Test FinishBreakpoint in normal conditions +# + +clean_restart ${testfile} + +if ![runto_main] then { + fail "Cannot run to main." + return 0 +} +gdb_test_no_output "set confirm off" "disable confirmation" +gdb_test "source $remote_python_file" ".*Python script imported.*" \ + "import python scripts" +gdb_test "python MyBreakpoint(\"increase_1\")" ".*Breakpoint 2.*" \ + "create Python function breakpoint" +gdb_test "continue" ".*Arrived at MyBreakpoint with 0.*" "check MyBreakpoint hit" + +# set FinishBreakpoint + +gdb_test "python finishbp = MyFinishBreakpoint (gdb.parse_and_eval (\"a\"), gdb.selected_frame ())" \ + ".*Breakpoint 3.*" "set FinishBreakpoint" +gdb_test "python print finishbp.out_of_scope_notif" ".*True.*" \ + "check out_of_scope_notif at init" +gdb_test "python print finishbp.return_value" ".*None.*" \ + "check return_value at init" + +# check normal bp hit + +gdb_test "continue" ".*MyFinishBreakpoint stop with.*#0.*increase.*" \ + "check MyFinishBreakpoint hit" +gdb_test "python print finishbp.return_value" ".*-5.*" "check return_value" +gdb_test "python print finishbp.out_of_scope_notif" ".*False.*" \ + "check out_of_scope_notif disabled after hit" +gdb_test "finish" ".*main.*" "return to main()" +gdb_test "python print finishbp.return_value" ".*None.*" "check return_value" + +# check forced return / check out of scpop +gdb_test_no_output "python finishbp.out_of_scope_notif = True" \ + "re-enable out_of_scope_notif" + +gdb_test "continue" ".*Arrived at MyBreakpoint with.*" "check MyBreakpoint second hit" +gdb_test "up" ".*increase_1.*" "go one frame up" +gdb_test_no_output "return" "return from the frame" +gdb_test "python print finishbp.check_scope()" ".*MyFinishBreakpoint out of scope.*True.*" \ + "go one frame up" + +# check forced return / automatic notification + +gdb_test_no_output "python finishbp.out_of_scope_notif = True" \ + "re-enable out_of_scope_notif" + +gdb_test "continue" ".*Arrived at MyBreakpoint with.*" "check MyBreakpoint third hit" +gdb_test "up" ".*increase_1.*" "go one frame up" +gdb_test_no_output "return" "return from the frame" +gdb_test "next" ".*MyFinishBreakpoint out of scope.*" "check Finish breakpoint discard" +gdb_test "python print finishbp.out_of_scope_notif" ".*False.*" "check out_of_scope_notif" + +# check FinishBreakpoint in main + +gdb_test "python MyFinishBreakpoint (None, gdb.selected_frame ())" \ + ".*ValueError: \"FinishBreakpoint\" not meaningful in the outermost frame..*" \ + "check FinishBP not allowed in main" + + diff --git a/gdb/testsuite/gdb.python/py-finish-breakpoint.py b/gdb/testsuite/gdb.python/py-finish-breakpoint.py new file mode 100644 index 0000000..f014cc6 --- /dev/null +++ b/gdb/testsuite/gdb.python/py-finish-breakpoint.py @@ -0,0 +1,85 @@ +# Copyright (C) 2011 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# This file is part of the GDB testsuite. It tests python Finish +# Breakpoints. + +class MyBreakpoint(gdb.Breakpoint): + def stop(self): + val = gdb.parse_and_eval ("a") + print "Arrived at MyBreakpoint with %d" % int(val.dereference()) + return True + +class MyFinishBreakpoint(gdb.FinishBreakpoint): + def __init__(self, val, frame): + super (MyFinishBreakpoint, self).__init__ (frame) + print "MyFinishBreakpoint init" + self.val = val + + def stop(self): + print "MyFinishBreakpoint stop with %d" % int(self.val.dereference()) + gdb.execute("where 1") + return True + + def out_of_scope(self): + print "MyFinishBreakpoint out of scope..." + +test_finish_bp = None +class TestBreakpoint(gdb.Breakpoint): + def __init__(self): + gdb.Breakpoint.__init__(self, spec="test_1", internal=1) + self.silent = True + self.finish = None + print "TestBreakpoint init" + + def stop(self): + global test_finish_bp + if (self.finish == None): + self.finish = TestFinishBreakpoint(gdb.newest_frame()) + test_finish_bp = self.finish + return False + + +class TestFinishBreakpoint(gdb.FinishBreakpoint): + def __init__(self, frame): + gdb.FinishBreakpoint.__init__(self, frame, internal=1) + self.count = 0 + + def stop(self): + self.count += 1 + if (self.count == 3): + print "test stop ..." + return True + else: + print "test don't stop %d" % self.count + return False + + + def out_of_scope(self): + print "test didn't finish ..." + +class LongjmpFinishBreakpoint(gdb.FinishBreakpoint): + def __init__(self, frame): + gdb.FinishBreakpoint.__init__(self, frame, internal=1) + print "LongjmpFinishBreakpoint init" + + def stop(self): + print "Stopped at LongjmpFinishBreakpoint" + + + def out_of_scope(self): + print "Longjmp didn't finish ..." + +print "Python script imported" -- 1.7.4.4