Add h/w watchpoint support to x86-linux, win32-i386.
authorDoug Evans <dje@google.com>
Tue, 30 Jun 2009 16:35:25 +0000 (16:35 +0000)
committerDoug Evans <dje@google.com>
Tue, 30 Jun 2009 16:35:25 +0000 (16:35 +0000)
* Makefile.in (SFILES): Add i386-low.c
(i386_low_h): Define.
(i386-low.o): Add dependencies.
(linux-x86-low.o): Add i386-low.h dependency.
(win32-i386-low.o): Ditto.
* i386-low.c: New file.
* i386-low.h: New file.
* configure.srv (i[34567]86-*-cygwin*): Add i386-low.o to srv_tgtobj.
(i[34567]86-*-linux*, i[34567]86-*-mingw*, x86_64-*-linux*): Ditto.
* linux-low.c (linux_add_process): Initialize arch_private.
(linux_remove_process): Free arch_private.
(add_lwp): Initialize arch_private.
(delete_lwp): Free arch_private.
(linux_resume_one_lwp): Call the_low_target.prepare_to_resume if
provided.
* linux-low.h (process_info_private): New member arch_private.
(lwp_info): New member arch_private.
(linux_target_ops): New members new_process, new_thread,
prepare_to_resume.
(ptid_of): New macro.
* linux-x86-low.c: Include stddef.h, i386-low.h.
(arch_process_info): New struct.
(arch_lwp_info): New struct.
(x86_linux_dr_get, x86_linux_dr_set): New functions.
(i386_dr_low_set_addr, i386_dr_low_set_control): New functions.
(i386_dr_low_get_status): New function.
(x86_insert_point, x86_remove_point): New functions.
(x86_stopped_by_watchpoint): New function.
(x86_stopped_data_address): New function.
(x86_linux_new_process, x86_linux_new_thread): New functions.
(x86_linux_prepare_to_resume): New function.
(the_low_target): Add entries for insert_point, remove_point,
stopped_by_watchpoint, stopped_data_address, new_process, new_thread,
prepare_to_resume.
* server.c (debug_hw_points): New global.
(monitor_show_help): Document set debug-hw-points.
(handle_query): Process "set debug-hw-points".
* server.h (debug_hw_points): Declare.
(paddress): Declare.
* utils.c (NUMCELLS, CELLSIZE): New macros.
(get_sell, xsnprintf, paddress): New functions.
* win32-arm-low.c (the_low_target): Add entries for insert_point,
remove_point, stopped_by_watchpoint, stopped_data_address.
* win32-i386-low.c: Include i386-low.h.
(debug_reg_state): Replaces dr.
(i386_dr_low_set_addr, i386_dr_low_set_control): New functions.
(i386_dr_low_get_status): New function.
(i386_insert_point, i386_remove_point): New functions.
(i386_stopped_by_watchpoint): New function.
(i386_stopped_data_address): New function.
(i386_initial_stuff): Update.
(get_thread_context,set_thread_context,i386_thread_added): Update.
(the_low_target): Add entries for insert_point,
remove_point, stopped_by_watchpoint, stopped_data_address.
* win32-low.c (win32_insert_watchpoint): New function.
(win32_remove_watchpoint): New function.
(win32_stopped_by_watchpoint): New function.
(win32_stopped_data_address): New function.
(win32_target_ops): Add entries for insert_watchpoint,
remove_watchpoint, stopped_by_watchpoint, stopped_data_address.
* win32-low.h (win32_target_ops): New members insert_point,
remove_point, stopped_by_watchpoint, stopped_data_address.

13 files changed:
gdb/gdbserver/ChangeLog
gdb/gdbserver/Makefile.in
gdb/gdbserver/configure.srv
gdb/gdbserver/linux-low.c
gdb/gdbserver/linux-low.h
gdb/gdbserver/linux-x86-low.c
gdb/gdbserver/server.c
gdb/gdbserver/server.h
gdb/gdbserver/utils.c
gdb/gdbserver/win32-arm-low.c
gdb/gdbserver/win32-i386-low.c
gdb/gdbserver/win32-low.c
gdb/gdbserver/win32-low.h

