Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src Add support for hardware assisted watchpoints/breakpoints AP...



details:   https://anonhg.NetBSD.org/src/rev/6dc7e5cd5e4b
branches:  trunk
changeset: 819731:6dc7e5cd5e4b
user:      kamil <kamil%NetBSD.org@localhost>
date:      Thu Dec 15 12:04:17 2016 +0000

description:
Add support for hardware assisted watchpoints/breakpoints API in ptrace(2)

Add new ptrace(2) calls:
 - PT_COUNT_WATCHPOINTS - count the number of available hardware watchpoints
 - PT_READ_WATCHPOINT   - read struct ptrace_watchpoint from the kernel state
 - PT_WRITE_WATCHPOINT  - write new struct ptrace_watchpoint state, this
                          includes enabling and disabling watchpoints

The ptrace_watchpoint structure contains MI and MD parts:

typedef struct ptrace_watchpoint {
        int             pw_index;       /* HW Watchpoint ID (count from 0) */
        lwpid_t         pw_lwpid;       /* LWP described */
        struct mdpw     pw_md;          /* MD fields */
} ptrace_watchpoint_t;

For example amd64 defines MD as follows:
struct mdpw {
        void    *md_address;
        int      md_condition;
        int      md_length;
};

These calls are protected with the __HAVE_PTRACE_WATCHPOINTS guard.

Tested on amd64, initial support added for i386 and XEN.

Sponsored by <The NetBSD Foundation>

diffstat:

 distrib/sets/lists/comp/md.amd64        |    3 +-
 distrib/sets/lists/comp/md.i386         |    3 +-
 sys/arch/amd64/amd64/machdep.c          |    7 +-
 sys/arch/amd64/amd64/netbsd32_machdep.c |    6 +-
 sys/arch/amd64/amd64/process_machdep.c  |   93 ++++++++++++-
 sys/arch/amd64/amd64/trap.c             |   17 ++-
 sys/arch/amd64/conf/files.amd64         |    3 +-
 sys/arch/amd64/include/proc.h           |    9 +-
 sys/arch/amd64/include/ptrace.h         |   53 ++++++-
 sys/arch/amd64/include/userret.h        |   14 +-
 sys/arch/i386/conf/files.i386           |    3 +-
 sys/arch/i386/i386/machdep.c            |    7 +-
 sys/arch/i386/i386/process_machdep.c    |   93 ++++++++++++-
 sys/arch/i386/include/proc.h            |    7 +-
 sys/arch/i386/include/ptrace.h          |   42 +++++-
 sys/arch/i386/include/userret.h         |   14 +-
 sys/arch/x86/include/Makefile           |    3 +-
 sys/arch/x86/include/dbregs.h           |  117 +++++++++++++++-
 sys/arch/x86/x86/dbregs.c               |  230 ++++++++++++++++++++++++++++++++
 sys/arch/x86/x86/vm_machdep.c           |   10 +-
 sys/arch/xen/conf/files.xen             |    3 +-
 sys/compat/netbsd32/netbsd32_ptrace.c   |   19 ++-
 sys/kern/sys_ptrace.c                   |    5 +-
 sys/kern/sys_ptrace_common.c            |  105 ++++++++++++++-
 sys/sys/ptrace.h                        |   55 +++++++-
 25 files changed, 865 insertions(+), 56 deletions(-)

diffs (truncated from 1497 to 300 lines):

diff -r ee47b748d336 -r 6dc7e5cd5e4b distrib/sets/lists/comp/md.amd64
--- a/distrib/sets/lists/comp/md.amd64  Thu Dec 15 11:32:03 2016 +0000
+++ b/distrib/sets/lists/comp/md.amd64  Thu Dec 15 12:04:17 2016 +0000
@@ -1,4 +1,4 @@
-# $NetBSD: md.amd64,v 1.239 2016/12/14 12:59:51 kre Exp $
+# $NetBSD: md.amd64,v 1.240 2016/12/15 12:04:18 kamil Exp $
 
 ./usr/include/amd64                            comp-c-include
 ./usr/include/amd64/ansi.h                     comp-c-include
@@ -496,6 +496,7 @@
 ./usr/include/x86/cpu_ucode.h                  comp-c-include
 ./usr/include/x86/cputypes.h                   comp-c-include
 ./usr/include/x86/cpuvar.h                     comp-c-include
