[v3] Guile: temporary breakpoints

Message ID lvnfrst_&9i7zz--iqxbfnkr1slc90cifguu1&y9yzvzxcynlso9@mail.bob131.so
State New
Headers show
Series
  • [v3] Guile: temporary breakpoints
Related show

Commit Message

Metzger, Markus T via Gdb-patches June 9, 2021, 1:56 p.m.
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  <bob@bob131.so>

	* 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  <bob@bob131.so>

	* 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  <bob@bob131.so>

	* gdb.guile/scm-breakpoint.exp: Add additional tests for
	temporary breakpoints.
---
 gdb/NEWS                                   |  3 ++
 gdb/doc/guile.texi                         | 16 +++++++-
 gdb/guile/scm-breakpoint.c                 | 43 ++++++++++++++++++----
 gdb/testsuite/gdb.guile/scm-breakpoint.exp | 33 +++++++++++++++++
 4 files changed, 86 insertions(+), 9 deletions(-)

-- 
2.31.1

Comments

Metzger, Markus T via Gdb-patches June 9, 2021, 2:55 p.m. | #1
On 2021-06-09 9:56 a.m., George Barrett via Gdb-patches wrote:
> 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  <bob@bob131.so>

> 

> 	* 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  <bob@bob131.so>

> 

> 	* 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  <bob@bob131.so>

> 

> 	* gdb.guile/scm-breakpoint.exp: Add additional tests for

> 	temporary breakpoints.


Thanks, this is OK.  Do you have push access or would you like me to
push the patch on your behalf?  Or, if you plan on contributing
regularly, would you like push access?

Simon
Metzger, Markus T via Gdb-patches June 9, 2021, 3:27 p.m. | #2
On Wed, Jun 09, 2021 at 10:55:46AM -0400, Simon Marchi wrote:
> Thanks, this is OK.  Do you have push access or would you like me to

> push the patch on your behalf?  Or, if you plan on contributing

> regularly, would you like push access?


I don't have push access, so I'd appreciate if you could push it for me.

As for getting push access, it really depends on how much extra burden it puts
on you guys to have to review _and_ push patches. I'd prefer not have the
opportunity to cause a disruption by absent-mindedly doing something dumb or
fat-fingering something, but if it's a real pain for the maintainers to push
then getting push access for myself sounds sensible.

Thanks.
Metzger, Markus T via Gdb-patches June 10, 2021, 2:41 p.m. | #3
On 2021-06-09 11:27 a.m., George Barrett wrote:
> On Wed, Jun 09, 2021 at 10:55:46AM -0400, Simon Marchi wrote:

>> Thanks, this is OK.  Do you have push access or would you like me to

>> push the patch on your behalf?  Or, if you plan on contributing

>> regularly, would you like push access?

> 

> I don't have push access, so I'd appreciate if you could push it for me.

> 

> As for getting push access, it really depends on how much extra burden it puts

> on you guys to have to review _and_ push patches. I'd prefer not have the

> opportunity to cause a disruption by absent-mindedly doing something dumb or

> fat-fingering something, but if it's a real pain for the maintainers to push

> then getting push access for myself sounds sensible.

> 

> Thanks.

> 


I don't mind, just make sure to mention it when a patch of yours gets
approved, otherwise it will just fall into the cracks, as we usually
assume that contributors push patches themselves.

Another thing I thought I checked before but apparently not.  Do you
have a copyright assignment on file?  I can't find one under your name.
It is required for any non-trivial patch.  If you don't please follow
the steps here:

  https://git.savannah.gnu.org/cgit/gnulib.git/tree/doc/Copyright/request-assign.future

Once you have that, I'll be able to merge your patch.

Simon
Tom Tromey June 10, 2021, 6:27 p.m. | #4
George> As for getting push access, it really depends on how much extra burden it puts
George> on you guys to have to review _and_ push patches. I'd prefer not have the
George> opportunity to cause a disruption by absent-mindedly doing something dumb or
George> fat-fingering something, but if it's a real pain for the maintainers to push
George> then getting push access for myself sounds sensible.

As long as you don't force-push you are probably pretty safe :)
Anyway the usual rule is that you can get write-after-approval access
after having a patch accepted.

Tom
Metzger, Markus T via Gdb-patches June 12, 2021, 10:07 a.m. | #5
> Date: Wed, 09 Jun 2021 23:56:11 +1000

> From: George Barrett via Gdb-patches <gdb-patches@sourceware.org>

> Cc: George Barrett <bob@bob131.so>

> 

> gdb/ChangeLog:

> 

> 2021-06-09  George Barrett  <bob@bob131.so>

> 

> 	* 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  <bob@bob131.so>

> 

> 	* 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  <bob@bob131.so>

> 

> 	* gdb.guile/scm-breakpoint.exp: Add additional tests for

> 	temporary breakpoints.


OK for the documentation parts.  Thanks.
Metzger, Markus T via Gdb-patches July 28, 2021, 11:03 p.m. | #6
Alrighty, copyright assignment completed! This patch applies cleanly to master
and has been reviewed, so I'd appreciate if someone could push it for me.

Thanks.

On Wed, Jun 09, 2021 at 11:56:11PM +1000, George Barrett wrote:
> 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  <bob@bob131.so>

> 

> 	* 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  <bob@bob131.so>

> 

> 	* 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  <bob@bob131.so>

> 

> 	* gdb.guile/scm-breakpoint.exp: Add additional tests for

> 	temporary breakpoints.