index 8cb2d92f4991dae8e17622032bd0640881d1ac49..86fe1746ae69be70bcf1d84172264f98497b353b 100644 (file)
@@ -1,3 +1,70 @@
+2009-06-30  Doug Evans  <dje@google.com>
+           Pierre Muller  <muller@ics.u-strasbg.fr>
+
+       Add h/w watchpoint support to x86-linux, win32-i386.
+       * Makefile.in (SFILES): Add i386-low.c
+       (i386_low_h): Define.
+       (i386-low.o): Add dependencies.
+       (linux-x86-low.o): Add i386-low.h dependency.
+       (win32-i386-low.o): Ditto.
+       * i386-low.c: New file.
+       * i386-low.h: New file.
+       * configure.srv (i[34567]86-*-cygwin*): Add i386-low.o to srv_tgtobj.
+       (i[34567]86-*-linux*, i[34567]86-*-mingw*, x86_64-*-linux*): Ditto.
+       * linux-low.c (linux_add_process): Initialize arch_private.
+       (linux_remove_process): Free arch_private.
+       (add_lwp): Initialize arch_private.
+       (delete_lwp): Free arch_private.
+       (linux_resume_one_lwp): Call the_low_target.prepare_to_resume if
+       provided.
+       * linux-low.h (process_info_private): New member arch_private.
+       (lwp_info): New member arch_private.
+       (linux_target_ops): New members new_process, new_thread,
+       prepare_to_resume.
+       (ptid_of): New macro.
+       * linux-x86-low.c: Include stddef.h, i386-low.h.
+       (arch_process_info): New struct.
+       (arch_lwp_info): New struct.
+       (x86_linux_dr_get, x86_linux_dr_set): New functions.
+       (i386_dr_low_set_addr, i386_dr_low_set_control): New functions.
+       (i386_dr_low_get_status): New function.
+       (x86_insert_point, x86_remove_point): New functions.
+       (x86_stopped_by_watchpoint): New function.
+       (x86_stopped_data_address): New function.
+       (x86_linux_new_process, x86_linux_new_thread): New functions.
+       (x86_linux_prepare_to_resume): New function.
+       (the_low_target): Add entries for insert_point, remove_point,
+       stopped_by_watchpoint, stopped_data_address, new_process, new_thread,
+       prepare_to_resume.
+       * server.c (debug_hw_points): New global.
+       (monitor_show_help): Document set debug-hw-points.
+       (handle_query): Process "set debug-hw-points".
+       * server.h (debug_hw_points): Declare.
+       (paddress): Declare.
+       * utils.c (NUMCELLS, CELLSIZE): New macros.
+       (get_sell, xsnprintf, paddress): New functions.
+       * win32-arm-low.c (the_low_target): Add entries for insert_point,
+       remove_point, stopped_by_watchpoint, stopped_data_address.
+       * win32-i386-low.c: Include i386-low.h.
+       (debug_reg_state): Replaces dr.
+       (i386_dr_low_set_addr, i386_dr_low_set_control): New functions.
+       (i386_dr_low_get_status): New function.
+       (i386_insert_point, i386_remove_point): New functions.
+       (i386_stopped_by_watchpoint): New function.
+       (i386_stopped_data_address): New function.
+       (i386_initial_stuff): Update.
+       (get_thread_context,set_thread_context,i386_thread_added): Update.
+       (the_low_target): Add entries for insert_point,
+       remove_point, stopped_by_watchpoint, stopped_data_address.
+       * win32-low.c (win32_insert_watchpoint): New function.
+       (win32_remove_watchpoint): New function.
+       (win32_stopped_by_watchpoint): New function.
+       (win32_stopped_data_address): New function.
+       (win32_target_ops): Add entries for insert_watchpoint,
+       remove_watchpoint, stopped_by_watchpoint, stopped_data_address.
+       * win32-low.h (win32_target_ops): New members insert_point,
+       remove_point, stopped_by_watchpoint, stopped_data_address.
+
 2009-06-25  Pedro Alves  <pedro@codesourcery.com>
 
        * server.c (process_serial_event): Re-return unsupported, not
index f395d9edb6abf248c049cb0088c24d6cffdb2844..37d6095922e96f71a71009a1238e8206d4a260c0 100644 (file)
@@ -104,7 +104,7 @@ SFILES=     $(srcdir)/gdbreplay.c $(srcdir)/inferiors.c \
        $(srcdir)/thread-db.c $(srcdir)/utils.c \
        $(srcdir)/linux-arm-low.c $(srcdir)/linux-cris-low.c \
        $(srcdir)/linux-crisv32-low.c \
-       $(srcdir)/i387-fp.c \
+       ${srcdir}/i386-low.c $(srcdir)/i387-fp.c \
        $(srcdir)/linux-ia64-low.c $(srcdir)/linux-low.c \
        $(srcdir)/linux-m32r-low.c \
        $(srcdir)/linux-m68k-low.c $(srcdir)/linux-mips-low.c \
@@ -287,6 +287,10 @@ signals.o: ../common/signals.c $(server_h)
 memmem.o: ../gnulib/memmem.c
        $(CC) -o memmem.o -c $(CPPFLAGS) $(INTERNAL_CFLAGS) $<
 
+i386_low_h = $(srcdir)/i386-low.h
+
+i386-low.o: i386-low.c $(i386_low_h) $(server_h) $(target_h)
+
 i387-fp.o: i387-fp.c $(server_h)
 
 linux-low.o: linux-low.c $(linux_low_h) $(server_h)