+./usr/include/x86/dbregs.h                     comp-c-include
 ./usr/include/x86/float.h                      comp-c-include
 ./usr/include/x86/fpu.h                                comp-c-include
 ./usr/include/x86/ieee.h                       comp-c-include
diff -r ee47b748d336 -r 6dc7e5cd5e4b distrib/sets/lists/comp/md.i386
--- a/distrib/sets/lists/comp/md.i386   Thu Dec 15 11:32:03 2016 +0000
+++ b/distrib/sets/lists/comp/md.i386   Thu Dec 15 12:04:17 2016 +0000
@@ -1,4 +1,4 @@
-# $NetBSD: md.i386,v 1.159 2016/10/15 11:34:30 christos Exp $
+# $NetBSD: md.i386,v 1.160 2016/12/15 12:04:18 kamil Exp $
 ./usr/include/clang-3.4/__wmmintrin_aes.h      comp-obsolete           obsolete
 ./usr/include/clang-3.4/__wmmintrin_pclmul.h   comp-obsolete           obsolete
 ./usr/include/clang-3.4/ammintrin.h            comp-obsolete           obsolete
@@ -370,6 +370,7 @@
 ./usr/include/x86/cpu_ucode.h                  comp-c-include
 ./usr/include/x86/cputypes.h                   comp-c-include
 ./usr/include/x86/cpuvar.h                     comp-c-include
+./usr/include/x86/dbregs.h                     comp-c-include
 ./usr/include/x86/float.h                      comp-c-include
 ./usr/include/x86/fpu.h                                comp-c-include
 ./usr/include/x86/ieee.h                       comp-c-include
diff -r ee47b748d336 -r 6dc7e5cd5e4b sys/arch/amd64/amd64/machdep.c
--- a/sys/arch/amd64/amd64/machdep.c    Thu Dec 15 11:32:03 2016 +0000
+++ b/sys/arch/amd64/amd64/machdep.c    Thu Dec 15 12:04:17 2016 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: machdep.c,v 1.237 2016/12/12 02:51:24 pgoyette Exp $   */
+/*     $NetBSD: machdep.c,v 1.238 2016/12/15 12:04:17 kamil Exp $      */
 
 /*-
  * Copyright (c) 1996, 1997, 1998, 2000, 2006, 2007, 2008, 2011
@@ -111,7 +111,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.237 2016/12/12 02:51:24 pgoyette Exp $");
+__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.238 2016/12/15 12:04:17 kamil Exp $");
 
 /* #define XENDEBUG_LOW  */
 
@@ -482,6 +482,7 @@
        pmap_kernel()->pm_ldt_sel = GSYSSEL(GLDT_SEL, SEL_KPL);
        pcb->pcb_cr0 = rcr0() & ~CR0_TS;
        l->l_md.md_regs = (struct trapframe *)pcb->pcb_rsp0 - 1;
+       memset(l->l_md.md_watchpoint, 0, sizeof(*l->l_md.md_watchpoint));
 
 #if !defined(XEN)
        lldt(pmap_kernel()->pm_ldt_sel);
@@ -1316,6 +1317,8 @@
 
        l->l_proc->p_flag &= ~PK_32;
 
+       memset(l->l_md.md_watchpoint, 0, sizeof(*l->l_md.md_watchpoint));
+
        tf = l->l_md.md_regs;
        tf->tf_ds = LSEL(LUDATA_SEL, SEL_UPL);
        tf->tf_es = LSEL(LUDATA_SEL, SEL_UPL);
