From: daney@mermaid.micro.umn.edu (Dave Daney)
Subject: 80386 Debug registers in gdb-4.5
Organization: GNUs Not Usenet
Distribution: gnu
Date: Wed, 15 Apr 1992 13:35:44 GMT

Greetings,

This is not really a bug report, but I am sending it here anyhow.

This should superceed the patch I sent a few days ago for gdb-4.4.

I have made a few modifications to gdb-4.5 to use the hardware debug
registers on the 386 running Interactive 2.2.1 (Sys V/386 Rel3.2).

They are implemented as a new type of breakpoint(I called it an Accesspoint).
I thought that they should be seperate from watchpoints because watchpoints break
on a whole expression changing.  Which  is different than a breakpoint on a memory
access, they (watchpoints) probably are usefull even with accesspoints.  Any how
there are two new commands to implement Accesspoints.

wbreak:  Break on a memory write to a location.
abreak:  Break on a memory access (read or write) to a location.

They can be set on any expression that evaluates to some thing located in a
memory location.

Special note:  To set an access breakpoint on location 0 (good for catching
reads or writes from a NULL pointer).

abreak *(int *)0

All of the rest of the breakpoint commands work on Accesspoints (info, enable, 
disable, delete, ... .  I haven't had any problems with them, although I have only
had this going a couple of days.

I think It is fairly straight forward.  I didn't make any info files for this.


I put the machine dependant parts in i386-xdep.c most of the rest of it is
in breakpoint.c.  Several other files just had the
struct target_ops XXXXX_target structures modified.

I think(hope) that all of the changes are inside of
#ifdef HAVE_MEM_BEEAKPOINT
#endif
blocks so hopefully this will not break any thing if you don't define
-DHAVE_MEM_BREAKPOINT
not positive about this however.  I hope this addition fits into the
scheme of gdb and does not break things for other systems. Let me know.


On the 386 there are only four Access breakpoint registers, they can be set
for one, two, and four byte accesses.  The addresses must be properly aligned.
The code in i386-xdep.c takes all of this into account, it will use as many
registers as necessary to cover the requested area.  It the registers are
exausted it will disable the Accesspoint.  There is a bug(feature) here, if
multiple registers are needed and at least one is available it  will fill from
the bottom of the area requested. Then it will report no more registers and disable
the Access point.  It does not deallocate the registers from the failed attempt.
When execution is resumed (continue) the access point is still set on the first
portion of the area.  If it is hit you will get some message about a SIGTRAP, but
the Accesspoint information will not print.  In short, set Accesspoints on
small properly aligned objects.

Also note:  For some reason I don't remember I initally ran
configure i386-none-sysv32 instead of what ever config thinks I should run
for this system.  I am not sure if that matters.  Maybe config thinks that is
what I should have done?

Here is how I made it.  The trad-core things are to get corefiles to read on this
machine.  For other 386 systems perhaps just -DHAVE_MEM_BREAKPOINT is sufficient.
I have a feeling that the things in i386-xdep.c might be different for other 
systems.

See my other patch(I Think you should have already seen it) for minor changes
needed to get unalterd gdb-4.5 to go.

gmake CC=gcc HDEFINES="-D_POSIX_SOURCE -DTRAD_CORE" HDEPFILES=trad-core.o\
READLINE_DEFINES="-D_POSIX_VERSION -D_POSIX_SOURCE" LOADLIBES=-lcposix\
USER_CFLAGS=-DHAVE_MEM_BREAKPOINT

--------------------------<just diffs after this>-----------------------------
diff -c -B ./breakpoint.c ../../gdb-4.5.new/gdb/breakpoint.c
*** ./breakpoint.c	Tue Apr  7 18:54:15 1992
--- ../../gdb-4.5.new/gdb/breakpoint.c	Wed Apr 15 16:34:38 1992
***************
*** 132,138 ****
--- 132,151 ----
  static void
  set_breakpoint_count PARAMS ((int));
  
+ #ifdef HAVE_MEM_BREAKPOINT
  
+ static void
+ write_access_breakpoint_command PARAMS ((char *, int));
+ 
+ static void
+ rw_access_breakpoint_command PARAMS ((char *, int));
+ 
+ static void
+ access_breakpoint_command PARAMS ((char *, int, enum access_break_type));
+ 
+ #endif /* HAVE_MEM_BREAKPOINT */
+ 
+ 
  extern int addressprint;		/* Print machine addresses? */
  extern int demangle;			/* Print de-mangled symbol names? */
  
***************
*** 432,437 ****
--- 445,453 ----
  
    ALL_BREAKPOINTS (b)
      if (b->type != bp_watchpoint
+ #ifdef HAVE_MEM_BREAKPOINT
+ 	&& b->type != bp_accesspoint
+ #endif
  	&& b->enable != disabled
  	&& ! b->inserted
  	&& ! b->duplicate)
***************
*** 448,454 ****
  		if (!disabled_breaks)
  		  {
  		    fprintf (stderr,
! 			 "Cannot insert breakpoint %d:\n", b->number);
  		    printf_filtered ("Disabling shared library breakpoints:\n");
  		  }
  		disabled_breaks = 1;
--- 464,470 ----
  		if (!disabled_breaks)
  		  {
  		    fprintf (stderr,
! 			     "Cannot insert breakpoint %d:\n", b->number);
  		    printf_filtered ("Disabling shared library breakpoints:\n");
  		  }
  		disabled_breaks = 1;
***************
*** 460,466 ****
  		fprintf (stderr, "Cannot insert breakpoint %d:\n", b->number);
  #ifdef ONE_PROCESS_WRITETEXT
  		fprintf (stderr,
! 		  "The same program may be running in another process.\n");
  #endif
  		memory_error (val, b->address);	/* which bombs us out */
  	      }