@@ -304,7 +308,7 @@ linux-ppc-low.o: linux-ppc-low.c $(linux_low_h) $(server_h)
 linux-s390-low.o: linux-s390-low.c $(linux_low_h) $(server_h)
 linux-sh-low.o: linux-sh-low.c $(linux_low_h) $(server_h)
 linux-x86-low.o: linux-x86-low.c $(linux_low_h) $(server_h) \
-       $(gdb_proc_service_h)
+       $(gdb_proc_service_h) $(i386_low_h)
 linux-xtensa-low.o: linux-xtensa-low.c xtensa-xtregs.c $(linux_low_h) $(server_h)
 
 win32_low_h = $(srcdir)/win32-low.h
@@ -312,7 +316,7 @@ win32_low_h = $(srcdir)/win32-low.h
 win32-low.o: win32-low.c $(win32_low_h) $(server_h) $(regdef_h) $(regcache_h)
 
 win32-arm-low.o: win32-arm-low.c $(win32_low_h) $(server_h)
-win32-i386-low.o: win32-i386-low.c $(win32_low_h) $(server_h)
+win32-i386-low.o: win32-i386-low.c $(win32_low_h) $(server_h) $(i386_low_h)
 
 spu-low.o: spu-low.c $(server_h)
 
index e4252af01e8345c91253f09266a8b141c18f4ba2..a3ffcb4733b1f6b91a37ba1e503b3162fb5fdd4e 100644 (file)
@@ -53,10 +53,10 @@ case "${target}" in
                        srv_linux_thread_db=yes
                        ;;
   i[34567]86-*-cygwin*)        srv_regobj=reg-i386.o
-                       srv_tgtobj="win32-low.o win32-i386-low.o"
+                       srv_tgtobj="i386-low.o win32-low.o win32-i386-low.o"
                        ;;
   i[34567]86-*-linux*) srv_regobj=reg-i386-linux.o
-                       srv_tgtobj="linux-low.o linux-x86-low.o i387-fp.o"
+                       srv_tgtobj="linux-low.o linux-x86-low.o i386-low.o i387-fp.o"
                        srv_linux_usrregs=yes
                        srv_linux_regsets=yes
                        srv_linux_thread_db=yes
@@ -71,7 +71,7 @@ case "${target}" in
                        srv_mingwce=yes
                        ;;
   i[34567]86-*-mingw*) srv_regobj=reg-i386.o
-                       srv_tgtobj="win32-low.o win32-i386-low.o"
+                       srv_tgtobj="i386-low.o win32-low.o win32-i386-low.o"
                        srv_mingw=yes
                        ;;
   ia64-*-linux*)       srv_regobj=reg-ia64.o
@@ -170,7 +170,7 @@ case "${target}" in
                        srv_tgtobj="spu-low.o"
                        ;;
   x86_64-*-linux*)     srv_regobj="reg-x86-64-linux.o reg-i386-linux.o"
-                       srv_tgtobj="linux-low.o linux-x86-low.o i387-fp.o"
+                       srv_tgtobj="linux-low.o linux-x86-low.o i386-low.o i387-fp.o"
                        srv_linux_usrregs=yes # This is for i386 progs.
                        srv_linux_regsets=yes
                        srv_linux_thread_db=yes
index 9f3251813917368a94458d8f0b82dcc681773b0b..5284a983971f7011b8fb005bfc9a5564d9338b4d 100644 (file)
@@ -224,6 +224,7 @@ delete_lwp (struct lwp_info *lwp)
 {
   remove_thread (get_lwp_thread (lwp));
   remove_inferior (&all_lwps, &lwp->head);
+  free (lwp->arch_private);
   free (lwp);
 }
 
@@ -242,6 +243,9 @@ linux_add_process (int pid, int attached)
   proc = add_process (pid, attached);
   proc->private = xcalloc (1, sizeof (*proc->private));
 
+  if (the_low_target.new_process != NULL)
+    proc->private->arch_private = the_low_target.new_process ();
+
   return proc;
 }
 
@@ -251,6 +255,7 @@ linux_add_process (int pid, int attached)
 static void
 linux_remove_process (struct process_info *process)
 {
+  free (process->private->arch_private);
   free (process->private);
   remove_process (process);
 }
@@ -376,6 +381,9 @@ add_lwp (ptid_t ptid)
 
   lwp->head.id = ptid;
 
+  if (the_low_target.new_thread != NULL)
+    lwp->arch_private = the_low_target.new_thread ();
+
   add_inferior_to_list (&all_lwps, &lwp->head);
 
   return lwp;
@@ -466,7 +474,6 @@ linux_attach_lwp_1 (unsigned long lwpid, int initial)
   new_lwp = (struct lwp_info *) add_lwp (ptid);
   add_thread (ptid, new_lwp);
 
-
   /* We need to wait for SIGSTOP before being able to make the next
      ptrace call on this LWP.  */
   new_lwp->must_set_ptrace_flags = 1;
