aboutsummaryrefslogtreecommitdiff
path: root/gdb/i386gnu-nat.c
diff options
context:
space:
mode:
authorSamuel Thibault <samuel.thibault@gnu.org>2014-09-12 20:29:11 +0200
committerThomas Schwinge <thomas@codesourcery.com>2014-09-16 14:38:09 +0200
commit05db5edd7923711a20c6225ea8e15f36e819d140 (patch)
tree34df8a05192ecafe3639c1ba3289edbaf18b68fb /gdb/i386gnu-nat.c
parent70e99720f9d558263756a482ae750b263ffd92ba (diff)
downloadgdb-05db5edd7923711a20c6225ea8e15f36e819d140.zip
gdb-05db5edd7923711a20c6225ea8e15f36e819d140.tar.gz
gdb-05db5edd7923711a20c6225ea8e15f36e819d140.tar.bz2
Add hardware watchpoint support for x86 GNU Hurd.
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.
Diffstat (limited to 'gdb/i386gnu-nat.c')
-rw-r--r--gdb/i386gnu-nat.c150
1 files changed, 150 insertions, 0 deletions
diff --git a/gdb/i386gnu-nat.c b/gdb/i386gnu-nat.c
index 8fad871..9317d29 100644
--- a/gdb/i386gnu-nat.c
+++ b/gdb/i386gnu-nat.c
@@ -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,
}
}
+
+/* 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;