From: daney@mermaid.micro.umn.edu (Dave Daney)
Subject: Hardware Debug Registers on 386
Organization: GNUs Not Usenet
Distribution: gnu
Date: Mon, 13 Apr 1992 18:44:00 GMT

Greetings,

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

I have made a few modifications to gdb-4.4 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 class of breakpoint.  I thought that
they should be seperate from watchpoints because watchpoints break on
a whole expression changing.  Which I think is much different than
a breakpoint on a memory access.  Any how there are three new commands.

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

info memorypoints:  Lists them all out (just like info break).

They can be set on any expression that evaluates to 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

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.

There is also a small patch to coffread.c in this diff to make user defined
types work.  I think It should also be integrated into gdb.  The final patch
is to trad-core.c to get core files to work on this machine.  I don't know
how it pertains to other machines.

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.




 these are the commands used to build gdb-4.4 from the main Makefile
 i.e. not the one in gdb/.

gmake CC="gcc -traditional" 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

-----------------------<diffs for gdb/>------------------------
diff -c -B ./breakpoint.c ../../gdb-4.4.dave/gdb/breakpoint.c
*** ./breakpoint.c	Mon Jan 27 20:57:01 1992
--- ../../gdb-4.4.dave/gdb/breakpoint.c	Mon Apr 13 20:02:36 1992
***************
*** 98,104 ****
    struct expression *cond;
  
    /* String we used to set the breakpoint (malloc'd).  Only matters if
!      address is non-NULL.  */
    char *addr_string;
    /* String form of the breakpoint condition (malloc'd), or NULL if there
       is no condition.  */
--- 99,105 ----
    struct expression *cond;
  
    /* String we used to set the breakpoint (malloc'd).  Only matters if
!      address is non-NULL, or if mem_break_enable is not mem_break_disabled.  */
    char *addr_string;
    /* String form of the breakpoint condition (malloc'd), or NULL if there
       is no condition.  */
***************
*** 111,116 ****
--- 112,129 ----
    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 mem_break_address;
+   /* length of block to look at */
+   int mem_break_length;
+   /* expression for address to look at */
+   struct expression *mem_break_exp;
+   /* set to mem_break_read, mem_break_write, or mem_break_rw if this is a
+    memory breakpoint.*/
+   enum mem_break_enable mem_break_enable;
+ #endif /* HAVE_MEM_BREAKPOINT */
+ 
  };
  
  #define ALL_BREAKPOINTS(b)  for (b = breakpoint_chain; b; b = b->next)
***************
*** 408,414 ****
  		if (!disabled_breaks)
  		  {
  		    fprintf (stderr,
! 			 "Cannot insert breakpoint %d:\n", b->number);
  		    printf_filtered ("Disabling shared library breakpoints:\n");
  		  }
  		disabled_breaks = 1;
--- 421,427 ----
  		if (!disabled_breaks)
  		  {
  		    fprintf (stderr,
! 			     "Cannot insert breakpoint %d:\n", b->number);
  		    printf_filtered ("Disabling shared library breakpoints:\n");
  		  }
  		disabled_breaks = 1;
***************
*** 420,426 ****
  		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 */
  	      }
--- 433,439 ----
  		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 */
  	      }
***************
*** 430,435 ****
--- 443,469 ----
        }
    if (disabled_breaks)
      printf_filtered ("\n");
+ 
+ #ifdef HAVE_MEM_BREAKPOINT
+   target_init_memory_breakpoint();
+ 
+   ALL_BREAKPOINTS (b)
+     if (b->mem_break_enable != mem_break_disabled
+ 	&& b->enable != disabled)
+       {
+ 	int rv;
+ 	rv = target_insert_memory_breakpoint(b->mem_break_address, b->mem_break_length,
+ 					      b->mem_break_enable, 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;
  }
  
***************
*** 459,464 ****
--- 493,501 ----
  		local_hex_string(b->shadow_contents[1]));
  #endif /* BREAKPOINT_DEBUG */
        }
+ #ifdef HAVE_MEM_BREAKPOINT
+   target_init_memory_breakpoint();
+ #endif /* HAVE_MEM_BREAKPOINT */
  
    return 0;
  }
***************
*** 664,670 ****
        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
--- 701,724 ----
        bs->old_val = NULL;
        return 1;
      }