@@ -1740,6 +1747,9 @@ linux_resume_one_lwp (struct lwp_info *lwp,
       *p_sig = NULL;
     }
 
+  if (the_low_target.prepare_to_resume != NULL)
+    the_low_target.prepare_to_resume (lwp);
+
   regcache_invalidate_one ((struct inferior_list_entry *)
                           get_lwp_thread (lwp));
   errno = 0;
index 8369db912d1de8a57e16512b22d1220e159489d3..603963e9b089a9386b06ab3fbfdd2f46972daa0c 100644 (file)
@@ -56,8 +56,13 @@ struct process_info_private
 
   /* Connection to the libthread_db library.  */
   td_thragent_t *thread_agent;
+
+  /* Arch-specific additions.  */
+  struct arch_process_info *arch_private;
 };
 
+struct lwp_info;
+
 struct linux_target_ops
 {
   /* Architecture-specific setup.  */
@@ -97,10 +102,24 @@ struct linux_target_ops
      If DIRECTION is 1, then copy from INF to NATIVE.
      If DIRECTION is 0, copy from NATIVE to INF.  */
   int (*siginfo_fixup) (struct siginfo *native, void *inf, int direction);
+
+  /* Hook to call when a new process is created or attached to.
+     If extra per-process architecture-specific data is needed,
+     allocate it here.  */
+  struct arch_process_info * (*new_process) (void);
+
+  /* Hook to call when a new thread is detected.
+     If extra per-thread architecture-specific data is needed,
+     allocate it here.  */
+  struct arch_lwp_info * (*new_thread) (void);
+
+  /* Hook to call prior to resuming a thread.  */
+  void (*prepare_to_resume) (struct lwp_info *);
 };
 
 extern struct linux_target_ops the_low_target;
 
+#define ptid_of(proc) ((proc)->head.id)
 #define pid_of(proc) ptid_get_pid ((proc)->head.id)
 #define lwpid_of(proc) ptid_get_lwp ((proc)->head.id)
 
@@ -173,6 +192,9 @@ struct lwp_info
      THREAD_KNOWN is set.  */
   td_thrhandle_t th;
 #endif
+
+  /* Arch-specific additions.  */
+  struct arch_lwp_info *arch_private;
 };
 
 extern struct inferior_list all_lwps;
index 416f19f9abbbe8df9db78ea456c6a062cdc2bd09..2f17f45927dc565ff946757aa8eba71da257b34b 100644 (file)
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
+#include <stddef.h>
 #include <signal.h>
 #include "server.h"
 #include "linux-low.h"
 #include "i387-fp.h"
+#include "i386-low.h"
 
 #include "gdb_proc_service.h"
 
@@ -56,6 +58,21 @@ void init_registers_x86_64_linux (void);
 #define ARCH_GET_GS 0x1004
 #endif
 
