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;