17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate * with the License.
87c478bd9Sstevel@tonic-gate *
97c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate * and limitations under the License.
137c478bd9Sstevel@tonic-gate *
147c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate *
207c478bd9Sstevel@tonic-gate * CDDL HEADER END
217c478bd9Sstevel@tonic-gate */
227c478bd9Sstevel@tonic-gate /*
237c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
247c478bd9Sstevel@tonic-gate * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate */
267c478bd9Sstevel@tonic-gate
277c478bd9Sstevel@tonic-gate #include <sys/types.h>
287c478bd9Sstevel@tonic-gate #include <sys/t_lock.h>
297c478bd9Sstevel@tonic-gate #include <sys/param.h>
307c478bd9Sstevel@tonic-gate #include <sys/cred.h>
317c478bd9Sstevel@tonic-gate #include <sys/debug.h>
327c478bd9Sstevel@tonic-gate #include <sys/inline.h>
337c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
347c478bd9Sstevel@tonic-gate #include <sys/proc.h>
357c478bd9Sstevel@tonic-gate #include <sys/regset.h>
367c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
377c478bd9Sstevel@tonic-gate #include <sys/systm.h>
387c478bd9Sstevel@tonic-gate #include <sys/prsystm.h>
397c478bd9Sstevel@tonic-gate #include <sys/buf.h>
407c478bd9Sstevel@tonic-gate #include <sys/signal.h>
417c478bd9Sstevel@tonic-gate #include <sys/user.h>
427c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h>
437c478bd9Sstevel@tonic-gate
447c478bd9Sstevel@tonic-gate #include <sys/fault.h>
457c478bd9Sstevel@tonic-gate #include <sys/syscall.h>
467c478bd9Sstevel@tonic-gate #include <sys/procfs.h>
477c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
487c478bd9Sstevel@tonic-gate #include <sys/stack.h>
497c478bd9Sstevel@tonic-gate #include <sys/watchpoint.h>
507c478bd9Sstevel@tonic-gate #include <sys/copyops.h>
517c478bd9Sstevel@tonic-gate #include <sys/schedctl.h>
527c478bd9Sstevel@tonic-gate
537c478bd9Sstevel@tonic-gate #include <sys/mman.h>
547c478bd9Sstevel@tonic-gate #include <vm/as.h>
557c478bd9Sstevel@tonic-gate #include <vm/seg.h>
567c478bd9Sstevel@tonic-gate
577c478bd9Sstevel@tonic-gate /*
587c478bd9Sstevel@tonic-gate * Copy ops vector for watchpoints.
597c478bd9Sstevel@tonic-gate */
607c478bd9Sstevel@tonic-gate static int watch_copyin(const void *, void *, size_t);
617c478bd9Sstevel@tonic-gate static int watch_xcopyin(const void *, void *, size_t);
627c478bd9Sstevel@tonic-gate static int watch_copyout(const void *, void *, size_t);
637c478bd9Sstevel@tonic-gate static int watch_xcopyout(const void *, void *, size_t);
647c478bd9Sstevel@tonic-gate static int watch_copyinstr(const char *, char *, size_t, size_t *);
657c478bd9Sstevel@tonic-gate static int watch_copyoutstr(const char *, char *, size_t, size_t *);
667c478bd9Sstevel@tonic-gate static int watch_fuword8(const void *, uint8_t *);
677c478bd9Sstevel@tonic-gate static int watch_fuword16(const void *, uint16_t *);
687c478bd9Sstevel@tonic-gate static int watch_fuword32(const void *, uint32_t *);
697c478bd9Sstevel@tonic-gate static int watch_suword8(void *, uint8_t);
707c478bd9Sstevel@tonic-gate static int watch_suword16(void *, uint16_t);
717c478bd9Sstevel@tonic-gate static int watch_suword32(void *, uint32_t);
727c478bd9Sstevel@tonic-gate static int watch_physio(int (*)(struct buf *), struct buf *,
737c478bd9Sstevel@tonic-gate dev_t, int, void (*)(struct buf *), struct uio *);
747c478bd9Sstevel@tonic-gate #ifdef _LP64
757c478bd9Sstevel@tonic-gate static int watch_fuword64(const void *, uint64_t *);
767c478bd9Sstevel@tonic-gate static int watch_suword64(void *, uint64_t);
777c478bd9Sstevel@tonic-gate #endif
787c478bd9Sstevel@tonic-gate
797c478bd9Sstevel@tonic-gate struct copyops watch_copyops = {
807c478bd9Sstevel@tonic-gate watch_copyin,
817c478bd9Sstevel@tonic-gate watch_xcopyin,
827c478bd9Sstevel@tonic-gate watch_copyout,
837c478bd9Sstevel@tonic-gate watch_xcopyout,
847c478bd9Sstevel@tonic-gate watch_copyinstr,
857c478bd9Sstevel@tonic-gate watch_copyoutstr,
867c478bd9Sstevel@tonic-gate watch_fuword8,
877c478bd9Sstevel@tonic-gate watch_fuword16,
887c478bd9Sstevel@tonic-gate watch_fuword32,
897c478bd9Sstevel@tonic-gate #ifdef _LP64
907c478bd9Sstevel@tonic-gate watch_fuword64,
917c478bd9Sstevel@tonic-gate #else
927c478bd9Sstevel@tonic-gate NULL,
937c478bd9Sstevel@tonic-gate #endif
947c478bd9Sstevel@tonic-gate watch_suword8,
957c478bd9Sstevel@tonic-gate watch_suword16,
967c478bd9Sstevel@tonic-gate watch_suword32,
977c478bd9Sstevel@tonic-gate #ifdef _LP64
987c478bd9Sstevel@tonic-gate watch_suword64,
997c478bd9Sstevel@tonic-gate #else
1007c478bd9Sstevel@tonic-gate NULL,
1017c478bd9Sstevel@tonic-gate #endif
1027c478bd9Sstevel@tonic-gate watch_physio
1037c478bd9Sstevel@tonic-gate };
1047c478bd9Sstevel@tonic-gate
1057c478bd9Sstevel@tonic-gate /*
1067c478bd9Sstevel@tonic-gate * Map the 'rw' argument to a protection flag.
1077c478bd9Sstevel@tonic-gate */
1087c478bd9Sstevel@tonic-gate static int
rw_to_prot(enum seg_rw rw)1097c478bd9Sstevel@tonic-gate rw_to_prot(enum seg_rw rw)
1107c478bd9Sstevel@tonic-gate {
1117c478bd9Sstevel@tonic-gate switch (rw) {
1127c478bd9Sstevel@tonic-gate case S_EXEC:
1137c478bd9Sstevel@tonic-gate return (PROT_EXEC);
1147c478bd9Sstevel@tonic-gate case S_READ:
1157c478bd9Sstevel@tonic-gate return (PROT_READ);
1167c478bd9Sstevel@tonic-gate case S_WRITE:
1177c478bd9Sstevel@tonic-gate return (PROT_WRITE);
1187c478bd9Sstevel@tonic-gate default:
1197c478bd9Sstevel@tonic-gate return (PROT_NONE); /* can't happen */
1207c478bd9Sstevel@tonic-gate }
1217c478bd9Sstevel@tonic-gate }
1227c478bd9Sstevel@tonic-gate
1237c478bd9Sstevel@tonic-gate /*
1247c478bd9Sstevel@tonic-gate * Map the 'rw' argument to an index into an array of exec/write/read things.
1257c478bd9Sstevel@tonic-gate * The index follows the precedence order: exec .. write .. read
1267c478bd9Sstevel@tonic-gate */
1277c478bd9Sstevel@tonic-gate static int
rw_to_index(enum seg_rw rw)1287c478bd9Sstevel@tonic-gate rw_to_index(enum seg_rw rw)
1297c478bd9Sstevel@tonic-gate {
1307c478bd9Sstevel@tonic-gate switch (rw) {
1317c478bd9Sstevel@tonic-gate default: /* default case "can't happen" */
1327c478bd9Sstevel@tonic-gate case S_EXEC:
1337c478bd9Sstevel@tonic-gate return (0);
1347c478bd9Sstevel@tonic-gate case S_WRITE:
1357c478bd9Sstevel@tonic-gate return (1);
1367c478bd9Sstevel@tonic-gate case S_READ:
1377c478bd9Sstevel@tonic-gate return (2);
1387c478bd9Sstevel@tonic-gate }
1397c478bd9Sstevel@tonic-gate }
1407c478bd9Sstevel@tonic-gate
1417c478bd9Sstevel@tonic-gate /*
1427c478bd9Sstevel@tonic-gate * Map an index back to a seg_rw.
1437c478bd9Sstevel@tonic-gate */
1447c478bd9Sstevel@tonic-gate static enum seg_rw S_rw[4] = {
1457c478bd9Sstevel@tonic-gate S_EXEC,
1467c478bd9Sstevel@tonic-gate S_WRITE,
1477c478bd9Sstevel@tonic-gate S_READ,
1487c478bd9Sstevel@tonic-gate S_READ,
1497c478bd9Sstevel@tonic-gate };
1507c478bd9Sstevel@tonic-gate
1517c478bd9Sstevel@tonic-gate #define X 0
1527c478bd9Sstevel@tonic-gate #define W 1
1537c478bd9Sstevel@tonic-gate #define R 2
1547c478bd9Sstevel@tonic-gate #define sum(a) (a[X] + a[W] + a[R])
1557c478bd9Sstevel@tonic-gate
1567c478bd9Sstevel@tonic-gate /*
1577c478bd9Sstevel@tonic-gate * Common code for pr_mappage() and pr_unmappage().
1587c478bd9Sstevel@tonic-gate */
1597c478bd9Sstevel@tonic-gate static int
pr_do_mappage(caddr_t addr,size_t size,int mapin,enum seg_rw rw,int kernel)1607c478bd9Sstevel@tonic-gate pr_do_mappage(caddr_t addr, size_t size, int mapin, enum seg_rw rw, int kernel)
1617c478bd9Sstevel@tonic-gate {
1627c478bd9Sstevel@tonic-gate proc_t *p = curproc;
1637c478bd9Sstevel@tonic-gate struct as *as = p->p_as;
1647c478bd9Sstevel@tonic-gate char *eaddr = addr + size;
1657c478bd9Sstevel@tonic-gate int prot_rw = rw_to_prot(rw);
1667c478bd9Sstevel@tonic-gate int xrw = rw_to_index(rw);
1677c478bd9Sstevel@tonic-gate int rv = 0;
1687c478bd9Sstevel@tonic-gate struct watched_page *pwp;
1697c478bd9Sstevel@tonic-gate struct watched_page tpw;
1707c478bd9Sstevel@tonic-gate avl_index_t where;
1717c478bd9Sstevel@tonic-gate uint_t prot;
1727c478bd9Sstevel@tonic-gate
1737c478bd9Sstevel@tonic-gate ASSERT(as != &kas);
1747c478bd9Sstevel@tonic-gate
1757c478bd9Sstevel@tonic-gate startover:
1767c478bd9Sstevel@tonic-gate ASSERT(rv == 0);
1777c478bd9Sstevel@tonic-gate if (avl_numnodes(&as->a_wpage) == 0)
1787c478bd9Sstevel@tonic-gate return (0);
1797c478bd9Sstevel@tonic-gate
1807c478bd9Sstevel@tonic-gate /*
1817c478bd9Sstevel@tonic-gate * as->a_wpage can only be changed while the process is totally stopped.
1827c478bd9Sstevel@tonic-gate * Don't grab p_lock here. Holding p_lock while grabbing the address
183*0d5ae8c1SJosef 'Jeff' Sipek * space lock leads to deadlocks with the clock thread.
1847c478bd9Sstevel@tonic-gate *
1857c478bd9Sstevel@tonic-gate * p_maplock prevents simultaneous execution of this function. Under
1867c478bd9Sstevel@tonic-gate * normal circumstances, holdwatch() will stop all other threads, so the
1877c478bd9Sstevel@tonic-gate * lock isn't really needed. But there may be multiple threads within
1887c478bd9Sstevel@tonic-gate * stop() when SWATCHOK is set, so we need to handle multiple threads
1897c478bd9Sstevel@tonic-gate * at once. See holdwatch() for the details of this dance.
1907c478bd9Sstevel@tonic-gate */
1917c478bd9Sstevel@tonic-gate
1927c478bd9Sstevel@tonic-gate mutex_enter(&p->p_maplock);
1937c478bd9Sstevel@tonic-gate
1947c478bd9Sstevel@tonic-gate tpw.wp_vaddr = (caddr_t)((uintptr_t)addr & (uintptr_t)PAGEMASK);
1957c478bd9Sstevel@tonic-gate if ((pwp = avl_find(&as->a_wpage, &tpw, &where)) == NULL)
1967c478bd9Sstevel@tonic-gate pwp = avl_nearest(&as->a_wpage, where, AVL_AFTER);
1977c478bd9Sstevel@tonic-gate
1987c478bd9Sstevel@tonic-gate for (; pwp != NULL && pwp->wp_vaddr < eaddr;
1997c478bd9Sstevel@tonic-gate pwp = AVL_NEXT(&as->a_wpage, pwp)) {
2007c478bd9Sstevel@tonic-gate
2017c478bd9Sstevel@tonic-gate /*
2027c478bd9Sstevel@tonic-gate * If the requested protection has not been
2037c478bd9Sstevel@tonic-gate * removed, we need not remap this page.
2047c478bd9Sstevel@tonic-gate */
2057c478bd9Sstevel@tonic-gate prot = pwp->wp_prot;
2067c478bd9Sstevel@tonic-gate if (kernel || (prot & PROT_USER))
2077c478bd9Sstevel@tonic-gate if (prot & prot_rw)
2087c478bd9Sstevel@tonic-gate continue;
2097c478bd9Sstevel@tonic-gate /*
2107c478bd9Sstevel@tonic-gate * If the requested access does not exist in the page's
2117c478bd9Sstevel@tonic-gate * original protections, we need not remap this page.
2127c478bd9Sstevel@tonic-gate * If the page does not exist yet, we can't test it.
2137c478bd9Sstevel@tonic-gate */
2147c478bd9Sstevel@tonic-gate if ((prot = pwp->wp_oprot) != 0) {
2157c478bd9Sstevel@tonic-gate if (!(kernel || (prot & PROT_USER)))
2167c478bd9Sstevel@tonic-gate continue;
2177c478bd9Sstevel@tonic-gate if (!(prot & prot_rw))
2187c478bd9Sstevel@tonic-gate continue;
2197c478bd9Sstevel@tonic-gate }
2207c478bd9Sstevel@tonic-gate
2217c478bd9Sstevel@tonic-gate if (mapin) {
2227c478bd9Sstevel@tonic-gate /*
2237c478bd9Sstevel@tonic-gate * Before mapping the page in, ensure that
2247c478bd9Sstevel@tonic-gate * all other lwps are held in the kernel.
2257c478bd9Sstevel@tonic-gate */
2267c478bd9Sstevel@tonic-gate if (p->p_mapcnt == 0) {
2277c478bd9Sstevel@tonic-gate mutex_exit(&p->p_maplock);
2287c478bd9Sstevel@tonic-gate if (holdwatch() != 0) {
2297c478bd9Sstevel@tonic-gate /*
2307c478bd9Sstevel@tonic-gate * We stopped in holdwatch().
2317c478bd9Sstevel@tonic-gate * Start all over again because the
2327c478bd9Sstevel@tonic-gate * watched page list may have changed.
2337c478bd9Sstevel@tonic-gate */
2347c478bd9Sstevel@tonic-gate goto startover;
2357c478bd9Sstevel@tonic-gate }
2367c478bd9Sstevel@tonic-gate mutex_enter(&p->p_maplock);
2377c478bd9Sstevel@tonic-gate }
2387c478bd9Sstevel@tonic-gate p->p_mapcnt++;
2397c478bd9Sstevel@tonic-gate }
2407c478bd9Sstevel@tonic-gate
2417c478bd9Sstevel@tonic-gate addr = pwp->wp_vaddr;
2427c478bd9Sstevel@tonic-gate rv++;
2437c478bd9Sstevel@tonic-gate
2447c478bd9Sstevel@tonic-gate prot = pwp->wp_prot;
2457c478bd9Sstevel@tonic-gate if (mapin) {
2467c478bd9Sstevel@tonic-gate if (kernel)
2477c478bd9Sstevel@tonic-gate pwp->wp_kmap[xrw]++;
2487c478bd9Sstevel@tonic-gate else
2497c478bd9Sstevel@tonic-gate pwp->wp_umap[xrw]++;
2507c478bd9Sstevel@tonic-gate pwp->wp_flags |= WP_NOWATCH;
2517c478bd9Sstevel@tonic-gate if (pwp->wp_kmap[X] + pwp->wp_umap[X])
2527c478bd9Sstevel@tonic-gate /* cannot have exec-only protection */
2537c478bd9Sstevel@tonic-gate prot |= PROT_READ|PROT_EXEC;
2547c478bd9Sstevel@tonic-gate if (pwp->wp_kmap[R] + pwp->wp_umap[R])
2557c478bd9Sstevel@tonic-gate prot |= PROT_READ;
2567c478bd9Sstevel@tonic-gate if (pwp->wp_kmap[W] + pwp->wp_umap[W])
2577c478bd9Sstevel@tonic-gate /* cannot have write-only protection */
2587c478bd9Sstevel@tonic-gate prot |= PROT_READ|PROT_WRITE;
2597c478bd9Sstevel@tonic-gate #if 0 /* damned broken mmu feature! */
2607c478bd9Sstevel@tonic-gate if (sum(pwp->wp_umap) == 0)
2617c478bd9Sstevel@tonic-gate prot &= ~PROT_USER;
2627c478bd9Sstevel@tonic-gate #endif
2637c478bd9Sstevel@tonic-gate } else {
2647c478bd9Sstevel@tonic-gate ASSERT(pwp->wp_flags & WP_NOWATCH);
2657c478bd9Sstevel@tonic-gate if (kernel) {
2667c478bd9Sstevel@tonic-gate ASSERT(pwp->wp_kmap[xrw] != 0);
2677c478bd9Sstevel@tonic-gate --pwp->wp_kmap[xrw];
2687c478bd9Sstevel@tonic-gate } else {
2697c478bd9Sstevel@tonic-gate ASSERT(pwp->wp_umap[xrw] != 0);
2707c478bd9Sstevel@tonic-gate --pwp->wp_umap[xrw];
2717c478bd9Sstevel@tonic-gate }
2727c478bd9Sstevel@tonic-gate if (sum(pwp->wp_kmap) + sum(pwp->wp_umap) == 0)
2737c478bd9Sstevel@tonic-gate pwp->wp_flags &= ~WP_NOWATCH;
2747c478bd9Sstevel@tonic-gate else {
2757c478bd9Sstevel@tonic-gate if (pwp->wp_kmap[X] + pwp->wp_umap[X])
2767c478bd9Sstevel@tonic-gate /* cannot have exec-only protection */
2777c478bd9Sstevel@tonic-gate prot |= PROT_READ|PROT_EXEC;
2787c478bd9Sstevel@tonic-gate if (pwp->wp_kmap[R] + pwp->wp_umap[R])
2797c478bd9Sstevel@tonic-gate prot |= PROT_READ;
2807c478bd9Sstevel@tonic-gate if (pwp->wp_kmap[W] + pwp->wp_umap[W])
2817c478bd9Sstevel@tonic-gate /* cannot have write-only protection */
2827c478bd9Sstevel@tonic-gate prot |= PROT_READ|PROT_WRITE;
2837c478bd9Sstevel@tonic-gate #if 0 /* damned broken mmu feature! */
2847c478bd9Sstevel@tonic-gate if (sum(pwp->wp_umap) == 0)
2857c478bd9Sstevel@tonic-gate prot &= ~PROT_USER;
2867c478bd9Sstevel@tonic-gate #endif
2877c478bd9Sstevel@tonic-gate }
2887c478bd9Sstevel@tonic-gate }
2897c478bd9Sstevel@tonic-gate
2907c478bd9Sstevel@tonic-gate
2917c478bd9Sstevel@tonic-gate if (pwp->wp_oprot != 0) { /* if page exists */
2927c478bd9Sstevel@tonic-gate struct seg *seg;
2937c478bd9Sstevel@tonic-gate uint_t oprot;
2947c478bd9Sstevel@tonic-gate int err, retrycnt = 0;
2957c478bd9Sstevel@tonic-gate
296dc32d872SJosef 'Jeff' Sipek AS_LOCK_ENTER(as, RW_WRITER);
2977c478bd9Sstevel@tonic-gate retry:
2987c478bd9Sstevel@tonic-gate seg = as_segat(as, addr);
2997c478bd9Sstevel@tonic-gate ASSERT(seg != NULL);
3007c478bd9Sstevel@tonic-gate SEGOP_GETPROT(seg, addr, 0, &oprot);
3017c478bd9Sstevel@tonic-gate if (prot != oprot) {
3027c478bd9Sstevel@tonic-gate err = SEGOP_SETPROT(seg, addr, PAGESIZE, prot);
3037c478bd9Sstevel@tonic-gate if (err == IE_RETRY) {
3047c478bd9Sstevel@tonic-gate ASSERT(retrycnt == 0);
3057c478bd9Sstevel@tonic-gate retrycnt++;
3067c478bd9Sstevel@tonic-gate goto retry;
3077c478bd9Sstevel@tonic-gate }
3087c478bd9Sstevel@tonic-gate }
309dc32d872SJosef 'Jeff' Sipek AS_LOCK_EXIT(as);
310*0d5ae8c1SJosef 'Jeff' Sipek }
3117c478bd9Sstevel@tonic-gate
3127c478bd9Sstevel@tonic-gate /*
3137c478bd9Sstevel@tonic-gate * When all pages are mapped back to their normal state,
3147c478bd9Sstevel@tonic-gate * continue the other lwps.
3157c478bd9Sstevel@tonic-gate */
3167c478bd9Sstevel@tonic-gate if (!mapin) {
3177c478bd9Sstevel@tonic-gate ASSERT(p->p_mapcnt > 0);
3187c478bd9Sstevel@tonic-gate p->p_mapcnt--;
3197c478bd9Sstevel@tonic-gate if (p->p_mapcnt == 0) {
3207c478bd9Sstevel@tonic-gate mutex_exit(&p->p_maplock);
3217c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock);
3227c478bd9Sstevel@tonic-gate continuelwps(p);
3237c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock);
3247c478bd9Sstevel@tonic-gate mutex_enter(&p->p_maplock);
3257c478bd9Sstevel@tonic-gate }
3267c478bd9Sstevel@tonic-gate }
3277c478bd9Sstevel@tonic-gate }
3287c478bd9Sstevel@tonic-gate
3297c478bd9Sstevel@tonic-gate mutex_exit(&p->p_maplock);
3307c478bd9Sstevel@tonic-gate
3317c478bd9Sstevel@tonic-gate return (rv);
3327c478bd9Sstevel@tonic-gate }
3337c478bd9Sstevel@tonic-gate
3347c478bd9Sstevel@tonic-gate /*
3357c478bd9Sstevel@tonic-gate * Restore the original page protections on an address range.
3367c478bd9Sstevel@tonic-gate * If 'kernel' is non-zero, just do it for the kernel.
3377c478bd9Sstevel@tonic-gate * pr_mappage() returns non-zero if it actually changed anything.
3387c478bd9Sstevel@tonic-gate *
3397c478bd9Sstevel@tonic-gate * pr_mappage() and pr_unmappage() must be executed in matched pairs,
3407c478bd9Sstevel@tonic-gate * but pairs may be nested within other pairs. The reference counts
3417c478bd9Sstevel@tonic-gate * sort it all out. See pr_do_mappage(), above.
3427c478bd9Sstevel@tonic-gate */
3437c478bd9Sstevel@tonic-gate static int
pr_mappage(const caddr_t addr,size_t size,enum seg_rw rw,int kernel)3447c478bd9Sstevel@tonic-gate pr_mappage(const caddr_t addr, size_t size, enum seg_rw rw, int kernel)
3457c478bd9Sstevel@tonic-gate {
3467c478bd9Sstevel@tonic-gate return (pr_do_mappage(addr, size, 1, rw, kernel));
3477c478bd9Sstevel@tonic-gate }
3487c478bd9Sstevel@tonic-gate
3497c478bd9Sstevel@tonic-gate /*
3507c478bd9Sstevel@tonic-gate * Set the modified page protections on a watched page.
3517c478bd9Sstevel@tonic-gate * Inverse of pr_mappage().
3527c478bd9Sstevel@tonic-gate * Needs to be called only if pr_mappage() returned non-zero.
3537c478bd9Sstevel@tonic-gate */
3547c478bd9Sstevel@tonic-gate static void
pr_unmappage(const caddr_t addr,size_t size,enum seg_rw rw,int kernel)3557c478bd9Sstevel@tonic-gate pr_unmappage(const caddr_t addr, size_t size, enum seg_rw rw, int kernel)
3567c478bd9Sstevel@tonic-gate {
3577c478bd9Sstevel@tonic-gate (void) pr_do_mappage(addr, size, 0, rw, kernel);
3587c478bd9Sstevel@tonic-gate }
3597c478bd9Sstevel@tonic-gate
3607c478bd9Sstevel@tonic-gate /*
3617c478bd9Sstevel@tonic-gate * Function called by an lwp after it resumes from stop().
3627c478bd9Sstevel@tonic-gate */
3637c478bd9Sstevel@tonic-gate void
setallwatch(void)3647c478bd9Sstevel@tonic-gate setallwatch(void)
3657c478bd9Sstevel@tonic-gate {
3667c478bd9Sstevel@tonic-gate proc_t *p = curproc;
3677c478bd9Sstevel@tonic-gate struct as *as = curproc->p_as;
3687c478bd9Sstevel@tonic-gate struct watched_page *pwp, *next;
3697c478bd9Sstevel@tonic-gate struct seg *seg;
3707c478bd9Sstevel@tonic-gate caddr_t vaddr;
3717c478bd9Sstevel@tonic-gate uint_t prot;
3727c478bd9Sstevel@tonic-gate int err, retrycnt;
3737c478bd9Sstevel@tonic-gate
3747c478bd9Sstevel@tonic-gate if (p->p_wprot == NULL)
3757c478bd9Sstevel@tonic-gate return;
3767c478bd9Sstevel@tonic-gate
3777c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&curproc->p_lock));
3787c478bd9Sstevel@tonic-gate
379dc32d872SJosef 'Jeff' Sipek AS_LOCK_ENTER(as, RW_WRITER);
3807c478bd9Sstevel@tonic-gate
3817c478bd9Sstevel@tonic-gate pwp = p->p_wprot;
3827c478bd9Sstevel@tonic-gate while (pwp != NULL) {
3837c478bd9Sstevel@tonic-gate
3847c478bd9Sstevel@tonic-gate vaddr = pwp->wp_vaddr;
3857c478bd9Sstevel@tonic-gate retrycnt = 0;
3867c478bd9Sstevel@tonic-gate retry:
3877c478bd9Sstevel@tonic-gate ASSERT(pwp->wp_flags & WP_SETPROT);
3887c478bd9Sstevel@tonic-gate if ((seg = as_segat(as, vaddr)) != NULL &&
3897c478bd9Sstevel@tonic-gate !(pwp->wp_flags & WP_NOWATCH)) {
3907c478bd9Sstevel@tonic-gate prot = pwp->wp_prot;
3917c478bd9Sstevel@tonic-gate err = SEGOP_SETPROT(seg, vaddr, PAGESIZE, prot);
3927c478bd9Sstevel@tonic-gate if (err == IE_RETRY) {
3937c478bd9Sstevel@tonic-gate ASSERT(retrycnt == 0);
3947c478bd9Sstevel@tonic-gate retrycnt++;
3957c478bd9Sstevel@tonic-gate goto retry;
3967c478bd9Sstevel@tonic-gate }
3977c478bd9Sstevel@tonic-gate }
3987c478bd9Sstevel@tonic-gate
3997c478bd9Sstevel@tonic-gate next = pwp->wp_list;
4007c478bd9Sstevel@tonic-gate
4017c478bd9Sstevel@tonic-gate if (pwp->wp_read + pwp->wp_write + pwp->wp_exec == 0) {
4027c478bd9Sstevel@tonic-gate /*
4037c478bd9Sstevel@tonic-gate * No watched areas remain in this page.
4047c478bd9Sstevel@tonic-gate * Free the watched_page structure.
4057c478bd9Sstevel@tonic-gate */
4067c478bd9Sstevel@tonic-gate avl_remove(&as->a_wpage, pwp);
4077c478bd9Sstevel@tonic-gate kmem_free(pwp, sizeof (struct watched_page));
4087c478bd9Sstevel@tonic-gate } else {
4097c478bd9Sstevel@tonic-gate pwp->wp_flags &= ~WP_SETPROT;
4107c478bd9Sstevel@tonic-gate }
4117c478bd9Sstevel@tonic-gate
4127c478bd9Sstevel@tonic-gate pwp = next;
4137c478bd9Sstevel@tonic-gate }
4147c478bd9Sstevel@tonic-gate p->p_wprot = NULL;
4157c478bd9Sstevel@tonic-gate
416dc32d872SJosef 'Jeff' Sipek AS_LOCK_EXIT(as);
4177c478bd9Sstevel@tonic-gate }
4187c478bd9Sstevel@tonic-gate
4197c478bd9Sstevel@tonic-gate
4207c478bd9Sstevel@tonic-gate
4217c478bd9Sstevel@tonic-gate int
pr_is_watchpage_as(caddr_t addr,enum seg_rw rw,struct as * as)4227c478bd9Sstevel@tonic-gate pr_is_watchpage_as(caddr_t addr, enum seg_rw rw, struct as *as)
4237c478bd9Sstevel@tonic-gate {
4247c478bd9Sstevel@tonic-gate register struct watched_page *pwp;
4257c478bd9Sstevel@tonic-gate struct watched_page tpw;
4267c478bd9Sstevel@tonic-gate uint_t prot;
4277c478bd9Sstevel@tonic-gate int rv = 0;
4287c478bd9Sstevel@tonic-gate
4297c478bd9Sstevel@tonic-gate switch (rw) {
4307c478bd9Sstevel@tonic-gate case S_READ:
4317c478bd9Sstevel@tonic-gate case S_WRITE:
4327c478bd9Sstevel@tonic-gate case S_EXEC:
4337c478bd9Sstevel@tonic-gate break;
4347c478bd9Sstevel@tonic-gate default:
4357c478bd9Sstevel@tonic-gate return (0);
4367c478bd9Sstevel@tonic-gate }
4377c478bd9Sstevel@tonic-gate
4387c478bd9Sstevel@tonic-gate /*
4397c478bd9Sstevel@tonic-gate * as->a_wpage can only be modified while the process is totally
4407c478bd9Sstevel@tonic-gate * stopped. We need, and should use, no locks here.
4417c478bd9Sstevel@tonic-gate */
4427c478bd9Sstevel@tonic-gate if (as != &kas && avl_numnodes(&as->a_wpage) != 0) {
4437c478bd9Sstevel@tonic-gate tpw.wp_vaddr = (caddr_t)((uintptr_t)addr & (uintptr_t)PAGEMASK);
4447c478bd9Sstevel@tonic-gate pwp = avl_find(&as->a_wpage, &tpw, NULL);
4457c478bd9Sstevel@tonic-gate if (pwp != NULL) {
4467c478bd9Sstevel@tonic-gate ASSERT(addr >= pwp->wp_vaddr &&
4477c478bd9Sstevel@tonic-gate addr < pwp->wp_vaddr + PAGESIZE);
4487c478bd9Sstevel@tonic-gate if (pwp->wp_oprot != 0) {
4497c478bd9Sstevel@tonic-gate prot = pwp->wp_prot;
4507c478bd9Sstevel@tonic-gate switch (rw) {
4517c478bd9Sstevel@tonic-gate case S_READ:
4527c478bd9Sstevel@tonic-gate rv = ((prot & (PROT_USER|PROT_READ))
4537c478bd9Sstevel@tonic-gate != (PROT_USER|PROT_READ));
4547c478bd9Sstevel@tonic-gate break;
4557c478bd9Sstevel@tonic-gate case S_WRITE:
4567c478bd9Sstevel@tonic-gate rv = ((prot & (PROT_USER|PROT_WRITE))
4577c478bd9Sstevel@tonic-gate != (PROT_USER|PROT_WRITE));
4587c478bd9Sstevel@tonic-gate break;
4597c478bd9Sstevel@tonic-gate case S_EXEC:
4607c478bd9Sstevel@tonic-gate rv = ((prot & (PROT_USER|PROT_EXEC))
4617c478bd9Sstevel@tonic-gate != (PROT_USER|PROT_EXEC));
4627c478bd9Sstevel@tonic-gate break;
4637c478bd9Sstevel@tonic-gate default:
4647c478bd9Sstevel@tonic-gate /* can't happen! */
4657c478bd9Sstevel@tonic-gate break;
4667c478bd9Sstevel@tonic-gate }
4677c478bd9Sstevel@tonic-gate }
4687c478bd9Sstevel@tonic-gate }
4697c478bd9Sstevel@tonic-gate }
4707c478bd9Sstevel@tonic-gate
4717c478bd9Sstevel@tonic-gate return (rv);
4727c478bd9Sstevel@tonic-gate }
4737c478bd9Sstevel@tonic-gate
4747c478bd9Sstevel@tonic-gate
4757c478bd9Sstevel@tonic-gate /*
4767c478bd9Sstevel@tonic-gate * trap() calls here to determine if a fault is in a watched page.
4777c478bd9Sstevel@tonic-gate * We return nonzero if this is true and the load/store would fail.
4787c478bd9Sstevel@tonic-gate */
4797c478bd9Sstevel@tonic-gate int
pr_is_watchpage(caddr_t addr,enum seg_rw rw)4807c478bd9Sstevel@tonic-gate pr_is_watchpage(caddr_t addr, enum seg_rw rw)
4817c478bd9Sstevel@tonic-gate {
4827c478bd9Sstevel@tonic-gate struct as *as = curproc->p_as;
4837c478bd9Sstevel@tonic-gate
4847c478bd9Sstevel@tonic-gate if ((as == &kas) || avl_numnodes(&as->a_wpage) == 0)
4857c478bd9Sstevel@tonic-gate return (0);
4867c478bd9Sstevel@tonic-gate
487*0d5ae8c1SJosef 'Jeff' Sipek return (pr_is_watchpage_as(addr, rw, as));
4887c478bd9Sstevel@tonic-gate }
4897c478bd9Sstevel@tonic-gate
4907c478bd9Sstevel@tonic-gate
4917c478bd9Sstevel@tonic-gate
4927c478bd9Sstevel@tonic-gate /*
4937c478bd9Sstevel@tonic-gate * trap() calls here to determine if a fault is a watchpoint.
4947c478bd9Sstevel@tonic-gate */
4957c478bd9Sstevel@tonic-gate int
pr_is_watchpoint(caddr_t * paddr,int * pta,size_t size,size_t * plen,enum seg_rw rw)4967c478bd9Sstevel@tonic-gate pr_is_watchpoint(caddr_t *paddr, int *pta, size_t size, size_t *plen,
4977c478bd9Sstevel@tonic-gate enum seg_rw rw)
4987c478bd9Sstevel@tonic-gate {
4997c478bd9Sstevel@tonic-gate proc_t *p = curproc;
5007c478bd9Sstevel@tonic-gate caddr_t addr = *paddr;
5017c478bd9Sstevel@tonic-gate caddr_t eaddr = addr + size;
5027c478bd9Sstevel@tonic-gate register struct watched_area *pwa;
5037c478bd9Sstevel@tonic-gate struct watched_area twa;
5047c478bd9Sstevel@tonic-gate int rv = 0;
5057c478bd9Sstevel@tonic-gate int ta = 0;
5067c478bd9Sstevel@tonic-gate size_t len = 0;
5077c478bd9Sstevel@tonic-gate
5087c478bd9Sstevel@tonic-gate switch (rw) {
5097c478bd9Sstevel@tonic-gate case S_READ:
5107c478bd9Sstevel@tonic-gate case S_WRITE:
5117c478bd9Sstevel@tonic-gate case S_EXEC:
5127c478bd9Sstevel@tonic-gate break;
5137c478bd9Sstevel@tonic-gate default:
5147c478bd9Sstevel@tonic-gate *pta = 0;
5157c478bd9Sstevel@tonic-gate return (0);
5167c478bd9Sstevel@tonic-gate }
5177c478bd9Sstevel@tonic-gate
5187c478bd9Sstevel@tonic-gate /*
5197c478bd9Sstevel@tonic-gate * p->p_warea is protected by p->p_lock.
5207c478bd9Sstevel@tonic-gate */
5217c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock);
5227c478bd9Sstevel@tonic-gate
5237c478bd9Sstevel@tonic-gate /* BEGIN CSTYLED */
5247c478bd9Sstevel@tonic-gate /*
5257c478bd9Sstevel@tonic-gate * This loop is somewhat complicated because the fault region can span
5267c478bd9Sstevel@tonic-gate * multiple watched areas. For example:
5277c478bd9Sstevel@tonic-gate *
5287c478bd9Sstevel@tonic-gate * addr eaddr
5297c478bd9Sstevel@tonic-gate * +-----------------+
5307c478bd9Sstevel@tonic-gate * | fault region |
5317c478bd9Sstevel@tonic-gate * +-------+--------+----+---+------------+
5327c478bd9Sstevel@tonic-gate * | prot not right | | prot correct |
5337c478bd9Sstevel@tonic-gate * +----------------+ +----------------+
5347c478bd9Sstevel@tonic-gate * wa_vaddr wa_eaddr
5357c478bd9Sstevel@tonic-gate * wa_vaddr wa_eaddr
5367c478bd9Sstevel@tonic-gate *
5377c478bd9Sstevel@tonic-gate * We start at the area greater than or equal to the starting address.
5387c478bd9Sstevel@tonic-gate * As long as some portion of the fault region overlaps the current
5397c478bd9Sstevel@tonic-gate * area, we continue checking permissions until we find an appropriate
5407c478bd9Sstevel@tonic-gate * match.
5417c478bd9Sstevel@tonic-gate */
5427c478bd9Sstevel@tonic-gate /* END CSTYLED */
5437c478bd9Sstevel@tonic-gate twa.wa_vaddr = addr;
5447c478bd9Sstevel@tonic-gate twa.wa_eaddr = eaddr;
5457c478bd9Sstevel@tonic-gate
5467c478bd9Sstevel@tonic-gate for (pwa = pr_find_watched_area(p, &twa, NULL);
5477c478bd9Sstevel@tonic-gate pwa != NULL && eaddr > pwa->wa_vaddr && addr < pwa->wa_eaddr;
5487c478bd9Sstevel@tonic-gate pwa = AVL_NEXT(&p->p_warea, pwa)) {
5497c478bd9Sstevel@tonic-gate
5507c478bd9Sstevel@tonic-gate switch (rw) {
5517c478bd9Sstevel@tonic-gate case S_READ:
5527c478bd9Sstevel@tonic-gate if (pwa->wa_flags & WA_READ)
5537c478bd9Sstevel@tonic-gate rv = TRAP_RWATCH;
5547c478bd9Sstevel@tonic-gate break;
5557c478bd9Sstevel@tonic-gate case S_WRITE:
5567c478bd9Sstevel@tonic-gate if (pwa->wa_flags & WA_WRITE)
5577c478bd9Sstevel@tonic-gate rv = TRAP_WWATCH;
5587c478bd9Sstevel@tonic-gate break;
5597c478bd9Sstevel@tonic-gate case S_EXEC:
5607c478bd9Sstevel@tonic-gate if (pwa->wa_flags & WA_EXEC)
5617c478bd9Sstevel@tonic-gate rv = TRAP_XWATCH;
5627c478bd9Sstevel@tonic-gate break;
5637c478bd9Sstevel@tonic-gate default:
5647c478bd9Sstevel@tonic-gate /* can't happen */
5657c478bd9Sstevel@tonic-gate break;
5667c478bd9Sstevel@tonic-gate }
5677c478bd9Sstevel@tonic-gate
5687c478bd9Sstevel@tonic-gate /*
5697c478bd9Sstevel@tonic-gate * If protections didn't match, check the next watched
5707c478bd9Sstevel@tonic-gate * area
5717c478bd9Sstevel@tonic-gate */
5727c478bd9Sstevel@tonic-gate if (rv != 0) {
5737c478bd9Sstevel@tonic-gate if (addr < pwa->wa_vaddr)
5747c478bd9Sstevel@tonic-gate addr = pwa->wa_vaddr;
5757c478bd9Sstevel@tonic-gate len = pwa->wa_eaddr - addr;
5767c478bd9Sstevel@tonic-gate if (pwa->wa_flags & WA_TRAPAFTER)
5777c478bd9Sstevel@tonic-gate ta = 1;
5787c478bd9Sstevel@tonic-gate break;
5797c478bd9Sstevel@tonic-gate }
5807c478bd9Sstevel@tonic-gate }
5817c478bd9Sstevel@tonic-gate
5827c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock);
5837c478bd9Sstevel@tonic-gate
5847c478bd9Sstevel@tonic-gate *paddr = addr;
5857c478bd9Sstevel@tonic-gate *pta = ta;
5867c478bd9Sstevel@tonic-gate if (plen != NULL)
5877c478bd9Sstevel@tonic-gate *plen = len;
5887c478bd9Sstevel@tonic-gate return (rv);
5897c478bd9Sstevel@tonic-gate }
5907c478bd9Sstevel@tonic-gate
5917c478bd9Sstevel@tonic-gate /*
5927c478bd9Sstevel@tonic-gate * Set up to perform a single-step at user level for the
5937c478bd9Sstevel@tonic-gate * case of a trapafter watchpoint. Called from trap().
5947c478bd9Sstevel@tonic-gate */
5957c478bd9Sstevel@tonic-gate void
do_watch_step(caddr_t vaddr,size_t sz,enum seg_rw rw,int watchcode,greg_t pc)5967c478bd9Sstevel@tonic-gate do_watch_step(caddr_t vaddr, size_t sz, enum seg_rw rw,
5977c478bd9Sstevel@tonic-gate int watchcode, greg_t pc)
5987c478bd9Sstevel@tonic-gate {
5997c478bd9Sstevel@tonic-gate register klwp_t *lwp = ttolwp(curthread);
6007c478bd9Sstevel@tonic-gate struct lwp_watch *pw = &lwp->lwp_watch[rw_to_index(rw)];
6017c478bd9Sstevel@tonic-gate
6027c478bd9Sstevel@tonic-gate /*
6037c478bd9Sstevel@tonic-gate * Check to see if we are already performing this special
6047c478bd9Sstevel@tonic-gate * watchpoint single-step. We must not do pr_mappage() twice.
6057c478bd9Sstevel@tonic-gate */
6067c478bd9Sstevel@tonic-gate
6077c478bd9Sstevel@tonic-gate /* special check for two read traps on the same instruction */
6087c478bd9Sstevel@tonic-gate if (rw == S_READ && pw->wpaddr != NULL &&
6097c478bd9Sstevel@tonic-gate !(pw->wpaddr <= vaddr && vaddr < pw->wpaddr + pw->wpsize)) {
6107c478bd9Sstevel@tonic-gate ASSERT(lwp->lwp_watchtrap != 0);
6117c478bd9Sstevel@tonic-gate pw++; /* use the extra S_READ struct */
6127c478bd9Sstevel@tonic-gate }
6137c478bd9Sstevel@tonic-gate
6147c478bd9Sstevel@tonic-gate if (pw->wpaddr != NULL) {
6157c478bd9Sstevel@tonic-gate ASSERT(lwp->lwp_watchtrap != 0);
6167c478bd9Sstevel@tonic-gate ASSERT(pw->wpaddr <= vaddr && vaddr < pw->wpaddr + pw->wpsize);
6177c478bd9Sstevel@tonic-gate if (pw->wpcode == 0) {
6187c478bd9Sstevel@tonic-gate pw->wpcode = watchcode;
6197c478bd9Sstevel@tonic-gate pw->wppc = pc;
6207c478bd9Sstevel@tonic-gate }
6217c478bd9Sstevel@tonic-gate } else {
6227c478bd9Sstevel@tonic-gate int mapped = pr_mappage(vaddr, sz, rw, 0);
6237c478bd9Sstevel@tonic-gate prstep(lwp, 1);
6247c478bd9Sstevel@tonic-gate lwp->lwp_watchtrap = 1;
6257c478bd9Sstevel@tonic-gate pw->wpaddr = vaddr;
6267c478bd9Sstevel@tonic-gate pw->wpsize = sz;
6277c478bd9Sstevel@tonic-gate pw->wpcode = watchcode;
6287c478bd9Sstevel@tonic-gate pw->wpmapped = mapped;
6297c478bd9Sstevel@tonic-gate pw->wppc = pc;
6307c478bd9Sstevel@tonic-gate }
6317c478bd9Sstevel@tonic-gate }
6327c478bd9Sstevel@tonic-gate
6337c478bd9Sstevel@tonic-gate /*
6347c478bd9Sstevel@tonic-gate * Undo the effects of do_watch_step().
6357c478bd9Sstevel@tonic-gate * Called from trap() after the single-step is finished.
6367c478bd9Sstevel@tonic-gate * Also called from issig_forreal() and stop() with a NULL
6377c478bd9Sstevel@tonic-gate * argument to avoid having these things set more than once.
6387c478bd9Sstevel@tonic-gate */
6397c478bd9Sstevel@tonic-gate int
undo_watch_step(k_siginfo_t * sip)6407c478bd9Sstevel@tonic-gate undo_watch_step(k_siginfo_t *sip)
6417c478bd9Sstevel@tonic-gate {
6427c478bd9Sstevel@tonic-gate register klwp_t *lwp = ttolwp(curthread);
6437c478bd9Sstevel@tonic-gate int fault = 0;
6447c478bd9Sstevel@tonic-gate
6457c478bd9Sstevel@tonic-gate if (lwp->lwp_watchtrap) {
6467c478bd9Sstevel@tonic-gate struct lwp_watch *pw = lwp->lwp_watch;
6477c478bd9Sstevel@tonic-gate int i;
6487c478bd9Sstevel@tonic-gate
6497c478bd9Sstevel@tonic-gate for (i = 0; i < 4; i++, pw++) {
6507c478bd9Sstevel@tonic-gate if (pw->wpaddr == NULL)
6517c478bd9Sstevel@tonic-gate continue;
6527c478bd9Sstevel@tonic-gate if (pw->wpmapped)
6537c478bd9Sstevel@tonic-gate pr_unmappage(pw->wpaddr, pw->wpsize, S_rw[i],
6547c478bd9Sstevel@tonic-gate 0);
6557c478bd9Sstevel@tonic-gate if (pw->wpcode != 0) {
6567c478bd9Sstevel@tonic-gate if (sip != NULL) {
6577c478bd9Sstevel@tonic-gate sip->si_signo = SIGTRAP;
6587c478bd9Sstevel@tonic-gate sip->si_code = pw->wpcode;
6597c478bd9Sstevel@tonic-gate sip->si_addr = pw->wpaddr;
6607c478bd9Sstevel@tonic-gate sip->si_trapafter = 1;
6617c478bd9Sstevel@tonic-gate sip->si_pc = (caddr_t)pw->wppc;
6627c478bd9Sstevel@tonic-gate }
6637c478bd9Sstevel@tonic-gate fault = FLTWATCH;
6647c478bd9Sstevel@tonic-gate pw->wpcode = 0;
6657c478bd9Sstevel@tonic-gate }
6667c478bd9Sstevel@tonic-gate pw->wpaddr = NULL;
6677c478bd9Sstevel@tonic-gate pw->wpsize = 0;
6687c478bd9Sstevel@tonic-gate pw->wpmapped = 0;
6697c478bd9Sstevel@tonic-gate }
6707c478bd9Sstevel@tonic-gate lwp->lwp_watchtrap = 0;
6717c478bd9Sstevel@tonic-gate }
6727c478bd9Sstevel@tonic-gate
6737c478bd9Sstevel@tonic-gate return (fault);
6747c478bd9Sstevel@tonic-gate }
6757c478bd9Sstevel@tonic-gate
6767c478bd9Sstevel@tonic-gate /*
6777c478bd9Sstevel@tonic-gate * Handle a watchpoint that occurs while doing copyin()
6787c478bd9Sstevel@tonic-gate * or copyout() in a system call.
6797c478bd9Sstevel@tonic-gate * Return non-zero if the fault or signal is cleared
6807c478bd9Sstevel@tonic-gate * by a debugger while the lwp is stopped.
6817c478bd9Sstevel@tonic-gate */
6827c478bd9Sstevel@tonic-gate static int
sys_watchpoint(caddr_t addr,int watchcode,int ta)6837c478bd9Sstevel@tonic-gate sys_watchpoint(caddr_t addr, int watchcode, int ta)
6847c478bd9Sstevel@tonic-gate {
6857c478bd9Sstevel@tonic-gate extern greg_t getuserpc(void); /* XXX header file */
6867c478bd9Sstevel@tonic-gate k_sigset_t smask;
6877c478bd9Sstevel@tonic-gate register proc_t *p = ttoproc(curthread);
6887c478bd9Sstevel@tonic-gate register klwp_t *lwp = ttolwp(curthread);
6897c478bd9Sstevel@tonic-gate register sigqueue_t *sqp;
6907c478bd9Sstevel@tonic-gate int rval;
6917c478bd9Sstevel@tonic-gate
6927c478bd9Sstevel@tonic-gate /* assert no locks are held */
6937c478bd9Sstevel@tonic-gate /* ASSERT(curthread->t_nlocks == 0); */
6947c478bd9Sstevel@tonic-gate
6957c478bd9Sstevel@tonic-gate sqp = kmem_zalloc(sizeof (sigqueue_t), KM_SLEEP);
6967c478bd9Sstevel@tonic-gate sqp->sq_info.si_signo = SIGTRAP;
6977c478bd9Sstevel@tonic-gate sqp->sq_info.si_code = watchcode;
6987c478bd9Sstevel@tonic-gate sqp->sq_info.si_addr = addr;
6997c478bd9Sstevel@tonic-gate sqp->sq_info.si_trapafter = ta;
7007c478bd9Sstevel@tonic-gate sqp->sq_info.si_pc = (caddr_t)getuserpc();
7017c478bd9Sstevel@tonic-gate
7027c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock);
7037c478bd9Sstevel@tonic-gate
7047c478bd9Sstevel@tonic-gate /* this will be tested and cleared by the caller */
7057c478bd9Sstevel@tonic-gate lwp->lwp_sysabort = 0;
7067c478bd9Sstevel@tonic-gate
7077c478bd9Sstevel@tonic-gate if (prismember(&p->p_fltmask, FLTWATCH)) {
7087c478bd9Sstevel@tonic-gate lwp->lwp_curflt = (uchar_t)FLTWATCH;
7097c478bd9Sstevel@tonic-gate lwp->lwp_siginfo = sqp->sq_info;
7107c478bd9Sstevel@tonic-gate stop(PR_FAULTED, FLTWATCH);
7117c478bd9Sstevel@tonic-gate if (lwp->lwp_curflt == 0) {
7127c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock);
7137c478bd9Sstevel@tonic-gate kmem_free(sqp, sizeof (sigqueue_t));
7147c478bd9Sstevel@tonic-gate return (1);
7157c478bd9Sstevel@tonic-gate }
7167c478bd9Sstevel@tonic-gate lwp->lwp_curflt = 0;
7177c478bd9Sstevel@tonic-gate }
7187c478bd9Sstevel@tonic-gate
7197c478bd9Sstevel@tonic-gate /*
7207c478bd9Sstevel@tonic-gate * post the SIGTRAP signal.
7217c478bd9Sstevel@tonic-gate * Block all other signals so we only stop showing SIGTRAP.
7227c478bd9Sstevel@tonic-gate */
7237c478bd9Sstevel@tonic-gate if (signal_is_blocked(curthread, SIGTRAP) ||
7247c478bd9Sstevel@tonic-gate sigismember(&p->p_ignore, SIGTRAP)) {
7257c478bd9Sstevel@tonic-gate /* SIGTRAP is blocked or ignored, forget the rest. */
7267c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock);
7277c478bd9Sstevel@tonic-gate kmem_free(sqp, sizeof (sigqueue_t));
7287c478bd9Sstevel@tonic-gate return (0);
7297c478bd9Sstevel@tonic-gate }
7307c478bd9Sstevel@tonic-gate sigdelq(p, curthread, SIGTRAP);
7317c478bd9Sstevel@tonic-gate sigaddqa(p, curthread, sqp);
7327c478bd9Sstevel@tonic-gate schedctl_finish_sigblock(curthread);
7337c478bd9Sstevel@tonic-gate smask = curthread->t_hold;
7347c478bd9Sstevel@tonic-gate sigfillset(&curthread->t_hold);
7357c478bd9Sstevel@tonic-gate sigdiffset(&curthread->t_hold, &cantmask);
7367c478bd9Sstevel@tonic-gate sigdelset(&curthread->t_hold, SIGTRAP);
7377c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock);
7387c478bd9Sstevel@tonic-gate
7397c478bd9Sstevel@tonic-gate rval = ((ISSIG_FAST(curthread, lwp, p, FORREAL))? 0 : 1);
7407c478bd9Sstevel@tonic-gate
7417c478bd9Sstevel@tonic-gate /* restore the original signal mask */
7427c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock);
7437c478bd9Sstevel@tonic-gate curthread->t_hold = smask;
7447c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock);
7457c478bd9Sstevel@tonic-gate
7467c478bd9Sstevel@tonic-gate return (rval);
7477c478bd9Sstevel@tonic-gate }
7487c478bd9Sstevel@tonic-gate
7497c478bd9Sstevel@tonic-gate /*
7507c478bd9Sstevel@tonic-gate * Wrappers for the copyin()/copyout() functions to deal
7517c478bd9Sstevel@tonic-gate * with watchpoints that fire while in system calls.
7527c478bd9Sstevel@tonic-gate */
7537c478bd9Sstevel@tonic-gate
7547c478bd9Sstevel@tonic-gate static int
watch_xcopyin(const void * uaddr,void * kaddr,size_t count)7557c478bd9Sstevel@tonic-gate watch_xcopyin(const void *uaddr, void *kaddr, size_t count)
7567c478bd9Sstevel@tonic-gate {
7577c478bd9Sstevel@tonic-gate klwp_t *lwp = ttolwp(curthread);
7587c478bd9Sstevel@tonic-gate caddr_t watch_uaddr = (caddr_t)uaddr;
7597c478bd9Sstevel@tonic-gate caddr_t watch_kaddr = (caddr_t)kaddr;
7607c478bd9Sstevel@tonic-gate int error = 0;
7617c478bd9Sstevel@tonic-gate label_t ljb;
7627c478bd9Sstevel@tonic-gate size_t part;
7637c478bd9Sstevel@tonic-gate int mapped;
7647c478bd9Sstevel@tonic-gate
7657c478bd9Sstevel@tonic-gate while (count && error == 0) {
7667c478bd9Sstevel@tonic-gate int watchcode;
7677c478bd9Sstevel@tonic-gate caddr_t vaddr;
7687c478bd9Sstevel@tonic-gate size_t len;
7697c478bd9Sstevel@tonic-gate int ta;
7707c478bd9Sstevel@tonic-gate
7717c478bd9Sstevel@tonic-gate if ((part = PAGESIZE -
7727c478bd9Sstevel@tonic-gate (((uintptr_t)uaddr) & PAGEOFFSET)) > count)
7737c478bd9Sstevel@tonic-gate part = count;
7747c478bd9Sstevel@tonic-gate
7757c478bd9Sstevel@tonic-gate if (!pr_is_watchpage(watch_uaddr, S_READ))
7767c478bd9Sstevel@tonic-gate watchcode = 0;
7777c478bd9Sstevel@tonic-gate else {
7787c478bd9Sstevel@tonic-gate vaddr = watch_uaddr;
7797c478bd9Sstevel@tonic-gate watchcode = pr_is_watchpoint(&vaddr, &ta,
7807c478bd9Sstevel@tonic-gate part, &len, S_READ);
7817c478bd9Sstevel@tonic-gate if (watchcode && ta == 0)
7827c478bd9Sstevel@tonic-gate part = vaddr - watch_uaddr;
7837c478bd9Sstevel@tonic-gate }
7847c478bd9Sstevel@tonic-gate
7857c478bd9Sstevel@tonic-gate /*
7867c478bd9Sstevel@tonic-gate * Copy the initial part, up to a watched address, if any.
7877c478bd9Sstevel@tonic-gate */
7887c478bd9Sstevel@tonic-gate if (part != 0) {
7897c478bd9Sstevel@tonic-gate mapped = pr_mappage(watch_uaddr, part, S_READ, 1);
7907c478bd9Sstevel@tonic-gate if (on_fault(&ljb))
7917c478bd9Sstevel@tonic-gate error = EFAULT;
7927c478bd9Sstevel@tonic-gate else
7937c478bd9Sstevel@tonic-gate copyin_noerr(watch_uaddr, watch_kaddr, part);
7947c478bd9Sstevel@tonic-gate no_fault();
7957c478bd9Sstevel@tonic-gate if (mapped)
7967c478bd9Sstevel@tonic-gate pr_unmappage(watch_uaddr, part, S_READ, 1);
7977c478bd9Sstevel@tonic-gate watch_uaddr += part;
7987c478bd9Sstevel@tonic-gate watch_kaddr += part;
7997c478bd9Sstevel@tonic-gate count -= part;
8007c478bd9Sstevel@tonic-gate }
8017c478bd9Sstevel@tonic-gate /*
8027c478bd9Sstevel@tonic-gate * If trapafter was specified, then copy through the
8037c478bd9Sstevel@tonic-gate * watched area before taking the watchpoint trap.
8047c478bd9Sstevel@tonic-gate */
8057c478bd9Sstevel@tonic-gate while (count && watchcode && ta && len > part && error == 0) {
8067c478bd9Sstevel@tonic-gate len -= part;
8077c478bd9Sstevel@tonic-gate if ((part = PAGESIZE) > count)
8087c478bd9Sstevel@tonic-gate part = count;
8097c478bd9Sstevel@tonic-gate if (part > len)
8107c478bd9Sstevel@tonic-gate part = len;
8117c478bd9Sstevel@tonic-gate mapped = pr_mappage(watch_uaddr, part, S_READ, 1);
8127c478bd9Sstevel@tonic-gate if (on_fault(&ljb))
8137c478bd9Sstevel@tonic-gate error = EFAULT;
8147c478bd9Sstevel@tonic-gate else
8157c478bd9Sstevel@tonic-gate copyin_noerr(watch_uaddr, watch_kaddr, part);
8167c478bd9Sstevel@tonic-gate no_fault();
8177c478bd9Sstevel@tonic-gate if (mapped)
8187c478bd9Sstevel@tonic-gate pr_unmappage(watch_uaddr, part, S_READ, 1);
8197c478bd9Sstevel@tonic-gate watch_uaddr += part;
8207c478bd9Sstevel@tonic-gate watch_kaddr += part;
8217c478bd9Sstevel@tonic-gate count -= part;
8227c478bd9Sstevel@tonic-gate }
8237c478bd9Sstevel@tonic-gate
8247c478bd9Sstevel@tonic-gate error:
8257c478bd9Sstevel@tonic-gate /* if we hit a watched address, do the watchpoint logic */
8267c478bd9Sstevel@tonic-gate if (watchcode &&
8277c478bd9Sstevel@tonic-gate (!sys_watchpoint(vaddr, watchcode, ta) ||
8287c478bd9Sstevel@tonic-gate lwp->lwp_sysabort)) {
8297c478bd9Sstevel@tonic-gate lwp->lwp_sysabort = 0;
8307c478bd9Sstevel@tonic-gate error = EFAULT;
8317c478bd9Sstevel@tonic-gate break;
8327c478bd9Sstevel@tonic-gate }
8337c478bd9Sstevel@tonic-gate }
8347c478bd9Sstevel@tonic-gate
8357c478bd9Sstevel@tonic-gate return (error);
8367c478bd9Sstevel@tonic-gate }
8377c478bd9Sstevel@tonic-gate
8387c478bd9Sstevel@tonic-gate static int
watch_copyin(const void * kaddr,void * uaddr,size_t count)8397c478bd9Sstevel@tonic-gate watch_copyin(const void *kaddr, void *uaddr, size_t count)
8407c478bd9Sstevel@tonic-gate {
8417c478bd9Sstevel@tonic-gate return (watch_xcopyin(kaddr, uaddr, count) ? -1 : 0);
8427c478bd9Sstevel@tonic-gate }
8437c478bd9Sstevel@tonic-gate
8447c478bd9Sstevel@tonic-gate
8457c478bd9Sstevel@tonic-gate static int
watch_xcopyout(const void * kaddr,void * uaddr,size_t count)8467c478bd9Sstevel@tonic-gate watch_xcopyout(const void *kaddr, void *uaddr, size_t count)
8477c478bd9Sstevel@tonic-gate {
8487c478bd9Sstevel@tonic-gate klwp_t *lwp = ttolwp(curthread);
8497c478bd9Sstevel@tonic-gate caddr_t watch_uaddr = (caddr_t)uaddr;
8507c478bd9Sstevel@tonic-gate caddr_t watch_kaddr = (caddr_t)kaddr;
8517c478bd9Sstevel@tonic-gate int error = 0;
8527c478bd9Sstevel@tonic-gate label_t ljb;
8537c478bd9Sstevel@tonic-gate
8547c478bd9Sstevel@tonic-gate while (count && error == 0) {
8557c478bd9Sstevel@tonic-gate int watchcode;
8567c478bd9Sstevel@tonic-gate caddr_t vaddr;
8577c478bd9Sstevel@tonic-gate size_t part;
8587c478bd9Sstevel@tonic-gate size_t len;
8597c478bd9Sstevel@tonic-gate int ta;
8607c478bd9Sstevel@tonic-gate int mapped;
8617c478bd9Sstevel@tonic-gate
8627c478bd9Sstevel@tonic-gate if ((part = PAGESIZE -
8637c478bd9Sstevel@tonic-gate (((uintptr_t)uaddr) & PAGEOFFSET)) > count)
8647c478bd9Sstevel@tonic-gate part = count;
8657c478bd9Sstevel@tonic-gate
8667c478bd9Sstevel@tonic-gate if (!pr_is_watchpage(watch_uaddr, S_WRITE))
8677c478bd9Sstevel@tonic-gate watchcode = 0;
8687c478bd9Sstevel@tonic-gate else {
8697c478bd9Sstevel@tonic-gate vaddr = watch_uaddr;
8707c478bd9Sstevel@tonic-gate watchcode = pr_is_watchpoint(&vaddr, &ta,
8717c478bd9Sstevel@tonic-gate part, &len, S_WRITE);
8727c478bd9Sstevel@tonic-gate if (watchcode) {
8737c478bd9Sstevel@tonic-gate if (ta == 0)
8747c478bd9Sstevel@tonic-gate part = vaddr - watch_uaddr;
8757c478bd9Sstevel@tonic-gate else {
8767c478bd9Sstevel@tonic-gate len += vaddr - watch_uaddr;
8777c478bd9Sstevel@tonic-gate if (part > len)
8787c478bd9Sstevel@tonic-gate part = len;
8797c478bd9Sstevel@tonic-gate }
8807c478bd9Sstevel@tonic-gate }
8817c478bd9Sstevel@tonic-gate }
8827c478bd9Sstevel@tonic-gate
8837c478bd9Sstevel@tonic-gate /*
8847c478bd9Sstevel@tonic-gate * Copy the initial part, up to a watched address, if any.
8857c478bd9Sstevel@tonic-gate */
8867c478bd9Sstevel@tonic-gate if (part != 0) {
8877c478bd9Sstevel@tonic-gate mapped = pr_mappage(watch_uaddr, part, S_WRITE, 1);
8887c478bd9Sstevel@tonic-gate if (on_fault(&ljb))
8897c478bd9Sstevel@tonic-gate error = EFAULT;
8907c478bd9Sstevel@tonic-gate else
8917c478bd9Sstevel@tonic-gate copyout_noerr(watch_kaddr, watch_uaddr, part);
8927c478bd9Sstevel@tonic-gate no_fault();
8937c478bd9Sstevel@tonic-gate if (mapped)
8947c478bd9Sstevel@tonic-gate pr_unmappage(watch_uaddr, part, S_WRITE, 1);
8957c478bd9Sstevel@tonic-gate watch_uaddr += part;
8967c478bd9Sstevel@tonic-gate watch_kaddr += part;
8977c478bd9Sstevel@tonic-gate count -= part;
8987c478bd9Sstevel@tonic-gate }
8997c478bd9Sstevel@tonic-gate
9007c478bd9Sstevel@tonic-gate /*
9017c478bd9Sstevel@tonic-gate * If trapafter was specified, then copy through the
9027c478bd9Sstevel@tonic-gate * watched area before taking the watchpoint trap.
9037c478bd9Sstevel@tonic-gate */
9047c478bd9Sstevel@tonic-gate while (count && watchcode && ta && len > part && error == 0) {
9057c478bd9Sstevel@tonic-gate len -= part;
9067c478bd9Sstevel@tonic-gate if ((part = PAGESIZE) > count)
9077c478bd9Sstevel@tonic-gate part = count;
9087c478bd9Sstevel@tonic-gate if (part > len)
9097c478bd9Sstevel@tonic-gate part = len;
9107c478bd9Sstevel@tonic-gate mapped = pr_mappage(watch_uaddr, part, S_WRITE, 1);
9117c478bd9Sstevel@tonic-gate if (on_fault(&ljb))
9127c478bd9Sstevel@tonic-gate error = EFAULT;
9137c478bd9Sstevel@tonic-gate else
9147c478bd9Sstevel@tonic-gate copyout_noerr(watch_kaddr, watch_uaddr, part);
9157c478bd9Sstevel@tonic-gate no_fault();
9167c478bd9Sstevel@tonic-gate if (mapped)
9177c478bd9Sstevel@tonic-gate pr_unmappage(watch_uaddr, part, S_WRITE, 1);
9187c478bd9Sstevel@tonic-gate watch_uaddr += part;
9197c478bd9Sstevel@tonic-gate watch_kaddr += part;
9207c478bd9Sstevel@tonic-gate count -= part;
9217c478bd9Sstevel@tonic-gate }
9227c478bd9Sstevel@tonic-gate
9237c478bd9Sstevel@tonic-gate /* if we hit a watched address, do the watchpoint logic */
9247c478bd9Sstevel@tonic-gate if (watchcode &&
9257c478bd9Sstevel@tonic-gate (!sys_watchpoint(vaddr, watchcode, ta) ||
9267c478bd9Sstevel@tonic-gate lwp->lwp_sysabort)) {
9277c478bd9Sstevel@tonic-gate lwp->lwp_sysabort = 0;
9287c478bd9Sstevel@tonic-gate error = EFAULT;
9297c478bd9Sstevel@tonic-gate break;
9307c478bd9Sstevel@tonic-gate }
9317c478bd9Sstevel@tonic-gate }
9327c478bd9Sstevel@tonic-gate
9337c478bd9Sstevel@tonic-gate return (error);
9347c478bd9Sstevel@tonic-gate }
9357c478bd9Sstevel@tonic-gate
9367c478bd9Sstevel@tonic-gate static int
watch_copyout(const void * kaddr,void * uaddr,size_t count)9377c478bd9Sstevel@tonic-gate watch_copyout(const void *kaddr, void *uaddr, size_t count)
9387c478bd9Sstevel@tonic-gate {
9397c478bd9Sstevel@tonic-gate return (watch_xcopyout(kaddr, uaddr, count) ? -1 : 0);
9407c478bd9Sstevel@tonic-gate }
9417c478bd9Sstevel@tonic-gate
9427c478bd9Sstevel@tonic-gate static int
watch_copyinstr(const char * uaddr,char * kaddr,size_t maxlength,size_t * lencopied)9437c478bd9Sstevel@tonic-gate watch_copyinstr(
9447c478bd9Sstevel@tonic-gate const char *uaddr,
9457c478bd9Sstevel@tonic-gate char *kaddr,
9467c478bd9Sstevel@tonic-gate size_t maxlength,
9477c478bd9Sstevel@tonic-gate size_t *lencopied)
9487c478bd9Sstevel@tonic-gate {
9497c478bd9Sstevel@tonic-gate klwp_t *lwp = ttolwp(curthread);
9507c478bd9Sstevel@tonic-gate size_t resid;
9517c478bd9Sstevel@tonic-gate int error = 0;
9527c478bd9Sstevel@tonic-gate label_t ljb;
9537c478bd9Sstevel@tonic-gate
9547c478bd9Sstevel@tonic-gate if ((resid = maxlength) == 0)
9557c478bd9Sstevel@tonic-gate return (ENAMETOOLONG);
9567c478bd9Sstevel@tonic-gate
9577c478bd9Sstevel@tonic-gate while (resid && error == 0) {
9587c478bd9Sstevel@tonic-gate int watchcode;
9597c478bd9Sstevel@tonic-gate caddr_t vaddr;
9607c478bd9Sstevel@tonic-gate size_t part;
9617c478bd9Sstevel@tonic-gate size_t len;
9627c478bd9Sstevel@tonic-gate size_t size;
9637c478bd9Sstevel@tonic-gate int ta;
9647c478bd9Sstevel@tonic-gate int mapped;
9657c478bd9Sstevel@tonic-gate
9667c478bd9Sstevel@tonic-gate if ((part = PAGESIZE -
9677c478bd9Sstevel@tonic-gate (((uintptr_t)uaddr) & PAGEOFFSET)) > resid)
9687c478bd9Sstevel@tonic-gate part = resid;
9697c478bd9Sstevel@tonic-gate
9707c478bd9Sstevel@tonic-gate if (!pr_is_watchpage((caddr_t)uaddr, S_READ))
9717c478bd9Sstevel@tonic-gate watchcode = 0;
9727c478bd9Sstevel@tonic-gate else {
9737c478bd9Sstevel@tonic-gate vaddr = (caddr_t)uaddr;
9747c478bd9Sstevel@tonic-gate watchcode = pr_is_watchpoint(&vaddr, &ta,
9757c478bd9Sstevel@tonic-gate part, &len, S_READ);
9767c478bd9Sstevel@tonic-gate if (watchcode) {
9777c478bd9Sstevel@tonic-gate if (ta == 0)
9787c478bd9Sstevel@tonic-gate part = vaddr - uaddr;
9797c478bd9Sstevel@tonic-gate else {
9807c478bd9Sstevel@tonic-gate len += vaddr - uaddr;
9817c478bd9Sstevel@tonic-gate if (part > len)
9827c478bd9Sstevel@tonic-gate part = len;
9837c478bd9Sstevel@tonic-gate }
9847c478bd9Sstevel@tonic-gate }
9857c478bd9Sstevel@tonic-gate }
9867c478bd9Sstevel@tonic-gate
9877c478bd9Sstevel@tonic-gate /*
9887c478bd9Sstevel@tonic-gate * Copy the initial part, up to a watched address, if any.
9897c478bd9Sstevel@tonic-gate */
9907c478bd9Sstevel@tonic-gate if (part != 0) {
9917c478bd9Sstevel@tonic-gate mapped = pr_mappage((caddr_t)uaddr, part, S_READ, 1);
9927c478bd9Sstevel@tonic-gate if (on_fault(&ljb))
9937c478bd9Sstevel@tonic-gate error = EFAULT;
9947c478bd9Sstevel@tonic-gate else
9957c478bd9Sstevel@tonic-gate error = copyinstr_noerr(uaddr, kaddr, part,
9967c478bd9Sstevel@tonic-gate &size);
9977c478bd9Sstevel@tonic-gate no_fault();
9987c478bd9Sstevel@tonic-gate if (mapped)
9997c478bd9Sstevel@tonic-gate pr_unmappage((caddr_t)uaddr, part, S_READ, 1);
10007c478bd9Sstevel@tonic-gate uaddr += size;
10017c478bd9Sstevel@tonic-gate kaddr += size;
10027c478bd9Sstevel@tonic-gate resid -= size;
10037c478bd9Sstevel@tonic-gate if (error == ENAMETOOLONG && resid > 0)
10047c478bd9Sstevel@tonic-gate error = 0;
10057c478bd9Sstevel@tonic-gate if (error != 0 || (watchcode &&
10067c478bd9Sstevel@tonic-gate (uaddr < vaddr || kaddr[-1] == '\0')))
10077c478bd9Sstevel@tonic-gate break; /* didn't reach the watched area */
10087c478bd9Sstevel@tonic-gate }
10097c478bd9Sstevel@tonic-gate
10107c478bd9Sstevel@tonic-gate /*
10117c478bd9Sstevel@tonic-gate * If trapafter was specified, then copy through the
10127c478bd9Sstevel@tonic-gate * watched area before taking the watchpoint trap.
10137c478bd9Sstevel@tonic-gate */
10147c478bd9Sstevel@tonic-gate while (resid && watchcode && ta && len > part && error == 0 &&
10157c478bd9Sstevel@tonic-gate size == part && kaddr[-1] != '\0') {
10167c478bd9Sstevel@tonic-gate len -= part;
10177c478bd9Sstevel@tonic-gate if ((part = PAGESIZE) > resid)
10187c478bd9Sstevel@tonic-gate part = resid;
10197c478bd9Sstevel@tonic-gate if (part > len)
10207c478bd9Sstevel@tonic-gate part = len;
10217c478bd9Sstevel@tonic-gate mapped = pr_mappage((caddr_t)uaddr, part, S_READ, 1);
10227c478bd9Sstevel@tonic-gate if (on_fault(&ljb))
10237c478bd9Sstevel@tonic-gate error = EFAULT;
10247c478bd9Sstevel@tonic-gate else
10257c478bd9Sstevel@tonic-gate error = copyinstr_noerr(uaddr, kaddr, part,
10267c478bd9Sstevel@tonic-gate &size);
10277c478bd9Sstevel@tonic-gate no_fault();
10287c478bd9Sstevel@tonic-gate if (mapped)
10297c478bd9Sstevel@tonic-gate pr_unmappage((caddr_t)uaddr, part, S_READ, 1);
10307c478bd9Sstevel@tonic-gate uaddr += size;
10317c478bd9Sstevel@tonic-gate kaddr += size;
10327c478bd9Sstevel@tonic-gate resid -= size;
10337c478bd9Sstevel@tonic-gate if (error == ENAMETOOLONG && resid > 0)
10347c478bd9Sstevel@tonic-gate error = 0;
10357c478bd9Sstevel@tonic-gate }
10367c478bd9Sstevel@tonic-gate
10377c478bd9Sstevel@tonic-gate /* if we hit a watched address, do the watchpoint logic */
10387c478bd9Sstevel@tonic-gate if (watchcode &&
10397c478bd9Sstevel@tonic-gate (!sys_watchpoint(vaddr, watchcode, ta) ||
10407c478bd9Sstevel@tonic-gate lwp->lwp_sysabort)) {
10417c478bd9Sstevel@tonic-gate lwp->lwp_sysabort = 0;
10427c478bd9Sstevel@tonic-gate error = EFAULT;
10437c478bd9Sstevel@tonic-gate break;
10447c478bd9Sstevel@tonic-gate }
10457c478bd9Sstevel@tonic-gate
10467c478bd9Sstevel@tonic-gate if (error == 0 && part != 0 &&
10477c478bd9Sstevel@tonic-gate (size < part || kaddr[-1] == '\0'))
10487c478bd9Sstevel@tonic-gate break;
10497c478bd9Sstevel@tonic-gate }
10507c478bd9Sstevel@tonic-gate
10517c478bd9Sstevel@tonic-gate if (error != EFAULT && lencopied)
10527c478bd9Sstevel@tonic-gate *lencopied = maxlength - resid;
10537c478bd9Sstevel@tonic-gate return (error);
10547c478bd9Sstevel@tonic-gate }
10557c478bd9Sstevel@tonic-gate
10567c478bd9Sstevel@tonic-gate static int
watch_copyoutstr(const char * kaddr,char * uaddr,size_t maxlength,size_t * lencopied)10577c478bd9Sstevel@tonic-gate watch_copyoutstr(
10587c478bd9Sstevel@tonic-gate const char *kaddr,
10597c478bd9Sstevel@tonic-gate char *uaddr,
10607c478bd9Sstevel@tonic-gate size_t maxlength,
10617c478bd9Sstevel@tonic-gate size_t *lencopied)
10627c478bd9Sstevel@tonic-gate {
10637c478bd9Sstevel@tonic-gate klwp_t *lwp = ttolwp(curthread);
10647c478bd9Sstevel@tonic-gate size_t resid;
10657c478bd9Sstevel@tonic-gate int error = 0;
10667c478bd9Sstevel@tonic-gate label_t ljb;
10677c478bd9Sstevel@tonic-gate
10687c478bd9Sstevel@tonic-gate if ((resid = maxlength) == 0)
10697c478bd9Sstevel@tonic-gate return (ENAMETOOLONG);
10707c478bd9Sstevel@tonic-gate
10717c478bd9Sstevel@tonic-gate while (resid && error == 0) {
10727c478bd9Sstevel@tonic-gate int watchcode;
10737c478bd9Sstevel@tonic-gate caddr_t vaddr;
10747c478bd9Sstevel@tonic-gate size_t part;
10757c478bd9Sstevel@tonic-gate size_t len;
10767c478bd9Sstevel@tonic-gate size_t size;
10777c478bd9Sstevel@tonic-gate int ta;
10787c478bd9Sstevel@tonic-gate int mapped;
10797c478bd9Sstevel@tonic-gate
10807c478bd9Sstevel@tonic-gate if ((part = PAGESIZE -
10817c478bd9Sstevel@tonic-gate (((uintptr_t)uaddr) & PAGEOFFSET)) > resid)
10827c478bd9Sstevel@tonic-gate part = resid;
10837c478bd9Sstevel@tonic-gate
10847c478bd9Sstevel@tonic-gate if (!pr_is_watchpage(uaddr, S_WRITE)) {
10857c478bd9Sstevel@tonic-gate watchcode = 0;
10867c478bd9Sstevel@tonic-gate } else {
10877c478bd9Sstevel@tonic-gate vaddr = uaddr;
10887c478bd9Sstevel@tonic-gate watchcode = pr_is_watchpoint(&vaddr, &ta,
10897c478bd9Sstevel@tonic-gate part, &len, S_WRITE);
10907c478bd9Sstevel@tonic-gate if (watchcode && ta == 0)
10917c478bd9Sstevel@tonic-gate part = vaddr - uaddr;
10927c478bd9Sstevel@tonic-gate }
10937c478bd9Sstevel@tonic-gate
10947c478bd9Sstevel@tonic-gate /*
10957c478bd9Sstevel@tonic-gate * Copy the initial part, up to a watched address, if any.
10967c478bd9Sstevel@tonic-gate */
10977c478bd9Sstevel@tonic-gate if (part != 0) {
10987c478bd9Sstevel@tonic-gate mapped = pr_mappage(uaddr, part, S_WRITE, 1);
10997c478bd9Sstevel@tonic-gate if (on_fault(&ljb))
11007c478bd9Sstevel@tonic-gate error = EFAULT;
11017c478bd9Sstevel@tonic-gate else
11027c478bd9Sstevel@tonic-gate error = copyoutstr_noerr(kaddr, uaddr, part,
11037c478bd9Sstevel@tonic-gate &size);
11047c478bd9Sstevel@tonic-gate no_fault();
11057c478bd9Sstevel@tonic-gate if (mapped)
11067c478bd9Sstevel@tonic-gate pr_unmappage(uaddr, part, S_WRITE, 1);
11077c478bd9Sstevel@tonic-gate uaddr += size;
11087c478bd9Sstevel@tonic-gate kaddr += size;
11097c478bd9Sstevel@tonic-gate resid -= size;
11107c478bd9Sstevel@tonic-gate if (error == ENAMETOOLONG && resid > 0)
11117c478bd9Sstevel@tonic-gate error = 0;
11127c478bd9Sstevel@tonic-gate if (error != 0 || (watchcode &&
11137c478bd9Sstevel@tonic-gate (uaddr < vaddr || kaddr[-1] == '\0')))
11147c478bd9Sstevel@tonic-gate break; /* didn't reach the watched area */
11157c478bd9Sstevel@tonic-gate }
11167c478bd9Sstevel@tonic-gate
11177c478bd9Sstevel@tonic-gate /*
11187c478bd9Sstevel@tonic-gate * If trapafter was specified, then copy through the
11197c478bd9Sstevel@tonic-gate * watched area before taking the watchpoint trap.
11207c478bd9Sstevel@tonic-gate */
11217c478bd9Sstevel@tonic-gate while (resid && watchcode && ta && len > part && error == 0 &&
11227c478bd9Sstevel@tonic-gate size == part && kaddr[-1] != '\0') {
11237c478bd9Sstevel@tonic-gate len -= part;
11247c478bd9Sstevel@tonic-gate if ((part = PAGESIZE) > resid)
11257c478bd9Sstevel@tonic-gate part = resid;
11267c478bd9Sstevel@tonic-gate if (part > len)
11277c478bd9Sstevel@tonic-gate part = len;
11287c478bd9Sstevel@tonic-gate mapped = pr_mappage(uaddr, part, S_WRITE, 1);
11297c478bd9Sstevel@tonic-gate if (on_fault(&ljb))
11307c478bd9Sstevel@tonic-gate error = EFAULT;
11317c478bd9Sstevel@tonic-gate else
11327c478bd9Sstevel@tonic-gate error = copyoutstr_noerr(kaddr, uaddr, part,
11337c478bd9Sstevel@tonic-gate &size);
11347c478bd9Sstevel@tonic-gate no_fault();
11357c478bd9Sstevel@tonic-gate if (mapped)
11367c478bd9Sstevel@tonic-gate pr_unmappage(uaddr, part, S_WRITE, 1);
11377c478bd9Sstevel@tonic-gate uaddr += size;
11387c478bd9Sstevel@tonic-gate kaddr += size;
11397c478bd9Sstevel@tonic-gate resid -= size;
11407c478bd9Sstevel@tonic-gate if (error == ENAMETOOLONG && resid > 0)
11417c478bd9Sstevel@tonic-gate error = 0;
11427c478bd9Sstevel@tonic-gate }
11437c478bd9Sstevel@tonic-gate
11447c478bd9Sstevel@tonic-gate /* if we hit a watched address, do the watchpoint logic */
11457c478bd9Sstevel@tonic-gate if (watchcode &&
11467c478bd9Sstevel@tonic-gate (!sys_watchpoint(vaddr, watchcode, ta) ||
11477c478bd9Sstevel@tonic-gate lwp->lwp_sysabort)) {
11487c478bd9Sstevel@tonic-gate lwp->lwp_sysabort = 0;
11497c478bd9Sstevel@tonic-gate error = EFAULT;
11507c478bd9Sstevel@tonic-gate break;
11517c478bd9Sstevel@tonic-gate }
11527c478bd9Sstevel@tonic-gate
11537c478bd9Sstevel@tonic-gate if (error == 0 && part != 0 &&
11547c478bd9Sstevel@tonic-gate (size < part || kaddr[-1] == '\0'))
11557c478bd9Sstevel@tonic-gate break;
11567c478bd9Sstevel@tonic-gate }
11577c478bd9Sstevel@tonic-gate
11587c478bd9Sstevel@tonic-gate if (error != EFAULT && lencopied)
11597c478bd9Sstevel@tonic-gate *lencopied = maxlength - resid;
11607c478bd9Sstevel@tonic-gate return (error);
11617c478bd9Sstevel@tonic-gate }
11627c478bd9Sstevel@tonic-gate
11637c478bd9Sstevel@tonic-gate typedef int (*fuword_func)(const void *, void *);
11647c478bd9Sstevel@tonic-gate
11657c478bd9Sstevel@tonic-gate /*
11667c478bd9Sstevel@tonic-gate * Generic form of watch_fuword8(), watch_fuword16(), etc.
11677c478bd9Sstevel@tonic-gate */
11687c478bd9Sstevel@tonic-gate static int
watch_fuword(const void * addr,void * dst,fuword_func func,size_t size)11697c478bd9Sstevel@tonic-gate watch_fuword(const void *addr, void *dst, fuword_func func, size_t size)
11707c478bd9Sstevel@tonic-gate {
11717c478bd9Sstevel@tonic-gate klwp_t *lwp = ttolwp(curthread);
11727c478bd9Sstevel@tonic-gate int watchcode;
11737c478bd9Sstevel@tonic-gate caddr_t vaddr;
11747c478bd9Sstevel@tonic-gate int mapped;
11757c478bd9Sstevel@tonic-gate int rv = 0;
11767c478bd9Sstevel@tonic-gate int ta;
11777c478bd9Sstevel@tonic-gate label_t ljb;
11787c478bd9Sstevel@tonic-gate
11797c478bd9Sstevel@tonic-gate for (;;) {
11807c478bd9Sstevel@tonic-gate
11817c478bd9Sstevel@tonic-gate vaddr = (caddr_t)addr;
11827c478bd9Sstevel@tonic-gate watchcode = pr_is_watchpoint(&vaddr, &ta, size, NULL, S_READ);
11837c478bd9Sstevel@tonic-gate if (watchcode == 0 || ta != 0) {
11847c478bd9Sstevel@tonic-gate mapped = pr_mappage((caddr_t)addr, size, S_READ, 1);
11857c478bd9Sstevel@tonic-gate if (on_fault(&ljb))
11867c478bd9Sstevel@tonic-gate rv = -1;
11877c478bd9Sstevel@tonic-gate else
11887c478bd9Sstevel@tonic-gate (*func)(addr, dst);
11897c478bd9Sstevel@tonic-gate no_fault();
11907c478bd9Sstevel@tonic-gate if (mapped)
11917c478bd9Sstevel@tonic-gate pr_unmappage((caddr_t)addr, size, S_READ, 1);
11927c478bd9Sstevel@tonic-gate }
11937c478bd9Sstevel@tonic-gate if (watchcode &&
11947c478bd9Sstevel@tonic-gate (!sys_watchpoint(vaddr, watchcode, ta) ||
11957c478bd9Sstevel@tonic-gate lwp->lwp_sysabort)) {
11967c478bd9Sstevel@tonic-gate lwp->lwp_sysabort = 0;
11977c478bd9Sstevel@tonic-gate rv = -1;
11987c478bd9Sstevel@tonic-gate break;
11997c478bd9Sstevel@tonic-gate }
12007c478bd9Sstevel@tonic-gate if (watchcode == 0 || ta != 0)
12017c478bd9Sstevel@tonic-gate break;
12027c478bd9Sstevel@tonic-gate }
12037c478bd9Sstevel@tonic-gate
12047c478bd9Sstevel@tonic-gate return (rv);
12057c478bd9Sstevel@tonic-gate }
12067c478bd9Sstevel@tonic-gate
12077c478bd9Sstevel@tonic-gate static int
watch_fuword8(const void * addr,uint8_t * dst)12087c478bd9Sstevel@tonic-gate watch_fuword8(const void *addr, uint8_t *dst)
12097c478bd9Sstevel@tonic-gate {
12107c478bd9Sstevel@tonic-gate return (watch_fuword(addr, dst, (fuword_func)fuword8_noerr,
12117c478bd9Sstevel@tonic-gate sizeof (*dst)));
12127c478bd9Sstevel@tonic-gate }
12137c478bd9Sstevel@tonic-gate
12147c478bd9Sstevel@tonic-gate static int
watch_fuword16(const void * addr,uint16_t * dst)12157c478bd9Sstevel@tonic-gate watch_fuword16(const void *addr, uint16_t *dst)
12167c478bd9Sstevel@tonic-gate {
12177c478bd9Sstevel@tonic-gate return (watch_fuword(addr, dst, (fuword_func)fuword16_noerr,
12187c478bd9Sstevel@tonic-gate sizeof (*dst)));
12197c478bd9Sstevel@tonic-gate }
12207c478bd9Sstevel@tonic-gate
12217c478bd9Sstevel@tonic-gate static int
watch_fuword32(const void * addr,uint32_t * dst)12227c478bd9Sstevel@tonic-gate watch_fuword32(const void *addr, uint32_t *dst)
12237c478bd9Sstevel@tonic-gate {
12247c478bd9Sstevel@tonic-gate return (watch_fuword(addr, dst, (fuword_func)fuword32_noerr,
12257c478bd9Sstevel@tonic-gate sizeof (*dst)));
12267c478bd9Sstevel@tonic-gate }
12277c478bd9Sstevel@tonic-gate
12287c478bd9Sstevel@tonic-gate #ifdef _LP64
12297c478bd9Sstevel@tonic-gate static int
watch_fuword64(const void * addr,uint64_t * dst)12307c478bd9Sstevel@tonic-gate watch_fuword64(const void *addr, uint64_t *dst)
12317c478bd9Sstevel@tonic-gate {
12327c478bd9Sstevel@tonic-gate return (watch_fuword(addr, dst, (fuword_func)fuword64_noerr,
12337c478bd9Sstevel@tonic-gate sizeof (*dst)));
12347c478bd9Sstevel@tonic-gate }
12357c478bd9Sstevel@tonic-gate #endif
12367c478bd9Sstevel@tonic-gate
12377c478bd9Sstevel@tonic-gate
12387c478bd9Sstevel@tonic-gate static int
watch_suword8(void * addr,uint8_t value)12397c478bd9Sstevel@tonic-gate watch_suword8(void *addr, uint8_t value)
12407c478bd9Sstevel@tonic-gate {
12417c478bd9Sstevel@tonic-gate klwp_t *lwp = ttolwp(curthread);
12427c478bd9Sstevel@tonic-gate int watchcode;
12437c478bd9Sstevel@tonic-gate caddr_t vaddr;
12447c478bd9Sstevel@tonic-gate int mapped;
12457c478bd9Sstevel@tonic-gate int rv = 0;
12467c478bd9Sstevel@tonic-gate int ta;
12477c478bd9Sstevel@tonic-gate label_t ljb;
12487c478bd9Sstevel@tonic-gate
12497c478bd9Sstevel@tonic-gate for (;;) {
12507c478bd9Sstevel@tonic-gate
12517c478bd9Sstevel@tonic-gate vaddr = (caddr_t)addr;
12527c478bd9Sstevel@tonic-gate watchcode = pr_is_watchpoint(&vaddr, &ta, sizeof (value), NULL,
12537c478bd9Sstevel@tonic-gate S_WRITE);
12547c478bd9Sstevel@tonic-gate if (watchcode == 0 || ta != 0) {
12557c478bd9Sstevel@tonic-gate mapped = pr_mappage((caddr_t)addr, sizeof (value),
12567c478bd9Sstevel@tonic-gate S_WRITE, 1);
12577c478bd9Sstevel@tonic-gate if (on_fault(&ljb))
12587c478bd9Sstevel@tonic-gate rv = -1;
12597c478bd9Sstevel@tonic-gate else
12607c478bd9Sstevel@tonic-gate suword8_noerr(addr, value);
12617c478bd9Sstevel@tonic-gate no_fault();
12627c478bd9Sstevel@tonic-gate if (mapped)
12637c478bd9Sstevel@tonic-gate pr_unmappage((caddr_t)addr, sizeof (value),
12647c478bd9Sstevel@tonic-gate S_WRITE, 1);
12657c478bd9Sstevel@tonic-gate }
12667c478bd9Sstevel@tonic-gate if (watchcode &&
12677c478bd9Sstevel@tonic-gate (!sys_watchpoint(vaddr, watchcode, ta) ||
12687c478bd9Sstevel@tonic-gate lwp->lwp_sysabort)) {
12697c478bd9Sstevel@tonic-gate lwp->lwp_sysabort = 0;
12707c478bd9Sstevel@tonic-gate rv = -1;
12717c478bd9Sstevel@tonic-gate break;
12727c478bd9Sstevel@tonic-gate }
12737c478bd9Sstevel@tonic-gate if (watchcode == 0 || ta != 0)
12747c478bd9Sstevel@tonic-gate break;
12757c478bd9Sstevel@tonic-gate }
12767c478bd9Sstevel@tonic-gate
12777c478bd9Sstevel@tonic-gate return (rv);
12787c478bd9Sstevel@tonic-gate }
12797c478bd9Sstevel@tonic-gate
12807c478bd9Sstevel@tonic-gate static int
watch_suword16(void * addr,uint16_t value)12817c478bd9Sstevel@tonic-gate watch_suword16(void *addr, uint16_t value)
12827c478bd9Sstevel@tonic-gate {
12837c478bd9Sstevel@tonic-gate klwp_t *lwp = ttolwp(curthread);
12847c478bd9Sstevel@tonic-gate int watchcode;
12857c478bd9Sstevel@tonic-gate caddr_t vaddr;
12867c478bd9Sstevel@tonic-gate int mapped;
12877c478bd9Sstevel@tonic-gate int rv = 0;
12887c478bd9Sstevel@tonic-gate int ta;
12897c478bd9Sstevel@tonic-gate label_t ljb;
12907c478bd9Sstevel@tonic-gate
12917c478bd9Sstevel@tonic-gate for (;;) {
12927c478bd9Sstevel@tonic-gate
12937c478bd9Sstevel@tonic-gate vaddr = (caddr_t)addr;
12947c478bd9Sstevel@tonic-gate watchcode = pr_is_watchpoint(&vaddr, &ta, sizeof (value), NULL,
12957c478bd9Sstevel@tonic-gate S_WRITE);
12967c478bd9Sstevel@tonic-gate if (watchcode == 0 || ta != 0) {
12977c478bd9Sstevel@tonic-gate mapped = pr_mappage((caddr_t)addr, sizeof (value),
12987c478bd9Sstevel@tonic-gate S_WRITE, 1);
12997c478bd9Sstevel@tonic-gate if (on_fault(&ljb))
13007c478bd9Sstevel@tonic-gate rv = -1;
13017c478bd9Sstevel@tonic-gate else
13027c478bd9Sstevel@tonic-gate suword16_noerr(addr, value);
13037c478bd9Sstevel@tonic-gate no_fault();
13047c478bd9Sstevel@tonic-gate if (mapped)
13057c478bd9Sstevel@tonic-gate pr_unmappage((caddr_t)addr, sizeof (value),
13067c478bd9Sstevel@tonic-gate S_WRITE, 1);
13077c478bd9Sstevel@tonic-gate }
13087c478bd9Sstevel@tonic-gate if (watchcode &&
13097c478bd9Sstevel@tonic-gate (!sys_watchpoint(vaddr, watchcode, ta) ||
13107c478bd9Sstevel@tonic-gate lwp->lwp_sysabort)) {
13117c478bd9Sstevel@tonic-gate lwp->lwp_sysabort = 0;
13127c478bd9Sstevel@tonic-gate rv = -1;
13137c478bd9Sstevel@tonic-gate break;
13147c478bd9Sstevel@tonic-gate }
13157c478bd9Sstevel@tonic-gate if (watchcode == 0 || ta != 0)
13167c478bd9Sstevel@tonic-gate break;
13177c478bd9Sstevel@tonic-gate }
13187c478bd9Sstevel@tonic-gate
13197c478bd9Sstevel@tonic-gate return (rv);
13207c478bd9Sstevel@tonic-gate }
13217c478bd9Sstevel@tonic-gate
13227c478bd9Sstevel@tonic-gate static int
watch_suword32(void * addr,uint32_t value)13237c478bd9Sstevel@tonic-gate watch_suword32(void *addr, uint32_t value)
13247c478bd9Sstevel@tonic-gate {
13257c478bd9Sstevel@tonic-gate klwp_t *lwp = ttolwp(curthread);
13267c478bd9Sstevel@tonic-gate int watchcode;
13277c478bd9Sstevel@tonic-gate caddr_t vaddr;
13287c478bd9Sstevel@tonic-gate int mapped;
13297c478bd9Sstevel@tonic-gate int rv = 0;
13307c478bd9Sstevel@tonic-gate int ta;
13317c478bd9Sstevel@tonic-gate label_t ljb;
13327c478bd9Sstevel@tonic-gate
13337c478bd9Sstevel@tonic-gate for (;;) {
13347c478bd9Sstevel@tonic-gate
13357c478bd9Sstevel@tonic-gate vaddr = (caddr_t)addr;
13367c478bd9Sstevel@tonic-gate watchcode = pr_is_watchpoint(&vaddr, &ta, sizeof (value), NULL,
13377c478bd9Sstevel@tonic-gate S_WRITE);
13387c478bd9Sstevel@tonic-gate if (watchcode == 0 || ta != 0) {
13397c478bd9Sstevel@tonic-gate mapped = pr_mappage((caddr_t)addr, sizeof (value),
13407c478bd9Sstevel@tonic-gate S_WRITE, 1);
13417c478bd9Sstevel@tonic-gate if (on_fault(&ljb))
13427c478bd9Sstevel@tonic-gate rv = -1;
13437c478bd9Sstevel@tonic-gate else
13447c478bd9Sstevel@tonic-gate suword32_noerr(addr, value);
13457c478bd9Sstevel@tonic-gate no_fault();
13467c478bd9Sstevel@tonic-gate if (mapped)
13477c478bd9Sstevel@tonic-gate pr_unmappage((caddr_t)addr, sizeof (value),
13487c478bd9Sstevel@tonic-gate S_WRITE, 1);
13497c478bd9Sstevel@tonic-gate }
13507c478bd9Sstevel@tonic-gate if (watchcode &&
13517c478bd9Sstevel@tonic-gate (!sys_watchpoint(vaddr, watchcode, ta) ||
13527c478bd9Sstevel@tonic-gate lwp->lwp_sysabort)) {
13537c478bd9Sstevel@tonic-gate lwp->lwp_sysabort = 0;
13547c478bd9Sstevel@tonic-gate rv = -1;
13557c478bd9Sstevel@tonic-gate break;
13567c478bd9Sstevel@tonic-gate }
13577c478bd9Sstevel@tonic-gate if (watchcode == 0 || ta != 0)
13587c478bd9Sstevel@tonic-gate break;
13597c478bd9Sstevel@tonic-gate }
13607c478bd9Sstevel@tonic-gate
13617c478bd9Sstevel@tonic-gate return (rv);
13627c478bd9Sstevel@tonic-gate }
13637c478bd9Sstevel@tonic-gate
13647c478bd9Sstevel@tonic-gate #ifdef _LP64
13657c478bd9Sstevel@tonic-gate static int
watch_suword64(void * addr,uint64_t value)13667c478bd9Sstevel@tonic-gate watch_suword64(void *addr, uint64_t value)
13677c478bd9Sstevel@tonic-gate {
13687c478bd9Sstevel@tonic-gate klwp_t *lwp = ttolwp(curthread);
13697c478bd9Sstevel@tonic-gate int watchcode;
13707c478bd9Sstevel@tonic-gate caddr_t vaddr;
13717c478bd9Sstevel@tonic-gate int mapped;
13727c478bd9Sstevel@tonic-gate int rv = 0;
13737c478bd9Sstevel@tonic-gate int ta;
13747c478bd9Sstevel@tonic-gate label_t ljb;
13757c478bd9Sstevel@tonic-gate
13767c478bd9Sstevel@tonic-gate for (;;) {
13777c478bd9Sstevel@tonic-gate
13787c478bd9Sstevel@tonic-gate vaddr = (caddr_t)addr;
13797c478bd9Sstevel@tonic-gate watchcode = pr_is_watchpoint(&vaddr, &ta, sizeof (value), NULL,
13807c478bd9Sstevel@tonic-gate S_WRITE);
13817c478bd9Sstevel@tonic-gate if (watchcode == 0 || ta != 0) {
13827c478bd9Sstevel@tonic-gate mapped = pr_mappage((caddr_t)addr, sizeof (value),
13837c478bd9Sstevel@tonic-gate S_WRITE, 1);
13847c478bd9Sstevel@tonic-gate if (on_fault(&ljb))
13857c478bd9Sstevel@tonic-gate rv = -1;
13867c478bd9Sstevel@tonic-gate else
13877c478bd9Sstevel@tonic-gate suword64_noerr(addr, value);
13887c478bd9Sstevel@tonic-gate no_fault();
13897c478bd9Sstevel@tonic-gate if (mapped)
13907c478bd9Sstevel@tonic-gate pr_unmappage((caddr_t)addr, sizeof (value),
13917c478bd9Sstevel@tonic-gate S_WRITE, 1);
13927c478bd9Sstevel@tonic-gate }
13937c478bd9Sstevel@tonic-gate if (watchcode &&
13947c478bd9Sstevel@tonic-gate (!sys_watchpoint(vaddr, watchcode, ta) ||
13957c478bd9Sstevel@tonic-gate lwp->lwp_sysabort)) {
13967c478bd9Sstevel@tonic-gate lwp->lwp_sysabort = 0;
13977c478bd9Sstevel@tonic-gate rv = -1;
13987c478bd9Sstevel@tonic-gate break;
13997c478bd9Sstevel@tonic-gate }
14007c478bd9Sstevel@tonic-gate if (watchcode == 0 || ta != 0)
14017c478bd9Sstevel@tonic-gate break;
14027c478bd9Sstevel@tonic-gate }
14037c478bd9Sstevel@tonic-gate
14047c478bd9Sstevel@tonic-gate return (rv);
14057c478bd9Sstevel@tonic-gate }
14067c478bd9Sstevel@tonic-gate #endif /* _LP64 */
14077c478bd9Sstevel@tonic-gate
14087c478bd9Sstevel@tonic-gate /*
14097c478bd9Sstevel@tonic-gate * Check for watched addresses in the given address space.
14107c478bd9Sstevel@tonic-gate * Return 1 if this is true, otherwise 0.
14117c478bd9Sstevel@tonic-gate */
14127c478bd9Sstevel@tonic-gate static int
pr_is_watched(caddr_t base,size_t len,int rw)14137c478bd9Sstevel@tonic-gate pr_is_watched(caddr_t base, size_t len, int rw)
14147c478bd9Sstevel@tonic-gate {
14157c478bd9Sstevel@tonic-gate caddr_t saddr = (caddr_t)((uintptr_t)base & (uintptr_t)PAGEMASK);
14167c478bd9Sstevel@tonic-gate caddr_t eaddr = base + len;
14177c478bd9Sstevel@tonic-gate caddr_t paddr;
14187c478bd9Sstevel@tonic-gate
14197c478bd9Sstevel@tonic-gate for (paddr = saddr; paddr < eaddr; paddr += PAGESIZE) {
14207c478bd9Sstevel@tonic-gate if (pr_is_watchpage(paddr, rw))
14217c478bd9Sstevel@tonic-gate return (1);
14227c478bd9Sstevel@tonic-gate }
14237c478bd9Sstevel@tonic-gate
14247c478bd9Sstevel@tonic-gate return (0);
14257c478bd9Sstevel@tonic-gate }
14267c478bd9Sstevel@tonic-gate
14277c478bd9Sstevel@tonic-gate /*
14287c478bd9Sstevel@tonic-gate * Wrapper for the physio() function.
14297c478bd9Sstevel@tonic-gate * Splits one uio operation with multiple iovecs into uio operations with
14307c478bd9Sstevel@tonic-gate * only one iovecs to do the watchpoint handling separately for each iovecs.
14317c478bd9Sstevel@tonic-gate */
14327c478bd9Sstevel@tonic-gate static int
watch_physio(int (* strat)(struct buf *),struct buf * bp,dev_t dev,int rw,void (* mincnt)(struct buf *),struct uio * uio)14337c478bd9Sstevel@tonic-gate watch_physio(int (*strat)(struct buf *), struct buf *bp, dev_t dev,
14347c478bd9Sstevel@tonic-gate int rw, void (*mincnt)(struct buf *), struct uio *uio)
14357c478bd9Sstevel@tonic-gate {
14367c478bd9Sstevel@tonic-gate struct uio auio;
14377c478bd9Sstevel@tonic-gate struct iovec *iov;
14387c478bd9Sstevel@tonic-gate caddr_t base;
14397c478bd9Sstevel@tonic-gate size_t len;
14407c478bd9Sstevel@tonic-gate int seg_rw;
14417c478bd9Sstevel@tonic-gate int error = 0;
14427c478bd9Sstevel@tonic-gate
14437c478bd9Sstevel@tonic-gate if (uio->uio_segflg == UIO_SYSSPACE)
14447c478bd9Sstevel@tonic-gate return (default_physio(strat, bp, dev, rw, mincnt, uio));
14457c478bd9Sstevel@tonic-gate
14467c478bd9Sstevel@tonic-gate seg_rw = (rw == B_READ) ? S_WRITE : S_READ;
14477c478bd9Sstevel@tonic-gate
14487c478bd9Sstevel@tonic-gate while (uio->uio_iovcnt > 0) {
14497c478bd9Sstevel@tonic-gate if (uio->uio_resid == 0) {
14507c478bd9Sstevel@tonic-gate /*
14517c478bd9Sstevel@tonic-gate * Make sure to return the uio structure with the
14527c478bd9Sstevel@tonic-gate * same values as default_physio() does.
14537c478bd9Sstevel@tonic-gate */
14547c478bd9Sstevel@tonic-gate uio->uio_iov++;
14557c478bd9Sstevel@tonic-gate uio->uio_iovcnt--;
14567c478bd9Sstevel@tonic-gate continue;
14577c478bd9Sstevel@tonic-gate }
14587c478bd9Sstevel@tonic-gate
14597c478bd9Sstevel@tonic-gate iov = uio->uio_iov;
14607c478bd9Sstevel@tonic-gate len = MIN(iov->iov_len, uio->uio_resid);
14617c478bd9Sstevel@tonic-gate
14627c478bd9Sstevel@tonic-gate auio.uio_iovcnt = 1;
14637c478bd9Sstevel@tonic-gate auio.uio_iov = iov;
14647c478bd9Sstevel@tonic-gate auio.uio_resid = len;
14657c478bd9Sstevel@tonic-gate auio.uio_loffset = uio->uio_loffset;
14667c478bd9Sstevel@tonic-gate auio.uio_llimit = uio->uio_llimit;
14677c478bd9Sstevel@tonic-gate auio.uio_fmode = uio->uio_fmode;
14687c478bd9Sstevel@tonic-gate auio.uio_extflg = uio->uio_extflg;
14697c478bd9Sstevel@tonic-gate auio.uio_segflg = uio->uio_segflg;
14707c478bd9Sstevel@tonic-gate
14717c478bd9Sstevel@tonic-gate base = iov->iov_base;
14727c478bd9Sstevel@tonic-gate
14737c478bd9Sstevel@tonic-gate if (!pr_is_watched(base, len, seg_rw)) {
14747c478bd9Sstevel@tonic-gate /*
14757c478bd9Sstevel@tonic-gate * The given memory references don't cover a
14767c478bd9Sstevel@tonic-gate * watched page.
14777c478bd9Sstevel@tonic-gate */
14787c478bd9Sstevel@tonic-gate error = default_physio(strat, bp, dev, rw, mincnt,
14797c478bd9Sstevel@tonic-gate &auio);
14807c478bd9Sstevel@tonic-gate
14817c478bd9Sstevel@tonic-gate /* Update uio with values from auio. */
14827c478bd9Sstevel@tonic-gate len -= auio.uio_resid;
14837c478bd9Sstevel@tonic-gate uio->uio_resid -= len;
14847c478bd9Sstevel@tonic-gate uio->uio_loffset += len;
14857c478bd9Sstevel@tonic-gate
14867c478bd9Sstevel@tonic-gate /*
14877c478bd9Sstevel@tonic-gate * Return if an error occurred or not all data
14887c478bd9Sstevel@tonic-gate * was copied.
14897c478bd9Sstevel@tonic-gate */
14907c478bd9Sstevel@tonic-gate if (auio.uio_resid || error)
14917c478bd9Sstevel@tonic-gate break;
14927c478bd9Sstevel@tonic-gate uio->uio_iov++;
14937c478bd9Sstevel@tonic-gate uio->uio_iovcnt--;
14947c478bd9Sstevel@tonic-gate } else {
14957c478bd9Sstevel@tonic-gate int mapped, watchcode, ta;
14967c478bd9Sstevel@tonic-gate caddr_t vaddr = base;
14977c478bd9Sstevel@tonic-gate klwp_t *lwp = ttolwp(curthread);
14987c478bd9Sstevel@tonic-gate
14997c478bd9Sstevel@tonic-gate watchcode = pr_is_watchpoint(&vaddr, &ta, len,
15007c478bd9Sstevel@tonic-gate NULL, seg_rw);
15017c478bd9Sstevel@tonic-gate
15027c478bd9Sstevel@tonic-gate if (watchcode == 0 || ta != 0) {
15037c478bd9Sstevel@tonic-gate /*
15047c478bd9Sstevel@tonic-gate * Do the io if the given memory references
15057c478bd9Sstevel@tonic-gate * don't cover a watched area (watchcode=0)
15067c478bd9Sstevel@tonic-gate * or if WA_TRAPAFTER was specified.
15077c478bd9Sstevel@tonic-gate */
15087c478bd9Sstevel@tonic-gate mapped = pr_mappage(base, len, seg_rw, 1);
15097c478bd9Sstevel@tonic-gate error = default_physio(strat, bp, dev, rw,
15107c478bd9Sstevel@tonic-gate mincnt, &auio);
15117c478bd9Sstevel@tonic-gate if (mapped)
15127c478bd9Sstevel@tonic-gate pr_unmappage(base, len, seg_rw, 1);
15137c478bd9Sstevel@tonic-gate
15147c478bd9Sstevel@tonic-gate len -= auio.uio_resid;
15157c478bd9Sstevel@tonic-gate uio->uio_resid -= len;
15167c478bd9Sstevel@tonic-gate uio->uio_loffset += len;
15177c478bd9Sstevel@tonic-gate }
15187c478bd9Sstevel@tonic-gate
15197c478bd9Sstevel@tonic-gate /*
15207c478bd9Sstevel@tonic-gate * If we hit a watched address, do the watchpoint logic.
15217c478bd9Sstevel@tonic-gate */
15227c478bd9Sstevel@tonic-gate if (watchcode &&
15237c478bd9Sstevel@tonic-gate (!sys_watchpoint(vaddr, watchcode, ta) ||
15247c478bd9Sstevel@tonic-gate lwp->lwp_sysabort)) {
15257c478bd9Sstevel@tonic-gate lwp->lwp_sysabort = 0;
15267c478bd9Sstevel@tonic-gate return (EFAULT);
15277c478bd9Sstevel@tonic-gate }
15287c478bd9Sstevel@tonic-gate
15297c478bd9Sstevel@tonic-gate /*
15307c478bd9Sstevel@tonic-gate * Check for errors from default_physio().
15317c478bd9Sstevel@tonic-gate */
15327c478bd9Sstevel@tonic-gate if (watchcode == 0 || ta != 0) {
15337c478bd9Sstevel@tonic-gate if (auio.uio_resid || error)
15347c478bd9Sstevel@tonic-gate break;
15357c478bd9Sstevel@tonic-gate uio->uio_iov++;
15367c478bd9Sstevel@tonic-gate uio->uio_iovcnt--;
15377c478bd9Sstevel@tonic-gate }
15387c478bd9Sstevel@tonic-gate }
15397c478bd9Sstevel@tonic-gate }
15407c478bd9Sstevel@tonic-gate
15417c478bd9Sstevel@tonic-gate return (error);
15427c478bd9Sstevel@tonic-gate }
15437c478bd9Sstevel@tonic-gate
15447c478bd9Sstevel@tonic-gate int
wa_compare(const void * a,const void * b)15457c478bd9Sstevel@tonic-gate wa_compare(const void *a, const void *b)
15467c478bd9Sstevel@tonic-gate {
15477c478bd9Sstevel@tonic-gate const watched_area_t *pa = a;
15487c478bd9Sstevel@tonic-gate const watched_area_t *pb = b;
15497c478bd9Sstevel@tonic-gate
15507c478bd9Sstevel@tonic-gate if (pa->wa_vaddr < pb->wa_vaddr)
15517c478bd9Sstevel@tonic-gate return (-1);
15527c478bd9Sstevel@tonic-gate else if (pa->wa_vaddr > pb->wa_vaddr)
15537c478bd9Sstevel@tonic-gate return (1);
15547c478bd9Sstevel@tonic-gate else
15557c478bd9Sstevel@tonic-gate return (0);
15567c478bd9Sstevel@tonic-gate }
15577c478bd9Sstevel@tonic-gate
15587c478bd9Sstevel@tonic-gate int
wp_compare(const void * a,const void * b)15597c478bd9Sstevel@tonic-gate wp_compare(const void *a, const void *b)
15607c478bd9Sstevel@tonic-gate {
15617c478bd9Sstevel@tonic-gate const watched_page_t *pa = a;
15627c478bd9Sstevel@tonic-gate const watched_page_t *pb = b;
15637c478bd9Sstevel@tonic-gate
15647c478bd9Sstevel@tonic-gate if (pa->wp_vaddr < pb->wp_vaddr)
15657c478bd9Sstevel@tonic-gate return (-1);
15667c478bd9Sstevel@tonic-gate else if (pa->wp_vaddr > pb->wp_vaddr)
15677c478bd9Sstevel@tonic-gate return (1);
15687c478bd9Sstevel@tonic-gate else
15697c478bd9Sstevel@tonic-gate return (0);
15707c478bd9Sstevel@tonic-gate }
15717c478bd9Sstevel@tonic-gate
15727c478bd9Sstevel@tonic-gate /*
15737c478bd9Sstevel@tonic-gate * Given an address range, finds the first watched area which overlaps some or
15747c478bd9Sstevel@tonic-gate * all of the range.
15757c478bd9Sstevel@tonic-gate */
15767c478bd9Sstevel@tonic-gate watched_area_t *
pr_find_watched_area(proc_t * p,watched_area_t * pwa,avl_index_t * where)15777c478bd9Sstevel@tonic-gate pr_find_watched_area(proc_t *p, watched_area_t *pwa, avl_index_t *where)
15787c478bd9Sstevel@tonic-gate {
15797c478bd9Sstevel@tonic-gate caddr_t vaddr = pwa->wa_vaddr;
15807c478bd9Sstevel@tonic-gate caddr_t eaddr = pwa->wa_eaddr;
15817c478bd9Sstevel@tonic-gate watched_area_t *wap;
15827c478bd9Sstevel@tonic-gate avl_index_t real_where;
15837c478bd9Sstevel@tonic-gate
15847c478bd9Sstevel@tonic-gate /* First, check if there is an exact match. */
15857c478bd9Sstevel@tonic-gate wap = avl_find(&p->p_warea, pwa, &real_where);
15867c478bd9Sstevel@tonic-gate
15877c478bd9Sstevel@tonic-gate
15887c478bd9Sstevel@tonic-gate /* Check to see if we overlap with the previous area. */
15897c478bd9Sstevel@tonic-gate if (wap == NULL) {
15907c478bd9Sstevel@tonic-gate wap = avl_nearest(&p->p_warea, real_where, AVL_BEFORE);
15917c478bd9Sstevel@tonic-gate if (wap != NULL &&
15927c478bd9Sstevel@tonic-gate (vaddr >= wap->wa_eaddr || eaddr <= wap->wa_vaddr))
15937c478bd9Sstevel@tonic-gate wap = NULL;
15947c478bd9Sstevel@tonic-gate }
15957c478bd9Sstevel@tonic-gate
15967c478bd9Sstevel@tonic-gate /* Try the next area. */
15977c478bd9Sstevel@tonic-gate if (wap == NULL) {
15987c478bd9Sstevel@tonic-gate wap = avl_nearest(&p->p_warea, real_where, AVL_AFTER);
15997c478bd9Sstevel@tonic-gate if (wap != NULL &&
16007c478bd9Sstevel@tonic-gate (vaddr >= wap->wa_eaddr || eaddr <= wap->wa_vaddr))
16017c478bd9Sstevel@tonic-gate wap = NULL;
16027c478bd9Sstevel@tonic-gate }
16037c478bd9Sstevel@tonic-gate
16047c478bd9Sstevel@tonic-gate if (where)
16057c478bd9Sstevel@tonic-gate *where = real_where;
16067c478bd9Sstevel@tonic-gate
16077c478bd9Sstevel@tonic-gate return (wap);
16087c478bd9Sstevel@tonic-gate }
16097c478bd9Sstevel@tonic-gate
16107c478bd9Sstevel@tonic-gate void
watch_enable(kthread_id_t t)16117c478bd9Sstevel@tonic-gate watch_enable(kthread_id_t t)
16127c478bd9Sstevel@tonic-gate {
16137c478bd9Sstevel@tonic-gate t->t_proc_flag |= TP_WATCHPT;
16147c478bd9Sstevel@tonic-gate install_copyops(t, &watch_copyops);
16157c478bd9Sstevel@tonic-gate }
16167c478bd9Sstevel@tonic-gate
16177c478bd9Sstevel@tonic-gate void
watch_disable(kthread_id_t t)16187c478bd9Sstevel@tonic-gate watch_disable(kthread_id_t t)
16197c478bd9Sstevel@tonic-gate {
16207c478bd9Sstevel@tonic-gate t->t_proc_flag &= ~TP_WATCHPT;
16217c478bd9Sstevel@tonic-gate remove_copyops(t);
16227c478bd9Sstevel@tonic-gate }
16237c478bd9Sstevel@tonic-gate
16247c478bd9Sstevel@tonic-gate int
copyin_nowatch(const void * uaddr,void * kaddr,size_t len)16257c478bd9Sstevel@tonic-gate copyin_nowatch(const void *uaddr, void *kaddr, size_t len)
16267c478bd9Sstevel@tonic-gate {
16277c478bd9Sstevel@tonic-gate int watched, ret;
16287c478bd9Sstevel@tonic-gate
16297c478bd9Sstevel@tonic-gate watched = watch_disable_addr(uaddr, len, S_READ);
16307c478bd9Sstevel@tonic-gate ret = copyin(uaddr, kaddr, len);
16317c478bd9Sstevel@tonic-gate if (watched)
16327c478bd9Sstevel@tonic-gate watch_enable_addr(uaddr, len, S_READ);
16337c478bd9Sstevel@tonic-gate
16347c478bd9Sstevel@tonic-gate return (ret);
16357c478bd9Sstevel@tonic-gate }
16367c478bd9Sstevel@tonic-gate
16377c478bd9Sstevel@tonic-gate int
copyout_nowatch(const void * kaddr,void * uaddr,size_t len)16387c478bd9Sstevel@tonic-gate copyout_nowatch(const void *kaddr, void *uaddr, size_t len)
16397c478bd9Sstevel@tonic-gate {
16407c478bd9Sstevel@tonic-gate int watched, ret;
16417c478bd9Sstevel@tonic-gate
16427c478bd9Sstevel@tonic-gate watched = watch_disable_addr(uaddr, len, S_WRITE);
16437c478bd9Sstevel@tonic-gate ret = copyout(kaddr, uaddr, len);
16447c478bd9Sstevel@tonic-gate if (watched)
16457c478bd9Sstevel@tonic-gate watch_enable_addr(uaddr, len, S_WRITE);
16467c478bd9Sstevel@tonic-gate
16477c478bd9Sstevel@tonic-gate return (ret);
16487c478bd9Sstevel@tonic-gate }
16497c478bd9Sstevel@tonic-gate
16507c478bd9Sstevel@tonic-gate #ifdef _LP64
16517c478bd9Sstevel@tonic-gate int
fuword64_nowatch(const void * addr,uint64_t * value)16527c478bd9Sstevel@tonic-gate fuword64_nowatch(const void *addr, uint64_t *value)
16537c478bd9Sstevel@tonic-gate {
16547c478bd9Sstevel@tonic-gate int watched, ret;
16557c478bd9Sstevel@tonic-gate
16567c478bd9Sstevel@tonic-gate watched = watch_disable_addr(addr, sizeof (*value), S_READ);
16577c478bd9Sstevel@tonic-gate ret = fuword64(addr, value);
16587c478bd9Sstevel@tonic-gate if (watched)
16597c478bd9Sstevel@tonic-gate watch_enable_addr(addr, sizeof (*value), S_READ);
16607c478bd9Sstevel@tonic-gate
16617c478bd9Sstevel@tonic-gate return (ret);
16627c478bd9Sstevel@tonic-gate }
16637c478bd9Sstevel@tonic-gate #endif
16647c478bd9Sstevel@tonic-gate
16657c478bd9Sstevel@tonic-gate int
fuword32_nowatch(const void * addr,uint32_t * value)16667c478bd9Sstevel@tonic-gate fuword32_nowatch(const void *addr, uint32_t *value)
16677c478bd9Sstevel@tonic-gate {
16687c478bd9Sstevel@tonic-gate int watched, ret;
16697c478bd9Sstevel@tonic-gate
16707c478bd9Sstevel@tonic-gate watched = watch_disable_addr(addr, sizeof (*value), S_READ);
16717c478bd9Sstevel@tonic-gate ret = fuword32(addr, value);
16727c478bd9Sstevel@tonic-gate if (watched)
16737c478bd9Sstevel@tonic-gate watch_enable_addr(addr, sizeof (*value), S_READ);
16747c478bd9Sstevel@tonic-gate
16757c478bd9Sstevel@tonic-gate return (ret);
16767c478bd9Sstevel@tonic-gate }
16777c478bd9Sstevel@tonic-gate
16787c478bd9Sstevel@tonic-gate #ifdef _LP64
16797c478bd9Sstevel@tonic-gate int
suword64_nowatch(void * addr,uint64_t value)16807c478bd9Sstevel@tonic-gate suword64_nowatch(void *addr, uint64_t value)
16817c478bd9Sstevel@tonic-gate {
16827c478bd9Sstevel@tonic-gate int watched, ret;
16837c478bd9Sstevel@tonic-gate
16847c478bd9Sstevel@tonic-gate watched = watch_disable_addr(addr, sizeof (value), S_WRITE);
16857c478bd9Sstevel@tonic-gate ret = suword64(addr, value);
16867c478bd9Sstevel@tonic-gate if (watched)
16877c478bd9Sstevel@tonic-gate watch_enable_addr(addr, sizeof (value), S_WRITE);
16887c478bd9Sstevel@tonic-gate
16897c478bd9Sstevel@tonic-gate return (ret);
16907c478bd9Sstevel@tonic-gate }
16917c478bd9Sstevel@tonic-gate #endif
16927c478bd9Sstevel@tonic-gate
16937c478bd9Sstevel@tonic-gate int
suword32_nowatch(void * addr,uint32_t value)16947c478bd9Sstevel@tonic-gate suword32_nowatch(void *addr, uint32_t value)
16957c478bd9Sstevel@tonic-gate {
16967c478bd9Sstevel@tonic-gate int watched, ret;
16977c478bd9Sstevel@tonic-gate
16987c478bd9Sstevel@tonic-gate watched = watch_disable_addr(addr, sizeof (value), S_WRITE);
16997c478bd9Sstevel@tonic-gate ret = suword32(addr, value);
17007c478bd9Sstevel@tonic-gate if (watched)
17017c478bd9Sstevel@tonic-gate watch_enable_addr(addr, sizeof (value), S_WRITE);
17027c478bd9Sstevel@tonic-gate
17037c478bd9Sstevel@tonic-gate return (ret);
17047c478bd9Sstevel@tonic-gate }
17057c478bd9Sstevel@tonic-gate
17067c478bd9Sstevel@tonic-gate int
watch_disable_addr(const void * addr,size_t len,enum seg_rw rw)17077c478bd9Sstevel@tonic-gate watch_disable_addr(const void *addr, size_t len, enum seg_rw rw)
17087c478bd9Sstevel@tonic-gate {
17097c478bd9Sstevel@tonic-gate if (pr_watch_active(curproc))
17107c478bd9Sstevel@tonic-gate return (pr_mappage((caddr_t)addr, len, rw, 1));
17117c478bd9Sstevel@tonic-gate return (0);
17127c478bd9Sstevel@tonic-gate }
17137c478bd9Sstevel@tonic-gate
17147c478bd9Sstevel@tonic-gate void
watch_enable_addr(const void * addr,size_t len,enum seg_rw rw)17157c478bd9Sstevel@tonic-gate watch_enable_addr(const void *addr, size_t len, enum seg_rw rw)
17167c478bd9Sstevel@tonic-gate {
17177c478bd9Sstevel@tonic-gate if (pr_watch_active(curproc))
17187c478bd9Sstevel@tonic-gate pr_unmappage((caddr_t)addr, len, rw, 1);
17197c478bd9Sstevel@tonic-gate }
1720