> ---

>  gdb/NEWS                                   |  3 ++

>  gdb/doc/guile.texi                         | 16 +++++++-

>  gdb/guile/scm-breakpoint.c                 | 43 ++++++++++++++++++----

>  gdb/testsuite/gdb.guile/scm-breakpoint.exp | 33 +++++++++++++++++

>  4 files changed, 86 insertions(+), 9 deletions(-)

> 

> diff --git a/gdb/NEWS b/gdb/NEWS

> index 56743fc9aea..7aa5a5e7d86 100644

> --- a/gdb/NEWS

> +++ b/gdb/NEWS

> @@ -214,6 +214,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 c7e43c8d63a..520ed6c85cb 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}

> @@ -3083,6 +3088,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 4ff197e48a4..2fd8a9c085b 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.  */

>  

> @@ -330,7 +334,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) -> <gdb:breakpoint>

> +    [#:internal boolean] [#:temporary boolean]) -> <gdb:breakpoint>

>  

>     The result is the <gdb:breakpoint> Scheme object.

>     The breakpoint is not available to be used yet, however.

> @@ -340,22 +344,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);

> @@ -398,6 +406,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;

>  }

> @@ -433,6 +442,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)

>  	{

> @@ -443,7 +453,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,

> @@ -1026,6 +1036,18 @@ gdbscm_breakpoint_number (SCM self)

>  

>    return scm_from_long (bp_smob->number);

>  }

> +

> +/* (breakpoint-temporary? <gdb:breakpoint>) -> 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.

>  

> @@ -1156,9 +1178,9 @@ static const scheme_function breakpoint_functions[] =

>  Create a GDB breakpoint object.\n\

>  \n\

>    Arguments:\n\

> -    location [#:type <type>] [#:wp-class <wp-class>] [#:internal <bool>]\n\

> +    location [#:type <type>] [#:wp-class <wp-class>] [#:internal <bool>] [#:temporary <bool>]\n\

>    Returns:\n\

> -    <gdb:breakpoint object" },

> +    <gdb:breakpoint> object" },

>  

>    { "register-breakpoint!", 1, 0, 0,

>      as_a_scm_t_subr (gdbscm_register_breakpoint_x),

> @@ -1187,6 +1209,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." },

> @@ -1330,4 +1356,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 56058942e64..a677976a2b3 100644

> --- a/gdb/testsuite/gdb.guile/scm-breakpoint.exp

> +++ b/gdb/testsuite/gdb.guile/scm-breakpoint.exp

> @@ -478,6 +478,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: <gdb:breakpoint>.*" \

> +	"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

>  

> @@ -520,5 +552,6 @@ test_watchpoints

>  test_bkpt_internal

>  test_bkpt_eval_funcs

>  test_bkpt_registration

> +test_bkpt_temporary

>  test_bkpt_address

>  test_bkpt_probe

> -- 

> 2.31.1
Metzger, Markus T via Gdb-patches July 29, 2021, 12:31 a.m. | #7
On 2021-07-28 7:03 p.m., George Barrett via Gdb-patches wrote:
> Alrighty, copyright assignment completed! This patch applies cleanly to master

> and has been reviewed, so I'd appreciate if someone could push it for me.

> 

> Thanks.


Done, thanks!

Simon

Patch

diff --git a/gdb/NEWS b/gdb/NEWS
index 56743fc9aea..7aa5a5e7d86 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -214,6 +214,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 c7e43c8d63a..520ed6c85cb 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}
@@ -3083,6 +3088,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 4ff197e48a4..2fd8a9c085b 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.  */
 
@@ -330,7 +334,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) -> <gdb:breakpoint>
+    [#:internal boolean] [#:temporary boolean]) -> <gdb:breakpoint>
 
    The result is the <gdb:breakpoint> Scheme object.
    The breakpoint is not available to be used yet, however.
@@ -340,22 +344,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);
@@ -398,6 +406,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;
 }
@@ -433,6 +442,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)
 	{
@@ -443,7 +453,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,
@@ -1026,6 +1036,18 @@  gdbscm_breakpoint_number (SCM self)
 
   return scm_from_long (bp_smob->number);
 }
+
+/* (breakpoint-temporary? <gdb:breakpoint>) -> 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.
 
@@ -1156,9 +1178,9 @@  static const scheme_function breakpoint_functions[] =
 Create a GDB breakpoint object.\n\
 \n\
   Arguments:\n\
-    location [#:type <type>] [#:wp-class <wp-class>] [#:internal <bool>]\n\
+    location [#:type <type>] [#:wp-class <wp-class>] [#:internal <bool>] [#:temporary <bool>]\n\
   Returns:\n\
-    <gdb:breakpoint object" },
+    <gdb:breakpoint> object" },
 
   { "register-breakpoint!", 1, 0, 0,
     as_a_scm_t_subr (gdbscm_register_breakpoint_x),
@@ -1187,6 +1209,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." },
@@ -1330,4 +1356,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 56058942e64..a677976a2b3 100644
--- a/gdb/testsuite/gdb.guile/scm-breakpoint.exp
+++ b/gdb/testsuite/gdb.guile/scm-breakpoint.exp
@@ -478,6 +478,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: <gdb:breakpoint>.*" \
+	"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
 
@@ -520,5 +552,6 @@  test_watchpoints
 test_bkpt_internal
 test_bkpt_eval_funcs
 test_bkpt_registration
+test_bkpt_temporary
 test_bkpt_address
 test_bkpt_probe