--- 476,482 ----
  		fprintf (stderr, "Cannot insert breakpoint %d:\n", b->number);
  #ifdef ONE_PROCESS_WRITETEXT
  		fprintf (stderr,
! 			 "The same program may be running in another process.\n");
  #endif
  		memory_error (val, b->address);	/* which bombs us out */
  	      }
***************
*** 470,475 ****
--- 486,512 ----
        }
    if (disabled_breaks)
      printf_filtered ("\n");
+ 
+ #ifdef HAVE_MEM_BREAKPOINT
+   target_init_access_breakpoint();
+ 
+   ALL_BREAKPOINTS (b)
+     if (b->type == bp_accesspoint && b->enable != disabled)
+       {
+ 	int rv;
+ 	rv = target_insert_access_breakpoint(b->access_break_address,
+ 					     b->access_break_length,
+ 					      b->access_break_type, b->number);
+ 	if (rv)
+ 	  {
+ 	    /* Can't set the breakpoint.  */
+ 	    fprintf(stderr, "Cannot set memory breakpoint %d.  Disableing it.\n", b->number);
+ 	    fprintf(stderr, "It is best to set memory breakpoints on small properly\n");
+ 	    fprintf(stderr, "aligned objects\n");
+ 	    b->enable = disabled;
+ 	  }	
+       }
+ #endif /* HAVE_MEM_BREAKPOINT */
    return val;
  }
  
***************
*** 499,504 ****
--- 536,544 ----
  		local_hex_string(b->shadow_contents[1]));
  #endif /* BREAKPOINT_DEBUG */
        }
+ #ifdef HAVE_MEM_BREAKPOINT
+   target_init_access_breakpoint();
+ #endif /* HAVE_MEM_BREAKPOINT */
  
    return 0;
  }
***************
*** 706,711 ****
--- 746,754 ----
    if (bs == NULL
        || bs->breakpoint_at == NULL
        || (bs->breakpoint_at->type != bp_breakpoint
+ #ifdef HAVE_MEM_BREAKPOINT
+ 	  && bs->breakpoint_at->type != bp_accesspoint
+ #endif /* HAVE_MEM_BREAKPOINT */
  	  && bs->breakpoint_at->type != bp_watchpoint))
      return 0;
    
***************
*** 741,747 ****
        bs->old_val = NULL;
        return 1;
      }
! 
    /* Maybe another breakpoint in the chain caused us to stop.
       (Currently all watchpoints go on the bpstat whether hit or
       not.  That probably could (should) be changed, provided care is taken
--- 784,807 ----
        bs->old_val = NULL;
        return 1;
      }
! #ifdef HAVE_MEM_BREAKPOINT
!   if (bs->breakpoint_at->type == bp_accesspoint)
!     {
!       printf_filtered ("\nMemory access breakpoint %d, ", bs->breakpoint_at->number);
!       printf_filtered ("%-10s",
! 		       local_hex_string(bs->breakpoint_at->access_break_address));
!       printf_filtered ("  ");
!       if(bs->breakpoint_at->access_break_type == access_break_write)
! 	printf_filtered ("w  ");
!       else
! 	printf_filtered ("r/w");
!       printf_filtered ("  ");
!       printf_filtered ("%d   ", bs->breakpoint_at->access_break_length);
!       print_expression (bs->breakpoint_at->access_break_exp, stdout);
!       printf_filtered ("\n");
!       return 0;
!     }
! #endif /* HAVE_MEM_BREAKPOINT */
    /* Maybe another breakpoint in the chain caused us to stop.
       (Currently all watchpoints go on the bpstat whether hit or
       not.  That probably could (should) be changed, provided care is taken
***************
*** 816,821 ****
--- 876,884 ----
    /* True if we've hit a breakpoint (as opposed to a watchpoint).  */
    int real_breakpoint = 0;
  #endif
+ #ifdef HAVE_MEM_BREAKPOINT
+   int access_breakpoint = target_get_access_breakpoint_status();
+ #endif
    /* Root of the chain of bpstat's */
    struct bpstat root_bs[1];
    /* Pointer to the last thing in the chain currently.  */
***************
*** 832,840 ****
        if (b->enable == disabled)
  	continue;
  
