[PATCH v2] Guile: temporary breakpoints
George Barrett
bob@bob131.so
Wed Jun 9 02:55:05 GMT 2021
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 | 35 ++++++++++++++++++
4 files changed, 88 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..112bf899dc9 100644
--- a/gdb/testsuite/gdb.guile/scm-breakpoint.exp
+++ b/gdb/testsuite/gdb.guile/scm-breakpoint.exp
@@ -478,6 +478,40 @@ proc_with_prefix test_bkpt_registration {} {
"= #t" "breakpoint valid after re-registration"
}
+proc_with_prefix test_bkpt_temporary { } {
+ global srcfile testfile hex decimal
+
+ with_test_prefix test_bkpt_temporary {
+ # 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 +554,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
More information about the Gdb-patches
mailing list