Add hardware watchpoint support for x86 GNU Hurd.
authorSamuel Thibault <samuel.thibault@gnu.org>
Fri, 12 Sep 2014 18:29:11 +0000 (20:29 +0200)
committerThomas Schwinge <thomas@codesourcery.com>
Tue, 16 Sep 2014 12:38:09 +0000 (14:38 +0200)
gdb/
* config/i386/i386gnu.mh (NATDEPFILES): Add x86-nat.o and
x86-dregs.o.
* gnu-nat.c (inf_threads): New function.
* gnu-nat.h (inf_threads_ftype): New typedef.
(inf_threads): New declaration.
* i386gnu-nat.c: Include "x86-nat.h" and "inf-child.h".
[i386_DEBUG_STATE] (i386_gnu_dr_get, i386_gnu_dr_set)
(i386_gnu_dr_set_control_one, i386_gnu_dr_set_control)
(i386_gnu_dr_set_addr_one, i386_gnu_dr_set_addr)
(i386_gnu_dr_get_reg, i386_gnu_dr_get_addr, 386_gnu_dr_get_status)
(i386_gnu_dr_get_control): New functions.
(reg_addr): New structure.
(_initialize_i386gnu_nat) [i386_DEBUG_STATE]: Initialize hardware
i386 debugging register hooks.
* NEWS: Mention this.

gdb/ChangeLog
gdb/NEWS
gdb/config/i386/i386gnu.mh
gdb/gnu-nat.c
gdb/gnu-nat.h
gdb/i386gnu-nat.c

index 3231d69d3d3248efb59e06ca1bd0eefc73c5f08b..125ab92bd916ca61371fa9629ecd73ab7a50cd06 100644 (file)
@@ -1,3 +1,21 @@
+2014-09-16  Samuel Thibault  <samuel.thibault@ens-lyon.org>
+
+       * config/i386/i386gnu.mh (NATDEPFILES): Add x86-nat.o and
+       x86-dregs.o.
+       * gnu-nat.c (inf_threads): New function.
+       * gnu-nat.h (inf_threads_ftype): New typedef.
+       (inf_threads): New declaration.
+       * i386gnu-nat.c: Include "x86-nat.h" and "inf-child.h".
+       [i386_DEBUG_STATE] (i386_gnu_dr_get, i386_gnu_dr_set)
+       (i386_gnu_dr_set_control_one, i386_gnu_dr_set_control)
+       (i386_gnu_dr_set_addr_one, i386_gnu_dr_set_addr)
+       (i386_gnu_dr_get_reg, i386_gnu_dr_get_addr, 386_gnu_dr_get_status)
+       (i386_gnu_dr_get_control): New functions.
+       (reg_addr): New structure.
+       (_initialize_i386gnu_nat) [i386_DEBUG_STATE]: Initialize hardware
+       i386 debugging register hooks.
+       * NEWS: Mention this.
+
 2014-08-13  Omair Javaid  <omair.javaid@linaro.org>
 
        * arm-tdep.c (arm_record_vdata_transfer_insn): Added record handler for
index d0a6ea557deb26ff2009d9677708ad1686ac0a86..343ee49c0a1c566bae63cdda291a8762afb68a4b 100644 (file)
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -3,6 +3,8 @@
 
 *** Changes since GDB 7.8
 
+* GDB now supports hardware watchpoints on x86 GNU Hurd.
+
 * Python Scripting
   You can now access frame registers from Python scripts.
 
index a3ea122b6d7e79c2ea960ee570182bcf4192fcdd..4cc23e4004eedf8a59615294f0abd63f2f6cd41b 100644 (file)
@@ -1,5 +1,6 @@
 # Host: Intel 386 running the GNU Hurd
-NATDEPFILES= i386gnu-nat.o gnu-nat.o core-regset.o fork-child.o \
+NATDEPFILES= i386gnu-nat.o gnu-nat.o \
+            x86-nat.o x86-dregs.o core-regset.o fork-child.o \
             notify_S.o process_reply_S.o msg_reply_S.o \
             msg_U.o exc_request_U.o exc_request_S.o
 HAVE_NATIVE_GCORE_HOST = 1
