From: George Barrett Date: Wed, 9 Jun 2021 13:56:11 +0000 (+1000) Subject: Guile: temporary breakpoints X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=ad42014be254b402f7a44e578cc709fe9e30dc1d;p=binutils-gdb.git Guile: temporary breakpoints Adds API to the Guile bindings for creating temporary breakpoints and querying whether an existing breakpoint object is temporary. This is effectively a transliteration of the Python implementation. It's worth noting that the added `is_temporary' flag is ignored in the watchpoint registration path. This replicates the behaviour of the Python implementation, but might be a bit surprising for users. gdb/ChangeLog: 2021-06-09 George Barrett * guile/scm-breakpoint.c (gdbscm_breakpoint_object::spec): Add is_temporary field. (temporary_keyword): Add keyword object for make-breakpoint argument parsing. (gdbscm_make_breakpoint): Accept #:temporary keyword argument and store the value in the allocated object's spec.is_temporary. (gdbscm_register_breakpoint_x): Pass the breakpoint's spec.is_temporary value to create_breakpoint. (gdbscm_breakpoint_temporary): Add breakpoint-temporary? procedure implementation. (breakpoint_functions::make-breakpoint): Update documentation string and fix a typo. (breakpoint_functions::breakpoint-temporary?): Add breakpoint-temporary? procedure. (gdbscm_initialize_breakpoints): Initialise temporary_keyword variable. NEWS (Guile API): Mention new temporary breakpoints API. gdb/doc/ChangeLog: 2021-06-09 George Barrett * guile.texi (Breakpoints In Guile): Update make-breakpoint documentation to reflect new #:temporary argument. Add documentation for new breakpoint-temporary? procedure. gdb/testsuite/ChangeLog: 2021-06-09 George Barrett * gdb.guile/scm-breakpoint.exp: Add additional tests for temporary breakpoints. Change-Id: I2de332ee7c256f5591d7141ab3ad50d31b871d17 --- diff --git a/gdb/NEWS b/gdb/NEWS index 062249aea98..51b276c2cc1 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -267,6 +267,9 @@ QMemTags value-reference-value, value-rvalue-reference-value and value-const-value. + ** Temporary breakpoints can now be created with make-breakpoint and + tested for using breakpoint-temporary?. + * Python API ** Inferior objects now contain a read-only 'connection_num' attribute that diff --git a/gdb/doc/guile.texi b/gdb/doc/guile.texi index 36fc9a7af79..a2448dd62cb 100644 --- a/gdb/doc/guile.texi +++ b/gdb/doc/guile.texi @@ -2965,7 +2965,7 @@ The following breakpoint-related procedures are provided by the @code{(gdb)} module: @c TODO: line length -@deffn {Scheme Procedure} make-breakpoint location @r{[}#:type type@r{]} @r{[}#:wp-class wp-class@r{]} @r{[}#:internal internal@r{]} +@deffn {Scheme Procedure} make-breakpoint location @r{[}#:type type@r{]} @r{[}#:wp-class wp-class@r{]} @r{[}#:internal internal@r{]} @r{[}#:temporary temporary@r{]} Create a new breakpoint at @var{location}, a string naming the location of the breakpoint, or an expression that defines a watchpoint. The contents can be any location recognized by the @code{break} command, @@ -2991,6 +2991,11 @@ registered, nor will it be listed in the output from @code{info breakpoints} If an internal flag is not provided, the breakpoint is visible (non-internal). +The optional @var{temporary} argument makes the breakpoint a temporary +breakpoint. Temporary breakpoints are deleted after they have been hit, +after which the Guile breakpoint is no longer usable (although it may be +re-registered with @code{register-breakpoint!}). + When a watchpoint is created, @value{GDBN} will try to create a hardware assisted watchpoint. If successful, the type of the watchpoint is changed from @code{BP_WATCHPOINT} to @code{BP_HARDWARE_WATCHPOINT} @@ -3087,6 +3092,15 @@ Return the breakpoint's number --- the identifier used by the user to manipulate the breakpoint. @end deffn +@deffn {Scheme Procedure} breakpoint-temporary? breakpoint +Return @code{#t} if the breakpoint was created as a temporary +breakpoint. Temporary breakpoints are automatically deleted after +they've been hit. Calling this procedure, and all other procedures +other than @code{breakpoint-valid?} and @code{register-breakpoint!}, +will result in an error after the breakpoint has been hit (since it has +been automatically deleted). +@end deffn + @deffn {Scheme Procedure} breakpoint-type breakpoint Return the breakpoint's type --- the identifier used to determine the actual breakpoint type or use-case. diff --git a/gdb/guile/scm-breakpoint.c b/gdb/guile/scm-breakpoint.c index 3f25708afff..67484e440f5 100644 --- a/gdb/guile/scm-breakpoint.c +++ b/gdb/guile/scm-breakpoint.c @@ -69,6 +69,9 @@ typedef struct gdbscm_breakpoint_object /* Non-zero if the breakpoint is an "internal" breakpoint. */ int is_internal; + + /* Non-zero if the breakpoint is temporary. */ + int is_temporary; } spec; /* The breakpoint number according to gdb. @@ -103,6 +106,7 @@ static SCM pending_breakpoint_scm = SCM_BOOL_F; static SCM type_keyword; static SCM wp_class_keyword; static SCM internal_keyword; +static SCM temporary_keyword; /* Administrivia for breakpoint smobs. */ @@ -332,7 +336,7 @@ bpscm_get_valid_breakpoint_smob_arg_unsafe (SCM self, int arg_pos, /* Breakpoint methods. */ /* (make-breakpoint string [#:type integer] [#:wp-class integer] - [#:internal boolean) -> + [#:internal boolean] [#:temporary boolean]) -> The result is the Scheme object. The breakpoint is not available to be used yet, however. @@ -342,22 +346,26 @@ static SCM gdbscm_make_breakpoint (SCM location_scm, SCM rest) { const SCM keywords[] = { - type_keyword, wp_class_keyword, internal_keyword, SCM_BOOL_F + type_keyword, wp_class_keyword, internal_keyword, + temporary_keyword, SCM_BOOL_F }; char *s; char *location; - int type_arg_pos = -1, access_type_arg_pos = -1, internal_arg_pos = -1; + int type_arg_pos = -1, access_type_arg_pos = -1, + internal_arg_pos = -1, temporary_arg_pos = -1; enum bptype type = bp_breakpoint; enum target_hw_bp_type access_type = hw_write; int internal = 0; + int temporary = 0; SCM result; breakpoint_smob *bp_smob; - gdbscm_parse_function_args (FUNC_NAME, SCM_ARG1, keywords, "s#iit", + gdbscm_parse_function_args (FUNC_NAME, SCM_ARG1, keywords, "s#iitt", location_scm, &location, rest, &type_arg_pos, &type, &access_type_arg_pos, &access_type, - &internal_arg_pos, &internal); + &internal_arg_pos, &internal, + &temporary_arg_pos, &temporary); result = bpscm_make_breakpoint_smob (); bp_smob = (breakpoint_smob *) SCM_SMOB_DATA (result); @@ -412,6 +420,7 @@ gdbscm_make_breakpoint (SCM location_scm, SCM rest) bp_smob->spec.type = type; bp_smob->spec.access_type = access_type; bp_smob->spec.is_internal = internal; + bp_smob->spec.is_temporary = temporary; return result; } @@ -447,6 +456,7 @@ gdbscm_register_breakpoint_x (SCM self) try { int internal = bp_smob->spec.is_internal; + int temporary = bp_smob->spec.is_temporary; switch (bp_smob->spec.type) { @@ -457,7 +467,7 @@ gdbscm_register_breakpoint_x (SCM self) create_breakpoint (get_current_arch (), eloc.get (), NULL, -1, NULL, false, 0, - 0, bp_breakpoint, + temporary, bp_breakpoint, 0, AUTO_BOOLEAN_TRUE, ops, @@ -1040,6 +1050,18 @@ gdbscm_breakpoint_number (SCM self) return scm_from_long (bp_smob->number); } + +/* (breakpoint-temporary? ) -> boolean */ + +static SCM +gdbscm_breakpoint_temporary (SCM self) +{ + breakpoint_smob *bp_smob + = bpscm_get_valid_breakpoint_smob_arg_unsafe (self, SCM_ARG1, FUNC_NAME); + + return scm_from_bool (bp_smob->bp->disposition == disp_del + || bp_smob->bp->disposition == disp_del_at_next_stop); +} /* Return TRUE if "stop" has been set for this breakpoint. @@ -1171,9 +1193,9 @@ static const scheme_function breakpoint_functions[] = Create a GDB breakpoint object.\n\ \n\ Arguments:\n\ - location [#:type ] [#:wp-class ] [#:internal ]\n\ + location [#:type ] [#:wp-class ] [#:internal ] [#:temporary ]\n\ Returns:\n\ - object" }, { "register-breakpoint!", 1, 0, 0, as_a_scm_t_subr (gdbscm_register_breakpoint_x), @@ -1202,6 +1224,10 @@ Return #t if the breakpoint has not been deleted from GDB." }, "\ Return the breakpoint's number." }, + { "breakpoint-temporary?", 1, 0, 0, as_a_scm_t_subr (gdbscm_breakpoint_temporary), + "\ +Return #t if the breakpoint is a temporary breakpoint." }, + { "breakpoint-type", 1, 0, 0, as_a_scm_t_subr (gdbscm_breakpoint_type), "\ Return the type of the breakpoint." }, @@ -1345,4 +1371,5 @@ gdbscm_initialize_breakpoints (void) type_keyword = scm_from_latin1_keyword ("type"); wp_class_keyword = scm_from_latin1_keyword ("wp-class"); internal_keyword = scm_from_latin1_keyword ("internal"); + temporary_keyword = scm_from_latin1_keyword ("temporary"); } diff --git a/gdb/testsuite/gdb.guile/scm-breakpoint.exp b/gdb/testsuite/gdb.guile/scm-breakpoint.exp index be898cacaa7..c5f19e154d7 100644 --- a/gdb/testsuite/gdb.guile/scm-breakpoint.exp +++ b/gdb/testsuite/gdb.guile/scm-breakpoint.exp @@ -485,6 +485,38 @@ proc_with_prefix test_bkpt_registration {} { "= #t" "breakpoint valid after re-registration" } +proc_with_prefix test_bkpt_temporary { } { + global srcfile testfile hex decimal + + # Start with a fresh gdb. + clean_restart ${testfile} + + if ![gdb_guile_runto_main] { + fail "cannot run to main." + return 0 + } + delete_breakpoints + + set ibp_location [gdb_get_line_number "Break at multiply."] + gdb_scm_test_silent_cmd "guile (define ibp (make-breakpoint \"$ibp_location\" #:temporary #t))" \ + "create temporary breakpoint" + gdb_scm_test_silent_cmd "guile (register-breakpoint! ibp)" \ + "register ibp" + gdb_test "info breakpoints" \ + "2.*breakpoint.*del.*scm-breakpoint\.c:$ibp_location.*" \ + "check info breakpoints shows breakpoint with temporary status" + gdb_test "guile (print (breakpoint-location ibp))" "scm-breakpoint\.c:$ibp_location*" \ + "check temporary breakpoint location" + gdb_test "guile (print (breakpoint-temporary? ibp))" "#t" \ + "check breakpoint temporary status" + gdb_continue_to_breakpoint "Break at multiply." \ + ".*$srcfile:$ibp_location.*" + gdb_test "guile (print (breakpoint-temporary? ibp))" "Invalid object: .*" \ + "check temporary breakpoint is deleted after being hit" + gdb_test "info breakpoints" "No breakpoints or watchpoints.*" \ + "check info breakpoints shows temporary breakpoint is deleted" +} + proc_with_prefix test_bkpt_address {} { global decimal srcfile @@ -564,5 +596,6 @@ test_watchpoints test_bkpt_internal test_bkpt_eval_funcs test_bkpt_registration +test_bkpt_temporary test_bkpt_address test_bkpt_probe