!       if (b->type != bp_watchpoint && b->address != bp_addr)
  	continue;
  
        /* Come here if it's a watchpoint, or if the break address matches */
  
        bs = bpstat_alloc (b, bs);	/* Alloc a bpstat to explain stop */
--- 895,911 ----
        if (b->enable == disabled)
  	continue;
  
! #ifdef HAVE_MEM_BREAKPOINT
!       if (b->type != bp_watchpoint && b->address != bp_addr &&
! 	  b->type != bp_accesspoint)
  	continue;
  
+       if(b->type == bp_accesspoint && b->number != access_breakpoint)
+ 	continue;
+ #else
+       if (b->type != bp_watchpoint && b->address != bp_addr)
+ 	continue;
+ #endif /* HAVE_MEM_BREAKPOINT */
        /* Come here if it's a watchpoint, or if the break address matches */
  
        bs = bpstat_alloc (b, bs);	/* Alloc a bpstat to explain stop */
***************
*** 895,902 ****
--- 966,978 ----
  	    }
  	}
  #if DECR_PC_AFTER_BREAK != 0 || defined (SHIFT_INST_REGS)
+ #ifdef HAVE_MEM_BREAKPOINT
+       else if (b->type != bp_accesspoint)
+ 	real_breakpoint = 1;
+ #else
        else
  	real_breakpoint = 1;
+ #endif /* HAVE_MEM_BREAKPOINT  */
  #endif
  
        if (b->frame && b->frame != frame_address)
***************
*** 989,997 ****
    return 0;
  }
  
! /* Print information on breakpoint number BNUM, or -1 if all.
!    If WATCHPOINTS is zero, process only breakpoints; if WATCHPOINTS
!    is nonzero, process only watchpoints.  */
  
  static void
  breakpoint_1 (bnum, allflag)
--- 1065,1071 ----
    return 0;
  }
  
! /* Print information on breakpoint number BNUM, or -1 if all. */
  
  static void
  breakpoint_1 (bnum, allflag)
***************
*** 1004,1010 ****
    CORE_ADDR last_addr = (CORE_ADDR)-1;
    int found_a_breakpoint = 0;
    static char *bptypes[] = {"breakpoint", "until", "finish", "watchpoint",
! 			      "longjmp", "longjmp resume"};
    static char *bpdisps[] = {"del", "dis", "keep"};
    static char bpenables[] = "ny";
  
--- 1078,1089 ----
    CORE_ADDR last_addr = (CORE_ADDR)-1;
    int found_a_breakpoint = 0;
    static char *bptypes[] = {"breakpoint", "until", "finish", "watchpoint",
! 			      "longjmp", "longjmp resume"
! #ifdef HAVE_MEM_BREAKPOINT
! 				,"accesspoint"
! #endif /* HAVE_MEM_BREAKPOINT */
! 				};
! 
    static char *bpdisps[] = {"del", "dis", "keep"};
    static char bpenables[] = "ny";
  
***************
*** 1021,1027 ****
  /*  We only print out user settable breakpoints unless the allflag is set. */
  	if (!allflag
  	    && b->type != bp_breakpoint
! 	    && b->type != bp_watchpoint)
  	  continue;
  
  	if (!found_a_breakpoint++)
--- 1100,1110 ----
  /*  We only print out user settable breakpoints unless the allflag is set. */
  	if (!allflag
  	    && b->type != bp_breakpoint
! 	    && b->type != bp_watchpoint
! #ifdef HAVE_MEM_BREAKPOINT
! 	    && b->type != bp_accesspoint
! #endif /* HAVE_MEM_BREAKPOINT */
! 	    )
  	  continue;
  
  	if (!found_a_breakpoint++)
***************
*** 1038,1043 ****
--- 1121,1140 ----
  	  case bp_watchpoint:
  	    print_expression (b->exp, stdout);
  	    break;
+ #ifdef HAVE_MEM_BREAKPOINT
+ 	  case bp_accesspoint:
+ 	    if (addressprint)
+ 	      printf_filtered ("%s ",
+ 			       local_hex_string_custom(b->access_break_address,
+ 						       "08"));
+ 	    if(b->access_break_type == access_break_write)
+  		  printf_filtered ("(w   ");
+  		else
+  		  printf_filtered ("(r/w ");
+  		printf_filtered ("%d) ", b->access_break_length);
+ 	    print_expression (b->access_break_exp, stdout);
+ 	    break;
+ #endif /* HAVE_MEM_BREAKPOINT */
  	  case bp_breakpoint:
  	  case bp_until:
  	  case bp_finish:
***************
*** 1179,1185 ****
    register struct breakpoint *b;
    register int count = 0;
  
!   if (address == 0)		/* Watchpoints are uninteresting */
      return;
  
    ALL_BREAKPOINTS (b)
--- 1276,1282 ----
    register struct breakpoint *b;
    register int count = 0;
  
!   if (address == 0)	/* Watchpoints and access_breakpoints are uninteresting */
      return;
  
    ALL_BREAKPOINTS (b)
