This is the mail archive of the
gdb-patches@sourceware.cygnus.com
mailing list for the GDB project.
RFA: permanent breakpoints
- To: Michael Snyder <msnyder@cygnus.com>, Jim Ingham <jingham@cygnus.com>, Jeff Law <law@cygnus.com>
- Subject: RFA: permanent breakpoints
- From: Jim Blandy <jimb@cygnus.com>
- Date: Sun, 12 Sep 1999 00:15:18 -0500 (EST)
- CC: gdb-patches@sourceware.cygnus.com
Request for approval. This contains changes mostly to breakpoint.c,
but also has a small change to the GDBTk files, and pa64solib.c.
Here are the internal changes necessary to support "permanent"
breakpoints: breakpoints that are hardwired into the inferior's code
by the programmer. GDB just knows they're there, but doesn't try to
insert or remove them.
GDB needs this to communicate properly with the dynamic linker on
HP/UX on PA 2.0 in wide (64-bit) mode.
There is no user interface for this, which is lame, but the HP
contract doesn't need it, and I'm low on time. If folks think it's
interesting, I could add one later, write docs and a NEWS entry, etc.
1999-09-11 Jim Blandy <jimb@cris.red-bean.com>
* breakpoint.c (breakpoint_here_p): Remove meaningless code,
testing b->enable against shlib_disabled and call_disabled after
we know it is enabled.
Implement "permanent breakpoints" --- breakpoints that are
hardwired into the inferior's code. GDB knows they're there, but
doesn't try to insert or remove them, etc.
* breakpoint.h (enum enable): Add `permanent' enablement state.
* breakpoint.c (breakpoint_is_permanent): New function.
* breakpoint.h (breakpoint_is_permanent): Add declaration.
* breakpoint.c (insert_breakpoints): Don't bother to insert
permanent breakpoints...
(remove_breakpoint): ... or remove them.
(breakpoint_here_p): Handle `permanent' like `enabled'.
(breakpoint_1): Extend bpenables to cover all the enablement states.
(describe_other_breakpoints): Describe permanent breakpoints.
(check_duplicates): If one of the breakpoints at ADDRESS is a
permanent breakpoint, treat all the others as the duplicates, so
we don't try to insert or remove any of them. Verify that only
the permanent breakpoint is actually inserted.
(delete_breakpoint): Complain if we discover that another
breakpoint was inserted at the same place as a permanent
breakpoint.
(disable_breakpoint): Fail silently if asked to disable a
permanent breakpoint.
(do_enable_breakpoint): Don't change a permanent breakpoint's
enablement to ordinary `enabled'. Leave it alone.
* breakpoint.c (create_solib_event_breakpoint): Return the
breakpoint object created.
* breakpoint.h (create_solib_event_breakpoint): Fix declaration.
* pa64solib.c (pa64_solib_create_inferior_hook): Make the dynamic
linker's breakpoint in __dld_break a permanent breakpoint.
* gdbtk-cmds.c (gdb_get_breakpoint_info): Report a permanent
breakpoint as enabled.
Index: breakpoint.c
===================================================================
RCS file: /cvs/cvsfiles/devo/gdb/breakpoint.c,v
retrieving revision 1.241
diff -c -r1.241 breakpoint.c
*** breakpoint.c 1999/09/01 20:13:42 1.241
--- breakpoint.c 1999/09/12 05:06:44
***************
*** 676,682 ****
ALL_BREAKPOINTS_SAFE (b, temp)
{
! if (b->type != bp_watchpoint
&& b->type != bp_hardware_watchpoint
&& b->type != bp_read_watchpoint
&& b->type != bp_access_watchpoint
--- 676,685 ----
ALL_BREAKPOINTS_SAFE (b, temp)
{
! if (b->enable == permanent)
! /* No need to do anything for a permanent breakpoint. */
! ;
! else if (b->type != bp_watchpoint
&& b->type != bp_hardware_watchpoint
&& b->type != bp_read_watchpoint
&& b->type != bp_access_watchpoint
***************
*** 1136,1141 ****
--- 1139,1148 ----
{
int val;
+ if (b->enable == permanent)
+ /* We shouldn't touch permament breakpoints. */
+ return;
+
if (b->type == bp_none)
warning ("attempted to remove apparently deleted breakpoint #%d?",
b->number);
***************
*** 1149,1155 ****
&& b->type != bp_catch_exec
&& b->type != bp_catch_catch
&& b->type != bp_catch_throw)
-
{
if (b->type == bp_hardware_breakpoint)
val = target_remove_hw_breakpoint (b->address, b->shadow_contents);
--- 1156,1161 ----
***************
*** 1373,1381 ****
register struct breakpoint *b;
ALL_BREAKPOINTS (b)
! if (b->enable == enabled
! && b->enable != shlib_disabled
! && b->enable != call_disabled
&& b->address == pc) /* bp is enabled and matches pc */
{
if (overlay_debugging &&
--- 1379,1386 ----
register struct breakpoint *b;
ALL_BREAKPOINTS (b)
! if ((b->enable == enabled
! || b->enable == permanent)
&& b->address == pc) /* bp is enabled and matches pc */
{
if (overlay_debugging &&
***************
*** 2863,2869 ****
static char *bpdisps[] =
{"del", "dstp", "dis", "keep"};
! static char bpenables[] = "nyn";
char wrap_indent[80];
/* start-sanitize-flathead */
#ifdef UI_OUT
--- 2868,2874 ----
static char *bpdisps[] =
{"del", "dstp", "dis", "keep"};
! static char bpenables[] = "nynny";
char wrap_indent[80];
/* start-sanitize-flathead */
#ifdef UI_OUT
***************
*** 3484,3491 ****
b->number,
((b->enable == disabled ||
b->enable == shlib_disabled ||
! b->enable == call_disabled)
! ? " (disabled)" : ""),
(others > 1) ? "," : ((others == 1) ? " and" : ""));
}
printf_filtered ("also set at pc ");
--- 3489,3497 ----
b->number,
((b->enable == disabled ||
b->enable == shlib_disabled ||
! b->enable == call_disabled) ? " (disabled)"
! : b->enable == permanent ? " (permanent)"
! : ""),
(others > 1) ? "," : ((others == 1) ? " and" : ""));
}
printf_filtered ("also set at pc ");
***************
*** 3512,3518 ****
/* Rescan breakpoints at address ADDRESS,
marking the first one as "first" and any others as "duplicates".
! This is so that the bpt instruction is only inserted once. */
static void
check_duplicates (address, section)
--- 3518,3526 ----
/* Rescan breakpoints at address ADDRESS,
marking the first one as "first" and any others as "duplicates".
! This is so that the bpt instruction is only inserted once.
! If we have a permanent breakpoint at ADDRESS, make that one
! the official one, and the rest as duplicates. */
static void
check_duplicates (address, section)
***************
*** 3521,3526 ****
--- 3529,3535 ----
{
register struct breakpoint *b;
register int count = 0;
+ struct breakpoint *perm_bp = 0;
if (address == 0) /* Watchpoints are uninteresting */
return;
***************
*** 3532,3540 ****
--- 3541,3584 ----
&& b->address == address
&& (overlay_debugging == 0 || b->section == section))
{
+ /* Have we found a permanent breakpoint? */
+ if (b->enable == permanent)
+ {
+ perm_bp = b;
+ break;
+ }
+
count++;
b->duplicate = count > 1;
}
+
+ /* If we found a permanent breakpoint at this address, go over the
+ list again and declare all the other breakpoints there to be the
+ duplicates. */
+ if (perm_bp)
+ {
+ perm_bp->duplicate = 0;
+
+ /* Permanent breakpoint should always be inserted. */
+ if (! perm_bp->inserted)
+ internal_error ("allegedly permanent breakpoint is not "
+ "actually inserted");
+
+ ALL_BREAKPOINTS (b)
+ if (b != perm_bp)
+ {
+ if (b->inserted)
+ internal_error ("another breakpoint was inserted on top of "
+ "a permanent breakpoint");
+
+ if (b->enable != disabled
+ && b->enable != shlib_disabled
+ && b->enable != call_disabled
+ && b->address == address
+ && (overlay_debugging == 0 || b->section == section))
+ b->duplicate = 1;
+ }
+ }
}
/* Low level routine to set a breakpoint.
***************
*** 3597,3602 ****
--- 3641,3657 ----
return b;
}
+
+ /* Note that b is actually a permanent breakpoint. */
+ void
+ breakpoint_is_permanent (struct breakpoint *b)
+ {
+ b->enable = permanent;
+
+ /* By definition, permanent breakpoints are already present in the code. */
+ b->inserted = 1;
+ }
+
#ifdef GET_LONGJMP_TARGET
static void
***************
*** 3676,3682 ****
delete_breakpoint (b);
}
! void
create_solib_event_breakpoint (address)
CORE_ADDR address;
{
--- 3731,3737 ----
delete_breakpoint (b);
}
! struct breakpoint *
create_solib_event_breakpoint (address)
CORE_ADDR address;
{
***************
*** 3690,3695 ****
--- 3745,3752 ----
b->number = internal_breakpoint_number--;
b->disposition = donttouch;
b->type = bp_shlib_event;
+
+ return b;
}
/* Disable any breakpoints that are on code in shared libraries. Only
***************
*** 6325,6330 ****
--- 6382,6395 ----
{
int val;
+ /* We should never reach this point if there is a permanent
+ breakpoint at the same address as the one being deleted.
+ If there is a permanent breakpoint somewhere, it should
+ always be the only one inserted. */
+ if (b->enable == permanent)
+ internal_error ("another breakpoint was inserted on top of "
+ "a permanent breakpoint");
+
if (b->type == bp_hardware_breakpoint)
val = target_insert_hw_breakpoint (b->address, b->shadow_contents);
else
***************
*** 6773,6778 ****
--- 6838,6847 ----
if (bpt->type == bp_watchpoint_scope)
return;
+ /* You can't disable permanent breakpoints. */
+ if (bpt->enable == permanent)
+ return;
+
bpt->enable = disabled;
check_duplicates (bpt->address, bpt->section);
***************
*** 6841,6847 ****
error ("Hardware breakpoints used exceeds limit.");
}
! bpt->enable = enabled;
bpt->disposition = disposition;
check_duplicates (bpt->address, bpt->section);
breakpoints_changed ();
--- 6910,6917 ----
error ("Hardware breakpoints used exceeds limit.");
}
! if (bpt->enable != permanent)
! bpt->enable = enabled;
bpt->disposition = disposition;
check_duplicates (bpt->address, bpt->section);
breakpoints_changed ();
Index: breakpoint.h
===================================================================
RCS file: /cvs/cvsfiles/devo/gdb/breakpoint.h,v
retrieving revision 1.52
diff -c -r1.52 breakpoint.h
*** breakpoint.h 1999/08/29 00:06:42 1.52
--- breakpoint.h 1999/09/12 05:06:45
***************
*** 129,141 ****
shlib_disabled, /* The eventpoint's address is in an unloaded solib.
The eventpoint will be automatically enabled
and reset when that solib is loaded. */
! call_disabled /* The eventpoint has been disabled while a call
into the inferior is "in flight", because some
eventpoints interfere with the implementation of
a call on some targets. The eventpoint will be
automatically enabled and reset when the call
"lands" (either completes, or stops at another
eventpoint). */
};
--- 129,146 ----
shlib_disabled, /* The eventpoint's address is in an unloaded solib.
The eventpoint will be automatically enabled
and reset when that solib is loaded. */
! call_disabled, /* The eventpoint has been disabled while a call
into the inferior is "in flight", because some
eventpoints interfere with the implementation of
a call on some targets. The eventpoint will be
automatically enabled and reset when the call
"lands" (either completes, or stops at another
eventpoint). */
+ permanent /* There is a breakpoint instruction hard-wired into
+ the target's code. Don't try to write another
+ breakpoint instruction on top of it, or restore
+ its value. Step over it using the architecture's
+ SKIP_INSN macro. */
};
***************
*** 594,600 ****
extern void enable_breakpoint PARAMS ((struct breakpoint *));
! extern void create_solib_event_breakpoint PARAMS ((CORE_ADDR));
extern void remove_solib_event_breakpoints PARAMS ((void));
--- 599,607 ----
extern void enable_breakpoint PARAMS ((struct breakpoint *));
! extern void breakpoint_is_permanent PARAMS ((struct breakpoint *));
!
! extern struct breakpoint *create_solib_event_breakpoint PARAMS ((CORE_ADDR));
extern void remove_solib_event_breakpoints PARAMS ((void));
Index: pa64solib.c
===================================================================
RCS file: /cvs/cvsfiles/devo/gdb/pa64solib.c,v
retrieving revision 2.3
diff -c -r2.3 pa64solib.c
*** pa64solib.c 1999/08/23 16:19:35 2.3
--- pa64solib.c 1999/09/12 05:06:46
***************
*** 621,627 ****
sym_addr = load_addr + sym_addr + 4;
/* Create the shared library breakpoint. */
! create_solib_event_breakpoint (sym_addr);
/* We're done with the temporary bfd. */
bfd_close (tmp_bfd);
--- 621,637 ----
sym_addr = load_addr + sym_addr + 4;
/* Create the shared library breakpoint. */
! {
! struct breakpoint *b
! = create_solib_event_breakpoint (sym_addr);
!
! /* The breakpoint is actually hard-coded into the dynamic linker,
! so we don't need to actually insert a breakpoint instruction
! there. In fact, the dynamic linker's code is immutable, even to
! ttrace, so we shouldn't even try to do that. For cases like
! this, we have "permanent" breakpoints. */
! breakpoint_is_permanent (b);
! }
/* We're done with the temporary bfd. */
bfd_close (tmp_bfd);
Index: gdbtk-cmds.c
===================================================================
RCS file: /cvs/cvsfiles/devo/gdb/gdbtk-cmds.c,v
retrieving revision 2.57
diff -c -r2.57 gdbtk-cmds.c
*** gdbtk-cmds.c 1999/09/03 10:15:31 2.57
--- gdbtk-cmds.c 1999/09/12 05:06:51
***************
*** 3968,3974 ****
Tcl_ListObjAppendElement (NULL, result_ptr->obj_ptr,
Tcl_NewStringObj (bptypes[b->type], -1));
Tcl_ListObjAppendElement (NULL, result_ptr->obj_ptr,
! Tcl_NewBooleanObj (b->enable == enabled));
Tcl_ListObjAppendElement (NULL, result_ptr->obj_ptr,
Tcl_NewStringObj (bpdisp[b->disposition], -1));
Tcl_ListObjAppendElement (NULL, result_ptr->obj_ptr,
--- 3968,3975 ----
Tcl_ListObjAppendElement (NULL, result_ptr->obj_ptr,
Tcl_NewStringObj (bptypes[b->type], -1));
Tcl_ListObjAppendElement (NULL, result_ptr->obj_ptr,
! Tcl_NewBooleanObj (b->enable == enabled
! || b->enable == permanent));
Tcl_ListObjAppendElement (NULL, result_ptr->obj_ptr,
Tcl_NewStringObj (bpdisp[b->disposition], -1));
Tcl_ListObjAppendElement (NULL, result_ptr->obj_ptr,