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


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

Watchpoint-related changes in go32-nat.c and friends



The following changes make watchpoints work much better in the DJGPP
port of GDB.  In particular, I can now watch double values.  These
patches also prevent crashes when single-stepping over INT nn
instructions.

1999-08-16  Eli Zaretskii  <eliz@is.elta.co.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@is.elta.co.il>

	* 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).

1999-08-07  Eli Zaretskii  <eliz@is.elta.co.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@is.elta.co.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.

*** 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");
  	}
      }

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