This is the mail archive of the gdb-patches@sourceware.cygnus.com mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

RFA: revised implementation of permanent breakpoints



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}.

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]