This is the mail archive of the
gdb-patches@sourceware.cygnus.com
mailing list for the GDB project.
RFA: revised implementation of permanent breakpoints
- To: Michael Snyder <msnyder@cygnus.com>, Jim Ingham <jingham@cygnus.com>, Stan Shebs <shebs@cygnus.com>
- Subject: RFA: revised implementation of permanent breakpoints
- From: Jim Blandy <jimb@cygnus.com>
- Date: Mon, 13 Sep 1999 13:17:28 -0500 (EST)
- CC: gdb-patches@sourceware.cygnus.com
Here is a revised implementation permanent breakpoints, which includes
the ability to continue past a permanent breakpoint, if the target
provides a macro explaining how to advance the PC past a breakpoint
instruction.
I added the SKIP_PERMANENT_BREAKPOINT macro in such a way that it
should be easy to adapt it to the gdbarch framework. It is always
used as a typed value, never in an #ifdef. So one should be able to
add a line to gdbarch.sh, and change the #define to a proper
gdbarch-style initialization, and everything will just work.
There is still no user interface.
gdb/ChangeLog:
1999-09-13 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 (make_breakpoint_permanent): New function.
* breakpoint.h (make_breakpoint_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'. Change
return value to indicate whether it's a permanent breakpoint here,
or an ordinary breakpoint.
* breakpoint.h (enum breakpoint_here): New enum.
(breakpoint_here_p): Change declaration.
* breakpoint.h (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.
(create_solib_event_breakpoint): Return the
breakpoint object created.
* breakpoint.h (create_solib_event_breakpoint): Fix declaration.
* pa64solib.c (pa64_solib_create_inferior_hook): Do turn on the
DT_HP_DEBUG_CALLBACK flag in the dynamic linker, so it will call
__dld_break, which contains the permanent breakpoint, when interesting
things happen. Tell GDB that the breakpoint in __dld_break is
permanent.
* gdbtk-cmds.c (gdb_get_breakpoint_info): Report a permanent
breakpoint as enabled.
* infrun.c (SKIP_PERMANENT_BREAKPOINT): Provide default definition.
(resume): If we're trying to resume at a permanent breakpoint, use
SKIP_PERMANENT_BREAKPOINT to step over it. If we don't have
SKIP_PERMANENT_BREAKPOINT, then print an error message suggesting
how the user might get past the breakpoint.
* hppa-tdep.c (hppa_skip_permanent_breakpoint): New function.
* config/pa/tm-hppa.h (hppa_skip_permanent_breakpoint): Declare.
(SKIP_PERMANENT_BREAKPOINT): Define.
gdb/doc/ChangeLog:
1999-09-13 Jim Blandy <jimb@cris.red-bean.com>
* gdbint.texinfo (Target Architecture Definition): Document the
SKIP_PERMANENT_BREAKPOINT macro.
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/13 16:26:19
***************
*** 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 ----
***************
*** 1362,1394 ****
}
}
! /* breakpoint_here_p (PC) returns 1 if an enabled breakpoint exists at
! PC. When continuing from a location with a breakpoint, we actually
! single step once before calling insert_breakpoints. */
! int
breakpoint_here_p (pc)
CORE_ADDR pc;
{
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 &&
! section_is_overlay (b->section) &&
! !section_is_mapped (b->section))
! continue; /* unmapped overlay -- can't be a match */
! else
! return 1;
! }
return 0;
}
/* breakpoint_inserted_here_p (PC) is just like breakpoint_here_p(),
but it only returns true if there is actually a breakpoint inserted
at PC. */
--- 1368,1428 ----
}
}
! /* breakpoint_here_p (PC) returns non-zero if an enabled breakpoint
! exists at PC. It returns ordinary_breakpoint_here if it's an
! ordinary breakpoint, or permanent_breakpoint_here if it's a
! permanent breakpoint.
! - When continuing from a location with an ordinary breakpoint, we
! actually single step once before calling insert_breakpoints.
! - When continuing from a localion with a permanent breakpoint, we
! need to use the `SKIP_PERMANENT_BREAKPOINT' macro, provided by
! the target, to advance the PC past the breakpoint. */
! enum breakpoint_here
breakpoint_here_p (pc)
CORE_ADDR pc;
{
register struct breakpoint *b;
+ int any_breakpoint_here = 0;
ALL_BREAKPOINTS (b)
! if ((b->enable == enabled
! || b->enable == permanent)
&& b->address == pc) /* bp is enabled and matches pc */
! {
! if (overlay_debugging &&
! section_is_overlay (b->section) &&
! !section_is_mapped (b->section))
! continue; /* unmapped overlay -- can't be a match */
! else if (b->enable == permanent)
! return permanent_breakpoint_here;
! else
! any_breakpoint_here = 1;
! }
!
! return any_breakpoint_here ? ordinary_breakpoint_here : 0;
! }
+
+ int
+ permanent_breakpoint_here_p (CORE_ADDR pc)
+ {
+ register struct breakpoint *b;
+ ALL_BREAKPOINTS (b)
+ if (b->enable == permanent
+ && b->address == pc)
+ {
+ if (overlay_debugging &&
+ section_is_overlay (b->section) &&
+ !section_is_mapped (b->section))
+ continue; /* unmapped overlay -- can't be a match */
+ else
+ return 1;
+ }
return 0;
}
+
/* breakpoint_inserted_here_p (PC) is just like breakpoint_here_p(),
but it only returns true if there is actually a breakpoint inserted
at PC. */
***************
*** 2863,2869 ****
static char *bpdisps[] =
{"del", "dstp", "dis", "keep"};
! static char bpenables[] = "nyn";
char wrap_indent[80];
/* start-sanitize-flathead */
#ifdef UI_OUT
--- 2897,2903 ----
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 ");
--- 3518,3526 ----
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)
--- 3547,3555 ----
/* 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 ****
--- 3558,3564 ----
{
register struct breakpoint *b;
register int count = 0;
+ struct breakpoint *perm_bp = 0;
if (address == 0) /* Watchpoints are uninteresting */
return;
***************
*** 3532,3540 ****
--- 3570,3613 ----
&& 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 ****
--- 3670,3687 ----
return b;
}
+
+ /* Note that the breakpoint object B describes a permanent breakpoint
+ instruction, hard-wired into the inferior's code. */
+ void
+ make_breakpoint_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;
{
--- 3761,3767 ----
delete_breakpoint (b);
}
! struct breakpoint *
create_solib_event_breakpoint (address)
CORE_ADDR address;
{
***************
*** 3690,3695 ****
--- 3775,3782 ----
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 ****
--- 6412,6425 ----
{
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 ****
--- 6868,6877 ----
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 ();
--- 6940,6947 ----
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/13 16:26:20
***************
*** 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. */
};
***************
*** 459,464 ****
--- 464,478 ----
inf_running,
inf_exited
};
+
+ /* The possible return values for breakpoint_here_p.
+ We guarantee that zero always means "no breakpoint here". */
+ enum breakpoint_here
+ {
+ no_breakpoint_here = 0,
+ ordinary_breakpoint_here,
+ permanent_breakpoint_here
+ };
/* Prototypes for breakpoint-related functions. */
***************
*** 466,472 ****
/* Forward declarations for prototypes */
struct frame_info;
! extern int breakpoint_here_p PARAMS ((CORE_ADDR));
extern int breakpoint_inserted_here_p PARAMS ((CORE_ADDR));
--- 480,486 ----
/* Forward declarations for prototypes */
struct frame_info;
! extern enum breakpoint_here breakpoint_here_p PARAMS ((CORE_ADDR));
extern int breakpoint_inserted_here_p PARAMS ((CORE_ADDR));
***************
*** 593,600 ****
extern void disable_breakpoint PARAMS ((struct breakpoint *));
extern void enable_breakpoint PARAMS ((struct breakpoint *));
! extern void create_solib_event_breakpoint PARAMS ((CORE_ADDR));
extern void remove_solib_event_breakpoints PARAMS ((void));
--- 607,616 ----
extern void disable_breakpoint PARAMS ((struct breakpoint *));
extern void enable_breakpoint PARAMS ((struct breakpoint *));
+
+ extern void make_breakpoint_permanent PARAMS ((struct breakpoint *));
! extern struct breakpoint *create_solib_event_breakpoint PARAMS ((CORE_ADDR));
extern void remove_solib_event_breakpoints PARAMS ((void));
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/13 16:26:25
***************
*** 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,
Index: hppa-tdep.c
===================================================================
RCS file: /cvs/cvsfiles/devo/gdb/hppa-tdep.c,v
retrieving revision 2.136
diff -c -r2.136 hppa-tdep.c
*** hppa-tdep.c 1999/09/01 03:24:30 2.136
--- hppa-tdep.c 1999/09/13 16:26:31
***************
*** 4542,4547 ****
--- 4542,4571 ----
#endif /* PREPARE_TO_PROCEED */
void
+ hppa_skip_permanent_breakpoint ()
+ {
+ /* To step over a breakpoint instruction on the PA takes some
+ fiddling with the instruction address queue.
+
+ When we stop at a breakpoint, the IA queue front (the instruction
+ we're executing now) points at the breakpoint instruction, and
+ the IA queue back (the next instruction to execute) points to
+ whatever instruction we would execute after the breakpoint, if it
+ were an ordinary instruction. This is the case even if the
+ breakpoint is in the delay slot of a branch instruction.
+
+ Clearly, to step past the breakpoint, we need to set the queue
+ front to the back. But what do we put in the back? What
+ instruction comes after that one? Because of the branch delay
+ slot, the next insn is always at the back + 4. */
+ write_register (PCOQ_HEAD_REGNUM, read_register (PCOQ_TAIL_REGNUM));
+ write_register (PCSQ_HEAD_REGNUM, read_register (PCSQ_TAIL_REGNUM));
+
+ write_register (PCOQ_TAIL_REGNUM, read_register (PCOQ_TAIL_REGNUM) + 4);
+ /* We can leave the tail's space the same, since there's no jump. */
+ }
+
+ void
_initialize_hppa_tdep ()
{
tm_print_insn = print_insn_hppa;
Index: infrun.c
===================================================================
RCS file: /cvs/cvsfiles/devo/gdb/infrun.c,v
retrieving revision 1.241
diff -c -r1.241 infrun.c
*** infrun.c 1999/09/07 15:20:54 1.241
--- infrun.c 1999/09/13 16:26:41
***************
*** 268,273 ****
--- 268,283 ----
#define INSTRUCTION_NULLIFIED 0
#endif
+ /* We can't step off a permanent breakpoint in the ordinary way, because we
+ can't remove it. Instead, we have to advance the PC to the next
+ instruction. This macro should expand to a pointer to a function that
+ does that, or zero if we have no such function. If we don't have a
+ definition for it, we have to report an error. */
+ #ifndef SKIP_PERMANENT_BREAKPOINT
+ #define SKIP_PERMANENT_BREAKPOINT ((void (*) (void)) 0)
+ #endif
+
+
/* Convert the #defines into values. This is temporary until wfi control
flow is completely sorted out. */
***************
*** 789,794 ****
--- 799,823 ----
if (step && breakpoints_inserted && breakpoint_here_p (read_pc ()))
step = 0;
#endif
+
+ /* Normally, by the time we reach `resume', the breakpoints are either
+ removed or inserted, as appropriate. The exception is if we're sitting
+ at a permanent breakpoint; we need to step over it, but permanent
+ breakpoints can't be removed. So we have to test for it here. */
+ if (breakpoint_here_p (read_pc ()) == permanent_breakpoint_here)
+ {
+ if (SKIP_PERMANENT_BREAKPOINT)
+ SKIP_PERMANENT_BREAKPOINT ();
+ else
+ {
+ error_begin ();
+ fprintf_filtered (gdb_stderr, "\
+ The program is stopped at a permanent breakpoint, but GDB does not know\n\
+ how to step past a permanent breakpoint on this architecture. Try using\n\
+ a command like `return' or `jump' to continue execution.\n");
+ return_to_top_level (RETURN_ERROR);
+ }
+ }
if (SOFTWARE_SINGLE_STEP_P && step)
{
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/13 16:26:45
***************
*** 559,569 ****
/* Turn on the flags we care about. */
dld_cache.dld_flags |= DT_HP_DEBUG_PRIVATE;
- /* ?!? Right now GDB is not recognizing hitting the callback breakpoint
- as a shared library event. Fix that and remove the #if0 code. */
- #if 0
dld_cache.dld_flags |= DT_HP_DEBUG_CALLBACK;
- #endif
status = target_write_memory (dld_cache.dld_flags_addr,
(char *) &dld_cache.dld_flags,
sizeof (dld_cache.dld_flags));
--- 559,565 ----
***************
*** 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);
--- 617,633 ----
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. */
! make_breakpoint_permanent (b);
! }
/* We're done with the temporary bfd. */
bfd_close (tmp_bfd);
Index: config/pa/tm-hppa.h
===================================================================
RCS file: /cvs/cvsfiles/devo/gdb/config/pa/tm-hppa.h,v
retrieving revision 1.74
diff -c -r1.74 tm-hppa.h
*** tm-hppa.h 1999/08/25 08:57:05 1.74
--- tm-hppa.h 1999/09/13 16:26:48
***************
*** 796,798 ****
--- 796,802 ----
probably much more common. (FIXME). */
#define COERCE_FLOAT_TO_DOUBLE (current_language -> la_language == language_c)
+
+ /* Here's how to step off a permanent breakpoint. */
+ #define SKIP_PERMANENT_BREAKPOINT (hppa_skip_permanent_breakpoint)
+ extern void hppa_skip_permanent_breakpoint (void);
Index: doc/gdbint.texinfo
===================================================================
RCS file: /cvs/cvsfiles/devo/gdb/doc/gdbint.texinfo,v
retrieving revision 1.134
diff -c -r1.134 gdbint.texinfo
*** gdbint.texinfo 1999/09/07 16:15:29 1.134
--- gdbint.texinfo 1999/09/13 16:26:55
***************
*** 1596,1601 ****
--- 1596,1611 ----
@item SHIFT_INST_REGS
(Only used for m88k targets.)
+ @item SKIP_PERMANENT_BREAKPOINT
+ Step the inferior past a permanent breakpoint. GDB normally steps over
+ a breakpoint by removing it, stepping one instruction, and re-inserting
+ the breakpoint. However, permanent breakpoints are hardwired into the
+ inferior, and can't be removed, so this strategy doesn't work. Calling
+ SKIP_PERMANENT_BREAKPOINT adjusts the processor's state so that
+ execution will resume just after the breakpoint. This macro does the
+ right thing even when the breakpoint is in the delay slot of a branch or
+ jump.
+
@item SKIP_PROLOGUE (pc)
A C expression that returns the address of the ``real'' code beyond the
function entry prologue found at @var{pc}.