diff --exclude='*~' -rNup gdb-clean/gdb-6.8/gdb/config/mips/linux.mh gdb-6.8/gdb/config/mips/linux.mh
--- gdb-clean/gdb-6.8/gdb/config/mips/linux.mh 2007-10-15 12:19:17.000000000 -0700
+++ gdb-6.8/gdb/config/mips/linux.mh 2008-04-15 14:25:17.000000000 -0700
@@ -1,5 +1,5 @@
# Host: Linux/MIPS
-NAT_FILE= config/nm-linux.h
+NAT_FILE= nm-linux.h
NATDEPFILES= inf-ptrace.o fork-child.o mips-linux-nat.o \
linux-thread-db.o proc-service.o gcore.o \
linux-nat.o linux-fork.o
diff --exclude='*~' -rNup gdb-clean/gdb-6.8/gdb/config/mips/nm-linux.h gdb-6.8/gdb/config/mips/nm-linux.h
--- gdb-clean/gdb-6.8/gdb/config/mips/nm-linux.h 1969-12-31 16:00:00.000000000 -0800
+++ gdb-6.8/gdb/config/mips/nm-linux.h 2008-04-17 11:35:42.000000000 -0700
@@ -0,0 +1,60 @@
+/* Native support for GNU/Linux mips.
+ Copyright 2008 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see . */
+
+#ifndef NM_LINUX_H
+#define NM_LINUX_H
+
+#include "config/nm-linux.h"
+
+/* GNU/Linux supports the mips hardware debugging registers. */
+#define MIPS_USE_GENERIC_WATCHPOINTS
+
+int mips_linux_can_use_hardware_watchpoint (int type, int cnt,
+ int ot);
+
+#define TARGET_CAN_USE_HARDWARE_WATCHPOINT(type, cnt, ot) \
+ mips_linux_can_use_hardware_watchpoint (type, cnt, ot)
+
+int mips_linux_region_ok_for_watchpoint (CORE_ADDR addr, int len);
+
+#define TARGET_REGION_OK_FOR_HW_WATCHPOINT(addr, len) \
+ mips_linux_region_ok_for_watchpoint (addr, len)
+
+int mips_linux_stopped_by_watchpoint (void);
+
+#define STOPPED_BY_WATCHPOINT(W) \
+ mips_linux_stopped_by_watchpoint ()
+
+struct target_ops;
+
+int mips_linux_stopped_data_address (CORE_ADDR *paddr);
+
+#define target_stopped_data_address(target, x) \
+ mips_linux_stopped_data_address (x)
+
+int mips_linux_insert_watchpoint (CORE_ADDR addr, int len, int type);
+
+#define target_insert_watchpoint(addr, len, type) \
+ mips_linux_insert_watchpoint (addr, len, type)
+
+int mips_linux_remove_watchpoint (CORE_ADDR addr, int len, int type);
+
+#define target_remove_watchpoint(addr, len, type) \
+ mips_linux_remove_watchpoint (addr, len, type)
+
+#endif /* NM_LINUX_H */
diff --exclude='*~' -rNup gdb-clean/gdb-6.8/gdb/infrun.c gdb-6.8/gdb/infrun.c
--- gdb-clean/gdb-6.8/gdb/infrun.c 2008-01-29 14:47:19.000000000 -0800
+++ gdb-6.8/gdb/infrun.c 2008-04-21 11:01:07.000000000 -0700
@@ -1830,6 +1830,7 @@ handle_inferior_event (struct execution_
&& (HAVE_STEPPABLE_WATCHPOINT
|| gdbarch_have_nonsteppable_watchpoint (current_gdbarch)))
{
+ int step_over_watchpoint = 1;
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: STOPPED_BY_WATCHPOINT\n");
@@ -1857,7 +1858,23 @@ handle_inferior_event (struct execution_
if (!HAVE_STEPPABLE_WATCHPOINT)
remove_breakpoints ();
registers_changed ();
- target_resume (ecs->ptid, 1, TARGET_SIGNAL_0); /* Single step */
+
+ if (gdbarch_software_single_step_p (current_gdbarch))
+ {
+ /* Do it the hard way, w/temp breakpoints */
+ if (gdbarch_software_single_step (current_gdbarch, get_current_frame ()))
+ {
+ /* ...and don't ask hardware to do it. */
+ step_over_watchpoint = 0;
+ /* and do not pull these breakpoints until after a `wait' in
+ `wait_for_inferior' */
+ singlestep_breakpoints_inserted_p = 1;
+ singlestep_ptid = inferior_ptid;
+ singlestep_pc = read_pc ();
+ }
+ }
+
+ target_resume (ecs->ptid, step_over_watchpoint, TARGET_SIGNAL_0); /* Single step */
ecs->waiton_ptid = ecs->ptid;
if (HAVE_STEPPABLE_WATCHPOINT)
ecs->infwait_state = infwait_step_watch_state;
diff --exclude='*~' -rNup gdb-clean/gdb-6.8/gdb/mips-linux-nat.c gdb-6.8/gdb/mips-linux-nat.c
--- gdb-clean/gdb-6.8/gdb/mips-linux-nat.c 2008-01-01 14:53:12.000000000 -0800
+++ gdb-6.8/gdb/mips-linux-nat.c 2008-04-28 16:18:53.000000000 -0700
@@ -19,6 +19,8 @@
along with this program. If not, see . */
#include "defs.h"
+#include "command.h"
+#include "gdbcmd.h"
#include "inferior.h"
#include "mips-tdep.h"
#include "target.h"
@@ -44,6 +46,9 @@
we'll clear this and use PTRACE_PEEKUSER instead. */
static int have_ptrace_regsets = 1;
+/* Whether or not to print the mirrored debug registers. */
+static int maint_show_dr;
+
/* Saved function pointers to fetch and store a single register using
PTRACE_PEEKUSER and PTRACE_POKEUSER. */
@@ -355,12 +360,225 @@ mips_linux_read_description (struct targ
return tdesc_mips64_linux;
}
+#ifndef PTRACE_GET_WATCH_REGS
+# define PTRACE_GET_WATCH_REGS 0xd0
+#endif
+
+#ifndef PTRACE_SET_WATCH_REGS
+# define PTRACE_SET_WATCH_REGS 0xd1
+#endif
+
+enum pt_watch_style {
+ pt_watch_style_mips32,
+ pt_watch_style_mips64
+};
+struct mips32_watch_regs {
+ unsigned long watchlo[8];
+ unsigned int watchhi[8];
+ unsigned int num_valid;
+ unsigned int reg_mask;
+ unsigned int irw_mask;
+};
+
+struct pt_watch_regs {
+ enum pt_watch_style style;
+ union {
+ struct mips32_watch_regs mips32;
+ };
+};
+
+/* A value of zero in a register indicates that it is available. */
+#define MAX_DEBUG_REGISTER 4
+static struct pt_watch_regs watch_mirror;
+
+static void
+mips_show_dr (const char *func, CORE_ADDR addr,
+ int len, enum target_hw_bp_type type)
+{
+ int i;
+
+ puts_unfiltered (func);
+ if (addr || len)
+ printf_unfiltered (" (addr=%lx, len=%d, type=%s)",
+ /* This code is for mips, so casting CORE_ADDR
+ to unsigned long should be okay. */
+ (unsigned long)addr, len,
+ type == hw_write ? "data-write"
+ : (type == hw_read ? "data-read"
+ : (type == hw_access ? "data-read/write"
+ : (type == hw_execute ? "instruction-execute"
+ /* FIXME: if/when I/O read/write
+ watchpoints are supported, add them
+ here. */
+ : "??unknown??"))));
+ puts_unfiltered (":\n");
+
+ for (i = 0; i < MAX_DEBUG_REGISTER; i++)
+ {
+ printf_unfiltered ("\
+\tDR%d: lo=0x%s, hi=0x%s\n",
+ i, paddr(watch_mirror.mips32.watchlo[i]),
+ paddr(watch_mirror.mips32.watchhi[i]));
+ }
+}
+
+int mips_linux_can_use_hardware_watchpoint (int type, int cnt,
+ int ot)
+{
+ switch (type)
+ {
+ case bp_hardware_watchpoint:
+ case bp_read_watchpoint:
+ case bp_access_watchpoint:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+int mips_linux_stopped_data_address (CORE_ADDR *paddr)
+{
+ int i;
+ struct pt_watch_regs watch_readback;
+ int tid = ptid_get_lwp (inferior_ptid);
+
+ if (ptrace (PTRACE_GET_WATCH_REGS, tid, &watch_readback) == -1)
+ {
+ perror_with_name (_("Couldn't read debug register"));
+ return 0;
+ }
+ for (i = 0; i < MAX_DEBUG_REGISTER; i++)
+ {
+ if (watch_readback.mips32.watchhi[i] & 3)
+ {
+ *paddr = watch_readback.mips32.watchlo[i] & ~7;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+int mips_linux_stopped_by_watchpoint (void)
+{
+ CORE_ADDR dummy;
+ return mips_linux_stopped_data_address (&dummy);
+}
+
+int mips_linux_region_ok_for_watchpoint (CORE_ADDR addr, int len)
+{
+ return 1;
+}
+
+static unsigned long watchlo_val(CORE_ADDR addr, int type)
+{
+ unsigned long irw;
+
+ switch (type)
+ {
+ case hw_write:
+ irw = 1;
+ break;
+ case hw_read:
+ irw = 2;
+ break;
+ case hw_access:
+ irw = 3;
+ break;
+ default:
+ return 0;
+ }
+
+ return irw | (addr & ~7UL);
+}
+
+static int write_watchpoint_regs(void)
+{
+ struct lwp_info *lp;
+ ptid_t ptid;
+ int tid;
+
+ ALL_LWPS (lp, ptid)
+ {
+ tid = ptid_get_lwp (ptid);
+ if (ptrace (PTRACE_SET_WATCH_REGS, tid, &watch_mirror) == -1)
+ {
+ perror_with_name (_("Couldn't write debug register"));
+ return -1;
+ }
+ }
+ return 0;
+}
+
+
+int mips_linux_insert_watchpoint (CORE_ADDR addr, int len, int type)
+{
+ int i;
+ int retval = -1;
+ unsigned long lo_val;
+ struct lwp_info *lp;
+ ptid_t ptid;
+
+ lo_val = watchlo_val(addr, type);
+
+ for (i = 0; i < MAX_DEBUG_REGISTER; i++)
+ {
+ if (watch_mirror.mips32.watchlo[i] == 0)
+ {
+ watch_mirror.mips32.watchlo[i] = lo_val;
+ watch_mirror.mips32.watchhi[i] = 0;
+ retval = write_watchpoint_regs();
+ break;
+ }
+ }
+
+ if (maint_show_dr)
+ mips_show_dr ("insert_watchpoint", addr, len, type);
+
+ return retval;
+}
+
+int mips_linux_remove_watchpoint (CORE_ADDR addr, int len, int type)
+{
+ int i;
+ int retval = -1;
+ unsigned long lo_val;
+
+ lo_val = watchlo_val(addr, type);
+
+ for (i = 0; i < MAX_DEBUG_REGISTER; i++)
+ {
+ if (watch_mirror.mips32.watchlo[i] == lo_val)
+ {
+ watch_mirror.mips32.watchlo[i] = 0;
+ retval = write_watchpoint_regs();
+ }
+ }
+
+ if (maint_show_dr)
+ mips_show_dr ("remove_watchpoint", addr, len, type);
+
+ return retval;
+}
+
+
void _initialize_mips_linux_nat (void);
void
_initialize_mips_linux_nat (void)
{
- struct target_ops *t = linux_trad_target (mips_linux_register_u_offset);
+ struct target_ops *t;
+
+ deprecated_add_set_cmd ("show-debug-regs", class_maintenance,
+ var_boolean, (char *) &maint_show_dr, _("\
+Set whether to show variables that mirror the mips debug registers.\n\
+Use \"on\" to enable, \"off\" to disable.\n\
+If enabled, the debug registers values are shown when GDB inserts\n\
+or removes a hardware breakpoint or watchpoint, and when the inferior\n\
+triggers a breakpoint or watchpoint."),
+ &maintenancelist);
+
+
+ t = linux_trad_target (mips_linux_register_u_offset);
super_fetch_registers = t->to_fetch_registers;
super_store_registers = t->to_store_registers;