***************
*** 1365,1370 ****
--- 1462,1473 ----
  {
    switch (b->type)
      {
+ #ifdef HAVE_MEM_BREAKPOINT
+     case bp_accesspoint:
+       printf_filtered ("Memory accesspoint %d at %s", b->number,
+ 		       local_hex_string_custom(b->access_break_address, "08"));
+       break;
+ #endif /* HAVE_MEM_BREAKPOINT  */
      case bp_watchpoint:
        printf_filtered ("Watchpoint %d: ", b->number);
        print_expression (b->exp, stdout);
***************
*** 1610,1615 ****
--- 1713,1780 ----
    b->cond_string = NULL;
    mention (b);
  }
+ 
+ #ifdef HAVE_MEM_BREAKPOINT
+ /* ARGSUSED */
+ static void
+ access_breakpoint_command (arg, from_tty, mode)
+      char *arg;
+      int from_tty;
+      enum access_break_type mode;
+ {
+   struct breakpoint *b;
+   struct symtab_and_line sal;
+   struct expression *exp;
+   struct block *exp_valid_block;
+   struct value *access_obj;
+ 
+   sal.pc = 0;
+   sal.symtab = NULL;
+   sal.line = 0;
+   
+   /* Parse arguments.  */
+   innermost_block = NULL;
+   exp = parse_expression (arg);
+   exp_valid_block = innermost_block;
+   access_obj = evaluate_expression (exp);
+ 
+   if(lval_memory != VALUE_LVAL(access_obj))
+     error("requested access breakpoint not in memory.  e.g. register or constant.");
+ 
+   /* Now set up the breakpoint.  */
+   b = set_raw_breakpoint (sal);
+   set_breakpoint_count (breakpoint_count + 1);
+   b->number = breakpoint_count;
+   b->type = bp_accesspoint;
+   b->disposition = donttouch;
+   b->exp = 0;
+   b->exp_valid_block = NULL;
+   b->val = NULL;
+   b->cond = 0;
+   b->cond_string = NULL;
+   b->access_break_exp = exp;
+   b->access_break_address = VALUE_ADDRESS(access_obj) + VALUE_OFFSET(access_obj);
+   b->access_break_length = TYPE_LENGTH(VALUE_TYPE(access_obj));
+   b->access_break_type = mode;
+   mention (b);
+ }
+ static void
+ write_access_breakpoint_command (arg, from_tty)
+      char *arg;
+      int from_tty;
+ {
+   access_breakpoint_command (arg, from_tty, access_break_write);
+ }
+ static void
+ rw_access_breakpoint_command (arg, from_tty)
+      char *arg;
+      int from_tty;
+ {
+   access_breakpoint_command (arg, from_tty, access_break_rw);
+ }
+ 
+ #endif /* HAVE_MEM_BREAKPOINT */
+ 
  
  /*
   * Helper routine for the until_command routine in infcmd.c.  Here
***************
*** 2051,2056 ****
--- 2216,2224 ----
        ALL_BREAKPOINTS (b)
  	while (b->next
  	       && b->next->type != bp_watchpoint
+ #ifdef HAVE_MEM_BREAKPOINT
+ 	       && b->next->type != bp_accesspoint
+ #endif /* HAVE_MEM_BREAKPOINT */
  	       && (sal.pc ? b->next->address == sal.pc
  		   : (b->next->symtab == sal.symtab
  		      && b->next->line_number == sal.line)))
***************
*** 2220,2225 ****
--- 2388,2396 ----
        break;
      default:
        printf_filtered ("Deleting unknown breakpoint type %d\n", b->type);
+ #ifdef HAVE_MEM_BREAKPOINT
+     case bp_accesspoint:
+ #endif /*HAVE_MEM_BREAKPOINT */
      case bp_until:
      case bp_finish:
      case bp_longjmp:
***************
*** 2596,2601 ****
--- 2767,2783 ----
  This command may be abbreviated \"delete\".",
  	   &deletelist);
  