index c8164d60f3037b19279300ad858e9fea1e10d87e..d17a7503c60b57830dda515f16caa9b0006d8142 100644 (file)
@@ -983,6 +983,17 @@ inf_port_to_thread (struct inf *inf, mach_port_t port)
   return 0;
 }
 
+/* See gnu-nat.h.  */
+
+void
+inf_threads (struct inf *inf, inf_threads_ftype *f, void *arg)
+{
+  struct proc *thread;
+
+  for (thread = inf->threads; thread; thread = thread->next)
+    f (thread, arg);
+}
+
 \f
 /* Make INF's list of threads be consistent with reality of TASK.  */
 void
index 8e949eba9850b3abefcc736793ac56effefe2f76..43d5b753ac12d352c1016894dc67b99c129cea63 100644 (file)
@@ -29,6 +29,11 @@ extern struct inf *gnu_current_inf;
 /* Converts a GDB pid to a struct proc.  */
 struct proc *inf_tid_to_thread (struct inf *inf, int tid);
 
+typedef void (inf_threads_ftype) (struct proc *thread, void *arg);
+
+/* Call F for every thread in inferior INF, passing ARG as second parameter.  */
+void inf_threads (struct inf *inf, inf_threads_ftype *f, void *arg);
+
 /* Makes sure that INF's thread list is synced with the actual process.  */
 int inf_update_procs (struct inf *inf);
 
index 8fad87117bec84b2164d08ee67ad8f246d2913fa..9317d29af81a1d4ea831522cbb7ec61b1a0acd60 100644 (file)
@@ -18,6 +18,7 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "defs.h"
+#include "x86-nat.h"
 #include "inferior.h"
 #include "floatformat.h"
 #include "regcache.h"
@@ -30,6 +31,7 @@
 #include "i386-tdep.h"
 
 #include "gnu-nat.h"
+#include "inf-child.h"
 #include "i387-tdep.h"
 
 #ifdef HAVE_SYS_PROCFS_H
@@ -304,6 +306,142 @@ gnu_store_registers (struct target_ops *ops,
     }
 }
 