! #ifdef HAVE_MEM_BREAKPOINT
!   if (bs->breakpoint_at->mem_break_enable != mem_break_disabled)
!     {
!       printf_filtered ("\nMemory Breakpoint %d, ", bs->breakpoint_at->number);
!       printf_filtered ("%-10s",
! 		       local_hex_string(bs->breakpoint_at->mem_break_address));
!       printf_filtered ("  ");
!       if(bs->breakpoint_at->mem_break_enable == mem_break_write)
! 	printf_filtered ("w  ");
!       else
! 	printf_filtered ("r/w");
!       printf_filtered ("  ");
!       printf_filtered ("%d   ", bs->breakpoint_at->mem_break_length);
!       print_expression (bs->breakpoint_at->mem_break_exp, stdout);
!       printf_filtered ("\n");
!       return 1;
!     }
! #endif
    /* 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
***************
*** 739,744 ****
--- 793,801 ----
    /* True if we've hit a breakpoint (as opposed to a watchpoint).  */
    int real_breakpoint = 0;
  #endif
+ #ifdef HAVE_MEM_BREAKPOINT
+   int memory_breakpoint = target_get_memory_breakpoint_status();
+ #endif
    /* Root of the chain of bpstat's */
    struct bpstat__struct root_bs[1];
    /* Pointer to the last thing in the chain currently.  */
***************
*** 757,762 ****
--- 814,827 ----
        if (b->address != 0 && b->address != bp_addr)
  	continue;
  
+ #ifdef HAVE_MEM_BREAKPOINT
+       if ((b->mem_break_enable != mem_break_disabled) &&
+ 	  (b->number != memory_breakpoint))
+ 	continue;
+ #endif
+ 
+ 
+ 
        bs = bpstat_alloc (b, bs);	/* Alloc a bpstat to explain stop */
  
        this_bp_stop = 1;
***************
*** 815,822 ****
--- 882,894 ----
  	    }
  	}
  #if DECR_PC_AFTER_BREAK != 0 || defined (SHIFT_INST_REGS)
+ #ifdef HAVE_MEM_BREAKPOINT
+       else if (b->mem_break_enable == mem_break_disabled)
+ 	real_breakpoint = 1;
+ #else
        else
  	real_breakpoint = 1;
+ #endif /* HAVE_MEM_BREAKPOINT  */
  #endif
  
        if (b->frame && b->frame != frame_address)
***************
*** 907,913 ****
  
  /* 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, watchpoints)
--- 979,986 ----
  
  /* Print information on breakpoint number BNUM, or -1 if all.
     If WATCHPOINTS is zero, process only breakpoints; if WATCHPOINTS
!    is one, process only watchpoints; if WATCHPOINTS is two, process
!    only memory break points.*/
  
  static void
  breakpoint_1 (bnum, watchpoints)
***************
*** 923,935 ****
    ALL_BREAKPOINTS (b)
      if (bnum == -1 || bnum == b->number)
        {
  	if (b->address == 0 && !watchpoints)
  	  {
  	    if (bnum == -1)
  	      continue;
  	    error ("That is a watchpoint, not a breakpoint.");
  	  }
! 	if (b->address != 0 && watchpoints)
  	  {
  	    if (bnum == -1)
  	      continue;
--- 996,1019 ----
    ALL_BREAKPOINTS (b)
      if (bnum == -1 || bnum == b->number)
        {
+ #ifdef HAVE_MEM_BREAKPOINT
+ 	if (b->address == 0 && b->mem_break_enable == mem_break_disabled
+ 	    && watchpoints == 0)
+ #else
  	if (b->address == 0 && !watchpoints)
+ #endif /* HAVE_MEM_BREAKPOINT */
  	  {
  	    if (bnum == -1)
  	      continue;
  	    error ("That is a watchpoint, not a breakpoint.");
  	  }
! 
! #ifdef HAVE_MEM_BREAKPOINT
! 	if (b->address != 0 && b->mem_break_enable == mem_break_disabled
! 	    && watchpoints == 1)
! #else
! 	if (b->address != 0 && watchpoints == 1)
! #endif /* HAVE_MEM_BREAKPOINT */
  	  {
  	    if (bnum == -1)
  	      continue;
***************
*** 936,945 ****
  	    error ("That is a breakpoint, not a watchpoint.");
  	  }
  
  	if (!header_printed)
  	  {
! 	    if (watchpoints)
  	      printf_filtered ("    Enb   Expression\n");
  	    else if (addressprint)
  	      printf_filtered ("    Enb   Address    Where\n");
  	    else
--- 1020,1065 ----
  	    error ("That is a breakpoint, not a watchpoint.");
  	  }
  
+ #ifdef HAVE_MEM_BREAKPOINT
+ 	if (b->address == 0 && b->mem_break_enable == mem_break_disabled
+ 	    && watchpoints == 2)
+ 	  {
+ 	    if (bnum == -1)
+ 	      continue;
+ 	    error ("That is a watchpoint, not a memory breakpoint.");
+ 	  }
+ 
+ 	if (b->address != 0 && b->mem_break_enable == mem_break_disabled
+ 	    && watchpoints == 2)
+ 	  {
+ 	    if (bnum == -1)
+ 	      continue;
+ 	    error ("That is a breakpoint, not a memory breakpoint.");
+ 	  }
+ 
+ 	if (b->address == 0 && b->mem_break_enable != mem_break_disabled
+ 	    && watchpoints == 0)
+ 	  {
+ 	    if (bnum == -1)
+ 	      continue;
+ 	    error ("That is a memory breakpoint, not a normal breakpoint.");
+ 	  }
+ 
+ 	if (b->address == 0 && b->mem_break_enable != mem_break_disabled
+ 	    && watchpoints == 1)
+ 	  {
+ 	    if (bnum == -1)
+ 	      continue;
+ 	    error ("That is a memory breakpoint, not a watchpoint.");
+ 	  }
+ #endif /* HAVE_MEM_BREAKPOINT */
+ 
  	if (!header_printed)
  	  {
! 	    if (watchpoints == 1)
  	      printf_filtered ("    Enb   Expression\n");
+ 	    else if (watchpoints == 2)
+ 	      printf_filtered ("    Enb   Address   R/W size Expression\n");
  	    else if (addressprint)
  	      printf_filtered ("    Enb   Address    Where\n");
  	    else
***************
*** 948,960 ****
  	  }
  
  	printf_filtered ("#%-3d %c ", b->number, "nyod"[(int) b->enable]);
! 	if (b->address == 0) {
! 	  printf_filtered (" ");
! 	  print_expression (b->exp, stdout);
! 	} else {
  	    if (addressprint)
  	      printf_filtered (" %s ", local_hex_string_custom(b->address, "08"));
! 
  	    last_addr = b->address;
  	    if (b->symtab)
  	      {
--- 1068,1101 ----
  	  }
  
  	printf_filtered ("#%-3d %c ", b->number, "nyod"[(int) b->enable]);
! 	if (b->address == 0)
! 	  {
! 	    printf_filtered (" ");
! #ifdef HAVE_MEM_BREAKPOINT
! 	    if(b->mem_break_enable == mem_break_disabled)
! 	      print_expression (b->exp, stdout);
! 	    else
! 	      {
! 		printf_filtered ("%-10s", local_hex_string(b->mem_break_address));
! 		printf_filtered ("  ");
! 		if(b->mem_break_enable == mem_break_write)
! 		  printf_filtered ("w  ");
! 		else
! 		  printf_filtered ("r/w");
! 		printf_filtered ("  ");
! 		printf_filtered ("%d   ", b->mem_break_length);
! 		print_expression (b->mem_break_exp, stdout);
! 
! 	      }
! #else
! 	    print_expression (b->exp, stdout);
! #endif /* HAVE_MEM_BREAKPOINT */
! 	  } 
! 	else
! 	  {
  	    if (addressprint)
  	      printf_filtered (" %s ", local_hex_string_custom(b->address, "08"));
! 	    
  	    last_addr = b->address;
  	    if (b->symtab)
  	      {
***************
*** 997,1003 ****
--- 1138,1154 ----
  
    if (!header_printed)
      {
+ #ifdef HAVE_MEM_BREAKPOINT
+       char *which;
+       if(watchpoints == 0)
+ 	which = "break";
+       else if(watchpoints == 1)
+ 	which = "watch";
+       else
+ 	which = "memory break";
+ #else
        char *which = watchpoints ? "watch" : "break";
+ #endif
        if (bnum == -1)
  	printf_filtered ("No %spoints.\n", which);
        else
***************
*** 1037,1043 ****
--- 1188,1208 ----
  
    breakpoint_1 (bnum, 1);
  }
+ #ifdef HAVE_MEM_BREAKPOINT
+ /* ARGSUSED */
+ static void
+ memory_breakpoint_info (bnum_exp, from_tty)
+      char *bnum_exp;
+      int from_tty;
+ {
+   int bnum = -1;
+ 
+   if (bnum_exp)
+     bnum = parse_and_eval_address (bnum_exp);
  
+   breakpoint_1 (bnum, 2);
+ }
+ #endif /* HAVE_MEM_BREAKPOINT */
  /* Print a message describing any breakpoints set at PC.  */
  
  static void
***************
*** 1093,1099 ****
    register struct breakpoint *b;
    register int count = 0;
  
!   if (address == 0)		/* Watchpoints are uninteresting */
      return;
  
    ALL_BREAKPOINTS (b)
--- 1258,1264 ----
    register struct breakpoint *b;
    register int count = 0;
  
!   if (address == 0)		/* Watchpoints and memorypoints are uninteresting */
      return;
  
    ALL_BREAKPOINTS (b)
***************
*** 1189,1194 ****
--- 1354,1366 ----
        printf_filtered ("Watchpoint %d: ", b->number);
        print_expression (b->exp, stdout);
      }
+ #ifdef HAVE_MEM_BREAKPOINT
+   else if (b->mem_break_enable != mem_break_disabled)
+     {
+       printf_filtered ("Memory breakpoint %d at %s", b->number,
+ 		       local_hex_string(b->mem_break_address));
+     }
+ #endif
    else
      {
        printf_filtered ("Breakpoint %d at %s", b->number,
***************
*** 1427,1432 ****
--- 1599,1664 ----
    b->cond_string = NULL;
    mention (b);
  }
+ 
+ #ifdef HAVE_MEM_BREAKPOINT
+ /* ARGSUSED */
+ static void
+ memory_breakpoint_command (arg, from_tty, mode)
+      char *arg;
+      int from_tty;
+      enum mem_break_enable mode;
+ {
+   struct breakpoint *b;
+   struct symtab_and_line sal;
+   struct expression *exp;
+   struct block *exp_valid_block;
+   struct value *watch_obj;
+ 
+   sal.pc = 0;
+   sal.symtab = NULL;
+   sal.line = 0;
+   
+   /* Parse arguments.  */
+   innermost_block = NULL;
+   exp = parse_expression (arg);
+   exp_valid_block = innermost_block;
+   watch_obj = evaluate_expression (exp);
+ 
+   if(lval_memory != VALUE_LVAL(watch_obj))
+     error("requested  memory break 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->exp = 0;
+   b->exp_valid_block = NULL;
+   b->val = NULL;
+   b->cond = 0;
+   b->cond_string = NULL;
+   b->mem_break_exp = exp;
+   b->mem_break_address = VALUE_ADDRESS(watch_obj);
+   b->mem_break_length = TYPE_LENGTH(VALUE_TYPE(watch_obj));
+   b->mem_break_enable = mode;
+   mention (b);
+ }
+ static void
+ write_memory_breakpoint_command (arg, from_tty)
+      char *arg;
+      int from_tty;
+ {
+   memory_breakpoint_command (arg, from_tty, mem_break_write);
+ }
+ static void
+ access_memory_breakpoint_command (arg, from_tty)
+      char *arg;
+      int from_tty;
+ {
+   memory_breakpoint_command (arg, from_tty, mem_break_rw);
+ }
+ 
+ #endif /* HAVE_MEM_BREAKPOINT */
+ 
  
  /*
   * Helper routine for the until_command routine in infcmd.c.  Here
***************
*** 2435,2438 ****
--- 2667,2687 ----
    add_info ("watchpoints", watchpoints_info,
  	    "Status of all watchpoints, or watchpoint number NUMBER.\n\
  Second column is \"y\" for enabled watchpoints, \"n\" for disabled.");
+ #ifdef HAVE_MEM_BREAKPOINT
+   add_com ("wbreak", class_breakpoint, write_memory_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, access_memory_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.");
+ 
+   add_info ("memorypoints", memory_breakpoint_info,
+ 	    "Status of all memory access breakpoints, or memory access\n\
+ breakpoint number NUMBER.  Second column is \"y\" for enabled memory\n\
+ access breakpoints, \"n\" for disabled.");
+ 
+ #endif /* HAVE_MEM_BREAKPOINT */
  }
diff -c -B ./breakpoint.h ../../gdb-4.4.dave/gdb/breakpoint.h
*** ./breakpoint.h	Tue Jun  4 02:28:10 1991
--- ../../gdb-4.4.dave/gdb/breakpoint.h	Mon Apr 13 16:57:18 1992
***************
*** 19,24 ****
--- 19,30 ----
  #if !defined (BREAKPOINT_H)
  #define BREAKPOINT_H 1
  
+ #ifdef HAVE_MEM_BREAKPOINT
+ enum mem_break_enable { mem_break_disabled, mem_break_write, mem_break_rw};
+ #endif /* HAVE_MEM_BREAKPOINT */
+ 
+ 
+ 
  /* This is the maximum number of bytes a breakpoint instruction can take.
     Feel free to increase it.  It's just used in a few places to size
     arrays that should be independent of the target architecture.  */
diff -c -B ./coffread.c ../../gdb-4.4.dave/gdb/coffread.c
*** ./coffread.c	Sat Dec 28 13:37:51 1991
--- ../../gdb-4.4.dave/gdb/coffread.c	Fri Mar  6 14:08:04 1992
***************
*** 1870,1875 ****
--- 1870,1876 ----
        struct nextfield *next;
        struct field field;
      };
+   struct type **type_addr;
  
    register struct type *type;
    register struct nextfield *list = 0;
***************
*** 1933,1938 ****
--- 1934,1942 ----
  	    break;
  
  	  case C_EOS:
+ 	    /*  Put the type in the tag table */
+ 	    type_addr = coff_lookup_type(sub_aux.x_sym.x_tagndx.l);
+ 	    *type_addr = type;
  	    done = 1;
  	    break;
  	}
***************
*** 1964,1969 ****
--- 1968,1974 ----
       int lastsym;
  {
    register struct symbol *sym;
+   struct type ** type_addr;
    register struct type *type;
    int nsyms = 0;
    int done = 0;
***************
*** 2012,2017 ****
--- 2017,2025 ----
  	    /* Sometimes the linker (on 386/ix 2.0.2 at least) screws
  	       up the count of how many symbols to read.  So stop
  	       on .eos.  */
+ 	    /*  Put the type in the tag table */
+ 	    type_addr = coff_lookup_type(sub_aux.x_sym.x_tagndx.l);
+ 	    *type_addr = type;
  	    done = 1;
  	    break;
  	}
diff -c -B ./core.c ../../gdb-4.4.dave/gdb/core.c
*** ./core.c	Fri Jan 31 02:45:11 1992
--- ../../gdb-4.4.dave/gdb/core.c	Mon Apr 13 19:11:06 1992
***************
*** 434,439 ****
--- 434,442 ----
  	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.4.dave/gdb/exec.c
*** ./exec.c	Fri Jan 31 02:45:09 1992
--- ../../gdb-4.4.dave/gdb/exec.c	Mon Apr 13 19:11:05 1992
***************
*** 380,385 ****
--- 380,388 ----
  	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.4.dave/gdb/i386-xdep.c
*** ./i386-xdep.c	Thu Nov 21 12:40:12 1991
--- ../../gdb-4.4.dave/gdb/i386-xdep.c	Mon Apr 13 20:36:17 1992
***************
*** 32,37 ****
--- 32,42 ----
  #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>
  
***************
*** 48,53 ****
--- 53,196 ----
  
  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_memory_breakpoint_status()
+ {
+   ptrace(6, inferior_pid, u_offset(u, u_debugreg[DR_STATUS]), 0);
+ }
+ 
+ int get_memory_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_memory_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_memory_breakpoint(addr, length, mode, breakpoint) 
+ CORE_ADDR addr;
+ int length;
+ enum mem_break_enable 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_memory_breakpoint(addr, size, mode, breakpoint))
+ 	return rv;
+       addr += size;
+       length -= size;
+     }
+   return rv;
+ }
+ 
+ 
+ 
+ int insert_memory_breakpoint(addr, length, mode, breakpoint)
+ CORE_ADDR addr;
+ int length;
+ enum mem_break_enable mode;
+ int breakpoint;
+ {
+   int rv;
+   int read_write_bits, len_bits;
+   
+   if(mem_break_write == mode)
+     read_write_bits = DR_RW_WRITE;
+   else if(mem_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_memory_breakpoint(addr, length, mode,
+ 						   breakpoint));
+       len_bits = DR_LEN_2;
+     }
+ 
+   else if(4 == length)
+     {
+       if(addr % 4)
+ 	return(insert_nonaligned_memory_breakpoint(addr, length, mode,
+ 						   breakpoint));
+       len_bits = DR_LEN_4;
+     }
+   else
+     {
+       return(insert_nonaligned_memory_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.4.dave/gdb/infrun.c
*** ./infrun.c	Thu Jan 30 19:24:32 1992
--- ../../gdb-4.4.dave/gdb/infrun.c	Mon Apr 13 20:02:39 1992
***************
*** 294,299 ****
--- 294,303 ----
    DO_DEFERRED_STORES;
  #endif
  
+ #ifdef HAVE_MEM_BREAKPOINT
+   target_clear_memory_breakpoint_status();
+ #endif	/* HAVE_MEM_BREAKPOINT */
+ 
    target_resume (step, sig);
    discard_cleanups (old_cleanups);
  }

diff -c -B ./inftarg.c ../../gdb-4.4.dave/gdb/inftarg.c
*** ./inftarg.c	Thu Nov 21 12:40:30 1991
--- ../../gdb-4.4.dave/gdb/inftarg.c	Mon Apr 13 19:14:28 1992
***************
*** 41,46 ****
--- 41,55 ----
  extern void child_mourn_inferior();
  extern void child_attach ();
  
+ #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;
  
***************
*** 189,194 ****
--- 198,209 ----
  	process_stratum, 0, /* next */
  	1, 1, 1, 1, 1,	/* all mem, mem, stack, regs, exec */
  	0, 0,			/* Section pointers */
+ #ifdef HAVE_MEM_BREAKPOINT
+ 	init_memory_breakpoint,         /* init, insert, get, clear */
+ 	insert_memory_breakpoint,
+ 	get_memory_breakpoint_status,
+ 	clear_memory_breakpoint_status,
+ #endif
  	OPS_MAGIC,		/* Always the last thing */
  };
  
diff -c -B ./remote-adapt.c ../../gdb-4.4.dave/gdb/remote-adapt.c
*** ./remote-adapt.c	Thu Nov 21 12:41:05 1991
--- ../../gdb-4.4.dave/gdb/remote-adapt.c	Mon Apr 13 19:11:02 1992
***************
*** 1434,1439 ****
--- 1434,1443 ----
  	process_stratum, 0, /* next */
  	1, 1, 1, 1, 1,	/* 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 ./remote-eb.c ../../gdb-4.4.dave/gdb/remote-eb.c
*** ./remote-eb.c	Fri Dec 13 22:18:45 1991
--- ../../gdb-4.4.dave/gdb/remote-eb.c	Mon Apr 13 19:10:59 1992
***************
*** 996,1001 ****
--- 996,1004 ----
  	process_stratum, 0, /* next */
  	1, 1, 1, 1, 1,	/* 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 ./remote-hms.c ../../gdb-4.4.dave/gdb/remote-hms.c
*** ./remote-hms.c	Mon Jan 27 21:33:04 1992
--- ../../gdb-4.4.dave/gdb/remote-hms.c	Mon Apr 13 19:10:58 1992
***************
*** 1284,1289 ****
--- 1284,1292 ----
  	process_stratum, 0, /* next */
  	1, 1, 1, 1, 1,	/* 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 ./remote-mm.c ../../gdb-4.4.dave/gdb/remote-mm.c
*** ./remote-mm.c	Fri Sep 13 02:52:09 1991
--- ../../gdb-4.4.dave/gdb/remote-mm.c	Mon Apr 13 19:10:57 1992
***************
*** 1688,1693 ****
--- 1688,1696 ----
          process_stratum, 0, /* next */
          1, 1, 1, 1, 1,  /* all mem, mem, stack, regs, exec */
  	0,0,		/* sections, sections_end */
+ #ifdef HAVE_MEM_BREAKPOINT
+     0, 0, 0, 0,         /* init, insert, get, clear */				    
+ #endif
          OPS_MAGIC,              /* Always the last thing */
  };
  