+ #ifdef HAVE_MEM_BREAKPOINT
+   add_com ("wbreak", class_breakpoint, write_access_breakpoint_command,
+ 	   "Set a memory write breakpoint at a location.\n\
+ A memory write breakpoint stops execution of your program whenever it\n\
+ tries to write data at that location.");
+ 
+   add_com ("abreak", class_breakpoint, rw_access_breakpoint_command,
+ 	   "Set a memory acsess breakpoint at a location.\n\
+ A memory acsess breakpoint stops execution of your program whenever it\n\
+ tries to read or write data at that location.");
+ #endif /* HAVE_MEM_BREAKPOINT */
    add_com ("clear", class_breakpoint, clear_command,
  	   "Clear breakpoint at specified line or function.\n\
  Argument may be line number, function name, or \"*\" and an address.\n\
***************
*** 2624,2629 ****
--- 2806,2848 ----
    add_com_alias ("bre", "break", class_run, 1);
    add_com_alias ("brea", "break", class_run, 1);
  
+ 
+ #ifdef HAVE_MEM_BREAKPOINT
+   add_info ("breakpoints", breakpoints_info,
+ 	    "Status of user-settable breakpoints, or breakpoint number NUMBER.\n\
+ The \"Type\" column indicates one of:\n\
+ \tbreakpoint     - for normal breakpoints\n\
+ \twatchpoint     - for watchpoints\n\
+ \taccesspoint    - for memory access breakpoints\n\
+ The \"Disp\" column contains one of \"keep\", \"del\", or \"dis\" to indicate\n\
+ the disposition of the breakpoint after it gets hit.  \"dis\" means that the\n\
+ breakpoint will be disabled.  The \"Address\" and \"What\" columns indicate the\n\
+ address and file/line number respectively.\n\n\
+ Convenience variable \"$_\" and default examine address for \"x\"\n\
+ are set to the address of the last breakpoint listed.\n\n\
+ Convenience variable \"$bpnum\" contains the number of the last\n\
+ breakpoint set.");
+ 
+   add_info ("all-breakpoints", all_breakpoints_info,
+ 	    "Status of all breakpoints, or breakpoint number NUMBER.\n\
+ The \"Type\" column indicates one of:\n\
+ \tbreakpoint     - for normal breakpoints\n\
+ \twatchpoint     - for watchpoints\n\
+ \taccesspoint    - for memory access breakpoints\n\
+ \tlongjmp        - for internal breakpoints to handle stepping through longjmp()\n\
+ \tlongjmp resume - for internal breakpoints at the target of longjmp()\n\
+ \tuntil          - for internal breakpoints used by the \"until\" command\n\
+ \tfinish         - for internal breakpoints used by the \"finish\" command\n\
+ The \"Disp\" column contains one of \"keep\", \"del\", or \"dis\" to indicate\n\
+ the disposition of the breakpoint after it gets hit.  \"dis\" means that the\n\
+ breakpoint will be disabled.  The \"Address\" and \"What\" columns indicate the\n\
+ address and file/line number respectively.\n\n\
+ Convenience variable \"$_\" and default examine address for \"x\"\n\
+ are set to the address of the last breakpoint listed.\n\n\
+ Convenience variable \"$bpnum\" contains the number of the last\n\
+ breakpoint set.");
+ #else /* !HAVE_MEM_BREAKPOINT */
+ 
    add_info ("breakpoints", breakpoints_info,
  	    "Status of user-settable breakpoints, or breakpoint number NUMBER.\n\
  The \"Type\" column indicates one of:\n\
***************
*** 2655,2660 ****
--- 2874,2880 ----
  are set to the address of the last breakpoint listed.\n\n\
  Convenience variable \"$bpnum\" contains the number of the last\n\
  breakpoint set.");
+ #endif /* !HAVE_MEM_BREAKPOINT */
  
    add_com ("catch", class_breakpoint, catch_command,
           "Set breakpoints to catch exceptions that are raised.\n\
diff -c -B ./breakpoint.h ../../gdb-4.5.new/gdb/breakpoint.h
*** ./breakpoint.h	Wed Apr  1 13:46:00 1992
--- ../../gdb-4.5.new/gdb/breakpoint.h	Wed Apr 15 11:49:58 1992
***************
*** 130,135 ****
--- 131,139 ----
    bp_watchpoint,		/* Watchpoint */
    bp_longjmp,			/* secret breakpoint to find longjmp() */
    bp_longjmp_resume		/* secret breakpoint to escape longjmp() */
+ #ifdef HAVE_MEM_BREAKPOINT
+   ,bp_accesspoint		/* Memory access breakpoint */
+ #endif /* HAVE_MEM_BREAKPOINT */
  };
  
  /* States of enablement of breakpoint. */
***************
*** 144,149 ****
--- 148,157 ----
    donttouch			/* Leave it alone */
  };
  
+ #ifdef HAVE_MEM_BREAKPOINT
+ enum access_break_type {access_break_write, access_break_rw};
+ #endif /* HAVE_MEM_BREAKPOINT */
+ 
  /* Note that the ->silent field is not currently used by any commands
     (though the code is in there if it was to be, and set_raw_breakpoint
     does set it to 0).  I implemented it because I thought it would be
***************
*** 210,215 ****
--- 218,234 ----
    struct block *exp_valid_block;
    /* Value of the watchpoint the last time we checked it.  */
    value val;
+ 
+ #ifdef HAVE_MEM_BREAKPOINT
+    /* Address to memory break at.  */
+    CORE_ADDR access_break_address;
+    /* length of block to look at */
+    int access_break_length;
+    /* expression for address to look at */
+    struct expression *access_break_exp;
+    /* set to mem_break_write, or mem_break_rw if this is a memory breakpoint.*/
+    enum access_break_type access_break_type;
+ #endif /* HAVE_MEM_BREAKPOINT */
  };
  
  /* Prototypes for breakpoint-related functions.  */
