[RFC] GDB patches for hw watchpoints

Manoj Iyer
2005-08-17T17:59:23Z

I am submitting this patch on behalf of Ben Elliston <bje@au1.ibm.com>,
this patch implements hardware watchpoints on PPC platform. Please review
and comment, so I can commit.

2005-05-04 Ben Elliston <bje@au.ibm.com>

* config/powerpc/nm-linux.h
(HAVE_NONSTEPPABLE_WATCHPOINT): Define.
(TARGET_REGION_OK_FOR_HW_WATCHPOINT): Likewise.
(TARGET_CAN_USE_HARDWARE_WATCHPOINT): Likewise.
(STOPPED_BY_WATCHPOINT): Likewise.
(target_insert_watchpoint): Likewise.
(target_remove_watchpoint): Likewise.
(ppc_linux_insert_watchpoint): Declare.
(ppc_linux_remove_watchpoint): Likewise.
* ppc-linux-nat.c (PTRACE_GET_DEBUGREG): Define, if not already.
(PTRACE_SET_DEBUGREG): Likewise.
(PTRACE_GETSINGOINFO): Likewise.
(ppc_linux_insert_watchpoint): New.
(ppc_linux_remove_watchpoint): Likewise.
(ppc_linux_stopped_by_watchpoint): Likewise.
(ppc_linux_check_watch_resources): Likewise.

Index: config/powerpc/nm-linux.h
===================================================================
RCS file: /home/bje/src-cvs/src/gdb/config/powerpc/nm-linux.h,v
retrieving revision 1.12
diff -u -p -r1.12 nm-linux.h
--- config/powerpc/nm-linux.h 29 Jul 2004 20:22:50 -0000 1.12
+++ config/powerpc/nm-linux.h 16 Aug 2005 01:53:56 -0000
@@ -34,4 +34,26 @@ extern int kernel_u_size (void);

#define FETCH_INFERIOR_REGISTERS

+/* Hardware watchpoints */
+
+#define HAVE_NONSTEPPABLE_WATCHPOINT 1
+#define TARGET_REGION_OK_FOR_HW_WATCHPOINT(addr, len) 1
+
+#define TARGET_CAN_USE_HARDWARE_WATCHPOINT(type, cnt, ot) \
+ ppc_linux_check_watch_resources (type, cnt, ot)
+
+#define STOPPED_BY_WATCHPOINT(w) \
+ ppc_linux_stopped_by_watchpoint (w)
+
+#define target_insert_watchpoint(addr, len, type) \
+ ppc_linux_insert_watchpoint (inferior_ptid, addr, len, type)
+#define target_remove_watchpoint(addr, len, type) \
+ ppc_linux_remove_watchpoint (inferior_ptid, addr, len)
+
+extern long ppc_linux_insert_watchpoint (ptid_t ptid, CORE_ADDR addr,
+ int len, int rw);
+
+extern long ppc_linux_remove_watchpoint (ptid_t ptid, CORE_ADDR addr,
+ int len);
+
#endif /* #ifndef NM_LINUX_H */Index: ppc-linux-nat.c
===================================================================
RCS file: /home/bje/src-cvs/src/gdb/ppc-linux-nat.c,v
retrieving revision 1.54
diff -u -p -r1.54 ppc-linux-nat.c
--- ppc-linux-nat.c 11 Feb 2005 18:13:51 -0000 1.54
+++ ppc-linux-nat.c 16 Aug 2005 01:53:56 -0000
@@ -79,6 +79,16 @@
#define PTRACE_SETEVRREGS 21
#endif

+/* Similarly for the hardware watchpoint support. */
+#ifndef PTRACE_GET_DEBUGREG
+#define PTRACE_GET_DEBUGREG 25
+#endif
+#ifndef PTRACE_SET_DEBUGREG
+#define PTRACE_SET_DEBUGREG 26
+#endif
+#ifndef PTRACE_GETSIGINFO
+#define PTRACE_GETSIGINFO 0x4202
+#endif

/* This oddity is because the Linux kernel defines elf_vrregset_t as
an array of 33 16 bytes long elements. I.e. it leaves out vrsave.
@@ -883,3 +893,82 @@ fill_fpregset (gdb_fpregset_t *fpregsetp
right_fill_reg (tdep->ppc_fpscr_regnum, (fpp + 8 * 32));
}
}
+
+/* Set a watchpoint of type TYPE at address ADDR. */
+long
+ppc_linux_insert_watchpoint (ptid_t ptid, CORE_ADDR addr, int len, int rw)
+{
+ int tid;
+ long dabr_value;
+
+ /* Handle sub-8-byte quantities. */
+ if (len <= 0)
+ return -1;
+
+ /* addr+len must fall in the 8 byte watchable region. */
+ if ((addr + len) > (addr & ~7) + 8)
+ return -1;
+
+ dabr_value = addr & ~7;
+ switch (rw)
+ {
+ case hw_read:
+ /* Set read and translate bits. */
+ dabr_value |= 5;
+ break;
+ case hw_write:
+ /* Set write and translate bits. */
+ dabr_value |= 6;
+ break;
+ case hw_access:
+ /* Set read, write and translate bits. */
+ dabr_value |= 7;
+ break;
+ }
+
+ tid = TIDGET (ptid);
+ if (tid == 0)
+ tid = PIDGET (ptid);
+
+ return ptrace (PTRACE_SET_DEBUGREG, tid, 0, dabr_value);
+}
+
+long
+ppc_linux_remove_watchpoint (ptid_t ptid, CORE_ADDR addr, int len)
+{
+ int tid;
+
+ tid = TIDGET (ptid);
+ if (tid == 0)
+ tid = PIDGET (ptid);
+
+ return ptrace (PTRACE_SET_DEBUGREG, tid, 0, 0);
+}
+
+int
+ppc_linux_stopped_by_watchpoint (void)
+{
+ int tid;
+ struct siginfo siginfo;
+ ptid_t ptid = inferior_ptid;
+
+ tid = TIDGET(ptid);
+ if (tid == 0)
+ tid = PIDGET (ptid);
+
+ errno = 0;
+ ptrace (PTRACE_GETSIGINFO, tid, (PTRACE_TYPE_ARG3) 0, &siginfo);
+
+ if (errno != 0 || siginfo.si_signo != SIGTRAP ||
+ (siginfo.si_code & 0xffff) != 0x0004)
+ return 0;
+
+ return 1;
+}
+
+int
+ppc_linux_check_watch_resources (int type, int cnt, int ot)
+{
+ /* PPC has one DABR (hardware watchpoint) register. */
+ return (cnt <= 1);
+}

----------
Manoj Iyer
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ Cogito ergo sum +
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++