diff -c -B ./remote-nindy.c ../../gdb-4.4.dave/gdb/remote-nindy.c
*** ./remote-nindy.c	Fri Dec 13 22:18:42 1991
--- ../../gdb-4.4.dave/gdb/remote-nindy.c	Mon Apr 13 19:10:56 1992
***************
*** 948,953 ****
--- 948,956 ----
  	process_stratum, 0, /* next */
  	1, 1, 1, 1, 1,	/* 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 ./remote-vx.c ../../gdb-4.4.dave/gdb/remote-vx.c
*** ./remote-vx.c	Fri Dec 13 22:18:44 1991
--- ../../gdb-4.4.dave/gdb/remote-vx.c	Mon Apr 13 19:10:55 1992
***************
*** 1440,1445 ****
--- 1440,1448 ----
  	core_stratum, 0, /* next */
  	1, 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 ./remote.c ../../gdb-4.4.dave/gdb/remote.c
*** ./remote.c	Thu Nov 21 12:41:13 1991
--- ../../gdb-4.4.dave/gdb/remote.c	Mon Apr 13 19:10:54 1992
***************
*** 845,850 ****
--- 845,853 ----
  	process_stratum, 0, /* next */
  	1, 1, 1, 1, 1,	/* 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 ./target.c ../../gdb-4.4.dave/gdb/target.c
*** ./target.c	Mon Jan 27 16:10:04 1992
--- ../../gdb-4.4.dave/gdb/target.c	Mon Apr 13 19:11:00 1992
***************
*** 34,39 ****
--- 34,46 ----
  extern int memory_insert_breakpoint(), memory_remove_breakpoint();
  extern void host_convert_to_virtual(), host_convert_from_virtual();
  
+ #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 */
+ 
  static void cleanup_target ();
  
  /* Pointer to array of target architecture structures; the size of the
***************
*** 61,66 ****
--- 68,76 ----
      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,
  };
  
***************
*** 303,309 ****
    de_fault (to_has_stack,		0);
    de_fault (to_has_registers,		0);
    de_fault (to_has_execution,		0);
! 
  #undef de_fault
  }
  
--- 313,324 ----
    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_memory_breakpoint,	init_memory_breakpoint);
!   de_fault (to_insert_memory_breakpoint,	insert_memory_breakpoint);
!   de_fault (to_get_memory_breakpoint_status,	get_memory_breakpoint_status);
!   de_fault (to_clear_memory_breakpoint_status,	clear_memory_breakpoint_status);
! #endif /* HAVE_MEM_BREAKPOINT */
  #undef de_fault
  }
  