diff -c -B ./core.c ../../gdb-4.5.new/gdb/core.c
*** ./core.c	Sun Mar 29 17:26:29 1992
--- ../../gdb-4.5.new/gdb/core.c	Tue Apr 14 16:50:08 1992
***************
*** 452,457 ****
--- 452,460 ----
  	core_stratum, 0, /* next */
  	0, 1, 1, 1, 0,	/* all mem, mem, stack, regs, exec */
  	0, 0,			/* section pointers */
+ #ifdef HAVE_MEM_BREAKPOINT
+     0, 0, 0, 0,         /* init, insert, get, clear */				    
+ #endif
  	OPS_MAGIC,		/* Always the last thing */
  };
  
diff -c -B ./exec.c ../../gdb-4.5.new/gdb/exec.c
*** ./exec.c	Tue Mar 31 10:16:32 1992
--- ../../gdb-4.5.new/gdb/exec.c	Tue Apr 14 16:50:09 1992
***************
*** 418,423 ****
--- 418,426 ----
  	file_stratum, 0, /* next */
  	0, 1, 0, 0, 0,	/* all mem, mem, stack, regs, exec */
  	0, 0,			/* section pointers */
+ #ifdef HAVE_MEM_BREAKPOINT
+     0, 0, 0, 0,         /* init, insert, get, clear */				    
+ #endif
  	OPS_MAGIC,		/* Always the last thing */
  };
  
diff -c -B ./i386-xdep.c ../../gdb-4.5.new/gdb/i386-xdep.c
*** ./i386-xdep.c	Sat Mar 14 19:08:36 1992
--- ../../gdb-4.5.new/gdb/i386-xdep.c	Wed Apr 15 12:32:07 1992
***************
*** 31,36 ****
--- 31,41 ----
  #include <sys/dir.h>
  #include <signal.h>
  #include <sys/user.h>
+ #ifdef HAVE_MEM_BREAKPOINT
+ #include "breakpoint.h"
+ #include <sys/debugreg.h>
+ #endif /* HAVE_MEM_BREAKPOINT */
+ 
  #include <sys/ioctl.h>
  #include <fcntl.h>
  
***************
*** 44,49 ****
--- 49,192 ----
  
  extern struct ext_format ext_format_i387;
  
+ 
+ #ifdef HAVE_MEM_BREAKPOINT
+ #define u_offset(a, b) ((int)((char *)(&(a.b))-(char *)(&a)))
+ 
+ static int free_debug_register;
+ static int debug_control_mirror;
+ /* record here which breakpoint associates with which register */
+ static int breakpoint_lookup[DR_LASTADDR + 1];
+ 
+ void clear_access_breakpoint_status()
+ {
+   ptrace(6, inferior_pid, u_offset(u, u_debugreg[DR_STATUS]), 0);
+ }
+ 
+ int get_access_breakpoint_status()
+ {
+   int i;
+   int status;
+ 
+   status = ptrace(3, inferior_pid, u_offset(u, u_debugreg[DR_STATUS]), 0);
+ 
+   for(i = 0; i <= DR_LASTADDR; i++)
+     {
+       if(status & (1 << i))
+ 	return(breakpoint_lookup[i]);
+     }
+ }
+ 
+ void init_access_breakpoint()
+ {
+   int i;
+   /* Clear the status register so only new status info is shown.
+      Turn off debugging by clearing control register */
+   ptrace(6, inferior_pid, u_offset(u, u_debugreg[DR_STATUS]), 0);
+   ptrace(6, inferior_pid, u_offset(u, u_debugreg[DR_CONTROL]), 0);
+   debug_control_mirror = 0;
+   free_debug_register = DR_FIRSTADDR;
+   for(i = 0; i <= DR_LASTADDR; i++)
+     breakpoint_lookup[i] = 0;
+ }
+ 
+ static int size_try_array[16] = {
+   1, 1, 1, 1,			/* trying size one */
+   2, 1, 2, 1,			/* trying size two */
+   2, 1, 2, 1,			/* trying size three */
+   4, 1, 2, 1			/* trying size four */
+ };
+ 
+ static int insert_nonaligned_access_breakpoint(addr, length, mode, breakpoint) 
+ CORE_ADDR addr;
+ int length;
+ enum access_break_type mode;
+ int breakpoint;
+ {
+   int align;
+   int size;
+   int rv;
+ 
+   rv = 0;
+   while(length > 0)
+     {
+       align = addr % 4;
+       size = (length > 4) ? 3 : length - 1;	/*four is the maximum length for 386*/
+       size = size_try_array[size * 4 + align];
+ 
+       if(rv = insert_access_breakpoint(addr, size, mode, breakpoint))
+ 	return rv;
+       addr += size;
+       length -= size;
+     }
+   return rv;
+ }
+ 
+ 
+ 
+ int insert_access_breakpoint(addr, length, mode, breakpoint)
+ CORE_ADDR addr;
+ int length;
+ enum access_break_type mode;
+ int breakpoint;
+ {
+   int rv;
+   int read_write_bits, len_bits;
+   
+   if(access_break_write == mode)
+     read_write_bits = DR_RW_WRITE;
+   else if(access_break_rw == mode)
+     read_write_bits = DR_RW_READ;
+   else
+     return 1;			/* bad mode! */
+ 
+   if(free_debug_register > DR_LASTADDR)
+     return 1;			/* no more debug registers! */
+ 
+   if(1 == length)
+     {
+       len_bits = DR_LEN_1;
+     }
+   else if(2 == length)
+     {
+       if(addr % 2)
+ 	return(insert_nonaligned_access_breakpoint(addr, length, mode,
+ 						   breakpoint));
+       len_bits = DR_LEN_2;
+     }
+ 
+   else if(4 == length)
+     {
+       if(addr % 4)
+ 	return(insert_nonaligned_access_breakpoint(addr, length, mode,
+ 						   breakpoint));
+       len_bits = DR_LEN_4;
+     }
+   else
+     {
+       return(insert_nonaligned_access_breakpoint(addr, length, mode,
+ 						 breakpoint));
+     }
+   
+   debug_control_mirror |= ((read_write_bits | len_bits) << 
+     (DR_CONTROL_SHIFT + DR_CONTROL_SIZE * free_debug_register));
+   debug_control_mirror |= (1 << (DR_LOCAL_ENABLE_SHIFT +
+ 				 DR_ENABLE_SIZE * free_debug_register));
+   debug_control_mirror |= DR_LOCAL_SLOWDOWN;
+   debug_control_mirror &= ~DR_CONTROL_RESERVED;
+   
+   ptrace(6, inferior_pid,
+ 	 u_offset(u, u_debugreg[DR_CONTROL]), debug_control_mirror);
+   ptrace(6, inferior_pid, u_offset(u, u_debugreg[free_debug_register]), addr);
+   /* record where we came from */
+   breakpoint_lookup[free_debug_register] = breakpoint;
+   free_debug_register++;
+   return 0;
+ }
+ #endif /* HAVE_MEM_BREAKPOINT */
+ 
+ 
+ 
  /* this table must line up with REGISTER_NAMES in m-i386.h */
  /* symbols like 'EAX' come from <sys/reg.h> */
  static int regmap[] = 