+/* Per-process arch-specific data we want to keep.  */
+
+struct arch_process_info
+{
+  struct i386_debug_reg_state debug_reg_state;
+};
+
+/* Per-thread arch-specific data we want to keep.  */
+
+struct arch_lwp_info
+{
+  /* Non-zero if our copy differs from what's recorded in the thread.  */
+  int debug_registers_changed;
+};
+
 #ifdef __x86_64__
 
 /* Mapping between the general-purpose registers in `struct user'
@@ -317,6 +334,198 @@ x86_breakpoint_at (CORE_ADDR pc)
   return 0;
 }
 \f
+/* Support for debug registers.  */
+
+static unsigned long
+x86_linux_dr_get (ptid_t ptid, int regnum)
+{
+  int tid;
+  unsigned long value;
+
+  tid = ptid_get_lwp (ptid);
+
+  errno = 0;
+  value = ptrace (PTRACE_PEEKUSER, tid,
+                 offsetof (struct user, u_debugreg[regnum]), 0);
+  if (errno != 0)
+    error ("Couldn't read debug register");
+
+  return value;
+}
+
+static void
+x86_linux_dr_set (ptid_t ptid, int regnum, unsigned long value)
+{
+  int tid;
+
+  tid = ptid_get_lwp (ptid);
+
+  errno = 0;
+  ptrace (PTRACE_POKEUSER, tid,
+         offsetof (struct user, u_debugreg[regnum]), value);
+  if (errno != 0)
+    error ("Couldn't write debug register");
+}
+
+/* Update the inferior's debug register REGNUM from STATE.  */
+
+void
+i386_dr_low_set_addr (const struct i386_debug_reg_state *state, int regnum)
+{
+  struct inferior_list_entry *lp;
+  CORE_ADDR addr;
+  /* Only need to update the threads of this process.  */
+  int pid = pid_of (get_thread_lwp (current_inferior));
+
+  if (! (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR))
+    fatal ("Invalid debug register %d", regnum);
+
+  addr = state->dr_mirror[regnum];
+
+  for (lp = all_lwps.head; lp; lp = lp->next)
+    {
+      struct lwp_info *lwp = (struct lwp_info *) lp;
+
+      /* The actual update is done later, we just mark that the register
+        needs updating.  */
+      if (pid_of (lwp) == pid)
+       lwp->arch_private->debug_registers_changed = 1;
+    }
+}
+
+/* Update the inferior's DR7 debug control register from STATE.  */
+
+void
+i386_dr_low_set_control (const struct i386_debug_reg_state *state)
+{
+  struct inferior_list_entry *lp;
+  /* Only need to update the threads of this process.  */
+  int pid = pid_of (get_thread_lwp (current_inferior));
+
+  for (lp = all_lwps.head; lp; lp = lp->next)
+    {
+      struct lwp_info *lwp = (struct lwp_info *) lp;
+
+      /* The actual update is done later, we just mark that the register
+        needs updating.  */
+      if (pid_of (lwp) == pid)
+       lwp->arch_private->debug_registers_changed = 1;
+    }
+}
+
+/* Get the value of the DR6 debug status register from the inferior
+   and record it in STATE.  */
+
+void
+i386_dr_low_get_status (struct i386_debug_reg_state *state)
+{
+  struct lwp_info *lwp = get_thread_lwp (current_inferior);
+  ptid_t ptid = ptid_of (lwp);
+
+  state->dr_status_mirror = x86_linux_dr_get (ptid, DR_STATUS);
+}
+\f
+/* Watchpoint support.  */
+
+static int
+x86_insert_point (char type, CORE_ADDR addr, int len)
+{
+  struct process_info *proc = current_process ();
+  switch (type)
+    {
+    case '2':
+    case '3':
+    case '4':
+      return i386_low_insert_watchpoint (&proc->private->arch_private->debug_reg_state,
+                                        type, addr, len);
+    default:
+      /* Unsupported.  */
+      return 1;
+    }
+}
+
+static int
+x86_remove_point (char type, CORE_ADDR addr, int len)
+{
+  struct process_info *proc = current_process ();
+  switch (type)
+    {
+    case '2':
+    case '3':
+    case '4':
+      return i386_low_remove_watchpoint (&proc->private->arch_private->debug_reg_state,
+                                        type, addr, len);
+    default:
+      /* Unsupported.  */
+      return 1;
+    }
+}
+
+static int
+x86_stopped_by_watchpoint (void)
+{
+  struct process_info *proc = current_process ();
+  return i386_low_stopped_by_watchpoint (&proc->private->arch_private->debug_reg_state);
+}
+
+static CORE_ADDR
+x86_stopped_data_address (void)
+{
+  struct process_info *proc = current_process ();
+  CORE_ADDR addr;
+  if (i386_low_stopped_data_address (&proc->private->arch_private->debug_reg_state,
+                                    &addr))
+    return addr;
+  return 0;
+}
+\f
+/* Called when a new process is created.  */
+
+static struct arch_process_info *
+x86_linux_new_process (void)
+{
+  struct arch_process_info *info = xcalloc (1, sizeof (*info));
+
+  i386_low_init_dregs (&info->debug_reg_state);
+
+  return info;
+}
+
+/* Called when a new thread is detected.  */
+
+static struct arch_lwp_info *
+x86_linux_new_thread (void)
+{
+  struct arch_lwp_info *info = xcalloc (1, sizeof (*info));
+
+  info->debug_registers_changed = 1;
+
+  return info;
+}
+
+/* Called when resuming a thread.
+   If the debug regs have changed, update the thread's copies.  */
+
+static void
+x86_linux_prepare_to_resume (struct lwp_info *lwp)
+{
+  if (lwp->arch_private->debug_registers_changed)
+    {
+      int i;
+      ptid_t ptid = ptid_of (lwp);
+      int pid = ptid_get_pid (ptid);
+      struct process_info *proc = find_process_pid (pid);
+      struct i386_debug_reg_state *state = &proc->private->arch_private->debug_reg_state;
+
+      for (i = DR_FIRSTADDR; i <= DR_LASTADDR; i++)
+       x86_linux_dr_set (ptid, i, state->dr_mirror[i]);
+
+      x86_linux_dr_set (ptid, DR_CONTROL, state->dr_control_mirror);
+
+      lwp->arch_private->debug_registers_changed = 0;
+    }
+}
+\f
 /* When GDBSERVER is built as a 64-bit application on linux, the
    PTRACE_GETSIGINFO data is always presented in 64-bit layout.  Since
    debugging a 32-bit inferior with a 64-bit GDBSERVER should look the same
@@ -630,10 +839,10 @@ struct linux_target_ops the_low_target =
   NULL,
   1,
   x86_breakpoint_at,
-  NULL,
-  NULL,
-  NULL,
-  NULL,
+  x86_insert_point,
+  x86_remove_point,
+  x86_stopped_by_watchpoint,
+  x86_stopped_data_address,
   /* collect_ptrace_register/supply_ptrace_register are not needed in the
      native i386 case (no registers smaller than an xfer unit), and are not
      used in the biarch case (HAVE_LINUX_USRREGS is not defined).  */