diff -r ee47b748d336 -r 6dc7e5cd5e4b sys/arch/amd64/amd64/netbsd32_machdep.c
--- a/sys/arch/amd64/amd64/netbsd32_machdep.c   Thu Dec 15 11:32:03 2016 +0000
+++ b/sys/arch/amd64/amd64/netbsd32_machdep.c   Thu Dec 15 12:04:17 2016 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: netbsd32_machdep.c,v 1.97 2016/10/19 09:44:00 skrll Exp $      */
+/*     $NetBSD: netbsd32_machdep.c,v 1.98 2016/12/15 12:04:17 kamil Exp $      */
 
 /*
  * Copyright (c) 2001 Wasabi Systems, Inc.
@@ -36,7 +36,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: netbsd32_machdep.c,v 1.97 2016/10/19 09:44:00 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: netbsd32_machdep.c,v 1.98 2016/12/15 12:04:17 kamil Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_compat_netbsd.h"
@@ -129,6 +129,8 @@
 
        p->p_flag |= PK_32;
 
+       memset(l->l_md.md_watchpoint, 0, sizeof(*l->l_md.md_watchpoint));
+
        tf = l->l_md.md_regs;
        tf->tf_ds = LSEL(LUDATA32_SEL, SEL_UPL);
        tf->tf_es = LSEL(LUDATA32_SEL, SEL_UPL);
diff -r ee47b748d336 -r 6dc7e5cd5e4b sys/arch/amd64/amd64/process_machdep.c
--- a/sys/arch/amd64/amd64/process_machdep.c    Thu Dec 15 11:32:03 2016 +0000
+++ b/sys/arch/amd64/amd64/process_machdep.c    Thu Dec 15 12:04:17 2016 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: process_machdep.c,v 1.29 2014/02/15 22:20:41 dsl Exp $ */
+/*     $NetBSD: process_machdep.c,v 1.30 2016/12/15 12:04:17 kamil Exp $       */
 
 /*-
  * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc.
@@ -49,11 +49,21 @@
  *
  * process_set_pc(proc)
  *     Set the process's program counter.
+ *
+ * process_count_watchpoints(proc, retval)
+ *     Return the number of supported hardware watchpoints.
+ *
+ * process_read_watchpoint(proc, watchpoint)
+ *     Read hardware watchpoint of the given index.
+ *
+ * process_write_watchpoint(proc, watchpoint)
+ *     Write hardware watchpoint of the given index.
+ *
  */
 
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: process_machdep.c,v 1.29 2014/02/15 22:20:41 dsl Exp $");
+__KERNEL_RCSID(0, "$NetBSD: process_machdep.c,v 1.30 2016/12/15 12:04:17 kamil Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -66,6 +76,7 @@
 #include <machine/psl.h>
 #include <machine/reg.h>
 #include <machine/segments.h>
+#include <x86/dbregs.h>
 #include <x86/fpu.h>
 
 static inline struct trapframe *process_frame(struct lwp *);
@@ -157,3 +168,81 @@
 
        return (0);
 }