diff -c -B ./infrun.c ../../gdb-4.5.new/gdb/infrun.c
*** ./infrun.c	Thu Apr  2 04:34:48 1992
--- ../../gdb-4.5.new/gdb/infrun.c	Wed Apr 15 13:18:29 1992
***************
*** 331,336 ****
--- 331,340 ----
    DO_DEFERRED_STORES;
  #endif
  
+ #ifdef HAVE_MEM_BREAKPOINT
+   target_clear_access_breakpoint_status();
+ #endif	/* HAVE_MEM_BREAKPOINT */
+ 
    target_resume (step, sig);
    discard_cleanups (old_cleanups);
  }
***************
*** 1082,1087 ****
--- 1086,1094 ----
  	      default:
  		fprintf(stderr, "Unknown breakpoint type %d\n",
  			stop_bpstat->breakpoint_at->type);
+ #ifdef HAVE_MEM_BREAKPOINT
+ 	      case bp_accesspoint:
+ #endif /* HAVE_MEM_BREAKPOINT */
  	      case bp_watchpoint:
  	      case bp_breakpoint:
  	      case bp_until:
diff -c -B ./inftarg.c ../../gdb-4.5.new/gdb/inftarg.c
*** ./inftarg.c	Sun Mar 29 17:21:27 1992
--- ../../gdb-4.5.new/gdb/inftarg.c	Wed Apr 15 11:49:53 1992
***************
*** 42,47 ****
--- 42,56 ----
  static void
  child_detach PARAMS ((char *, int));
  
+ #ifdef HAVE_MEM_BREAKPOINT
+ extern void init_memory_breakpoint();
+ extern int insert_memory_breakpoint();
+ extern int get_memory_breakpoint_status();
+ extern void clear_memory_breakpoint_status();
+ #endif /* HAVE_MEM_BREAKPOINT */
+ 
+ 
+ 
  /* Forward declaration */
  extern struct target_ops child_ops;
  
***************
*** 208,213 ****
--- 217,228 ----
    1,				/* to_has_execution */
    0,				/* sections */
    0,				/* sections_end */
+ #ifdef HAVE_MEM_BREAKPOINT
+   init_access_breakpoint,         /* init, insert, get, clear */
+   insert_access_breakpoint,
+   get_access_breakpoint_status,
+   clear_access_breakpoint_status,
+ #endif
    OPS_MAGIC			/* to_magic */
  };
  
diff -c -B ./remote.c ../../gdb-4.5.new/gdb/remote.c
*** ./remote.c	Thu Apr  2 04:34:55 1992
--- ../../gdb-4.5.new/gdb/remote.c	Wed Apr 15 11:49:52 1992
***************
*** 1034,1039 ****
--- 1034,1045 ----
    1,				/* to_has_execution */
    NULL,				/* sections */
    NULL,				/* sections_end */
