diff -rcp ../gdb-clean/gdb-6.8/gdb/config/mips/linux.mh gdb/config/mips/linux.mh *** ../gdb-clean/gdb-6.8/gdb/config/mips/linux.mh 2007-10-15 12:19:17.000000000 -0700 --- gdb/config/mips/linux.mh 2008-04-15 14:25:17.000000000 -0700 *************** *** 1,5 **** # Host: Linux/MIPS ! NAT_FILE= config/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 --- 1,5 ---- # Host: Linux/MIPS ! 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 -rcp ../gdb-clean/gdb-6.8/gdb/infrun.c gdb/infrun.c *** ../gdb-clean/gdb-6.8/gdb/infrun.c 2008-01-29 14:47:19.000000000 -0800 --- gdb/infrun.c 2008-04-21 11:01:07.000000000 -0700 *************** handle_inferior_event (struct execution_ *** 1830,1835 **** --- 1830,1836 ---- && (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"); *************** handle_inferior_event (struct execution_ *** 1857,1863 **** if (!HAVE_STEPPABLE_WATCHPOINT) remove_breakpoints (); registers_changed (); ! target_resume (ecs->ptid, 1, TARGET_SIGNAL_0); /* Single step */ ecs->waiton_ptid = ecs->ptid; if (HAVE_STEPPABLE_WATCHPOINT) ecs->infwait_state = infwait_step_watch_state; --- 1858,1880 ---- if (!HAVE_STEPPABLE_WATCHPOINT) remove_breakpoints (); registers_changed (); ! ! 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 -rcp ../gdb-clean/gdb-6.8/gdb/mips-linux-nat.c gdb/mips-linux-nat.c *** ../gdb-clean/gdb-6.8/gdb/mips-linux-nat.c 2008-01-01 14:53:12.000000000 -0800 --- gdb/mips-linux-nat.c 2008-08-27 22:23:34.000000000 -0700 *************** *** 19,24 **** --- 19,26 ---- 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,49 **** --- 46,54 ---- 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. */ *************** mips_linux_read_description (struct targ *** 355,366 **** return tdesc_mips64_linux; } void _initialize_mips_linux_nat (void); void _initialize_mips_linux_nat (void) { ! struct target_ops *t = linux_trad_target (mips_linux_register_u_offset); super_fetch_registers = t->to_fetch_registers; super_store_registers = t->to_store_registers; --- 360,584 ---- 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_by_watchpoint (void) + { + 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 < watch_readback.mips32.num_valid; i++) + { + if (watch_readback.mips32.watchhi[i] & 3) + { + return 1; + } + } + return 0; + } + int mips_linux_stopped_data_address (CORE_ADDR *paddr) + { + /* On mips we don't know the low order 3 bits of the data address, + so we must return false. */ + return 0; + } + + 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; ! ! 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;