+
+int
+process_count_watchpoints(struct lwp *l, register_t *retval)
+{
+
+       *retval = X86_HW_WATCHPOINTS;
+
+       return (0);
+}
+
+int
+process_read_watchpoint(struct lwp *l, struct ptrace_watchpoint *pw)
+{
+
+       pw->pw_md.md_address =
+           (void*)(intptr_t)l->l_md.md_watchpoint[pw->pw_index].address;
+       pw->pw_md.md_condition = l->l_md.md_watchpoint[pw->pw_index].condition;
+       pw->pw_md.md_length = l->l_md.md_watchpoint[pw->pw_index].length;
+
+       return (0);
+}
+
+static void
+update_mdl_x86_hw_watchpoints(struct lwp *l)
+{
+       size_t i;
+
+       for (i = 0; i < X86_HW_WATCHPOINTS; i++) {
+               if (l->l_md.md_watchpoint[0].address != 0) {
+                       return;
+               }
+       }
+       l->l_md.md_flags &= ~MDL_X86_HW_WATCHPOINTS;
+}
+
+int
+process_write_watchpoint(struct lwp *l, struct ptrace_watchpoint *pw)
+{
+
+       if (pw->pw_index > X86_HW_WATCHPOINTS)
+               return (EINVAL);
+
+       if (pw->pw_md.md_address == 0) {
+               l->l_md.md_watchpoint[pw->pw_index].address = 0;
+               update_mdl_x86_hw_watchpoints(l);
+               return (0);
+       }
+
+       if ((vaddr_t)pw->pw_md.md_address > VM_MAXUSER_ADDRESS)
+               return (EINVAL);
+
+       switch (pw->pw_md.md_condition) {
+       case X86_HW_WATCHPOINT_DR7_CONDITION_EXECUTION:
+       case X86_HW_WATCHPOINT_DR7_CONDITION_DATA_WRITE:
+       case X86_HW_WATCHPOINT_DR7_CONDITION_DATA_READWRITE:
+               break;
+       default:
+               return (EINVAL);
+       }
+
+       switch (pw->pw_md.md_length) {
+       case X86_HW_WATCHPOINT_DR7_LENGTH_BYTE:
+       case X86_HW_WATCHPOINT_DR7_LENGTH_TWOBYTES:
+       case X86_HW_WATCHPOINT_DR7_LENGTH_FOURBYTES:
+               break;
+       default:
+               return (EINVAL);
+       }
+
+       l->l_md.md_watchpoint[pw->pw_index].address =
+           (vaddr_t)pw->pw_md.md_address;
+       l->l_md.md_watchpoint[pw->pw_index].condition = pw->pw_md.md_condition;
+       l->l_md.md_watchpoint[pw->pw_index].length = pw->pw_md.md_length;
+
+       l->l_md.md_flags |= MDL_X86_HW_WATCHPOINTS;
+
+       return (0);
+}
diff -r ee47b748d336 -r 6dc7e5cd5e4b sys/arch/amd64/amd64/trap.c
--- a/sys/arch/amd64/amd64/trap.c       Thu Dec 15 11:32:03 2016 +0000
+++ b/sys/arch/amd64/amd64/trap.c       Thu Dec 15 12:04:17 2016 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: trap.c,v 1.87 2016/10/26 22:02:14 christos Exp $       */
+/*     $NetBSD: trap.c,v 1.88 2016/12/15 12:04:17 kamil Exp $  */
 
 /*-
  * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc.
@@ -68,7 +68,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.87 2016/10/26 22:02:14 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.88 2016/12/15 12:04:17 kamil Exp $");
 
 #include "opt_ddb.h"
 #include "opt_kgdb.h"
@@ -673,6 +673,19 @@
        }
 
        case T_TRCTRAP:
+               /*
+                * Ignore debug register trace traps due to
+                * accesses in the user's address space, which
+                * can happen under several conditions such as
+                * if a user sets a watchpoint on a buffer and
+                * then passes that buffer to a system call.
+                * We still want to get TRCTRAPS for addresses
+                * in kernel space because that is useful when
+                * debugging the kernel.
+                */
+               if (user_trap_x86_hw_watchpoint())
+                       break;
+
                /* Check whether they single-stepped into a lcall. */
                if (frame->tf_rip == (uint64_t)IDTVEC(oosyscall) ||
                    frame->tf_rip == (uint64_t)IDTVEC(osyscall) ||
diff -r ee47b748d336 -r 6dc7e5cd5e4b sys/arch/amd64/conf/files.amd64
--- a/sys/arch/amd64/conf/files.amd64   Thu Dec 15 11:32:03 2016 +0000
+++ b/sys/arch/amd64/conf/files.amd64   Thu Dec 15 12:04:17 2016 +0000
@@ -1,4 +1,4 @@
-#      $NetBSD: files.amd64,v 1.87 2015/09/06 07:17:14 uebayasi Exp $
+#      $NetBSD: files.amd64,v 1.88 2016/12/15 12:04:17 kamil Exp $
 #
 # new style config file for amd64 architecture
 #
@@ -49,6 +49,7 @@
 file   arch/amd64/amd64/process_machdep.c      machdep
 file   arch/amd64/amd64/trap.c                 machdep
 file   arch/x86/x86/fpu.c                      machdep
+file   arch/x86/x86/dbregs.c                   machdep
 file   arch/x86/x86/convert_xmm_s87.c          machdep
 file   arch/amd64/amd64/lock_stubs.S           machdep
 file   dev/cons.c                              machdep
diff -r ee47b748d336 -r 6dc7e5cd5e4b sys/arch/amd64/include/proc.h
--- a/sys/arch/amd64/include/proc.h     Thu Dec 15 11:32:03 2016 +0000
+++ b/sys/arch/amd64/include/proc.h     Thu Dec 15 12:04:17 2016 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: proc.h,v 1.19 2014/02/20 18:19:10 dsl Exp $    */
+/*     $NetBSD: proc.h,v 1.20 2016/12/15 12:04:17 kamil Exp $  */
 
 /*
  * Copyright (c) 1991 Regents of the University of California.
@@ -38,6 +38,7 @@
 
 #include <machine/frame.h>
 #include <machine/pcb.h>
+#include <x86/dbregs.h>
 
 /*
  * Machine-dependent part of the lwp structure for amd64.
@@ -51,10 +52,12 @@
        struct vm_page *md_gc_ptp;      /* pages from pmap g/c */
        int     md_flags;               /* machine-dependent flags */
        volatile int md_astpending;
+       struct  x86_hw_watchpoint md_watchpoint[X86_HW_WATCHPOINTS];
 };
 
-#define        MDL_COMPAT32    0x0008  /* i386, always return via iret */
-#define        MDL_IRET        0x0010  /* force return via iret, not sysret */
+#define        MDL_COMPAT32            0x0008  /* i386, always return via iret */



Home | Main Index | Thread Index | Old Index