+ #ifdef HAVE_MEM_BREAKPOINT
+   NULL,                         /* accesspoint init */
+   NULL,                         /* accesspoint insert */
+   NULL,                         /* accesspoint get */
+   NULL,                         /* accesspoint clear */
+ #endif
    OPS_MAGIC			/* to_magic */
  };
  
diff -c -B ./target.c ../../gdb-4.5.new/gdb/target.c
*** ./target.c	Sun Mar 29 17:14:33 1992
--- ../../gdb-4.5.new/gdb/target.c	Wed Apr 15 11:23:12 1992
***************
*** 88,93 ****
--- 88,96 ----
      dummy_stratum, 0,	/* stratum, next */
      0, 0, 0, 0, 0,	/* all mem, mem, stack, regs, exec */
      0, 0,		/* section pointers */
+ #ifdef HAVE_MEM_BREAKPOINT
+     0, 0, 0, 0,         /* init, insert, get, clear */				    
+ #endif
      OPS_MAGIC,
  };
  
***************
*** 331,337 ****
    de_fault (to_has_stack,		0);
    de_fault (to_has_registers,		0);
    de_fault (to_has_execution,		0);
! 
  #undef de_fault
  }
  
--- 334,345 ----
    de_fault (to_has_stack,		0);
    de_fault (to_has_registers,		0);
    de_fault (to_has_execution,		0);
! #ifdef HAVE_MEM_BREAKPOINT
!   de_fault (to_init_access_breakpoint,	init_access_breakpoint);
!   de_fault (to_insert_access_breakpoint,	insert_access_breakpoint);
!   de_fault (to_get_access_breakpoint_status,	get_access_breakpoint_status);
!   de_fault (to_clear_access_breakpoint_status,	clear_access_breakpoint_status);
! #endif /* HAVE_MEM_BREAKPOINT */
  #undef de_fault
  }
  
diff -c -B ./target.h ../../gdb-4.5.new/gdb/target.h
*** ./target.h	Fri Feb 21 19:46:03 1992
--- ../../gdb-4.5.new/gdb/target.h	Wed Apr 15 12:18:35 1992
***************
*** 39,45 ****
     never get to the process target).  So when you push a file target,
     it goes into the file stratum, which is always below the process
     stratum.  */
! 
  #include "bfd.h"
  
  enum strata {
--- 39,45 ----
     never get to the process target).  So when you push a file target,
     it goes into the file stratum, which is always below the process
     stratum.  */
! #include "breakpoint.h"
  #include "bfd.h"
  
  enum strata {
***************
*** 94,99 ****
--- 94,106 ----
      	       *to_sections;
    struct section_table
  	       *to_sections_end;
+ #ifdef HAVE_MEM_BREAKPOINT
+   void    (* to_init_access_breakpoint) PARAMS ((void));
+   int     (*to_insert_access_breakpoint) PARAMS ((CORE_ADDR, int,
+ 					 enum access_break_type, int));
+   int     (* to_get_access_breakpoint_status) PARAMS ((void));
+   void    (* to_clear_access_breakpoint_status) PARAMS ((void));
+ #endif /* HAVE_MEM_BREAKPOINT */
    int		to_magic;
    /* Need sub-structure for target machine related rather than comm related? */
  };
***************
*** 222,227 ****
--- 229,266 ----
  
  #define	target_files_info()	\
  	(*current_target->to_files_info) (current_target)
+ 
+ #ifdef HAVE_MEM_BREAKPOINT
+ extern void
+ init_access_breakpoint PARAMS ((void));
+ extern int
+ insert_access_breakpoint PARAMS ((CORE_ADDR, int,
+ 				  enum access_break_type, int));
+ extern int
+ get_access_breakpoint_status PARAMS ((void));
+ extern void
+ clear_access_breakpoint_status PARAMS ((void));
+ 
+ 
+ /* Initialize (clear), and set memory access breakpoints.  This is probably
+    done with hardware debug registers in the cpu.  Result is 0 for success,
+    or errno value for failure.  If there is a failure there probably are not
+    any more debug registers left.  */
+ 
+ #define target_init_access_breakpoint() (*current_target->to_init_access_breakpoint)()
+ 
+ #define target_insert_access_breakpoint(addr, len, type, bp_num) \
+   (*current_target->to_insert_access_breakpoint)(addr, len, type, bp_num)
+ 
+ /* Return the breakpoint number that caused the memory access breakpoint.
+    Returns 0 if no memory acess breakpoint */
+ #define target_get_access_breakpoint_status() \
+   (*current_target->to_get_access_breakpoint_status)()
+ 
+ /* Clear the memory breakpoint status.  Called before execution is resumed*/
+ #define target_clear_access_breakpoint_status() \
+   (*current_target->to_clear_access_breakpoint_status)()
+ #endif /* HAVE_MEM_BREAKPOINT */
  
  /* Insert a breakpoint at address ADDR in the target machine.
     SAVE is a pointer to memory allocated for saving the

Newsgroups: gnu.gdb.bug