@@ -641,4 +850,7 @@ struct linux_target_ops the_low_target =
   NULL,
   /* need to fix up i386 siginfo if host is amd64 */
   x86_siginfo_fixup,
+  x86_linux_new_process,
+  x86_linux_new_thread,
+  x86_linux_prepare_to_resume
 };
index 76c2e0ec5505f7b98d8311deb557d4175fb8c13e..d704180a5399894f23ab0a23c79de5ec133166fb 100644 (file)
@@ -51,6 +51,9 @@ static char **program_argv, **wrapper_argv;
    was originally used to debug LinuxThreads support.  */
 int debug_threads;
 
+/* Enable debugging of h/w breakpoint/watchpoint support.  */
+int debug_hw_points;
+
 int pass_signals[TARGET_SIGNAL_LAST];
 
 jmp_buf toplevel;
@@ -495,6 +498,8 @@ monitor_show_help (void)
   monitor_output ("The following monitor commands are supported:\n");
   monitor_output ("  set debug <0|1>\n");
   monitor_output ("    Enable general debugging messages\n");
+  monitor_output ("  set debug-hw-points <0|1>\n");
+  monitor_output ("    Enable h/w breakpoint/watchpoint debugging messages\n");
   monitor_output ("  set remote-debug <0|1>\n");
   monitor_output ("    Enable remote protocol debugging messages\n");
   monitor_output ("  exit\n");
@@ -1216,6 +1221,16 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
          debug_threads = 0;
          monitor_output ("Debug output disabled.\n");
        }
+      else if (strcmp (mon, "set debug-hw-points 1") == 0)
+       {
+         debug_hw_points = 1;
+         monitor_output ("H/W point debugging output enabled.\n");
+       }
+      else if (strcmp (mon, "set debug-hw-points 0") == 0)
+       {
+         debug_hw_points = 0;
+         monitor_output ("H/W point debugging output disabled.\n");
+       }
       else if (strcmp (mon, "set remote-debug 1") == 0)
        {
          remote_debug = 1;
index 89ffeb7ea619dc556980d01da83d80cef6aaf3d5..9dc7d3b15479e39708729fcde41912989ddac538 100644 (file)
@@ -271,6 +271,7 @@ extern ptid_t step_thread;
 
 extern int server_waiting;
 extern int debug_threads;
+extern int debug_hw_points;
 extern int pass_signals[];
 
 extern jmp_buf toplevel;
@@ -407,6 +408,7 @@ void perror_with_name (const char *string);
 void error (const char *string,...) ATTR_NORETURN ATTR_FORMAT (printf, 1, 2);
 void fatal (const char *string,...) ATTR_NORETURN ATTR_FORMAT (printf, 1, 2);
 void warning (const char *string,...) ATTR_FORMAT (printf, 1, 2);
+char *paddress (CORE_ADDR addr);
 
 /* Maximum number of bytes to read/write at once.  The value here
    is chosen to fill up a packet (the headers account for the 32).  */
index a03c6b2a6b2613da0850703b9bcdf4b62622702f..5935380e064dea53d0263df61aea80473f939e6b 100644 (file)
@@ -170,3 +170,46 @@ warning (const char *string,...)
   fprintf (stderr, "\n");
   va_end (args);
 }
+
+/* Temporary storage using circular buffer.  */
+#define NUMCELLS 4
+#define CELLSIZE 50
+
+/* Return the next entry in the circular buffer.  */
+
+static char *
+get_cell (void)
+{
+  static char buf[NUMCELLS][CELLSIZE];
+  static int cell = 0;
+  if (++cell >= NUMCELLS)
+    cell = 0;
+  return buf[cell];
+}
+
+/* Stdarg wrapper around vsnprintf.
+   SIZE is the size of the buffer pointed to by STR.  */
+
+static int
+xsnprintf (char *str, size_t size, const char *format, ...)
+{
+  va_list args;
+  int ret;
+
+  va_start (args, format);
+  ret = vsnprintf (str, size, format, args);
+  va_end (args);
+
+  return ret;
+}
+
+/* Convert a CORE_ADDR into a HEX string, like %lx.
+   The result is stored in a circular static buffer, NUMCELLS deep.  */
+
+char *
+paddress (CORE_ADDR addr)
+{
+  char *str = get_cell ();
+  xsnprintf (str, CELLSIZE, "%lx", (long) addr);
+  return str;
+}
index 3913a9693167881c6471c8a15548125827270ac4..3254eec1a954084b0d51470e7f1f5908ca32b751 100644 (file)
@@ -122,4 +122,9 @@ struct win32_target_ops the_low_target = {
   NULL, /* single_step */
   (const unsigned char *) &arm_wince_breakpoint,
   arm_wince_breakpoint_len,
+  /* Watchpoint related functions.  See target.h for comments.  */
+  NULL, /* insert_point */
+  NULL, /* remove_point */
+  NULL, /* stopped_by_watchpoint */
+  NULL  /* stopped_data_address */
 };
