* RFC: Hardware watchpoint register support for mips-linux.
@ 2008-04-21 19:46 David Daney
2008-04-21 20:03 ` Daniel Jacobowitz
` (2 more replies)
0 siblings, 3 replies; 8+ messages in thread
From: David Daney @ 2008-04-21 19:46 UTC (permalink / raw)
To: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 1944 bytes --]
This patch adds support for hardware watchpoint registers present in
some mips processors. I consider it a very rough first version of the
patch as there are several things missing before it would be fully
functional. However it is sufficient to demonstrate that the kernel
support is working.
Notes about the patch:
* Corresponding Linux kernel support is needed. I will post the
corresponding patches to linux-mips.org shortly.
* The patch is against gdb 6.8.
* I need to add the thread creation hook so new threads install the
watch registers.
* Logic to cover large regions of memory is missing.
* The mips specific code should probably be moved to more generic place
with only linux specific implementations in mips-linux-nat.c as is done
with i386.
* Hardware breakpoints are not yet supported. Since the smallest region
covers two instructions, I was not sure how to implement it.
* Probably there are other issues I have not addressed yet.
Comments are welcome.
2008-04-21 David Daney <ddaney@avtrex.com>
* config/mips/linux.mh (NAT_FILE): Change to nm-linux.h.
* config/mips/nm-linux.h: New file.
* infrun.c (handle_inferior_event): Use software single step when
target requires it.
* mips-linux-nat.c: Include command.h and gdbcmd.h.
(maint_show_dr): New variable.
(PTRACE_GET_WATCH_REGS): New macro.
(PTRACE_SET_WATCH_REGS): Same.
(enum pt_watch_style): Define.
(struct mips32_watch_regs): Define.
(struct pt_watch_regs): Define.
(MAX_DEBUG_REGISTER): New macro.
(watch_mirror): New variable.
(mips_show_dr, mips_linux_can_use_hardware_watchpoint,
mips_linux_stopped_data_address, mips_linux_stopped_by_watchpoint,
mips_linux_region_ok_for_watchpoint, watchlo_val,
write_watchpoint_regs, mips_linux_insert_watchpoint,
mips_linux_remove_watchpoint): New functions.
(_initialize_mips_linux_nat): Register show-debug-regs maintenance
command.
[-- Attachment #2: gdb.patch --]
[-- Type: text/x-patch, Size: 10328 bytes --]
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 <http://www.gnu.org/licenses/>. */
+
+#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-18 15:15:13.000000000 -0700
@@ -19,6 +19,8 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#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 int num_valid;
+ unsigned int reg_mask;
+ unsigned int irw_mask;
+ unsigned long watchlo[8];
+ unsigned int watchhi[8];
+};
+
+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;
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: RFC: Hardware watchpoint register support for mips-linux.
2008-04-21 19:46 RFC: Hardware watchpoint register support for mips-linux David Daney
@ 2008-04-21 20:03 ` Daniel Jacobowitz
2008-04-21 20:34 ` David Daney
2008-04-21 22:36 ` Maciej W. Rozycki
2008-04-29 3:47 ` David Daney
2 siblings, 1 reply; 8+ messages in thread
From: Daniel Jacobowitz @ 2008-04-21 20:03 UTC (permalink / raw)
To: David Daney; +Cc: gdb-patches
On Mon, Apr 21, 2008 at 12:34:15PM -0700, David Daney wrote:
> Comments are welcome.
You've made most of my comments already. My only addition is do not
use a new nm-linux.h at all. Everything can be done from the
target_ops in mips-linux-nat.c now.
For infrun.c, can you just use resume instead of target_resume?
There's some GNU formatting issues but nothing huge. Spaces,
newlines before function names in definitions.
--
Daniel Jacobowitz
CodeSourcery
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: RFC: Hardware watchpoint register support for mips-linux.
2008-04-21 20:03 ` Daniel Jacobowitz
@ 2008-04-21 20:34 ` David Daney
2008-04-21 21:14 ` Daniel Jacobowitz
0 siblings, 1 reply; 8+ messages in thread
From: David Daney @ 2008-04-21 20:34 UTC (permalink / raw)
To: David Daney, gdb-patches
Daniel Jacobowitz wrote:
> On Mon, Apr 21, 2008 at 12:34:15PM -0700, David Daney wrote:
>> Comments are welcome.
>
> For infrun.c, can you just use resume instead of target_resume?
>
I don't know. The original code called target_resume, the only real
change I made was to use software single step if the target requires it.
David Daney
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: RFC: Hardware watchpoint register support for mips-linux.
2008-04-21 20:34 ` David Daney
@ 2008-04-21 21:14 ` Daniel Jacobowitz
0 siblings, 0 replies; 8+ messages in thread
From: Daniel Jacobowitz @ 2008-04-21 21:14 UTC (permalink / raw)
To: David Daney; +Cc: gdb-patches
On Mon, Apr 21, 2008 at 01:04:04PM -0700, David Daney wrote:
> I don't know. The original code called target_resume, the only real
> change I made was to use software single step if the target requires it.
Yes, I'd prefer not to duplicate that code.
--
Daniel Jacobowitz
CodeSourcery
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: RFC: Hardware watchpoint register support for mips-linux.
2008-04-21 19:46 RFC: Hardware watchpoint register support for mips-linux David Daney
2008-04-21 20:03 ` Daniel Jacobowitz
@ 2008-04-21 22:36 ` Maciej W. Rozycki
2008-04-22 3:25 ` David Daney
2008-04-29 3:47 ` David Daney
2 siblings, 1 reply; 8+ messages in thread
From: Maciej W. Rozycki @ 2008-04-21 22:36 UTC (permalink / raw)
To: David Daney; +Cc: gdb-patches
On Mon, 21 Apr 2008, David Daney wrote:
> This patch adds support for hardware watchpoint registers present in
> some mips processors. I consider it a very rough first version of the
> patch as there are several things missing before it would be fully
> functional. However it is sufficient to demonstrate that the kernel
> support is working.
Well done! -- something I have meant to do for years, but never come to.
Out of curiousity -- does your kernel side support MIPS architecture style
watchpoints only or does it work with the R4000-style watch registers as
well? I recall having a discussion with Daniel about how to support both
in a reasonably abstract way long ago. Either way thanks a lot, and I
have an R4k machine handy, so I can see if I find some time to give it a
shot.
Maciej
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: RFC: Hardware watchpoint register support for mips-linux.
2008-04-21 22:36 ` Maciej W. Rozycki
@ 2008-04-22 3:25 ` David Daney
2008-04-22 20:27 ` Maciej W. Rozycki
0 siblings, 1 reply; 8+ messages in thread
From: David Daney @ 2008-04-22 3:25 UTC (permalink / raw)
To: Maciej W. Rozycki; +Cc: gdb-patches
Maciej W. Rozycki wrote:
>
> Well done! -- something I have meant to do for years, but never come to.
> Out of curiousity -- does your kernel side support MIPS architecture style
> watchpoints only or does it work with the R4000-style watch registers as
> well? I recall having a discussion with Daniel about how to support both
> in a reasonably abstract way long ago. Either way thanks a lot, and I
> have an R4k machine handy, so I can see if I find some time to give it a
> shot.
>
Currently it only handles mips32 style watch registers. I have no
documentation on the R4000 style registers.
I do however have an SGI Indy w/ R4400 which /proc/cpuinfo reports as
having watch registers, but since there is a lack of documentation, I
could not try it.
My plan for supporting different watch register formats is to have a
format identifier that is read by GDB via PTRACE_GET_WATCH_REGS. The
rest of the information is a union of the known formats.
Currently it reports the number of registers and the active mask bits.
But if R4000 does not fit with the mips32 register layout, its registers
would be layed out in a different union member.
I hope that makes sense.
David Daney
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: RFC: Hardware watchpoint register support for mips-linux.
2008-04-22 3:25 ` David Daney
@ 2008-04-22 20:27 ` Maciej W. Rozycki
0 siblings, 0 replies; 8+ messages in thread
From: Maciej W. Rozycki @ 2008-04-22 20:27 UTC (permalink / raw)
To: David Daney; +Cc: gdb-patches
On Mon, 21 Apr 2008, David Daney wrote:
> Currently it only handles mips32 style watch registers. I have no
> documentation on the R4000 style registers.
Specs for the R4000 and the R10000 (which uses the same model) are both
available online. Search for "R4000 Microprocessor User's Manual"
(substitute R10000 as necessary).
The R4k-style watchpoint is trickier, as the registers hold a physical
address, so some additional handling is required for cases where the
virtual-to-physical mapping is changed (like when the area being watched
is paged in from the backing store).
Maciej
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: RFC: Hardware watchpoint register support for mips-linux.
2008-04-21 19:46 RFC: Hardware watchpoint register support for mips-linux David Daney
2008-04-21 20:03 ` Daniel Jacobowitz
2008-04-21 22:36 ` Maciej W. Rozycki
@ 2008-04-29 3:47 ` David Daney
2 siblings, 0 replies; 8+ messages in thread
From: David Daney @ 2008-04-29 3:47 UTC (permalink / raw)
To: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 2468 bytes --]
David Daney wrote:
> This patch adds support for hardware watchpoint registers present in
> some mips processors. I consider it a very rough first version of the
> patch as there are several things missing before it would be fully
> functional. However it is sufficient to demonstrate that the kernel
> support is working.
>
> Notes about the patch:
>
> * Corresponding Linux kernel support is needed. I will post the
> corresponding patches to linux-mips.org shortly.
> * The patch is against gdb 6.8.
> * I need to add the thread creation hook so new threads install the
> watch registers.
> * Logic to cover large regions of memory is missing.
> * The mips specific code should probably be moved to more generic place
> with only linux specific implementations in mips-linux-nat.c as is done
> with i386.
> * Hardware breakpoints are not yet supported. Since the smallest region
> covers two instructions, I was not sure how to implement it.
> * Probably there are other issues I have not addressed yet.
>
> Comments are welcome.
>
> 2008-04-21 David Daney <ddaney@avtrex.com>
>
> * config/mips/linux.mh (NAT_FILE): Change to nm-linux.h.
> * config/mips/nm-linux.h: New file.
> * infrun.c (handle_inferior_event): Use software single step when
> target requires it.
> * mips-linux-nat.c: Include command.h and gdbcmd.h.
> (maint_show_dr): New variable.
> (PTRACE_GET_WATCH_REGS): New macro.
> (PTRACE_SET_WATCH_REGS): Same.
> (enum pt_watch_style): Define.
> (struct mips32_watch_regs): Define.
> (struct pt_watch_regs): Define.
> (MAX_DEBUG_REGISTER): New macro.
> (watch_mirror): New variable.
> (mips_show_dr, mips_linux_can_use_hardware_watchpoint,
> mips_linux_stopped_data_address, mips_linux_stopped_by_watchpoint,
> mips_linux_region_ok_for_watchpoint, watchlo_val,
> write_watchpoint_regs, mips_linux_insert_watchpoint,
> mips_linux_remove_watchpoint): New functions.
> (_initialize_mips_linux_nat): Register show-debug-regs maintenance
> command.
>
I changed the layout of the structures used by ptrace to set the watch
registers in the new version of the kernel patch (posted soon to
linux-mips.org), so here is the corresponding gdb patch.
It is identical to the previous version except for the structure
layout. My plan is to improve the gdb patch once the Linux kernel patch
gains acceptance.
The change log is the same as the previous version.
David Daney
[-- Attachment #2: gdb.patch --]
[-- Type: text/x-patch, Size: 10328 bytes --]
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 <http://www.gnu.org/licenses/>. */
+
+#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 <http://www.gnu.org/licenses/>. */
#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;
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2008-04-29 1:10 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2008-04-21 19:46 RFC: Hardware watchpoint register support for mips-linux David Daney
2008-04-21 20:03 ` Daniel Jacobowitz
2008-04-21 20:34 ` David Daney
2008-04-21 21:14 ` Daniel Jacobowitz
2008-04-21 22:36 ` Maciej W. Rozycki
2008-04-22 3:25 ` David Daney
2008-04-22 20:27 ` Maciej W. Rozycki
2008-04-29 3:47 ` David Daney
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox