diff --git a/lib/libc/amd64/sys/Makefile.inc b/lib/libc/amd64/sys/Makefile.inc index c1c3d2d0e715..f6707050a6d6 100644 --- a/lib/libc/amd64/sys/Makefile.inc +++ b/lib/libc/amd64/sys/Makefile.inc @@ -1,8 +1,8 @@ # from: Makefile.inc,v 1.1 1993/09/03 19:04:23 jtc Exp # $FreeBSD$ -SRCS+= i386_get_ioperm.c i386_get_ldt.c i386_set_ioperm.c i386_set_ldt.c \ - i386_vm86.c +SRCS+= i386_clr_watch.c i386_get_ioperm.c i386_get_ldt.c i386_set_ioperm.c \ + i386_set_ldt.c i386_set_watch.c i386_vm86.c MDASM= Ovfork.S brk.S cerror.S exect.S fork.S pipe.S ptrace.S reboot.S \ rfork.S sbrk.S setlogin.S sigreturn.S syscall.S @@ -22,7 +22,9 @@ PSEUDOR= _exit.o .if ${LIB} == "c" MAN2+= i386_get_ioperm.2 i386_get_ldt.2 i386_vm86.2 +MAN3+= i386_set_watch.3 MLINKS+=i386_get_ioperm.2 i386_set_ioperm.2 MLINKS+=i386_get_ldt.2 i386_set_ldt.2 +MLINKS+=i386_set_watch.3 i386_clr_watch.3 .endif diff --git a/lib/libc/i386/sys/Makefile.inc b/lib/libc/i386/sys/Makefile.inc index c1c3d2d0e715..f6707050a6d6 100644 --- a/lib/libc/i386/sys/Makefile.inc +++ b/lib/libc/i386/sys/Makefile.inc @@ -1,8 +1,8 @@ # from: Makefile.inc,v 1.1 1993/09/03 19:04:23 jtc Exp # $FreeBSD$ -SRCS+= i386_get_ioperm.c i386_get_ldt.c i386_set_ioperm.c i386_set_ldt.c \ - i386_vm86.c +SRCS+= i386_clr_watch.c i386_get_ioperm.c i386_get_ldt.c i386_set_ioperm.c \ + i386_set_ldt.c i386_set_watch.c i386_vm86.c MDASM= Ovfork.S brk.S cerror.S exect.S fork.S pipe.S ptrace.S reboot.S \ rfork.S sbrk.S setlogin.S sigreturn.S syscall.S @@ -22,7 +22,9 @@ PSEUDOR= _exit.o .if ${LIB} == "c" MAN2+= i386_get_ioperm.2 i386_get_ldt.2 i386_vm86.2 +MAN3+= i386_set_watch.3 MLINKS+=i386_get_ioperm.2 i386_set_ioperm.2 MLINKS+=i386_get_ldt.2 i386_set_ldt.2 +MLINKS+=i386_set_watch.3 i386_clr_watch.3 .endif diff --git a/lib/libc/i386/sys/i386_clr_watch.c b/lib/libc/i386/sys/i386_clr_watch.c new file mode 100644 index 000000000000..0320634ca76d --- /dev/null +++ b/lib/libc/i386/sys/i386_clr_watch.c @@ -0,0 +1,50 @@ +/* + * Copyright 2000 Brian S. Dean + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BRIAN S. DEAN ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BRIAN S. DEAN BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + */ + +/* + * $FreeBSD$ + */ + + +#include +#include + + +int +i386_clr_watch(int watchnum, struct dbreg * d) +{ + + if (watchnum < 0 || watchnum >= 4) + return -1; + + d->dr7 = d->dr7 & ~((0x3 << (watchnum*2)) | (0x0f << (watchnum*4+16))); + DBREG_DRX(d,watchnum) = 0; + + return 0; +} diff --git a/lib/libc/i386/sys/i386_set_watch.3 b/lib/libc/i386/sys/i386_set_watch.3 new file mode 100644 index 000000000000..a85ae85c7b5e --- /dev/null +++ b/lib/libc/i386/sys/i386_set_watch.3 @@ -0,0 +1,103 @@ +.\" Copyright (c) 2000 Brian S. Dean +.\" All rights reserved. +.\" +.\" This man-page is based on a similar man-page by Jonathan Lemon +.\" which is copyrighted under the following conditions: +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.Dd August 24, 2000 +.Os +.Dt I386_SET_WATCH 3 +.Sh NAME +.Nm i386_clr_watch , +.Nm i386_set_watch +.Nd manage i386 debug register values +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.Fd #include +.Fd #include +.Ft int +.Fn i386_clr_watch "int watchnum" "struct dbreg *d" +.Ft int +.Fn i386_set_watch "int watchnum" "unsigned int watchaddr" "int size" "int access" "struct dbreg *d" +.Sh DESCRIPTION +.Fn i386_clr_watch +will disable the indicated watch point within the specified debug +register set. +.Pp +.Fn i386_set_watch +will set up the specified debug registers as indicated by the +parameters. The +.Fa watchnum +argument specifies which watch register is used, 0, 1, 2, 3, or -1. If +.Fa watchnum +is -1, a free watch register is found and used. If there are no free +watch registers, an error code of -1 is returned. +.Fa Watchaddr +specifies the watch address, +.Fa size +specifies the size in bytes of the area to be watched (1, 2, or 4 bytes), +and +.Fa access +specifes the type of watch point: +.Pp +.Bd -literal -offset indent -compact +DBREG_DR7_EXEC An execution breakpoint. +DBREG_DR7_WRONLY Break only when the watch area is written to. +DBREG_DR7_RDWR Break when the watch area is read from or written + to. +.Ed +.Pp +Note that these functions do not actually set or clear breakpoints; +they manipulate the indicated debug register set. You must use +.Xr ptrace 2 +to retrieve and install the debug register values for a process. +.Sh RETURN VALUES +.Fn i386_clr_watch +returns 0 on success, or -1 if +.Fa watchnum +is invalid (not in the range of 0-3). +.Pp +.Fn i386_set_watch +will return the +.Fa watchnum +argument, or the watchnum actually used in the case that +.Fa watchnum +is -1 on success. On error, +.Fn i386_set_watch +will return -1 indicating that the watchpoint could not be set up +because either no more watchpoints are available, or +.Fa watchnum , +.Fa size , +or +.Fa access +is invalid. +.Sh SEE ALSO +.Xr ptrace 2 , +.Xr procfs 5 +.Sh AUTHORS +This man page was written by +.An Brian S. Dean . diff --git a/lib/libc/i386/sys/i386_set_watch.c b/lib/libc/i386/sys/i386_set_watch.c new file mode 100644 index 000000000000..bb710dc701c3 --- /dev/null +++ b/lib/libc/i386/sys/i386_set_watch.c @@ -0,0 +1,88 @@ +/* + * Copyright 2000 Brian S. Dean + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BRIAN S. DEAN ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BRIAN S. DEAN BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + */ + +/* + * $FreeBSD$ + */ + + +#include +#include + + +int +i386_set_watch(int watchnum, unsigned int watchaddr, int size, + int access, struct dbreg * d) +{ + int i; + unsigned int mask; + + if (watchnum == -1) { + for (i = 0, mask = 0x3; i < 4; i++, mask <<= 2) + if ((d->dr7 & mask) == 0) + break; + if (i < 4) + watchnum = i; + else + return -1; + } + + switch (access) { + case DBREG_DR7_EXEC: + size = 1; /* size must be 1 for an execution breakpoint */ + /* fall through */ + case DBREG_DR7_WRONLY: + case DBREG_DR7_RDWR: + break; + default : return -1; break; + } + + /* + * we can watch a 1, 2, or 4 byte sized location + */ + switch (size) { + case 1 : mask = 0x00; break; + case 2 : mask = 0x01 << 2; break; + case 4 : mask = 0x03 << 2; break; + default : return -1; break; + } + + mask |= access; + + /* clear the bits we are about to affect */ + d->dr7 &= ~((0x3 << (watchnum*2)) | (0x0f << (watchnum*4+16))); + + /* set drN register to the address, N=watchnum */ + DBREG_DRX(d,watchnum) = watchaddr; + + /* enable the watchpoint */ + d->dr7 |= (0x2 << (watchnum*2)) | (mask << (watchnum*4+16)); + + return watchnum; +} diff --git a/sys/amd64/include/reg.h b/sys/amd64/include/reg.h index 6effd1a60d6f..47856a313543 100644 --- a/sys/amd64/include/reg.h +++ b/sys/amd64/include/reg.h @@ -132,6 +132,12 @@ struct dbreg { unsigned int dr7; /* debug control register */ }; +#define DBREG_DR7_EXEC 0x00 /* break on execute */ +#define DBREG_DR7_WRONLY 0x01 /* break on write */ +#define DBREG_DR7_RDWR 0x03 /* break on read or write */ +#define DBREG_DRX(d,x) ((&d->dr0)[x]) /* reference dr0 - dr7 by + register number */ + #ifdef _KERNEL /* diff --git a/sys/amd64/include/sysarch.h b/sys/amd64/include/sysarch.h index 01e63c569a78..7e355af2f43a 100644 --- a/sys/amd64/include/sysarch.h +++ b/sys/amd64/include/sysarch.h @@ -68,6 +68,7 @@ struct i386_vm86_args { #include union descriptor; +struct dbreg; __BEGIN_DECLS int i386_get_ldt __P((int, union descriptor *, int)); @@ -75,6 +76,9 @@ int i386_set_ldt __P((int, union descriptor *, int)); int i386_get_ioperm __P((unsigned int, unsigned int *, int *)); int i386_set_ioperm __P((unsigned int, unsigned int, int)); int i386_vm86 __P((int, void *)); +int i386_set_watch __P((int watchnum, unsigned int watchaddr, int size, + int access, struct dbreg * d)); +int i386_clr_watch __P((int watchnum, struct dbreg * d)); __END_DECLS #endif diff --git a/sys/i386/include/reg.h b/sys/i386/include/reg.h index 6effd1a60d6f..47856a313543 100644 --- a/sys/i386/include/reg.h +++ b/sys/i386/include/reg.h @@ -132,6 +132,12 @@ struct dbreg { unsigned int dr7; /* debug control register */ }; +#define DBREG_DR7_EXEC 0x00 /* break on execute */ +#define DBREG_DR7_WRONLY 0x01 /* break on write */ +#define DBREG_DR7_RDWR 0x03 /* break on read or write */ +#define DBREG_DRX(d,x) ((&d->dr0)[x]) /* reference dr0 - dr7 by + register number */ + #ifdef _KERNEL /* diff --git a/sys/i386/include/sysarch.h b/sys/i386/include/sysarch.h index 01e63c569a78..7e355af2f43a 100644 --- a/sys/i386/include/sysarch.h +++ b/sys/i386/include/sysarch.h @@ -68,6 +68,7 @@ struct i386_vm86_args { #include union descriptor; +struct dbreg; __BEGIN_DECLS int i386_get_ldt __P((int, union descriptor *, int)); @@ -75,6 +76,9 @@ int i386_set_ldt __P((int, union descriptor *, int)); int i386_get_ioperm __P((unsigned int, unsigned int *, int *)); int i386_set_ioperm __P((unsigned int, unsigned int, int)); int i386_vm86 __P((int, void *)); +int i386_set_watch __P((int watchnum, unsigned int watchaddr, int size, + int access, struct dbreg * d)); +int i386_clr_watch __P((int watchnum, struct dbreg * d)); __END_DECLS #endif