index a9ede549a5305502493d289922bb5ec3f76730a1..7e058a58b564866122d4ea07845a257833e92b88 100644 (file)
@@ -17,6 +17,7 @@
 
 #include "server.h"
 #include "win32-low.h"
+#include "i386-low.h"
 
 #define FCS_REGNUM 27
 #define FOP_REGNUM 31
 /* Defined in auto-generated file reg-i386.c.  */
 void init_registers_i386 (void);
 
-static unsigned dr[8];
+static struct i386_debug_reg_state debug_reg_state;
 
 static int debug_registers_changed = 0;
 static int debug_registers_used = 0;
 
+/* Update the inferior's debug register REGNUM from STATE.  */
+
+void
+i386_dr_low_set_addr (const struct i386_debug_reg_state *state, int regnum)
+{
+  if (! (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR))
+    fatal ("Invalid debug register %d", regnum);
+
+  /* debug_reg_state.dr_mirror is already set.
+     Just notify i386_set_thread_context, i386_thread_added
+     that the registers need to be updated.  */
+  debug_registers_changed = 1;
+  debug_registers_used = 1;
+}
+
+/* Update the inferior's DR7 debug control register from STATE.  */
+
+void
+i386_dr_low_set_control (const struct i386_debug_reg_state *state)
+{
+  /* debug_reg_state.dr_control_mirror is already set.
+     Just notify i386_set_thread_context, i386_thread_added
+     that the registers need to be updated.  */
+  debug_registers_changed = 1;
+  debug_registers_used = 1;
+}
+
+/* Get the value of the DR6 debug status register from the inferior
+   and record it in STATE.  */
+
+void
+i386_dr_low_get_status (struct i386_debug_reg_state *state)
+{
+  /* We don't need to do anything here, the last call to thread_rec for
+     current_event.dwThreadId id has already set it.  */
+}
+
+/* Watchpoint support.  */
+
+static int
+i386_insert_point (char type, CORE_ADDR addr, int len)
+{
+  switch (type)
+    {
+    case '2':
+    case '3':
+    case '4':
+      return i386_low_insert_watchpoint (&debug_reg_state,
+                                        type, addr, len);
+    default:
+      /* Unsupported.  */
+      return 1;
+    }
+}
+
+static int
+i386_remove_point (char type, CORE_ADDR addr, int len)
+{
+  switch (type)
+    {
+    case '2':
+    case '3':
+    case '4':
+      return i386_low_remove_watchpoint (&debug_reg_state,
+                                        type, addr, len);
+    default:
+      /* Unsupported.  */
+      return 1;
+    }
+}
+
+static int
+i386_stopped_by_watchpoint (void)
+{
+  return i386_low_stopped_by_watchpoint (&debug_reg_state);
+}
+
+static CORE_ADDR
+i386_stopped_data_address (void)
+{
+  CORE_ADDR addr;
+  if (i386_low_stopped_data_address (&debug_reg_state, &addr))
+    return addr;
+  return 0;
+}
+
 static void
 i386_initial_stuff (void)
 {
-  memset (&dr, 0, sizeof (dr));
+  i386_low_init_dregs (&debug_reg_state);
   debug_registers_changed = 0;
   debug_registers_used = 0;
 }
@@ -55,12 +142,13 @@ i386_get_thread_context (win32_thread_info *th, DEBUG_EVENT* current_event)
   if (th->tid == current_event->dwThreadId)
     {
       /* Copy dr values from the current thread.  */
-      dr[0] = th->context.Dr0;
-      dr[1] = th->context.Dr1;
-      dr[2] = th->context.Dr2;
-      dr[3] = th->context.Dr3;
-      dr[6] = th->context.Dr6;
-      dr[7] = th->context.Dr7;
+      struct i386_debug_reg_state *dr = &debug_reg_state;
+      dr->dr_mirror[0] = th->context.Dr0;
+      dr->dr_mirror[1] = th->context.Dr1;
+      dr->dr_mirror[2] = th->context.Dr2;
+      dr->dr_mirror[3] = th->context.Dr3;
+      dr->dr_status_mirror = th->context.Dr6;
+      dr->dr_control_mirror = th->context.Dr7;
     }
 }
 