+\f
+/* Support for debug registers.  */
+
+#ifdef i386_DEBUG_STATE
+/* Get debug registers for thread THREAD.  */
+
+static void
+i386_gnu_dr_get (struct i386_debug_state *regs, struct proc *thread)
+{
+  mach_msg_type_number_t count = i386_DEBUG_STATE_COUNT;
+  error_t err;
+
+  err = thread_get_state (thread->port, i386_DEBUG_STATE,
+                         (thread_state_t) regs, &count);
+  if (err != 0 || count != i386_DEBUG_STATE_COUNT)
+    warning (_("Couldn't fetch debug state from %s"),
+            proc_string (thread));
+}
+
+/* Set debug registers for thread THREAD.  */
+
+static void
+i386_gnu_dr_set (const struct i386_debug_state *regs, struct proc *thread)
+{
+  error_t err;
+
+  err = thread_set_state (thread->port, i386_DEBUG_STATE,
+                         (thread_state_t) regs, i386_DEBUG_STATE_COUNT);
+  if (err != 0)
+    warning (_("Couldn't store debug state into %s"),
+            proc_string (thread));
+}
+
+/* Set DR_CONTROL in THREAD.  */
+
+static void
+i386_gnu_dr_set_control_one (struct proc *thread, void *arg)
+{
+  unsigned long *control = arg;
+  struct i386_debug_state regs;
+
+  i386_gnu_dr_get (&regs, thread);
+  regs.dr[DR_CONTROL] = *control;
+  i386_gnu_dr_set (&regs, thread);
+}
+
+/* Set DR_CONTROL to CONTROL in all threads.  */
+
+static void
+i386_gnu_dr_set_control (unsigned long control)
+{
+  inf_update_procs (gnu_current_inf);
+  inf_threads (gnu_current_inf, i386_gnu_dr_set_control_one, &control);
+}
+
+/* Parameters to set a debugging address.  */
+
+struct reg_addr
+{
+  int regnum;          /* Register number (zero based).  */
+  CORE_ADDR addr;      /* Address.  */
+};
+
+/* Set address REGNUM (zero based) to ADDR in THREAD.  */
+
+static void
+i386_gnu_dr_set_addr_one (struct proc *thread, void *arg)
+{
+  struct reg_addr *reg_addr = arg;
+  struct i386_debug_state regs;
+
+  i386_gnu_dr_get (&regs, thread);
+  regs.dr[reg_addr->regnum] = reg_addr->addr;
+  i386_gnu_dr_set (&regs, thread);
+}
+
+/* Set address REGNUM (zero based) to ADDR in all threads.  */
+
+static void
+i386_gnu_dr_set_addr (int regnum, CORE_ADDR addr)
+{
+  struct reg_addr reg_addr;
+
+  gdb_assert (DR_FIRSTADDR <= regnum && regnum <= DR_LASTADDR);
+
+  reg_addr.regnum = regnum;
+  reg_addr.addr = addr;
+
+  inf_update_procs (gnu_current_inf);
+  inf_threads (gnu_current_inf, i386_gnu_dr_set_addr_one, &reg_addr);
+}
+
+/* Get debug register REGNUM value from only the one LWP of PTID.  */
+
+static unsigned long
+i386_gnu_dr_get_reg (ptid_t ptid, int regnum)
+{
+  struct i386_debug_state regs;
+  struct proc *thread;
+
+  /* Make sure we know about new threads.  */
+  inf_update_procs (gnu_current_inf);
+
+  thread = inf_tid_to_thread (gnu_current_inf, ptid_get_lwp (ptid));
+  i386_gnu_dr_get (&regs, thread);
+
+  return regs.dr[regnum];
+}
+
+/* Return the inferior's debug register REGNUM.  */
+
+static CORE_ADDR
+i386_gnu_dr_get_addr (int regnum)
+{
+  gdb_assert (DR_FIRSTADDR <= regnum && regnum <= DR_LASTADDR);
+
+  return i386_gnu_dr_get_reg (inferior_ptid, regnum);
+}
+
+/* Get DR_STATUS from only the one thread of INFERIOR_PTID.  */
+
+static unsigned long
+i386_gnu_dr_get_status (void)
+{
+  return i386_gnu_dr_get_reg (inferior_ptid, DR_STATUS);
+}
+
+/* Return the inferior's DR7 debug control register.  */
+
+static unsigned long
+i386_gnu_dr_get_control (void)
+{
+  return i386_gnu_dr_get_reg (inferior_ptid, DR_CONTROL);
+}
+#endif /* i386_DEBUG_STATE */
+
 /* Provide a prototype to silence -Wmissing-prototypes.  */
 extern initialize_file_ftype _initialize_i386gnu_nat;
 
@@ -315,6 +453,18 @@ _initialize_i386gnu_nat (void)
   /* Fill in the generic GNU/Hurd methods.  */
   t = gnu_target ();
 
+#ifdef i386_DEBUG_STATE
+  x86_use_watchpoints (t);
+
+  x86_dr_low.set_control = i386_gnu_dr_set_control;
+  gdb_assert (DR_FIRSTADDR == 0 && DR_LASTADDR < i386_DEBUG_STATE_COUNT);
+  x86_dr_low.set_addr = i386_gnu_dr_set_addr;
+  x86_dr_low.get_addr = i386_gnu_dr_get_addr;
+  x86_dr_low.get_status = i386_gnu_dr_get_status;
+  x86_dr_low.get_control = i386_gnu_dr_get_control;
+  x86_set_debug_register_length (4);
+#endif /* i386_DEBUG_STATE */
+
   t->to_fetch_registers = gnu_fetch_registers;
   t->to_store_registers = gnu_store_registers;