diff -c -B ./target.h ../../gdb-4.4.dave/gdb/target.h
*** ./target.h	Tue Jan 14 18:40:34 1992
--- ../../gdb-4.4.dave/gdb/target.h	Mon Apr 13 17:36:34 1992
***************
*** 36,42 ****
     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 {
--- 36,42 ----
     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 {
***************
*** 91,96 ****
--- 91,103 ----
  	int	to_has_execution;
  struct section_table *sections;
  struct section_table *sections_end;
+ #ifdef HAVE_MEM_BREAKPOINT
+ 	void    (* to_init_memory_breakpoint)();
+ 	int     (*to_insert_memory_breakpoint)(CORE_ADDR *addrp, int len,
+ 					       enum mem_break_enable, int b );
+ 	int     (* to_get_memory_breakpoint_status)();
+ 	void    (* to_clear_memory_breakpoint_status)();
+ #endif /* HAVE_MEM_BREAKPOINT */
  	int     to_magic;
  /* Need sub-structure for target machine related rather than comm related? */
  #else  /* STDC */
***************
*** 129,134 ****
--- 136,147 ----
  	int	to_has_execution;
  struct section_table *sections;
  struct section_table *sections_end;
+ #ifdef HAVE_MEM_BREAKPOINT
+ 	void    (* to_init_memory_breakpoint)();
+ 	int     (* to_insert_memory_breakpoint)();
+ 	int     (* to_get_memory_breakpoint_status)();
+ 	void    (* to_clear_memory_breakpoint_status)();
+ #endif /* HAVE_MEM_BREAKPOINT */
  	int     to_magic;
  /* Need sub-structure for target machine related rather than comm related? */
  #endif
***************
*** 250,255 ****
--- 263,289 ----
  #define	target_files_info()	\
  	(*current_target->to_files_info) (current_target)
  
+ #ifdef HAVE_MEM_BREAKPOINT
+ /* 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_memory_breakpoint() (*current_target->to_init_memory_breakpoint)()
+ 
+ #define target_insert_memory_breakpoint(addr, len, type, bp_num) \
+   (*current_target->to_insert_memory_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_memory_breakpoint_status() \
+   (*current_target->to_get_memory_breakpoint_status)()
+ 
+ /* Clear the memory breakpoint status.  Called before execution is resumed*/
+ #define target_clear_memory_breakpoint_status() \
+   (*current_target->to_clear_memory_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
     target contents.  It is guaranteed by the caller to be long enough
diff -c -B ./xcoffexec.c ../../gdb-4.4.dave/gdb/xcoffexec.c
*** ./xcoffexec.c	Wed Dec  4 02:36:17 1991
--- ../../gdb-4.4.dave/gdb/xcoffexec.c	Mon Apr 13 19:10:53 1992
***************
*** 898,903 ****
--- 898,906 ----
  	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 */
  };
---------------<end of diffs for gdb/>--------------------------------
Here are some diffs for bfd/trad-core.c that make core files work on this
system.

----------------<diffs for bfd/>--------------------------------------
*** trad-core.c	Tue Jan 28 16:53:18 1992
--- trad-core.c.new	Mon Feb 10 19:20:40 1992
***************
*** 34,47 ****
  #include <stdio.h>
  #include <sys/types.h>
  #include <sys/param.h>
  #include <sys/dir.h>
  #include <signal.h>
- #include <machine/reg.h>
  
  #include <sys/user.h>		/* After a.out.h  */
! #include <sys/file.h>
  
  #include <errno.h>
  
    struct trad_core_struct 
      {
--- 34,49 ----
  #include <stdio.h>
  #include <sys/types.h>
  #include <sys/param.h>
  #include <sys/dir.h>
  #include <signal.h>
  
+ /*#include <machine/reg.h>*/
+ #include <sys/reg.h>
+ 
  #include <sys/user.h>		/* After a.out.h  */
! /*  #include <sys/file.h> */
  
  #include <errno.h>
  
    struct trad_core_struct 
      {
***************
*** 125,146 ****
  
    core_stacksec (abfd)->flags = SEC_ALLOC + SEC_LOAD + SEC_HAS_CONTENTS;
    core_datasec (abfd)->flags = SEC_ALLOC + SEC_LOAD + SEC_HAS_CONTENTS;
    core_regsec (abfd)->flags = SEC_ALLOC + SEC_HAS_CONTENTS;
  
!   core_datasec (abfd)->_raw_size =  NBPG * u.u_dsize;
!   core_stacksec (abfd)->_raw_size = NBPG * u.u_ssize;
!   core_regsec (abfd)->_raw_size = NBPG * UPAGES; /* Larger than sizeof struct u */
  
    /* What a hack... we'd like to steal it from the exec file,
       since the upage does not seem to provide it.  FIXME.  */
  #ifdef HOST_DATA_START_ADDR
    core_datasec (abfd)->vma = HOST_DATA_START_ADDR;
  #else
!   core_datasec (abfd)->vma = HOST_TEXT_START_ADDR + (NBPG * u.u_tsize);
  #endif
!   core_stacksec (abfd)->vma = HOST_STACK_END_ADDR - (NBPG * u.u_ssize);
    /* This is tricky.  As the "register section", we give them the entire
       upage and stack.  u.u_ar0 points to where "register 0" is stored.
       There are two tricks with this, though.  One is that the rest of the
       registers might be at positive or negative (or both) displacements
       from *u_ar0.  The other is that u_ar0 is sometimes an absolute address
--- 127,153 ----
  
    core_stacksec (abfd)->flags = SEC_ALLOC + SEC_LOAD + SEC_HAS_CONTENTS;
    core_datasec (abfd)->flags = SEC_ALLOC + SEC_LOAD + SEC_HAS_CONTENTS;
    core_regsec (abfd)->flags = SEC_ALLOC + SEC_HAS_CONTENTS;
  
!   core_datasec (abfd)->_raw_size =  NBPC * u.u_dsize;
!   core_stacksec (abfd)->_raw_size = NBPC * u.u_ssize;
!   core_regsec (abfd)->_raw_size = NBPC * USIZE; /* Larger than sizeof struct u */
  
    /* What a hack... we'd like to steal it from the exec file,
       since the upage does not seem to provide it.  FIXME.  */
+ 
+ #define HOST_DATA_START_ADDR u.u_exdata.ux_datorg
+ #define HOST_STACK_END_ADDR 0x80000000
+ 
  #ifdef HOST_DATA_START_ADDR
    core_datasec (abfd)->vma = HOST_DATA_START_ADDR;
  #else
!   core_datasec (abfd)->vma = HOST_TEXT_START_ADDR + (NBPC * u.u_tsize);
  #endif
!   core_stacksec (abfd)->vma = HOST_STACK_END_ADDR - (NBPC * u.u_ssize);
! 
    /* This is tricky.  As the "register section", we give them the entire
       upage and stack.  u.u_ar0 points to where "register 0" is stored.
       There are two tricks with this, though.  One is that the rest of the
       registers might be at positive or negative (or both) displacements
       from *u_ar0.  The other is that u_ar0 is sometimes an absolute address
***************
*** 153,164 ****
       0 is at the place pointed to by u_ar0 (by setting the vma of the start
       of the section to -u_ar0).  GDB uses this info to locate the regs,
       using minor trickery to get around the offset-or-absolute-addr problem. */
    core_regsec (abfd)->vma = 0 - (int) u.u_ar0;
  
!   core_datasec (abfd)->filepos = NBPG * UPAGES;
!   core_stacksec (abfd)->filepos = (NBPG * UPAGES) + NBPG * u.u_dsize;
    core_regsec (abfd)->filepos = 0; /* Register segment is the upage */
  
    /* Align to word at least */
    core_stacksec (abfd)->alignment_power = 2;
    core_datasec (abfd)->alignment_power = 2;
--- 160,171 ----
       0 is at the place pointed to by u_ar0 (by setting the vma of the start
       of the section to -u_ar0).  GDB uses this info to locate the regs,
       using minor trickery to get around the offset-or-absolute-addr problem. */
    core_regsec (abfd)->vma = 0 - (int) u.u_ar0;
  
!   core_datasec (abfd)->filepos = NBPC * USIZE;
!   core_stacksec (abfd)->filepos = (NBPC * USIZE) + NBPC * u.u_dsize;
    core_regsec (abfd)->filepos = 0; /* Register segment is the upage */
  
    /* Align to word at least */
    core_stacksec (abfd)->alignment_power = 2;
    core_datasec (abfd)->alignment_power = 2;
----------------<end of diffs for bfd/>--------------------------------------
David Daney   daney@walrus.micro.umn.edu
P.S.  I see that gdb-4.5 is here I will see what I can do with it.

Newsgroups: gnu.gdb.bug