@@ -69,13 +157,14 @@ i386_set_thread_context (win32_thread_info *th, DEBUG_EVENT* current_event)
 {
   if (debug_registers_changed)
     {
-      th->context.Dr0 = dr[0];
-      th->context.Dr1 = dr[1];
-      th->context.Dr2 = dr[2];
-      th->context.Dr3 = dr[3];
-      /* th->context.Dr6 = dr[6];
+      struct i386_debug_reg_state *dr = &debug_reg_state;
+      th->context.Dr0 = dr->dr_mirror[0];
+      th->context.Dr1 = dr->dr_mirror[1];
+      th->context.Dr2 = dr->dr_mirror[2];
+      th->context.Dr3 = dr->dr_mirror[3];
+      /* th->context.Dr6 = dr->dr_status_mirror;
         FIXME: should we set dr6 also ?? */
-      th->context.Dr7 = dr[7];
+      th->context.Dr7 = dr->dr_control_mirror;
     }
 
   SetThreadContext (th->h, &th->context);
@@ -87,16 +176,17 @@ i386_thread_added (win32_thread_info *th)
   /* Set the debug registers for the new thread if they are used.  */
   if (debug_registers_used)
     {
+      struct i386_debug_reg_state *dr = &debug_reg_state;
       th->context.ContextFlags = CONTEXT_DEBUG_REGISTERS;
       GetThreadContext (th->h, &th->context);
 
-      th->context.Dr0 = dr[0];
-      th->context.Dr1 = dr[1];
-      th->context.Dr2 = dr[2];
-      th->context.Dr3 = dr[3];
-      /* th->context.Dr6 = dr[6];
+      th->context.Dr0 = dr->dr_mirror[0];
+      th->context.Dr1 = dr->dr_mirror[1];
+      th->context.Dr2 = dr->dr_mirror[2];
+      th->context.Dr3 = dr->dr_mirror[3];
+      /* th->context.Dr6 = dr->dr_status_mirror;
         FIXME: should we set dr6 also ?? */
-      th->context.Dr7 = dr[7];
+      th->context.Dr7 = dr->dr_control_mirror;
 
       SetThreadContext (th->h, &th->context);
       th->context.ContextFlags = 0;
@@ -205,4 +295,8 @@ struct win32_target_ops the_low_target = {
   i386_single_step,
   NULL, /* breakpoint */
   0, /* breakpoint_len */
+  i386_insert_point,
+  i386_remove_point,
+  i386_stopped_by_watchpoint,
+  i386_stopped_data_address
 };
index 869a1cdba79f1edd36431c8b093780575396bafe..a1380f6030b93bbf2117bcd9f6c366ede1b29b10 100644 (file)
@@ -228,6 +228,48 @@ child_delete_thread (DWORD pid, DWORD tid)
   delete_thread_info (thread);
 }
 
+/* These watchpoint related wrapper functions simply pass on the function call
+   if the low target has registered a corresponding function.  */
+
+static int
+win32_insert_point (char type, CORE_ADDR addr, int len)
+{
+  if (the_low_target.insert_point != NULL)
+    return the_low_target.insert_point (type, addr, len);
+  else
+    /* Unsupported (see target.h).  */
+    return 1;
+}
+
+static int
+win32_remove_point (char type, CORE_ADDR addr, int len)
+{
+  if (the_low_target.remove_point != NULL)
+    return the_low_target.remove_point (type, addr, len);
+  else
+    /* Unsupported (see target.h).  */
+    return 1;
+}
+
+static int
+win32_stopped_by_watchpoint (void)
+{
+  if (the_low_target.stopped_by_watchpoint != NULL)
+    return the_low_target.stopped_by_watchpoint ();
+  else
+    return 0;
+}
+
+static CORE_ADDR
+win32_stopped_data_address (void)
+{
+  if (the_low_target.stopped_data_address != NULL)
+    return the_low_target.stopped_data_address ();
+  else
+    return 0;
+}
+
+
 /* Transfer memory from/to the debugged process.  */
 static int
 child_xfer_memory (CORE_ADDR memaddr, char *our, int len,
@@ -1697,10 +1739,10 @@ static struct target_ops win32_target_ops = {
   NULL,
   win32_request_interrupt,
   NULL,
-  NULL,
-  NULL,
-  NULL,
-  NULL,
+  win32_insert_point,
+  win32_remove_point,
+  win32_stopped_by_watchpoint,
+  win32_stopped_data_address,
   NULL,
   NULL,
   NULL,
index 10c257eb2dc43d79c303bdd29f9639b085845fac..5720c55804083c5959d804a4a9aa79e42b8e30ff 100644 (file)
@@ -70,6 +70,12 @@ struct win32_target_ops
 
   const unsigned char *breakpoint;
   int breakpoint_len;
+
+  /* Breakpoint/Watchpoint related functions.  See target.h for comments.  */
+  int (*insert_point) (char type, CORE_ADDR addr, int len);
+  int (*remove_point) (char type, CORE_ADDR addr, int len);
+  int (*stopped_by_watchpoint) (void);
+  CORE_ADDR (*stopped_data_address) (void);
 };
 
 extern struct win32_target_ops the_low_target;