delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp-workers/1999/08/18/12:43:53

Date: Wed, 18 Aug 1999 18:41:22 +0300 (IDT)
From: Eli Zaretskii <eliz AT is DOT elta DOT co DOT il>
X-Sender: eliz AT is
To: djgpp-workers AT delorie DOT com
cc: Robert Hoehne <robert DOT hoehne AT gmx DOT net>,
Pierre Muller <muller AT cerbere DOT u-strasbg DOT fr>
Subject: Watchpoint-related patches for GDB
Message-ID: <Pine.SUN.3.91.990818183137.10490k-100000@is>
MIME-Version: 1.0
Reply-To: djgpp-workers AT delorie DOT com

I sent today to the GDB mailing list the patches below.  They make 
several improvements to support of signals and watchpoints.  You can now 
pass signals to the debuggee, watch `double' values, use several types of 
watchpoints (e.g., rwatch and watch) at the same address, etc.  Also,
the code that assigns debug registers now checks for the case where GDB 
wants to watch the same address more than once (yes, it really happens), 
and if so, uses a single register with a reference count.

In addition, you can now single-step across a function that calls 
__dpmi_int (previously, the debuggee would crash).

Thanks to Pierre for useful discussions about these issues, and for 
providing his versions of code that handles these problems (the patches 
below are different, but many ideas are Pierre's).

Btw, Pierre, do you have examples of code where INT nn instructions are 
issued other than system calls through __dpmi_int?  I would like to see 
how well this version works in those cases.

1999-08-16  Eli Zaretskii  <eliz AT is DOT elta DOT co DOT il>

	* go32-nat.c (go32_wait): If we are in a single-step mode, and the
	next instruction is INT nn or INTO, use a temporary breakpoint to
	simulate single-step mode, and reset the trace flag.

1999-08-14  Eli Zaretskii  <eliz AT is DOT elta DOT co DOT il>

	* breakpoint.c (bpstat_stop_status): Handle hardware watchpoints
	like we do with access and read watchpoints.  Accept triggered
	addresses anywhere inside the region occupied by a watched value
	as a sign that the watchpoint fired.
	(TARGET_REGION_OK_FOR_HW_WATCHPOINT): Supply a default definition.
	(can_use_hardware_watchpoint): Call TARGET_REGION_OK_FOR_HW_WATCHPOINT;
	if it returns zero, return zero immediately.
	(insert_breakpoints): Try to insert watchpoints for all the values
	on the value chain, even if some of them fail to insert.  Remove
	the breakpoint if parts of its value chain couldn't be inserted.

	* go32-nat.c (wp_op): New typedef.
	(SHOW_DR): Print the length of watched region as well.
	(go32_insert_aligned_watchpoint): Remove unused argument PID.  All
	callers and the prototype changed.
	(go32_handle_nonaligned_watchpoint): Renamed from
	go32_insert_nonaligned_watchpoint.  Now handles all operations on
	non-aligned watchpoints: insertion, deletion, and counting.  If
	called with wp_count as the first argument, return the count of
	debug registers needed to watch the region.  Don't break out of
	the loop before all the addresses in the region are processed.
	(go32_remove_watchpoint): Call go32_remove_aligned_watchpoint to
	do the actual work.
	(go32_remove_aligned_watchpoint): New function, modeled after
	go32_insert_aligned_watchpoint.  Removes watchpoints that watch
	regions of arbitrary length by calling
	go32_handle_nonaligned_watchpoint as needed.
	(go32_region_ok_for_watchpoint): New function, called from
	can_use_hardware_watchpoint via the new macro
	TARGET_REGION_OK_FOR_HW_WATCHPOINT.

	* config/i386/nm-go32.h (TARGET_REGION_OK_FOR_HW_WATCHPOINT):
	Define to call go32_region_ok_for_watchpoint.
	(DECR_PC_AFTER_HW_BREAK): Define back to zero (previous redefinition
	to 1 was due to a bug in go32-nat.c).

	* target.h (TARGET_REGION_OK_FOR_HW_WATCHPOINT): New macro.

1999-08-07  Eli Zaretskii  <eliz AT is DOT elta DOT co DOT il>

	* go32-nat.c (cleanup_dregs): New function.
	(go32_mourn_inferior): Call it.
	(IS_REG_FREE, LOCAL_ENABLE_REG, GLOBAL_ENABLE_REG, DISABLE_REG,
	SET_BREAK, SET_WATCH, IS_WATCH, WATCH_HIT): Protect arguments with
	parentheses.
	(SET_BREAK): Increment the debug register's reference count.
	(DR_DEF): New macro, returns the access and length bits of the
	breakpoint.
	(SHOW_DR): Print the reference count of each register.  Disable or
	enable print-out depending on an environment variable GDB_SHOW_DR.
	(go32_insert_aligned_watchpoint): Look for an occupied debug
	register with the same address and access/length bits, and reuse
	it by incrementing reference the count, before occupying another
	register.  Return zero upon success.
	(go32_insert_nonaligned_watchpoint): Pass the read/write bits to
	go32_remove_watchpoint.
	(go32_remove_watchpoint): Accept an additional parameter: the
	read/write bits of the watchpoint to remove, and only remove a
	watchpoint if it's occupied and its address and read/write bits
	match.  Only disable the register if its reference count is zero;
	otherwise just decrease the reference count.
	(go32_remove_hw_breakpoint): Only decrease reference count and
	disable the debug register if it is occupied and its access bits
	match those of an instruction breakpoint.
	(go32_insert_hw_breakpoint): Before occupying another debug
	register, look for an already occupied register that defines an
	instruction breakpoint with the same address.  If found, increment
	its reference count.  Call SHOW_DR even if failed to insert a
	breakpoint.

	* config/i386/nm-go32.h (target_remove_watchpoint): Accept the
	TYPE argument as well.

1999-08-06  Eli Zaretskii  <eliz AT is DOT elta DOT co DOT il>

	* infrun.c (proceed) [__DJGPP__]: If some hardware breakpoints
	couldn't be inserted, print a message that they may have set too
	many of them.
	(normal_stop) [__DJGPP__]: Likewise.
	Reset breakpoints_failed, they might do something that will cause
	insert_breakpoints() succeed next time.

	* breakpoint.c (bpstat_stop_status): Don't decrement the hit count
	if not going to stop, leave it as it was before.  Don't stop if
	target_stopped_data_address() returns zero.  Don't stop if a read
	watchpoint fired, but the value has changed.  Don't stop if some
	watchpoint was triggered, but its address doesn't match the
	address of this watchpoint.


*** gdb/config/i386/nm-go32.h~0	Tue May 25 20:13:40 1999
--- gdb/config/i386/nm-go32.h	Sat Aug 14 14:59:08 1999
***************
*** 23,30 ****
--- 23,53 ----
  
  #define TARGET_HAS_HARDWARE_WATCHPOINTS
  
+ /* Returns the number of hardware watchpoints of type TYPE that we can
+    set.  Value is positive if we can set CNT watchpoints, zero if
+    setting watchpoints of type TYPE is not supported, and negative if
+    CNT is more than the maximum number of watchpoints of type TYPE
+    that we can support.  TYPE is one of bp_hardware_watchpoint,
+    bp_read_watchpoint, bp_write_watchpoint, or bp_hardware_breakpoint.
+    CNT is the number of such watchpoints used so far (including this
+    one).  OTHERTYPE is non-zero if other types of watchpoints are
+    currently enabled.
+ 
+    We always return 1 here because we don't have enough information
+    about possible overlap of addresses that they want to watch.  As
+    an extreme example, consider the case where all the watchpoints
+    watch the same address and the same region length: then we can
+    handle a virtually unlimited number of watchpoints, due to debug
+    register sharing implemented via reference counts in go32-nat.c.  */
+ 
  #define TARGET_CAN_USE_HARDWARE_WATCHPOINT(type, cnt, ot) 1
  
+ /* Returns non-zero if we can use hardware watchpoints to watch a region
+    whose address is ADDR and whose length is LEN.  */
+ 
+ #define TARGET_REGION_OK_FOR_HW_WATCHPOINT(addr,len) \
+ 	go32_region_ok_for_watchpoint(addr,len)
+ 
  /* After a watchpoint trap, the PC points to the instruction after the
     one that caused the trap.  Therefore we don't need to step over it.
     But we do need to reset the status register to avoid another trap.  */
***************
*** 32,46 ****
  #define HAVE_CONTINUABLE_WATCHPOINT
  
  #define STOPPED_BY_WATCHPOINT(W)  \
!   go32_stopped_by_watchpoint (inferior_pid)
  
  /* Use these macros for watchpoint insertion/removal.  */
  
  #define target_insert_watchpoint(addr, len, type)  \
!   go32_insert_watchpoint (inferior_pid, addr, len, 2)
  
  #define target_remove_watchpoint(addr, len, type)  \
!   go32_remove_watchpoint (inferior_pid, addr, len)
  
  #define target_insert_hw_breakpoint(addr, shadow)  \
    go32_insert_hw_breakpoint(addr, shadow)
--- 55,72 ----
  #define HAVE_CONTINUABLE_WATCHPOINT
  
  #define STOPPED_BY_WATCHPOINT(W)  \
!   go32_stopped_by_watchpoint (inferior_pid, 0)
! 
! #define target_stopped_data_address() \
!   go32_stopped_by_watchpoint (inferior_pid, 1)
  
  /* Use these macros for watchpoint insertion/removal.  */
  
  #define target_insert_watchpoint(addr, len, type)  \
!   go32_insert_watchpoint (inferior_pid, addr, len, type)
  
  #define target_remove_watchpoint(addr, len, type)  \
!   go32_remove_watchpoint (inferior_pid, addr, len, type)
  
  #define target_insert_hw_breakpoint(addr, shadow)  \
    go32_insert_hw_breakpoint(addr, shadow)
***************
*** 48,54 ****
  #define target_remove_hw_breakpoint(addr, shadow)  \
    go32_remove_hw_breakpoint(addr, shadow)
  
! #define DECR_PC_AFTER_HW_BREAK 1
  
  #undef FLOAT_INFO
  #define FLOAT_INFO { i386_go32_float_info (); }
--- 74,80 ----
  #define target_remove_hw_breakpoint(addr, shadow)  \
    go32_remove_hw_breakpoint(addr, shadow)
  
! #define DECR_PC_AFTER_HW_BREAK 0
  
  #undef FLOAT_INFO
  #define FLOAT_INFO { i386_go32_float_info (); }
*** gdb/go32-nat.~10	Sat Jun 26 20:25:54 1999
--- gdb/go32-nat.c	Mon Aug 16 18:01:14 1999
*************** struct env387
*** 141,146 ****
--- 141,151 ----
    unsigned char regs[8][10];
  };
  
+ typedef enum { wp_insert, wp_remove, wp_count } wp_op;
+ 
+ /* This holds the current reference counts for each debug register.  */
+ static int dr_ref_count[4];
+ 
  extern char **environ;
  
  #define SOME_PID 42
*************** go32_kill_inferior (void);
*** 180,185 ****
--- 185,192 ----
  static void
  go32_create_inferior (char *exec_file, char *args, char **env);
  static void
+ cleanup_dregs (void);
+ static void
  go32_mourn_inferior (void);
  static int
  go32_can_run (void);
*************** static void
*** 187,195 ****
  ignore (void);
  static void
  ignore2 (char *a, int b);
! static int go32_insert_aligned_watchpoint (int pid, CORE_ADDR waddr,
!                                           CORE_ADDR addr, int len, int rw);
! static int go32_insert_nonaligned_watchpoint (int pid, CORE_ADDR waddr,
                                               CORE_ADDR addr, int len, int rw);
  
  static struct target_ops go32_ops;
--- 194,204 ----
  ignore (void);
  static void
  ignore2 (char *a, int b);
! static int go32_insert_aligned_watchpoint (CORE_ADDR waddr, CORE_ADDR addr,
! 					   int len, int rw);
! static int go32_remove_aligned_watchpoint (CORE_ADDR waddr, CORE_ADDR addr,
! 					   int len, int rw);
! static int go32_handle_nonaligned_watchpoint (wp_op what, CORE_ADDR waddr,
                                               CORE_ADDR addr, int len, int rw);
  
  static struct target_ops go32_ops;
*************** static struct {
*** 372,386 ****
  } excepn_map[] = {
    TARGET_SIGNAL_0, -1,
    TARGET_SIGNAL_ILL, 6,		/* Invalid Opcode */
!   TARGET_SIGNAL_TRAP, 1,	/* Debug */
!   TARGET_SIGNAL_BUS, 17,	/* Alignment Check */
    TARGET_SIGNAL_SEGV, 13,	/* GPF */
!   TARGET_SIGNAL_FPE, 0x75,	/* this and the rest are fake exceptions */
!   TARGET_SIGNAL_INT, 0x79,	/* see dpmiexcp.c in djlsr*.zip for details */
    TARGET_SIGNAL_QUIT, 0x7a,
!   TARGET_SIGNAL_ALRM, 0x78,
    TARGET_SIGNAL_PROF, 0x78,
!   0, 0
  };
  
  static void
--- 381,398 ----
  } excepn_map[] = {
    TARGET_SIGNAL_0, -1,
    TARGET_SIGNAL_ILL, 6,		/* Invalid Opcode */
!   TARGET_SIGNAL_EMT, 7,		/* triggers SIGNOFP */
    TARGET_SIGNAL_SEGV, 13,	/* GPF */
!   TARGET_SIGNAL_BUS, 17,	/* Alignment Check */
!   /* The rest are fake exceptions, see dpmiexcp.c in djlsr*.zip for
!      details.  */
!   TARGET_SIGNAL_TERM, 0x1b,	/* triggers Ctrl-Break type of SIGINT */
!   TARGET_SIGNAL_FPE, 0x75,
!   TARGET_SIGNAL_INT, 0x79,
    TARGET_SIGNAL_QUIT, 0x7a,
!   TARGET_SIGNAL_ALRM, 0x78,	/* triggers SIGTIMR */
    TARGET_SIGNAL_PROF, 0x78,
!   -1, -1
  };
  
  static void
*************** go32_resume (int pid, int step, enum tar
*** 417,428 ****
  
    resume_is_step = step;
  
!   for (i = 0, resume_signal = -1; excepn_map[i].gdb_sig != 0; i++)
!     if (excepn_map[i].gdb_sig == siggnal)
!       {
! 	resume_signal = excepn_map[i].djgpp_excepno;
! 	break;
!       }
  }
  
  static char child_cwd[FILENAME_MAX];
--- 429,446 ----
  
    resume_is_step = step;
  
!   if (siggnal != TARGET_SIGNAL_0 && siggnal != TARGET_SIGNAL_TRAP)
!     {
!       for (i = 0, resume_signal = -1; excepn_map[i].gdb_sig != -1; i++)
! 	if (excepn_map[i].gdb_sig == siggnal)
! 	  {
! 	    resume_signal = excepn_map[i].djgpp_excepno;
! 	    break;
! 	  }
!       if (resume_signal == -1)
! 	printf_unfiltered ("Cannot deliver signal %s on this platform.\n",
! 			   target_signal_to_name (siggnal));
!     }
  }
  
  static char child_cwd[FILENAME_MAX];
*************** static int
*** 431,447 ****
  go32_wait (int pid, struct target_waitstatus *status)
  {
    int i;
  
    if (resume_is_step)
!     a_tss.tss_eflags |= 0x0100;
!   else
!     a_tss.tss_eflags &= 0xfeff;
    if (resume_signal <= -1)
!     a_tss.tss_trap = 0;
    else
      {
-       /* FIXME: this doesn't seem to work for all signals.  SIGSEGV
-          and SIGTRAP do work, but SIGFPE and SIGBUS don't.  Why?  */
        a_tss.tss_trap = 0xffff;	/* run_child looks for this */
        a_tss.tss_irqn = resume_signal;
      }
--- 449,499 ----
  go32_wait (int pid, struct target_waitstatus *status)
  {
    int i;
+   unsigned char saved_opcode;
+   unsigned long INT3_addr;
+   int stepping_over_INT = 0;
  
+   a_tss.tss_eflags &= 0xfeff;	/* reset the single-step flag (TF) */
    if (resume_is_step)
!     {
!       /* If the next instruction is INT xx or INTO, we need to handle
! 	 them specially.  Intel manuals say that these instructions
! 	 reset the single-step flag (a.k.a. TF).  However, it seems
! 	 that, at least in the DPMI environment, and at least when
! 	 stepping over the DPMI interrupt 31h, the problem is having
! 	 TF set at all when INT 31h is executed: the debuggee either
! 	 crashes (and takes the system with it) or is killed by a
! 	 SIGTRAP.
! 
! 	 So we need to emulate single-step mode: we put an INT3 opcode
! 	 right after the INT xx instruction, let the debuggee run
! 	 until it hits INT3 and stops, then restore the original
! 	 instruction which we overwrote with the INT3 opcode, and back
! 	 up the debuggee's EIP to that instruction.  */
!       read_child (a_tss.tss_eip, &saved_opcode, 1);
!       if (saved_opcode == 0xCD || saved_opcode == 0xCE)
! 	{
! 	  unsigned char INT3_opcode = 0xCC;
! 
! 	  INT3_addr
! 	    = saved_opcode == 0xCD ? a_tss.tss_eip + 2 : a_tss.tss_eip + 1;
! 	  stepping_over_INT = 1;
! 	  read_child (INT3_addr, &saved_opcode, 1);
! 	  write_child (INT3_addr, &INT3_opcode, 1);
! 	}
!       else
! 	a_tss.tss_eflags |= 0x0100; /* normal instruction: set TF */
!     }
! 
!   /* The special value FFFFh in tss_trap indicates to run_child that
!      tss_irqn holds a signal to be delivered to the debuggee.  */
    if (resume_signal <= -1)
!     {
!       a_tss.tss_trap = 0;
!       a_tss.tss_irqn = 0xff;
!     }
    else
      {
        a_tss.tss_trap = 0xffff;	/* run_child looks for this */
        a_tss.tss_irqn = resume_signal;
      }
*************** go32_wait (int pid, struct target_waitst
*** 463,468 ****
--- 515,531 ----
    save_npx ();
  #endif
  
+   /* Did we step over an INT xx instruction?  */
+   if (stepping_over_INT && a_tss.tss_eip == INT3_addr + 1)
+     {
+       /* Restore the original opcode.  */
+       a_tss.tss_eip--;	/* EIP points *after* the INT3 instruction */
+       write_child (a_tss.tss_eip, &saved_opcode, 1);
+       /* Simulate a TRAP exception.  */
+       a_tss.tss_irqn = 1;
+       a_tss.tss_eflags |= 0x0100;
+     }
+ 
    getcwd (child_cwd, sizeof (child_cwd)); /* in case it has changed */
    chdir (current_directory);
  
*************** go32_create_inferior (char *exec_file, c
*** 672,677 ****
--- 735,748 ----
  static void
  go32_mourn_inferior (void)
  {
+   /* We need to make sure all the breakpoint enable bits in the DR7
+      register are reset when the inferior exits.  Otherwise, if they
+      rerun the inferior, the uncleared bits may cause random SIGTRAPs,
+      failure to set more watchpoints, and other calamities.  It would
+      be nice if GDB itself would take care to remove all breakpoints
+      at all times, but it doesn't, probably under an assumption that
+      the OS cleans up when the debuggee exits.  */
+   cleanup_dregs ();
    go32_kill_inferior ();
    generic_mourn_inferior ();
  }
*************** ignore (void)
*** 698,704 ****
  #define DR_GLOBAL_SLOWDOWN 0x200
  #define DR_CONTROL_SHIFT 16
  #define DR_CONTROL_SIZE 4
! #define DR_RW_READ 0x3
  #define DR_RW_WRITE 0x1
  #define DR_CONTROL_MASK 0xf
  #define DR_ENABLE_MASK 0x3
--- 769,775 ----
  #define DR_GLOBAL_SLOWDOWN 0x200
  #define DR_CONTROL_SHIFT 16
  #define DR_CONTROL_SIZE 4
! #define DR_RW_READWRITE 0x3
  #define DR_RW_WRITE 0x1
  #define DR_CONTROL_MASK 0xf
  #define DR_ENABLE_MASK 0x3
*************** ignore (void)
*** 711,726 ****
  #define STATUS D_REGS[DR_STATUS]
  
  #define IS_REG_FREE(index) \
!   (!(CONTROL & (3 << (DR_ENABLE_SIZE * index))))
  
  #define LOCAL_ENABLE_REG(index) \
!   (CONTROL |= (1 << (DR_LOCAL_ENABLE_SHIFT + DR_ENABLE_SIZE * index)))
  
  #define GLOBAL_ENABLE_REG(index) \
!   (CONTROL |= (1 << (DR_GLOBAL_ENABLE_SHIFT + DR_ENABLE_SIZE * index)))
  
  #define DISABLE_REG(index) \
!   (CONTROL &= ~(3 << (DR_ENABLE_SIZE * index)))
  
  #define SET_LOCAL_EXACT() \
    (CONTROL |= DR_LOCAL_SLOWDOWN)
--- 782,797 ----
  #define STATUS D_REGS[DR_STATUS]
  
  #define IS_REG_FREE(index) \
!   (!(CONTROL & (3 << (DR_ENABLE_SIZE * (index)))))
  
  #define LOCAL_ENABLE_REG(index) \
!   (CONTROL |= (1 << (DR_LOCAL_ENABLE_SHIFT + DR_ENABLE_SIZE * (index))))
  
  #define GLOBAL_ENABLE_REG(index) \
!   (CONTROL |= (1 << (DR_GLOBAL_ENABLE_SHIFT + DR_ENABLE_SIZE * (index))))
  
  #define DISABLE_REG(index) \
!   (CONTROL &= ~(3 << (DR_ENABLE_SIZE * (index))))
  
  #define SET_LOCAL_EXACT() \
    (CONTROL |= DR_LOCAL_SLOWDOWN)
*************** ignore (void)
*** 728,781 ****
  #define SET_GLOBAL_EXACT() \
    (CONTROL |= DR_GLOBAL_SLOWDOWN)
  
  #define SET_BREAK(index,address) \
    do {\
!     CONTROL &= ~(DR_CONTROL_MASK << (DR_CONTROL_SHIFT + DR_CONTROL_SIZE * index));\
      D_REGS[index] = address;\
    } while(0)
  
  #define SET_WATCH(index,address,rw,len) \
    do {\
      SET_BREAK(index,address);\
!     CONTROL |= (len | rw) << (DR_CONTROL_SHIFT + DR_CONTROL_SIZE * index);\
    } while (0)
  
  #define WATCH_HIT(index) \
    (\
!    (STATUS & (1 << index)) && \
!    (CONTROL & (DR_CONTROL_MASK << (DR_CONTROL_SHIFT + DR_CONTROL_SIZE * index)))\
    )
  
! #if 0 /* use debugging macro */
! #define SHOW_DR(text) \
  do { \
    fprintf(stderr,"%08x %08x ",edi.dr[7],edi.dr[6]); \
!   fprintf(stderr,"%08x %08x ",edi.dr[0],edi.dr[1]); \
!   fprintf(stderr,"%08x %08x ",edi.dr[2],edi.dr[3]); \
!   fprintf(stderr,"(%s)\n",#text); \
  } while (0)
  #else
! #define SHOW_DR(text) do {} while (0)
  #endif
  
  /* Insert a watchpoint.  */
  
  int
  go32_insert_watchpoint (int pid, CORE_ADDR addr, int len, int rw)
  {
!   int ret = go32_insert_aligned_watchpoint (pid, addr, addr, len, rw);
  
!   SHOW_DR (insert_watch);
    return ret;
  }
  
  static int
! go32_insert_aligned_watchpoint (int pid, CORE_ADDR waddr, CORE_ADDR addr,
  				int len, int rw)
  {
    int i;
    int read_write_bits, len_bits;
  
    /* Look for a free debug register.  */
    for (i = 0; i <= 3; i++)
      {
--- 799,917 ----
  #define SET_GLOBAL_EXACT() \
    (CONTROL |= DR_GLOBAL_SLOWDOWN)
  
+ #define RESET_LOCAL_EXACT() \
+   (CONTROL &= ~(DR_LOCAL_SLOWDOWN))
+ 
+ #define RESET_GLOBAL_EXACT() \
+   (CONTROL &= ~(DR_GLOBAL_SLOWDOWN))
+ 
  #define SET_BREAK(index,address) \
    do {\
!     CONTROL &= ~(DR_CONTROL_MASK << (DR_CONTROL_SHIFT + DR_CONTROL_SIZE * (index)));\
      D_REGS[index] = address;\
+     dr_ref_count[index]++;\
    } while(0)
  
  #define SET_WATCH(index,address,rw,len) \
    do {\
      SET_BREAK(index,address);\
!     CONTROL |= ((len)|(rw)) << (DR_CONTROL_SHIFT + DR_CONTROL_SIZE * (index));\
    } while (0)
  
+ #define IS_WATCH(index) \
+   (CONTROL & (DR_CONTROL_MASK << (DR_CONTROL_SHIFT + DR_CONTROL_SIZE*(index))))
+ 
  #define WATCH_HIT(index) \
    (\
!    (STATUS & (1 << (index))) && \
!    IS_WATCH(index) \
    )
  
! #define DR_DEF(index) \
!   ((CONTROL >> (DR_CONTROL_SHIFT + DR_CONTROL_SIZE * (index))) & 0x0f)
!     
! 
! #if 0 /* use debugging macro */
! #define SHOW_DR(text,len) \
  do { \
+   if (!getenv ("GDB_SHOW_DR")) break; \
    fprintf(stderr,"%08x %08x ",edi.dr[7],edi.dr[6]); \
!   fprintf(stderr,"%08x %d %08x %d ", \
! 	  edi.dr[0],dr_ref_count[0],edi.dr[1],dr_ref_count[1]); \
!   fprintf(stderr,"%08x %d %08x %d ", \
! 	  edi.dr[2],dr_ref_count[2],edi.dr[3],dr_ref_count[3]); \
!   fprintf(stderr,(len)?"(%s:%d)\n":"(%s)\n",#text,len); \
  } while (0)
  #else
! #define SHOW_DR(text,len) do {} while (0)
  #endif
  
+ static void
+ cleanup_dregs (void)
+ {
+   int i;
+ 
+   CONTROL = 0;
+   STATUS = 0;
+   for (i = 0; i < 4; i++)
+     {
+       D_REGS[i] = 0;
+       dr_ref_count[i] = 0;
+     }
+ }
+ 
  /* Insert a watchpoint.  */
  
  int
  go32_insert_watchpoint (int pid, CORE_ADDR addr, int len, int rw)
  {
!   int ret = go32_insert_aligned_watchpoint (addr, addr, len, rw);
  
!   SHOW_DR (insert_watch, len);
    return ret;
  }
  
  static int
! go32_insert_aligned_watchpoint (CORE_ADDR waddr, CORE_ADDR addr,
  				int len, int rw)
  {
    int i;
    int read_write_bits, len_bits;
  
+   /* Values of rw: 0 - write, 1 - read, 2 - access (read and write).
+      However, x86 doesn't support read-only data breakpoints.  */
+   read_write_bits = rw ? DR_RW_READWRITE : DR_RW_WRITE;
+ 
+   switch (len)
+     {
+       case 4:
+ 	len_bits = DR_LEN_4;
+ 	break;
+       case 2:
+ 	len_bits = DR_LEN_2;
+ 	break;
+       case 1:
+ 	len_bits = DR_LEN_1;
+ 	break;
+       default:
+ 	/* The debug registers only have 2 bits for the length, so
+ 	   so this value will always fail the loop below.  */
+ 	len_bits = 0x10;
+     }
+ 
+   /* Look for an occupied debug register with the same address and the
+      same RW and LEN definitions.  If we find one, we can use it for
+      this watchpoint as well (and save a register).  */
+   for (i = 0; i < 4; i++)
+     {
+       if (!IS_REG_FREE (i) && D_REGS[i] == addr
+ 	  && DR_DEF (i) == (len_bits | read_write_bits))
+ 	{
+ 	  dr_ref_count[i]++;
+ 	  return 0;
+ 	}
+     }
+ 
    /* Look for a free debug register.  */
    for (i = 0; i <= 3; i++)
      {
*************** go32_insert_aligned_watchpoint (int pid,
*** 787,823 ****
    if (i > 3)
      return -1;
  
!   read_write_bits = ((rw & 1) ? DR_RW_READ : 0) | ((rw & 2) ? DR_RW_WRITE : 0);
! 
!   if (len == 1)
!     len_bits = DR_LEN_1;
!   else if (len == 2)
      {
        if (addr % 2)
! 	return go32_insert_nonaligned_watchpoint (pid, waddr, addr, len, rw);
!       len_bits = DR_LEN_2;
      }
    else if (len == 4)
      {
        if (addr % 4)
! 	return go32_insert_nonaligned_watchpoint (pid, waddr, addr, len, rw);
!       len_bits = DR_LEN_4;
      }
!   else
!     return go32_insert_nonaligned_watchpoint (pid, waddr, addr, len, rw);
  
    SET_WATCH (i, addr, read_write_bits, len_bits);
    LOCAL_ENABLE_REG (i);
    SET_LOCAL_EXACT ();
  }
  
  static int
! go32_insert_nonaligned_watchpoint (int pid, CORE_ADDR waddr, CORE_ADDR addr,
  				   int len, int rw)
  {
    int align;
    int size;
!   int rv = 0;
  
    static int size_try_array[16] =
    {
--- 923,957 ----
    if (i > 3)
      return -1;
  
!   if (len == 2)
      {
        if (addr % 2)
! 	return go32_handle_nonaligned_watchpoint (wp_insert, waddr, addr,
! 						  len, rw);
      }
    else if (len == 4)
      {
        if (addr % 4)
! 	return go32_handle_nonaligned_watchpoint (wp_insert, waddr, addr,
! 						  len, rw);
      }
!   else if (len != 1)
!     return go32_handle_nonaligned_watchpoint (wp_insert, waddr, addr, len, rw);
  
    SET_WATCH (i, addr, read_write_bits, len_bits);
    LOCAL_ENABLE_REG (i);
    SET_LOCAL_EXACT ();
+   SET_GLOBAL_EXACT ();
+   return 0;
  }
  
  static int
! go32_handle_nonaligned_watchpoint (wp_op what, CORE_ADDR waddr, CORE_ADDR addr,
  				   int len, int rw)
  {
    int align;
    int size;
!   int rv = 0, status = 0;
  
    static int size_try_array[16] =
    {
*************** go32_insert_nonaligned_watchpoint (int p
*** 833,844 ****
        /* Four is the maximum length for 386.  */
        size = (len > 4) ? 3 : len - 1;
        size = size_try_array[size * 4 + align];
!       rv = go32_insert_aligned_watchpoint (pid, waddr, addr, size, rw);
!       if (rv)
! 	{
! 	  go32_remove_watchpoint (pid, waddr, size);
! 	  return rv;
! 	}
        addr += size;
        len -= size;
      }
--- 967,990 ----
        /* Four is the maximum length for 386.  */
        size = (len > 4) ? 3 : len - 1;
        size = size_try_array[size * 4 + align];
!       if (what == wp_insert)
! 	status = go32_insert_aligned_watchpoint (waddr, addr, size, rw);
!       else if (what == wp_remove)
! 	status = go32_remove_aligned_watchpoint (waddr, addr, size, rw);
!       else if (what == wp_count)
! 	rv++;
!       else
! 	status = -1;
!       /* We keep the loop going even after a failure, because some of
! 	 the other aligned watchpoints might still succeed, e.g. if
! 	 they watch addresses that are already watched, and thus just
! 	 increment the reference counts of occupied debug registers.
! 	 If we break out of the loop too early, we could cause those
! 	 addresses watched by other watchpoints to be disabled when
! 	 GDB reacts to our failure to insert this watchpoint and tries
! 	 to remove it.  */
!       if (status)
! 	rv = status;
        addr += size;
        len -= size;
      }
*************** go32_insert_nonaligned_watchpoint (int p
*** 848,894 ****
  /* Remove a watchpoint.  */
  
  int
! go32_remove_watchpoint (int pid, CORE_ADDR addr, int len)
  {
    int i;
  
    for (i = 0; i <= 3; i++)
      {
!       if (D_REGS[i] == addr)
  	{
! 	  DISABLE_REG (i);
  	}
      }
!   SHOW_DR (remove_watch);
  
    return 0;
  }
  
! /* Check if stopped by a watchpoint.  */
  
  CORE_ADDR
! go32_stopped_by_watchpoint (int pid)
  {
    int i, ret = 0;
    int status;
  
    status = edi.dr[DR_STATUS];
!   SHOW_DR (stopped_by);
    for (i = 0; i <= 3; i++)
      {
!       if (WATCH_HIT (i))
  	{
! 	  SHOW_DR (HIT);
  	  ret = D_REGS[i];
  	}
      }
!   /* this is a hack to GDB. If we stopped at a hardware breakpoint,
!      the stop_pc must incremented by DECR_PC_AFTER_BREAK. I tried everything
!      with the DECR_PC_AFTER_HW_BREAK, but nothing works. */
!   /* This is probably fixed by jtc's recent patch -sts 2/19/99 */
!   if (STATUS && !ret)
      stop_pc += DECR_PC_AFTER_BREAK;
!   STATUS = 0;
  
    return ret;
  }
--- 994,1108 ----
  /* Remove a watchpoint.  */
  
  int
! go32_remove_watchpoint (int pid, CORE_ADDR addr, int len, int rw)
! {
!   int ret = go32_remove_aligned_watchpoint (addr, addr, len, rw);
! 
!   SHOW_DR (remove_watch, len);
!   return ret;
! }
! 
! static int
! go32_remove_aligned_watchpoint (CORE_ADDR waddr, CORE_ADDR addr,
! 				int len, int rw)
  {
    int i;
+   int read_write_bits, len_bits;
+ 
+   /* Values of rw: 0 - write, 1 - read, 2 - access (read and write).
+      However, x86 doesn't support read-only data breakpoints.  */
+   read_write_bits = rw ? DR_RW_READWRITE : DR_RW_WRITE;
+ 
+   switch (len)
+     {
+       case 4:
+ 	len_bits = DR_LEN_4;
+ 	break;
+       case 2:
+ 	len_bits = DR_LEN_2;
+ 	break;
+       case 1:
+ 	len_bits = DR_LEN_1;
+ 	break;
+       default:
+ 	/* The debug registers only have 2 bits for the length, so
+ 	   so this value will always fail the loop below.  */
+ 	len_bits = 0x10;
+     }
+ 
+   if (len == 2)
+     {
+       if (addr % 2)
+ 	return go32_handle_nonaligned_watchpoint (wp_remove, waddr, addr,
+ 						  len, rw);
+     }
+   else if (len == 4)
+     {
+       if (addr % 4)
+ 	return go32_handle_nonaligned_watchpoint (wp_remove, waddr, addr,
+ 						  len, rw);
+     }
+   else if (len != 1)
+     return go32_handle_nonaligned_watchpoint (wp_remove, waddr, addr, len, rw);
  
    for (i = 0; i <= 3; i++)
      {
!       if (!IS_REG_FREE (i) && D_REGS[i] == addr
! 	  && DR_DEF (i) == (len_bits | read_write_bits))
  	{
! 	  dr_ref_count[i]--;
! 	  if (dr_ref_count[i] == 0)
! 	    DISABLE_REG (i);
  	}
      }
!   RESET_LOCAL_EXACT ();
!   RESET_GLOBAL_EXACT ();
  
    return 0;
  }
  
! /* Can we use debug registers to watch a region whose address is ADDR
!    and whose length is LEN bytes?  */
! 
! int
! go32_region_ok_for_watchpoint (CORE_ADDR addr, int len)
! {
!   /* Compute how many aligned watchpoints we would need to cover this
!      region.  */
!   int nregs = go32_handle_nonaligned_watchpoint (wp_count, addr, addr, len, 0);
! 
!   return nregs <= 4 ? 1 : 0;
! }
! 
! /* Check if stopped by a data watchpoint.  If so, return the address
!    whose access triggered the watchpoint.  */
  
  CORE_ADDR
! go32_stopped_by_watchpoint (int pid, int data_watchpoint)
  {
    int i, ret = 0;
    int status;
  
    status = edi.dr[DR_STATUS];
!   SHOW_DR (stopped_by, 0);
    for (i = 0; i <= 3; i++)
      {
!       if (WATCH_HIT (i) && data_watchpoint)
  	{
! 	  SHOW_DR (WP_HIT, 0);
  	  ret = D_REGS[i];
  	}
      }
! #if 0
!   /* Hardware breakpoints and data watchpoints utilize the same
!      machinery of debug registers, but the processor behaves
!      differently in these two cases: if we stopped at an instruction
!      breakpoint, the processor generates a fault-class exception,
!      whereby data breakpoint generates a trap.  Therefore, instruction
!      breakpoints need to increment the program counter.  */
!   if (!data_watchpoint && STATUS && !ret)
      stop_pc += DECR_PC_AFTER_BREAK;
! #endif
  
    return ret;
  }
*************** go32_remove_hw_breakpoint (CORE_ADDR add
*** 901,912 ****
    int i;
    for (i = 0; i <= 3; i++)
      {
!       if (D_REGS[i] == addr)
  	{
! 	  DISABLE_REG (i);
  	}
      }
!   SHOW_DR (remove_hw);
    return 0;
  }
  
--- 1115,1128 ----
    int i;
    for (i = 0; i <= 3; i++)
      {
!       if (!IS_REG_FREE (i) && D_REGS[i] == addr && DR_DEF (i) == 0)
  	{
! 	  dr_ref_count[i]--;
! 	  if (dr_ref_count[i] == 0)
! 	    DISABLE_REG (i);
  	}
      }
!   SHOW_DR (remove_hw, 0);
    return 0;
  }
  
*************** go32_insert_hw_breakpoint (CORE_ADDR add
*** 918,923 ****
--- 1134,1152 ----
    int free_debug_register;
    int register_number;
  
+   /* Look for an occupied debug register with the same address and the
+      same RW and LEN definitions.  If we find one, we can use it for
+      this breakpoint as well (and save a register).  */
+   for (i = 0; i < 4; i++)
+     {
+       if (!IS_REG_FREE (i) && D_REGS[i] == addr && DR_DEF (i) == 0)
+ 	{
+ 	  dr_ref_count[i]++;
+ 	  SHOW_DR (insert_hw, 0);
+ 	  return 0;
+ 	}
+     }
+ 
    /* Look for a free debug register.  */
    for (i = 0; i <= 3; i++)
      {
*************** go32_insert_hw_breakpoint (CORE_ADDR add
*** 925,939 ****
  	break;
      }
  
!   /* No more debug registers!  */
!   if (i > 3)
!     return -1;
! 
!   SET_BREAK (i, addr);
!   LOCAL_ENABLE_REG (i);
!   SHOW_DR (insert_hw);
  
!   return 0;
  }
  
  /* Put the device open on handle FD into either raw or cooked
--- 1154,1168 ----
  	break;
      }
  
!   /* No more debug registers?  */
!   if (i < 4)
!     {
!       SET_BREAK (i, addr);
!       LOCAL_ENABLE_REG (i);
!     }
!   SHOW_DR (insert_hw, 0);
  
!   return i < 4 ? 0 : -1;
  }
  
  /* Put the device open on handle FD into either raw or cooked
*** gdb/infrun.c~2	Sat May 22 09:06:26 1999
--- gdb/infrun.c	Fri Aug  6 22:42:20 1999
***************
*** 892,900 ****
--- 892,914 ----
        int temp = insert_breakpoints ();
        if (temp)
  	{
+ #ifdef __DJGPP__
+ 	  /* Telling them about ptrace and another process won't make
+ 	     any sense.  Let's say something sensible instead.  */
+ 	  if (temp == -1)
+ 	    {
+ 	      gdb_flush (gdb_stdout);
+ 	      fprintf_unfiltered (gdb_stderr, "Too many watchpoints \
+ and hardware breakpoints requested.\n\
+ Delete some and try again.\n");
+ 	    }
+ 	  else
+ 	    error ("Cannot insert breakpoints.");
+ #else
  	  print_sys_errmsg ("ptrace", temp);
  	  error ("Cannot insert breakpoints.\n\
  The same program may be running in another process.");
+ #endif
  	}
  
        breakpoints_inserted = 1;
***************
*** 2968,2976 ****
--- 2982,3004 ----
    if (breakpoints_failed)
      {
        target_terminal_ours_for_output ();
+ #ifdef __DJGPP__
+       /* Telling them about ptrace and another process won't make any
+ 	 sense.  Let's say something sensible instead.  */
+       printf_filtered ("Stopped; cannot insert breakpoints.\n");
+       if (breakpoints_failed == -1)
+ 	printf_filtered ("\
+ You may have requested too many hardware breakpoints and watchpoints.\n");
+ #else
        print_sys_errmsg ("ptrace", breakpoints_failed);
        printf_filtered ("Stopped; cannot insert breakpoints.\n\
  The same program may be running in another process.\n");
+ #endif
+       /* Once they read the above message, they might do something
+ 	 that will cause insert_breakpoints() to succeed next time.
+ 	 So reset breakpoints_failed, to avoid printing this message
+ 	 again without a good reason.  */
+       breakpoints_failed = 0;
      }
  
    if (target_has_execution && breakpoints_inserted)
***************
*** 2980,2986 ****
--- 3008,3016 ----
  	  target_terminal_ours_for_output ();
  	  printf_filtered ("Cannot remove breakpoints because ");
  	  printf_filtered ("program is no longer writable.\n");
+ #ifndef __DJGPP__
  	  printf_filtered ("It might be running in another process.\n");
+ #endif
  	  printf_filtered ("Further execution is probably impossible.\n");
  	}
      }
*** gdb/breakpoint.c~0	Fri Mar 26 06:23:50 1999
--- gdb/breakpoint.c	Sat Aug 14 17:52:58 1999
*************** insert_breakpoints ()
*** 796,803 ****
  		      val = target_insert_watchpoint (addr, len, type);
  		      if (val == -1)
  			{
  			  b->inserted = 0;
- 			  break;
  			}
  		      val = 0;
  		    }
--- 796,807 ----
  		      val = target_insert_watchpoint (addr, len, type);
  		      if (val == -1)
  			{
+ 			  /* Don't exit the loop, try to insert every
+ 			     value on the value chain.  That's because
+ 			     we will be removing all the watches below,
+ 			     and removing a watchpoint we didn't insert
+ 			     could have adverse effects.  */
  			  b->inserted = 0;
  			}
  		      val = 0;
  		    }
*************** insert_breakpoints ()
*** 805,812 ****
  	      /* Failure to insert a watchpoint on any memory value in the
  		 value chain brings us here.  */
  	      if (!b->inserted)
! 		warning ("Hardware watchpoint %d: Could not insert watchpoint\n",
! 			 b->number);
  	    }
  	  else
  	    {
--- 809,825 ----
  	      /* Failure to insert a watchpoint on any memory value in the
  		 value chain brings us here.  */
  	      if (!b->inserted)
! 		{
! 		  warning ("\
! Hardware watchpoint %d: Could not insert watchpoint\n", b->number);
! 		  /* This watchpoint couldn't be inserted, but some of
! 		     the values on its value chain might have their
! 		     watchpoints inserted.  We must remove them,
! 		     otherwise the resources they use will remain
! 		     occupied.  */
! 		  remove_breakpoint (b, mark_uninserted);
! 		  val = -1;	/* to return failure indication */
! 		}
  	    }
  	  else
  	    {
*************** bpstat_stop_status (pc, not_a_breakpoint
*** 2124,2130 ****
        bs->print = 1;
  
        sprintf (message, message1, b->number);
!       if (b->type == bp_watchpoint || b->type == bp_hardware_watchpoint)
  	{
  	  switch (catch_errors (watchpoint_check, bs, message, RETURN_MASK_ALL))
  	    {
--- 2137,2143 ----
        bs->print = 1;
  
        sprintf (message, message1, b->number);
!       if (b->type == bp_watchpoint)
  	{
  	  switch (catch_errors (watchpoint_check, bs, message, RETURN_MASK_ALL))
  	    {
*************** bpstat_stop_status (pc, not_a_breakpoint
*** 2141,2148 ****
  	      /* Don't stop.  */
  	      bs->print_it = print_it_noop;
  	      bs->stop = 0;
- 	      /* Don't consider this a hit.  */
- 	      --(b->hit_count);
  	      continue;
  	    default:
  	      /* Can't happen.  */
--- 2154,2159 ----
*************** bpstat_stop_status (pc, not_a_breakpoint
*** 2160,2173 ****
  	      break;
  	    }
  	}
!       else if (b->type == bp_read_watchpoint || b->type == bp_access_watchpoint)
          {
  	  CORE_ADDR addr;
  	  value_ptr v;
            int found = 0;
  
  	  addr = target_stopped_data_address();
! 	  if (addr == 0) continue;
            for (v = b->val_chain; v; v = v->next)
              {
                if (v->lval == lval_memory)
--- 2171,2192 ----
  	      break;
  	    }
  	}
!       else if (b->type == bp_read_watchpoint
! 	       || b->type == bp_access_watchpoint
! 	       || b->type == bp_hardware_watchpoint)
          {
  	  CORE_ADDR addr;
  	  value_ptr v;
            int found = 0;
  
  	  addr = target_stopped_data_address();
! 	  if (addr == 0)
! 	    {
! 	      /* Don't stop.  */
! 	      bs->print_it = print_it_noop;
! 	      bs->stop = 0;
! 	      continue;
! 	    }
            for (v = b->val_chain; v; v = v->next)
              {
                if (v->lval == lval_memory)
*************** bpstat_stop_status (pc, not_a_breakpoint
*** 2175,2181 ****
                    CORE_ADDR vaddr;
  
                    vaddr = VALUE_ADDRESS (v) + VALUE_OFFSET (v);
! 	          if (addr == vaddr)
  	            found = 1;
                  }
              }
--- 2194,2205 ----
                    CORE_ADDR vaddr;
  
                    vaddr = VALUE_ADDRESS (v) + VALUE_OFFSET (v);
! 		  /* If VADDR is watched as a sequence of several
! 		     addresses (e.g., with several debug registers),
! 		     the address that triggered might be anywhere
! 		     in the region that V defines.  */
! 	          if (addr >= vaddr
! 		      && addr < vaddr + TYPE_LENGTH (VALUE_TYPE (v)))
  	            found = 1;
                  }
              }
*************** bpstat_stop_status (pc, not_a_breakpoint
*** 2188,2199 ****
                    /* Stop.  */
                    break;
                  case WP_VALUE_CHANGED:
                  case WP_VALUE_NOT_CHANGED:
!                   /* Stop.  */
  		  ++(b->hit_count);
                    break;
                  default:
                    /* Can't happen.  */
                  case 0:
                    /* Error from catch_errors.  */
                    printf_filtered ("Watchpoint %d deleted.\n", b->number);
--- 2212,2251 ----
                    /* Stop.  */
                    break;
                  case WP_VALUE_CHANGED:
+ 		  if (b->type == bp_read_watchpoint)
+ 		    {
+ 		      /* Don't stop: read watchpoints shouldn't fire if
+ 			 the value has changed.  This is for targets
+ 			 which cannot set read-only watchpoints.  */
+ 		      bs->print_it = print_it_noop;
+ 		      bs->stop = 0;
+ 		      continue;
+ 		    }
+ 		  ++(b->hit_count);
+ 		  break;
                  case WP_VALUE_NOT_CHANGED:
!                   /* Stop, but not if this is a write-only watchpoint.
! 		     FIXME: this causes GDB to not report watchpoints
! 		     if the memory was written with the same value.
! 		     However, to correct this, we need maintain a
! 		     one-to-one correspeondence between the watchpoint
! 		     and the target resources used to implement it, and
! 		     let the target tell us which watchpoint(s) fired.
! 		     With the current design, if we don't check that the
! 		     value has changed, we might erroneously say that a
! 		     read watchpoint triggered if it watches the same
! 		     address as some other write watchpoint.  */
! 		  if (b->type == bp_hardware_watchpoint)
! 		    {
! 		      bs->print_it = print_it_noop;
! 		      bs->stop = 0;
! 		      continue;
! 		    }
  		  ++(b->hit_count);
                    break;
                  default:
                    /* Can't happen.  */
+ 		  /* FALLTHROUGH */
                  case 0:
                    /* Error from catch_errors.  */
                    printf_filtered ("Watchpoint %d deleted.\n", b->number);
*************** bpstat_stop_status (pc, not_a_breakpoint
*** 2204,2209 ****
--- 2256,2271 ----
                    bs->print_it = print_it_done;
                    break;
  	      }
+ 	  else
+ 	    {
+ 	      /* This is a case where some watchpoint(s) triggered,
+ 		 but not at the address of this watchpoint (FOUND
+ 		 was left zero).  So don't print anything for this
+ 		 watchpoint.  */
+ 	      bs->print_it = print_it_noop;
+ 	      bs->stop = 0;
+ 	      continue;
+ 	    }
          }
        else 
          {
*************** watch_command_1 (arg, accessflag, from_t
*** 4393,4398 ****
--- 4455,4465 ----
      ((byte_size) <= (REGISTER_SIZE))
  #endif
  
+ #if !defined(TARGET_REGION_OK_FOR_HW_WATCHPOINT)
+ #define TARGET_REGION_OK_FOR_HW_WATCHPOINT(addr,len) \
+ 	TARGET_REGION_SIZE_OK_FOR_HW_WATCHPOINT(len)
+ #endif
+ 
  static int
  can_use_hardware_watchpoint (v)
       struct value *v;
*************** can_use_hardware_watchpoint (v)
*** 4411,4418 ****
      {
        if (v->lval == lval_memory)
  	{
! 	  if (TARGET_REGION_SIZE_OK_FOR_HW_WATCHPOINT (TYPE_LENGTH (VALUE_TYPE (v))))
! 	    found_memory_cnt++;
          }
        else if (v->lval != not_lval && v->modifiable == 0)
  	return 0;
--- 4478,4489 ----
      {
        if (v->lval == lval_memory)
  	{
! 	  int vaddr = VALUE_ADDRESS (v) + VALUE_OFFSET (v);
! 	  int len = TYPE_LENGTH (VALUE_TYPE (v));
! 
! 	  if (!TARGET_REGION_OK_FOR_HW_WATCHPOINT (vaddr, len))
! 	    return 0;
! 	  found_memory_cnt++;
          }
        else if (v->lval != not_lval && v->modifiable == 0)
  	return 0;
*************** delete_breakpoint (bpt)
*** 5667,5673 ****
  	    && b->enable != call_disabled)
  	  {
  	    int val;
! 	    val = target_insert_breakpoint (b->address, b->shadow_contents);
  	    if (val != 0)
  	      {
  		target_terminal_ours_for_output ();
--- 5738,5746 ----
  	    && b->enable != call_disabled)
  	  {
  	    int val;
! 	    val = b->type == bp_hardware_breakpoint
! 	      ? target_insert_hw_breakpoint (b->address, b->shadow_contents)
! 	      : target_insert_breakpoint (b->address, b->shadow_contents);
  	    if (val != 0)
  	      {
  		target_terminal_ours_for_output ();
*** gdb/target.h~0	Fri Mar 26 06:26:02 1999
--- gdb/target.h	Sat Aug 14 14:46:04 1999
*************** extern char *normal_pid_to_str PARAMS ((
*** 1046,1055 ****
  
  #ifndef TARGET_HAS_HARDWARE_WATCHPOINTS
  
! /* Returns non-zero if we can set a hardware watchpoint of type TYPE.  TYPE is
!    one of bp_hardware_watchpoint, bp_read_watchpoint, bp_write_watchpoint, or
!    bp_hardware_breakpoint.  CNT is the number of such watchpoints used so far
!    (including this one?).  OTHERTYPE is who knows what...  */
  
  #define TARGET_CAN_USE_HARDWARE_WATCHPOINT(TYPE,CNT,OTHERTYPE) 0
  
--- 1046,1061 ----
  
  #ifndef TARGET_HAS_HARDWARE_WATCHPOINTS
  
! /* Returns the number of hardware watchpoints of type TYPE that we can
!    set.  Value is positive if we can set CNT watchpoints, zero if
!    setting watchpoints of type TYPE is not supported, and negative if
!    CNT is more than the maximum number of watchpoints of type TYPE
!    that we can support.  TYPE is one of bp_hardware_watchpoint,
!    bp_read_watchpoint, bp_write_watchpoint, or bp_hardware_breakpoint.
!    CNT is the number of such watchpoints used so far (including this
!    one).  OTHERTYPE is non-zero if other types of watchpoints are
!    currently enabled (this is for targets where all watchpoints need to
!    be of the same type, for example).  */
  
  #define TARGET_CAN_USE_HARDWARE_WATCHPOINT(TYPE,CNT,OTHERTYPE) 0
  
*************** extern char *normal_pid_to_str PARAMS ((
*** 1058,1063 ****
--- 1064,1076 ----
          (LONGEST)(byte_count) <= REGISTER_SIZE
  #endif
  
+ /* Returns non-zero if we can use hardware watchpoints to watch a region
+    whose address is ADDR and whose length is LEN.  */
+ #if !defined(TARGET_REGION_OK_FOR_HW_WATCHPOINT)
+ #define TARGET_REGION_OK_FOR_HW_WATCHPOINT(addr,len) \
+ 	TARGET_REGION_SIZE_OK_FOR_HW_WATCHPOINT(len)
+ #endif
+ 
  /* However, some addresses may not be profitable to use hardware to watch,
     or may be difficult to understand when the addressed object is out of
     scope, and hence should be unwatched.  On some targets, this may have

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019