From: Kevin Pouget Date: Fri, 23 Dec 2011 17:55:23 +0000 (+0000) Subject: Introduce gdb.FinishBreakpoint in Python X-Git-Tag: gdb_7_4-2012-01-24-release~60 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e5d5cc0538930f956edc95282da72ebb20f803c2;p=thirdparty%2Fbinutils-gdb.git Introduce gdb.FinishBreakpoint in Python * Makefile.in (SUBDIR_PYTHON_OBS): Add py-finishbreakpoint.o. (SUBDIR_PYTHON_SRCS): Add python/py-finishbreakpoint.c. Add build rule for this file. * infcmd.c (print_return_value): Split to create get_return_value. (get_return_value): New function based on print_return_value. Handle case where stop_registers are not set. * inferior.h (get_return_value): New prototype. * python/py-breakpoint.c (bppy_pending_object): Make non-static. (gdbpy_breakpoint_created): Set is_py_finish_bp is necessary. (struct breakpoint_object): Move to python-internal.h (BPPY_REQUIRE_VALID): Likewise. (BPPY_SET_REQUIRE_VALID): Likewise. (gdbpy_breakpoint_created): Initialize is_finish_bp. (gdbpy_should_stop): Add pre/post hooks before/after calling stop method. * python/python-internal.h (breakpoint_object_type): Add as extern. (bppy_pending_object): Likewise. (typedef struct breakpoint_object) Removed. (struct breakpoint_object): Moved from py-breakpoint.c. Add field is_finish_bp. (BPPY_REQUIRE_VALID): Moved from py-breakpoint.c. (BPPY_SET_REQUIRE_VALID): Likewise. (frame_object_to_frame_info): New prototype. (gdbpy_initialize_finishbreakpoints): New prototype. (bpfinishpy_is_finish_bp): Likewise. (bpfinishpy_pre_stop_hook): Likewise. (bpfinishpy_post_stop_hook): Likewise. * python/py-finishbreakpoint.c: New file. * python/py-frame.c(frame_object_to_frame_info): Make non-static and accept PyObject instead of frame_object. (frapy_is_valid): Don't cast to frame_object. (frapy_name): Likewise. (frapy_type): Likewise. (frapy_unwind_stop_reason): Likewise. (frapy_pc): Likewise. (frapy_block): Likewise. (frapy_function): Likewise. (frapy_older): Likewise. (frapy_newer): Likewise. (frapy_find_sal): Likewise. (frapy_read_var): Likewise. (frapy_select): Likewise. * python/python.c (gdbpy_is_stopped_at_finish_bp): New noop function. (_initialize_python): Add gdbpy_initialize_finishbreakpoints. * python/python.h: Include breakpoint.h (gdbpy_is_stopped_at_finish_bp): New prototype. doc/ * gdb.texinfo (Finish Breakpoints in Python): New subsection. (Python API): Add menu entry for Finish Breakpoints. testsuite/ * Makefile.in (EXECUTABLES): Add py-finish-breakpoint and py-finish-breakpoint2 (MISCALLANEOUS): Add py-events-shlib.so and py-events-shlib-nodebug.so * gdb.python/py-breakpoint.exp (mult_line): Define and use variable instead of line number. * gdb.python/py-finish-breakpoint.c: New file. * gdb.python/py-finish-breakpoint.exp: New file. * gdb.python/py-finish-breakpoint.py: New file. * gdb.python/py-finish-breakpoint2.cc: New file. * gdb.python/py-finish-breakpoint2.exp: New file. * gdb.python/py-finish-breakpoint2.py: New file. --- diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 7fe23fef12a..16ec8e17e64 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,53 @@ +2011-12-23 Kevin Pouget + + Introduce gdb.FinishBreakpoint in Python + * Makefile.in (SUBDIR_PYTHON_OBS): Add py-finishbreakpoint.o. + (SUBDIR_PYTHON_SRCS): Add python/py-finishbreakpoint.c. + Add build rule for this file. + * infcmd.c (print_return_value): Split to create get_return_value. + (get_return_value): New function based on print_return_value. Handle + case where stop_registers are not set. + * inferior.h (get_return_value): New prototype. + * python/py-breakpoint.c (bppy_pending_object): Make non-static. + (gdbpy_breakpoint_created): Set is_py_finish_bp is necessary. + (struct breakpoint_object): Move to python-internal.h + (BPPY_REQUIRE_VALID): Likewise. + (BPPY_SET_REQUIRE_VALID): Likewise. + (gdbpy_breakpoint_created): Initialize is_finish_bp. + (gdbpy_should_stop): Add pre/post hooks before/after calling stop + method. + * python/python-internal.h (breakpoint_object_type): Add as extern. + (bppy_pending_object): Likewise. + (typedef struct breakpoint_object) Removed. + (struct breakpoint_object): Moved from py-breakpoint.c. + Add field is_finish_bp. + (BPPY_REQUIRE_VALID): Moved from py-breakpoint.c. + (BPPY_SET_REQUIRE_VALID): Likewise. + (frame_object_to_frame_info): New prototype. + (gdbpy_initialize_finishbreakpoints): New prototype. + (bpfinishpy_is_finish_bp): Likewise. + (bpfinishpy_pre_stop_hook): Likewise. + (bpfinishpy_post_stop_hook): Likewise. + * python/py-finishbreakpoint.c: New file. + * python/py-frame.c(frame_object_to_frame_info): Make non-static and + accept PyObject instead of frame_object. + (frapy_is_valid): Don't cast to frame_object. + (frapy_name): Likewise. + (frapy_type): Likewise. + (frapy_unwind_stop_reason): Likewise. + (frapy_pc): Likewise. + (frapy_block): Likewise. + (frapy_function): Likewise. + (frapy_older): Likewise. + (frapy_newer): Likewise. + (frapy_find_sal): Likewise. + (frapy_read_var): Likewise. + (frapy_select): Likewise. + * python/python.c (gdbpy_is_stopped_at_finish_bp): New noop function. + (_initialize_python): Add gdbpy_initialize_finishbreakpoints. + * python/python.h: Include breakpoint.h + (gdbpy_is_stopped_at_finish_bp): New prototype. + 2011-12-22 Andreas Schwab * ppc-linux-nat.c (create_watchpoint_request): Only use ranged diff --git a/gdb/Makefile.in b/gdb/Makefile.in index b71db339d06..d8d1b40ec3b 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -287,6 +287,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 \ @@ -318,6 +319,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 \ @@ -2109,6 +2111,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/NEWS b/gdb/NEWS index 3aa67019893..58955df9d2c 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -58,6 +58,10 @@ ** The "gdb.breakpoint" function has been deprecated in favor of "gdb.breakpoints". + ** A new class "gdb.FinishBreakpoint" is provided to catch the return + of a function. This class is based on the "finish" command + available in the CLI. + ** Type objects for struct and union types now allow access to the fields using standard Python dictionary (mapping) methods. For example, "some_type['myfield']" now works, as does diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c index 783b797494b..172e4198b5b 100644 --- a/gdb/breakpoint.c +++ b/gdb/breakpoint.c @@ -7934,7 +7934,8 @@ create_breakpoint (struct gdbarch *gdbarch, b->disposition = tempflag ? disp_del : disp_donttouch; b->condition_not_parsed = 1; b->enable_state = enabled ? bp_enabled : bp_disabled; - if (type_wanted != bp_breakpoint && type_wanted != bp_hardware_breakpoint) + if ((type_wanted != bp_breakpoint + && type_wanted != bp_hardware_breakpoint) || thread != -1) b->pspace = current_program_space; install_breakpoint (internal, b, 0); diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h index ddf1881011d..d22e5646ff5 100644 --- a/gdb/breakpoint.h +++ b/gdb/breakpoint.h @@ -569,7 +569,7 @@ struct breakpoint /* The program space used to set the breakpoint. This is only set for breakpoints which are specific to a program space; for - ordinary breakpoints this is NULL. */ + non-thread-specific ordinary breakpoints this is NULL. */ struct program_space *pspace; /* String we used to set the breakpoint (malloc'd). */ diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog index 7465f4fba5a..9ef38a0fdd8 100644 --- a/gdb/doc/ChangeLog +++ b/gdb/doc/ChangeLog @@ -1,3 +1,9 @@ +2011-12-23 Kevin Pouget + + Introduce gdb.FinishBreakpoint in Python + * gdb.texinfo (Finish Breakpoints in Python): New subsection. + (Python API): Add menu entry for Finish Breakpoints. + 2011-12-16 Phil Muldoon * gdb.texinfo (Python Commands): Remove "maint set/show print diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index a7b1ebb4ddd..9589750b992 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -21497,6 +21497,8 @@ situation, a Python @code{KeyboardInterrupt} exception is thrown. * Symbol Tables In Python:: Python representation of symbol tables. * Lazy Strings In Python:: Python representation of lazy strings. * Breakpoints In Python:: Manipulating breakpoints using Python. +* Finish Breakpoints in Python:: Setting Breakpoints on function return + using Python. @end menu @node Basic Python @@ -24331,6 +24333,57 @@ commands, separated by newlines. If there are no commands, this attribute is @code{None}. This attribute is not writable. @end defvar +@node Finish Breakpoints in Python +@subsubsection Finish Breakpoints + +@cindex python finish breakpoints +@tindex gdb.FinishBreakpoint + +A finish breakpoint is a temporary breakpoint set at the return address of +a frame, based on the @code{finish} command. @code{gdb.FinishBreakpoint} +extends @code{gdb.Breakpoint}. The underlying breakpoint will be disabled +and deleted when the execution will run out of the breakpoint scope (i.e.@: +@code{Breakpoint.stop} or @code{FinishBreakpoint.out_of_scope} triggered). +Finish breakpoints are thread specific and must be create with the right +thread selected. + +@defun FinishBreakpoint.__init__ (@r{[}frame@r{]} @r{[}, internal@r{]}) +Create a finish breakpoint at the return address of the @code{gdb.Frame} +object @var{frame}. If @var{frame} is not provided, this defaults to the +newest frame. The optional @var{internal} argument allows the breakpoint to +become invisible to the user. @xref{Breakpoints In Python}, for further +details about this argument. +@end defun + +@defun FinishBreakpoint.out_of_scope (self) +In some circumstances (e.g.@: @code{longjmp}, C@t{++} exceptions, @value{GDBN} +@code{return} command, @dots{}), a function may not properly terminate, and +thus never hit the finish breakpoint. When @value{GDBN} notices such a +situation, the @code{out_of_scope} callback will be triggered. + +You may want to sub-class @code{gdb.FinishBreakpoint} and override this +method: + +@smallexample +class MyFinishBreakpoint (gdb.FinishBreakpoint) + def stop (self): + print "normal finish" + return True + + def out_of_scope (): + print "abnormal finish" +@end smallexample +@end defun + +@defvar FinishBreakpoint.return_value +When @value{GDBN} is stopped at a finish breakpoint and the frame +used to build the @code{gdb.FinishBreakpoint} object had debug symbols, this +attribute will contain a @code{gdb.Value} object corresponding to the return +value of the function. The value will be @code{None} if the function return +type is @code{void} or if the return value was not computable. This attribute +is not writable. +@end defvar + @node Lazy Strings In Python @subsubsection Python representation of lazy strings. diff --git a/gdb/infcmd.c b/gdb/infcmd.c index 5d94cd45c09..cffa194aaa1 100644 --- a/gdb/infcmd.c +++ b/gdb/infcmd.c @@ -1414,16 +1414,26 @@ 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. */ +/* Return the value of the result of a function 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 regcache *stop_regs = stop_registers; + struct gdbarch *gdbarch; struct value *value; struct ui_out *uiout = current_uiout; + struct cleanup *cleanup = make_cleanup (null_cleanup, NULL); + + /* If stop_registers were not saved, use the current registers. */ + if (!stop_regs) + { + stop_regs = regcache_dup (get_current_regcache ()); + cleanup = make_cleanup_regcache_xfree (stop_regs); + } + + gdbarch = get_regcache_arch (stop_regs); CHECK_TYPEDEF (value_type); gdb_assert (TYPE_CODE (value_type) != TYPE_CODE_VOID); @@ -1442,7 +1452,7 @@ print_return_value (struct type *func_type, struct type *value_type) case RETURN_VALUE_ABI_RETURNS_ADDRESS: case RETURN_VALUE_ABI_PRESERVES_ADDRESS: value = allocate_value (value_type); - gdbarch_return_value (gdbarch, func_type, value_type, stop_registers, + gdbarch_return_value (gdbarch, func_type, value_type, stop_regs, value_contents_raw (value), NULL); break; case RETURN_VALUE_STRUCT_CONVENTION: @@ -1452,6 +1462,21 @@ print_return_value (struct type *func_type, struct type *value_type) internal_error (__FILE__, __LINE__, _("bad switch")); } + do_cleanups (cleanup); + + 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; + struct ui_out *uiout = current_uiout; + if (value) { struct value_print_options opts; diff --git a/gdb/inferior.h b/gdb/inferior.h index cfaea7f0d00..f1986961954 100644 --- a/gdb/inferior.h +++ b/gdb/inferior.h @@ -269,6 +269,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/python/py-breakpoint.c b/gdb/python/py-breakpoint.c index 11d60fe09d6..64ef45fdac8 100644 --- a/gdb/python/py-breakpoint.c +++ b/gdb/python/py-breakpoint.c @@ -31,52 +31,16 @@ #include "arch-utils.h" #include "language.h" -static 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 { @@ -762,6 +726,9 @@ gdbpy_should_stop (struct breakpoint_object *bp_obj) struct gdbarch *garch = b->gdbarch ? b->gdbarch : get_current_arch (); struct cleanup *cleanup = ensure_python_env (garch, current_language); + if (bp_obj->is_finish_bp) + bpfinishpy_pre_stop_hook (bp_obj); + if (PyObject_HasAttrString (py_bp, stop_func)) { PyObject *result = PyObject_CallMethod (py_bp, stop_func, NULL); @@ -783,6 +750,10 @@ gdbpy_should_stop (struct breakpoint_object *bp_obj) else gdbpy_print_stack (); } + + if (bp_obj->is_finish_bp) + bpfinishpy_post_stop_hook (bp_obj); + do_cleanups (cleanup); return stop; @@ -845,6 +816,7 @@ gdbpy_breakpoint_created (struct breakpoint *bp) newbp->number = bp->number; newbp->bp = bp; newbp->bp->py_bp_object = newbp; + newbp->is_finish_bp = 0; Py_INCREF (newbp); ++bppy_live; } @@ -1006,7 +978,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-frame.c b/gdb/python/py-frame.c index 20064cab49d..c334f63d723 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); @@ -106,7 +107,7 @@ frapy_is_valid (PyObject *self, PyObject *args) TRY_CATCH (except, RETURN_MASK_ALL) { - frame = frame_object_to_frame_info ((frame_object *) self); + frame = frame_object_to_frame_info (self); } GDB_PY_HANDLE_EXCEPTION (except); @@ -130,7 +131,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); } @@ -159,7 +160,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); } @@ -180,7 +181,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); @@ -201,7 +202,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); } @@ -222,7 +223,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); @@ -263,7 +264,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)); } @@ -330,7 +331,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) @@ -359,7 +360,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) @@ -388,7 +389,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); @@ -444,7 +445,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); @@ -472,7 +473,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); } @@ -487,12 +488,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 ef39d5dfbe2..1ba71331fff 100644 --- a/gdb/python/python-internal.h +++ b/gdb/python/python-internal.h @@ -120,9 +120,50 @@ 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; + + /* 1 is this is a FinishBreakpoint object, 0 otherwise. */ + int is_finish_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 { @@ -188,6 +229,7 @@ struct value *convert_value_from_python (PyObject *obj); struct type *type_object_to_type (PyObject *obj); struct symtab *symtab_object_to_symtab (PyObject *obj); struct symtab_and_line *sal_object_to_symtab_and_line (PyObject *obj); +struct frame_info *frame_object_to_frame_info (PyObject *frame_obj); void gdbpy_initialize_auto_load (void); void gdbpy_initialize_values (void); @@ -202,6 +244,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); @@ -275,6 +318,9 @@ PyObject *gdbpy_get_varobj_pretty_printer (struct value *value); char *gdbpy_get_display_hint (PyObject *printer); PyObject *gdbpy_default_visualizer (PyObject *self, PyObject *args); +void bpfinishpy_pre_stop_hook (struct breakpoint_object *bp_obj); +void bpfinishpy_post_stop_hook (struct breakpoint_object *bp_obj); + extern PyObject *gdbpy_doc_cst; extern PyObject *gdbpy_children_cst; extern PyObject *gdbpy_to_string_cst; diff --git a/gdb/python/python.c b/gdb/python/python.c index 9b00cdc8d1b..13ac15e867e 100644 --- a/gdb/python/python.c +++ b/gdb/python/python.c @@ -1243,6 +1243,7 @@ message == an error message without a stack will be printed."), 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/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index f6252f03001..d23332d4036 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,18 @@ +2011-12-23 Kevin Pouget + + Introduce gdb.FinishBreakpoint in Python + * Makefile.in (EXECUTABLES): Add py-finish-breakpoint and + py-finish-breakpoint2 + (MISCALLANEOUS): Add py-events-shlib.so and py-events-shlib-nodebug.so + * gdb.python/py-breakpoint.exp (mult_line): Define and use variable + instead of line number. + * gdb.python/py-finish-breakpoint.c: New file. + * gdb.python/py-finish-breakpoint.exp: New file. + * gdb.python/py-finish-breakpoint.py: New file. + * gdb.python/py-finish-breakpoint2.cc: New file. + * gdb.python/py-finish-breakpoint2.exp: New file. + * gdb.python/py-finish-breakpoint2.py: New file. + 2011-12-21 Ulrich Weigand PR tdep/12797 diff --git a/gdb/testsuite/gdb.python/Makefile.in b/gdb/testsuite/gdb.python/Makefile.in index 9c98db9efcf..58901919082 100644 --- a/gdb/testsuite/gdb.python/Makefile.in +++ b/gdb/testsuite/gdb.python/Makefile.in @@ -4,9 +4,10 @@ srcdir = @srcdir@ EXECUTABLES = py-type py-value py-prettyprint py-template py-block \ py-symbol py-mi py-breakpoint py-inferior py-infthread \ py-shared python lib-types py-events py-evthreads py-frame \ - py-mi py-pp-maint py-progspace py-section-script py-objfile + py-mi py-pp-maint py-progspace py-section-script py-objfile \ + py-finish-breakpoint py-finish-breakpoint2 -MISCELLANEOUS = py-shared-sl.sl +MISCELLANEOUS = py-shared-sl.sl py-events-shlib.so py-events-shlib-nodebug.so all info install-info dvi install uninstall installcheck check: @echo "Nothing to be done for $@..." diff --git a/gdb/testsuite/gdb.python/py-breakpoint.exp b/gdb/testsuite/gdb.python/py-breakpoint.exp index e0dd08708e0..0e3adbd0502 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"