1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 30*7c478bd9Sstevel@tonic-gate #include <sys/t_lock.h> 31*7c478bd9Sstevel@tonic-gate #include <sys/param.h> 32*7c478bd9Sstevel@tonic-gate #include <sys/cred.h> 33*7c478bd9Sstevel@tonic-gate #include <sys/debug.h> 34*7c478bd9Sstevel@tonic-gate #include <sys/inline.h> 35*7c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 36*7c478bd9Sstevel@tonic-gate #include <sys/proc.h> 37*7c478bd9Sstevel@tonic-gate #include <sys/regset.h> 38*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 39*7c478bd9Sstevel@tonic-gate #include <sys/systm.h> 40*7c478bd9Sstevel@tonic-gate #include <sys/prsystm.h> 41*7c478bd9Sstevel@tonic-gate #include <sys/buf.h> 42*7c478bd9Sstevel@tonic-gate #include <sys/signal.h> 43*7c478bd9Sstevel@tonic-gate #include <sys/user.h> 44*7c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h> 45*7c478bd9Sstevel@tonic-gate 46*7c478bd9Sstevel@tonic-gate #include <sys/fault.h> 47*7c478bd9Sstevel@tonic-gate #include <sys/syscall.h> 48*7c478bd9Sstevel@tonic-gate #include <sys/procfs.h> 49*7c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 50*7c478bd9Sstevel@tonic-gate #include <sys/stack.h> 51*7c478bd9Sstevel@tonic-gate #include <sys/watchpoint.h> 52*7c478bd9Sstevel@tonic-gate #include <sys/copyops.h> 53*7c478bd9Sstevel@tonic-gate #include <sys/schedctl.h> 54*7c478bd9Sstevel@tonic-gate 55*7c478bd9Sstevel@tonic-gate #include <sys/mman.h> 56*7c478bd9Sstevel@tonic-gate #include <vm/as.h> 57*7c478bd9Sstevel@tonic-gate #include <vm/seg.h> 58*7c478bd9Sstevel@tonic-gate 59*7c478bd9Sstevel@tonic-gate /* 60*7c478bd9Sstevel@tonic-gate * Copy ops vector for watchpoints. 61*7c478bd9Sstevel@tonic-gate */ 62*7c478bd9Sstevel@tonic-gate static int watch_copyin(const void *, void *, size_t); 63*7c478bd9Sstevel@tonic-gate static int watch_xcopyin(const void *, void *, size_t); 64*7c478bd9Sstevel@tonic-gate static int watch_copyout(const void *, void *, size_t); 65*7c478bd9Sstevel@tonic-gate static int watch_xcopyout(const void *, void *, size_t); 66*7c478bd9Sstevel@tonic-gate static int watch_copyinstr(const char *, char *, size_t, size_t *); 67*7c478bd9Sstevel@tonic-gate static int watch_copyoutstr(const char *, char *, size_t, size_t *); 68*7c478bd9Sstevel@tonic-gate static int watch_fuword8(const void *, uint8_t *); 69*7c478bd9Sstevel@tonic-gate static int watch_fuword16(const void *, uint16_t *); 70*7c478bd9Sstevel@tonic-gate static int watch_fuword32(const void *, uint32_t *); 71*7c478bd9Sstevel@tonic-gate static int watch_suword8(void *, uint8_t); 72*7c478bd9Sstevel@tonic-gate static int watch_suword16(void *, uint16_t); 73*7c478bd9Sstevel@tonic-gate static int watch_suword32(void *, uint32_t); 74*7c478bd9Sstevel@tonic-gate static int watch_physio(int (*)(struct buf *), struct buf *, 75*7c478bd9Sstevel@tonic-gate dev_t, int, void (*)(struct buf *), struct uio *); 76*7c478bd9Sstevel@tonic-gate #ifdef _LP64 77*7c478bd9Sstevel@tonic-gate static int watch_fuword64(const void *, uint64_t *); 78*7c478bd9Sstevel@tonic-gate static int watch_suword64(void *, uint64_t); 79*7c478bd9Sstevel@tonic-gate #endif 80*7c478bd9Sstevel@tonic-gate 81*7c478bd9Sstevel@tonic-gate struct copyops watch_copyops = { 82*7c478bd9Sstevel@tonic-gate watch_copyin, 83*7c478bd9Sstevel@tonic-gate watch_xcopyin, 84*7c478bd9Sstevel@tonic-gate watch_copyout, 85*7c478bd9Sstevel@tonic-gate watch_xcopyout, 86*7c478bd9Sstevel@tonic-gate watch_copyinstr, 87*7c478bd9Sstevel@tonic-gate watch_copyoutstr, 88*7c478bd9Sstevel@tonic-gate watch_fuword8, 89*7c478bd9Sstevel@tonic-gate watch_fuword16, 90*7c478bd9Sstevel@tonic-gate watch_fuword32, 91*7c478bd9Sstevel@tonic-gate #ifdef _LP64 92*7c478bd9Sstevel@tonic-gate watch_fuword64, 93*7c478bd9Sstevel@tonic-gate #else 94*7c478bd9Sstevel@tonic-gate NULL, 95*7c478bd9Sstevel@tonic-gate #endif 96*7c478bd9Sstevel@tonic-gate watch_suword8, 97*7c478bd9Sstevel@tonic-gate watch_suword16, 98*7c478bd9Sstevel@tonic-gate watch_suword32, 99*7c478bd9Sstevel@tonic-gate #ifdef _LP64 100*7c478bd9Sstevel@tonic-gate watch_suword64, 101*7c478bd9Sstevel@tonic-gate #else 102*7c478bd9Sstevel@tonic-gate NULL, 103*7c478bd9Sstevel@tonic-gate #endif 104*7c478bd9Sstevel@tonic-gate watch_physio 105*7c478bd9Sstevel@tonic-gate }; 106*7c478bd9Sstevel@tonic-gate 107*7c478bd9Sstevel@tonic-gate /* 108*7c478bd9Sstevel@tonic-gate * Map the 'rw' argument to a protection flag. 109*7c478bd9Sstevel@tonic-gate */ 110*7c478bd9Sstevel@tonic-gate static int 111*7c478bd9Sstevel@tonic-gate rw_to_prot(enum seg_rw rw) 112*7c478bd9Sstevel@tonic-gate { 113*7c478bd9Sstevel@tonic-gate switch (rw) { 114*7c478bd9Sstevel@tonic-gate case S_EXEC: 115*7c478bd9Sstevel@tonic-gate return (PROT_EXEC); 116*7c478bd9Sstevel@tonic-gate case S_READ: 117*7c478bd9Sstevel@tonic-gate return (PROT_READ); 118*7c478bd9Sstevel@tonic-gate case S_WRITE: 119*7c478bd9Sstevel@tonic-gate return (PROT_WRITE); 120*7c478bd9Sstevel@tonic-gate default: 121*7c478bd9Sstevel@tonic-gate return (PROT_NONE); /* can't happen */ 122*7c478bd9Sstevel@tonic-gate } 123*7c478bd9Sstevel@tonic-gate } 124*7c478bd9Sstevel@tonic-gate 125*7c478bd9Sstevel@tonic-gate /* 126*7c478bd9Sstevel@tonic-gate * Map the 'rw' argument to an index into an array of exec/write/read things. 127*7c478bd9Sstevel@tonic-gate * The index follows the precedence order: exec .. write .. read 128*7c478bd9Sstevel@tonic-gate */ 129*7c478bd9Sstevel@tonic-gate static int 130*7c478bd9Sstevel@tonic-gate rw_to_index(enum seg_rw rw) 131*7c478bd9Sstevel@tonic-gate { 132*7c478bd9Sstevel@tonic-gate switch (rw) { 133*7c478bd9Sstevel@tonic-gate default: /* default case "can't happen" */ 134*7c478bd9Sstevel@tonic-gate case S_EXEC: 135*7c478bd9Sstevel@tonic-gate return (0); 136*7c478bd9Sstevel@tonic-gate case S_WRITE: 137*7c478bd9Sstevel@tonic-gate return (1); 138*7c478bd9Sstevel@tonic-gate case S_READ: 139*7c478bd9Sstevel@tonic-gate return (2); 140*7c478bd9Sstevel@tonic-gate } 141*7c478bd9Sstevel@tonic-gate } 142*7c478bd9Sstevel@tonic-gate 143*7c478bd9Sstevel@tonic-gate /* 144*7c478bd9Sstevel@tonic-gate * Map an index back to a seg_rw. 145*7c478bd9Sstevel@tonic-gate */ 146*7c478bd9Sstevel@tonic-gate static enum seg_rw S_rw[4] = { 147*7c478bd9Sstevel@tonic-gate S_EXEC, 148*7c478bd9Sstevel@tonic-gate S_WRITE, 149*7c478bd9Sstevel@tonic-gate S_READ, 150*7c478bd9Sstevel@tonic-gate S_READ, 151*7c478bd9Sstevel@tonic-gate }; 152*7c478bd9Sstevel@tonic-gate 153*7c478bd9Sstevel@tonic-gate #define X 0 154*7c478bd9Sstevel@tonic-gate #define W 1 155*7c478bd9Sstevel@tonic-gate #define R 2 156*7c478bd9Sstevel@tonic-gate #define sum(a) (a[X] + a[W] + a[R]) 157*7c478bd9Sstevel@tonic-gate 158*7c478bd9Sstevel@tonic-gate /* 159*7c478bd9Sstevel@tonic-gate * Common code for pr_mappage() and pr_unmappage(). 160*7c478bd9Sstevel@tonic-gate */ 161*7c478bd9Sstevel@tonic-gate static int 162*7c478bd9Sstevel@tonic-gate pr_do_mappage(caddr_t addr, size_t size, int mapin, enum seg_rw rw, int kernel) 163*7c478bd9Sstevel@tonic-gate { 164*7c478bd9Sstevel@tonic-gate proc_t *p = curproc; 165*7c478bd9Sstevel@tonic-gate struct as *as = p->p_as; 166*7c478bd9Sstevel@tonic-gate char *eaddr = addr + size; 167*7c478bd9Sstevel@tonic-gate int prot_rw = rw_to_prot(rw); 168*7c478bd9Sstevel@tonic-gate int xrw = rw_to_index(rw); 169*7c478bd9Sstevel@tonic-gate int rv = 0; 170*7c478bd9Sstevel@tonic-gate struct watched_page *pwp; 171*7c478bd9Sstevel@tonic-gate struct watched_page tpw; 172*7c478bd9Sstevel@tonic-gate avl_index_t where; 173*7c478bd9Sstevel@tonic-gate uint_t prot; 174*7c478bd9Sstevel@tonic-gate 175*7c478bd9Sstevel@tonic-gate ASSERT(as != &kas); 176*7c478bd9Sstevel@tonic-gate 177*7c478bd9Sstevel@tonic-gate startover: 178*7c478bd9Sstevel@tonic-gate ASSERT(rv == 0); 179*7c478bd9Sstevel@tonic-gate if (avl_numnodes(&as->a_wpage) == 0) 180*7c478bd9Sstevel@tonic-gate return (0); 181*7c478bd9Sstevel@tonic-gate 182*7c478bd9Sstevel@tonic-gate /* 183*7c478bd9Sstevel@tonic-gate * as->a_wpage can only be changed while the process is totally stopped. 184*7c478bd9Sstevel@tonic-gate * Don't grab p_lock here. Holding p_lock while grabbing the address 185*7c478bd9Sstevel@tonic-gate * space lock leads to deadlocks with the clock thread. Note that if an 186*7c478bd9Sstevel@tonic-gate * as_fault() is servicing a fault to a watched page on behalf of an 187*7c478bd9Sstevel@tonic-gate * XHAT provider, watchpoint will be temporarily cleared (and wp_prot 188*7c478bd9Sstevel@tonic-gate * will be set to wp_oprot). Since this is done while holding as writer 189*7c478bd9Sstevel@tonic-gate * lock, we need to grab as lock (reader lock is good enough). 190*7c478bd9Sstevel@tonic-gate * 191*7c478bd9Sstevel@tonic-gate * p_maplock prevents simultaneous execution of this function. Under 192*7c478bd9Sstevel@tonic-gate * normal circumstances, holdwatch() will stop all other threads, so the 193*7c478bd9Sstevel@tonic-gate * lock isn't really needed. But there may be multiple threads within 194*7c478bd9Sstevel@tonic-gate * stop() when SWATCHOK is set, so we need to handle multiple threads 195*7c478bd9Sstevel@tonic-gate * at once. See holdwatch() for the details of this dance. 196*7c478bd9Sstevel@tonic-gate */ 197*7c478bd9Sstevel@tonic-gate 198*7c478bd9Sstevel@tonic-gate mutex_enter(&p->p_maplock); 199*7c478bd9Sstevel@tonic-gate AS_LOCK_ENTER(as, &as->a_lock, RW_READER); 200*7c478bd9Sstevel@tonic-gate 201*7c478bd9Sstevel@tonic-gate tpw.wp_vaddr = (caddr_t)((uintptr_t)addr & (uintptr_t)PAGEMASK); 202*7c478bd9Sstevel@tonic-gate if ((pwp = avl_find(&as->a_wpage, &tpw, &where)) == NULL) 203*7c478bd9Sstevel@tonic-gate pwp = avl_nearest(&as->a_wpage, where, AVL_AFTER); 204*7c478bd9Sstevel@tonic-gate 205*7c478bd9Sstevel@tonic-gate for (; pwp != NULL && pwp->wp_vaddr < eaddr; 206*7c478bd9Sstevel@tonic-gate pwp = AVL_NEXT(&as->a_wpage, pwp)) { 207*7c478bd9Sstevel@tonic-gate 208*7c478bd9Sstevel@tonic-gate /* 209*7c478bd9Sstevel@tonic-gate * If the requested protection has not been 210*7c478bd9Sstevel@tonic-gate * removed, we need not remap this page. 211*7c478bd9Sstevel@tonic-gate */ 212*7c478bd9Sstevel@tonic-gate prot = pwp->wp_prot; 213*7c478bd9Sstevel@tonic-gate if (kernel || (prot & PROT_USER)) 214*7c478bd9Sstevel@tonic-gate if (prot & prot_rw) 215*7c478bd9Sstevel@tonic-gate continue; 216*7c478bd9Sstevel@tonic-gate /* 217*7c478bd9Sstevel@tonic-gate * If the requested access does not exist in the page's 218*7c478bd9Sstevel@tonic-gate * original protections, we need not remap this page. 219*7c478bd9Sstevel@tonic-gate * If the page does not exist yet, we can't test it. 220*7c478bd9Sstevel@tonic-gate */ 221*7c478bd9Sstevel@tonic-gate if ((prot = pwp->wp_oprot) != 0) { 222*7c478bd9Sstevel@tonic-gate if (!(kernel || (prot & PROT_USER))) 223*7c478bd9Sstevel@tonic-gate continue; 224*7c478bd9Sstevel@tonic-gate if (!(prot & prot_rw)) 225*7c478bd9Sstevel@tonic-gate continue; 226*7c478bd9Sstevel@tonic-gate } 227*7c478bd9Sstevel@tonic-gate 228*7c478bd9Sstevel@tonic-gate if (mapin) { 229*7c478bd9Sstevel@tonic-gate /* 230*7c478bd9Sstevel@tonic-gate * Before mapping the page in, ensure that 231*7c478bd9Sstevel@tonic-gate * all other lwps are held in the kernel. 232*7c478bd9Sstevel@tonic-gate */ 233*7c478bd9Sstevel@tonic-gate if (p->p_mapcnt == 0) { 234*7c478bd9Sstevel@tonic-gate /* 235*7c478bd9Sstevel@tonic-gate * Release as lock while in holdwatch() 236*7c478bd9Sstevel@tonic-gate * in case other threads need to grab it. 237*7c478bd9Sstevel@tonic-gate */ 238*7c478bd9Sstevel@tonic-gate AS_LOCK_EXIT(as, &as->a_lock); 239*7c478bd9Sstevel@tonic-gate mutex_exit(&p->p_maplock); 240*7c478bd9Sstevel@tonic-gate if (holdwatch() != 0) { 241*7c478bd9Sstevel@tonic-gate /* 242*7c478bd9Sstevel@tonic-gate * We stopped in holdwatch(). 243*7c478bd9Sstevel@tonic-gate * Start all over again because the 244*7c478bd9Sstevel@tonic-gate * watched page list may have changed. 245*7c478bd9Sstevel@tonic-gate */ 246*7c478bd9Sstevel@tonic-gate goto startover; 247*7c478bd9Sstevel@tonic-gate } 248*7c478bd9Sstevel@tonic-gate mutex_enter(&p->p_maplock); 249*7c478bd9Sstevel@tonic-gate AS_LOCK_ENTER(as, &as->a_lock, RW_READER); 250*7c478bd9Sstevel@tonic-gate } 251*7c478bd9Sstevel@tonic-gate p->p_mapcnt++; 252*7c478bd9Sstevel@tonic-gate } 253*7c478bd9Sstevel@tonic-gate 254*7c478bd9Sstevel@tonic-gate addr = pwp->wp_vaddr; 255*7c478bd9Sstevel@tonic-gate rv++; 256*7c478bd9Sstevel@tonic-gate 257*7c478bd9Sstevel@tonic-gate prot = pwp->wp_prot; 258*7c478bd9Sstevel@tonic-gate if (mapin) { 259*7c478bd9Sstevel@tonic-gate if (kernel) 260*7c478bd9Sstevel@tonic-gate pwp->wp_kmap[xrw]++; 261*7c478bd9Sstevel@tonic-gate else 262*7c478bd9Sstevel@tonic-gate pwp->wp_umap[xrw]++; 263*7c478bd9Sstevel@tonic-gate pwp->wp_flags |= WP_NOWATCH; 264*7c478bd9Sstevel@tonic-gate if (pwp->wp_kmap[X] + pwp->wp_umap[X]) 265*7c478bd9Sstevel@tonic-gate /* cannot have exec-only protection */ 266*7c478bd9Sstevel@tonic-gate prot |= PROT_READ|PROT_EXEC; 267*7c478bd9Sstevel@tonic-gate if (pwp->wp_kmap[R] + pwp->wp_umap[R]) 268*7c478bd9Sstevel@tonic-gate prot |= PROT_READ; 269*7c478bd9Sstevel@tonic-gate if (pwp->wp_kmap[W] + pwp->wp_umap[W]) 270*7c478bd9Sstevel@tonic-gate /* cannot have write-only protection */ 271*7c478bd9Sstevel@tonic-gate prot |= PROT_READ|PROT_WRITE; 272*7c478bd9Sstevel@tonic-gate #if 0 /* damned broken mmu feature! */ 273*7c478bd9Sstevel@tonic-gate if (sum(pwp->wp_umap) == 0) 274*7c478bd9Sstevel@tonic-gate prot &= ~PROT_USER; 275*7c478bd9Sstevel@tonic-gate #endif 276*7c478bd9Sstevel@tonic-gate } else { 277*7c478bd9Sstevel@tonic-gate ASSERT(pwp->wp_flags & WP_NOWATCH); 278*7c478bd9Sstevel@tonic-gate if (kernel) { 279*7c478bd9Sstevel@tonic-gate ASSERT(pwp->wp_kmap[xrw] != 0); 280*7c478bd9Sstevel@tonic-gate --pwp->wp_kmap[xrw]; 281*7c478bd9Sstevel@tonic-gate } else { 282*7c478bd9Sstevel@tonic-gate ASSERT(pwp->wp_umap[xrw] != 0); 283*7c478bd9Sstevel@tonic-gate --pwp->wp_umap[xrw]; 284*7c478bd9Sstevel@tonic-gate } 285*7c478bd9Sstevel@tonic-gate if (sum(pwp->wp_kmap) + sum(pwp->wp_umap) == 0) 286*7c478bd9Sstevel@tonic-gate pwp->wp_flags &= ~WP_NOWATCH; 287*7c478bd9Sstevel@tonic-gate else { 288*7c478bd9Sstevel@tonic-gate if (pwp->wp_kmap[X] + pwp->wp_umap[X]) 289*7c478bd9Sstevel@tonic-gate /* cannot have exec-only protection */ 290*7c478bd9Sstevel@tonic-gate prot |= PROT_READ|PROT_EXEC; 291*7c478bd9Sstevel@tonic-gate if (pwp->wp_kmap[R] + pwp->wp_umap[R]) 292*7c478bd9Sstevel@tonic-gate prot |= PROT_READ; 293*7c478bd9Sstevel@tonic-gate if (pwp->wp_kmap[W] + pwp->wp_umap[W]) 294*7c478bd9Sstevel@tonic-gate /* cannot have write-only protection */ 295*7c478bd9Sstevel@tonic-gate prot |= PROT_READ|PROT_WRITE; 296*7c478bd9Sstevel@tonic-gate #if 0 /* damned broken mmu feature! */ 297*7c478bd9Sstevel@tonic-gate if (sum(pwp->wp_umap) == 0) 298*7c478bd9Sstevel@tonic-gate prot &= ~PROT_USER; 299*7c478bd9Sstevel@tonic-gate #endif 300*7c478bd9Sstevel@tonic-gate } 301*7c478bd9Sstevel@tonic-gate } 302*7c478bd9Sstevel@tonic-gate 303*7c478bd9Sstevel@tonic-gate 304*7c478bd9Sstevel@tonic-gate if (pwp->wp_oprot != 0) { /* if page exists */ 305*7c478bd9Sstevel@tonic-gate struct seg *seg; 306*7c478bd9Sstevel@tonic-gate uint_t oprot; 307*7c478bd9Sstevel@tonic-gate int err, retrycnt = 0; 308*7c478bd9Sstevel@tonic-gate 309*7c478bd9Sstevel@tonic-gate AS_LOCK_EXIT(as, &as->a_lock); 310*7c478bd9Sstevel@tonic-gate AS_LOCK_ENTER(as, &as->a_lock, RW_WRITER); 311*7c478bd9Sstevel@tonic-gate retry: 312*7c478bd9Sstevel@tonic-gate seg = as_segat(as, addr); 313*7c478bd9Sstevel@tonic-gate ASSERT(seg != NULL); 314*7c478bd9Sstevel@tonic-gate SEGOP_GETPROT(seg, addr, 0, &oprot); 315*7c478bd9Sstevel@tonic-gate if (prot != oprot) { 316*7c478bd9Sstevel@tonic-gate err = SEGOP_SETPROT(seg, addr, PAGESIZE, prot); 317*7c478bd9Sstevel@tonic-gate if (err == IE_RETRY) { 318*7c478bd9Sstevel@tonic-gate ASSERT(retrycnt == 0); 319*7c478bd9Sstevel@tonic-gate retrycnt++; 320*7c478bd9Sstevel@tonic-gate goto retry; 321*7c478bd9Sstevel@tonic-gate } 322*7c478bd9Sstevel@tonic-gate } 323*7c478bd9Sstevel@tonic-gate AS_LOCK_EXIT(as, &as->a_lock); 324*7c478bd9Sstevel@tonic-gate } else 325*7c478bd9Sstevel@tonic-gate AS_LOCK_EXIT(as, &as->a_lock); 326*7c478bd9Sstevel@tonic-gate 327*7c478bd9Sstevel@tonic-gate /* 328*7c478bd9Sstevel@tonic-gate * When all pages are mapped back to their normal state, 329*7c478bd9Sstevel@tonic-gate * continue the other lwps. 330*7c478bd9Sstevel@tonic-gate */ 331*7c478bd9Sstevel@tonic-gate if (!mapin) { 332*7c478bd9Sstevel@tonic-gate ASSERT(p->p_mapcnt > 0); 333*7c478bd9Sstevel@tonic-gate p->p_mapcnt--; 334*7c478bd9Sstevel@tonic-gate if (p->p_mapcnt == 0) { 335*7c478bd9Sstevel@tonic-gate mutex_exit(&p->p_maplock); 336*7c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 337*7c478bd9Sstevel@tonic-gate continuelwps(p); 338*7c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 339*7c478bd9Sstevel@tonic-gate mutex_enter(&p->p_maplock); 340*7c478bd9Sstevel@tonic-gate } 341*7c478bd9Sstevel@tonic-gate } 342*7c478bd9Sstevel@tonic-gate 343*7c478bd9Sstevel@tonic-gate AS_LOCK_ENTER(as, &as->a_lock, RW_READER); 344*7c478bd9Sstevel@tonic-gate } 345*7c478bd9Sstevel@tonic-gate 346*7c478bd9Sstevel@tonic-gate AS_LOCK_EXIT(as, &as->a_lock); 347*7c478bd9Sstevel@tonic-gate mutex_exit(&p->p_maplock); 348*7c478bd9Sstevel@tonic-gate 349*7c478bd9Sstevel@tonic-gate return (rv); 350*7c478bd9Sstevel@tonic-gate } 351*7c478bd9Sstevel@tonic-gate 352*7c478bd9Sstevel@tonic-gate /* 353*7c478bd9Sstevel@tonic-gate * Restore the original page protections on an address range. 354*7c478bd9Sstevel@tonic-gate * If 'kernel' is non-zero, just do it for the kernel. 355*7c478bd9Sstevel@tonic-gate * pr_mappage() returns non-zero if it actually changed anything. 356*7c478bd9Sstevel@tonic-gate * 357*7c478bd9Sstevel@tonic-gate * pr_mappage() and pr_unmappage() must be executed in matched pairs, 358*7c478bd9Sstevel@tonic-gate * but pairs may be nested within other pairs. The reference counts 359*7c478bd9Sstevel@tonic-gate * sort it all out. See pr_do_mappage(), above. 360*7c478bd9Sstevel@tonic-gate */ 361*7c478bd9Sstevel@tonic-gate static int 362*7c478bd9Sstevel@tonic-gate pr_mappage(const caddr_t addr, size_t size, enum seg_rw rw, int kernel) 363*7c478bd9Sstevel@tonic-gate { 364*7c478bd9Sstevel@tonic-gate return (pr_do_mappage(addr, size, 1, rw, kernel)); 365*7c478bd9Sstevel@tonic-gate } 366*7c478bd9Sstevel@tonic-gate 367*7c478bd9Sstevel@tonic-gate /* 368*7c478bd9Sstevel@tonic-gate * Set the modified page protections on a watched page. 369*7c478bd9Sstevel@tonic-gate * Inverse of pr_mappage(). 370*7c478bd9Sstevel@tonic-gate * Needs to be called only if pr_mappage() returned non-zero. 371*7c478bd9Sstevel@tonic-gate */ 372*7c478bd9Sstevel@tonic-gate static void 373*7c478bd9Sstevel@tonic-gate pr_unmappage(const caddr_t addr, size_t size, enum seg_rw rw, int kernel) 374*7c478bd9Sstevel@tonic-gate { 375*7c478bd9Sstevel@tonic-gate (void) pr_do_mappage(addr, size, 0, rw, kernel); 376*7c478bd9Sstevel@tonic-gate } 377*7c478bd9Sstevel@tonic-gate 378*7c478bd9Sstevel@tonic-gate /* 379*7c478bd9Sstevel@tonic-gate * Function called by an lwp after it resumes from stop(). 380*7c478bd9Sstevel@tonic-gate */ 381*7c478bd9Sstevel@tonic-gate void 382*7c478bd9Sstevel@tonic-gate setallwatch(void) 383*7c478bd9Sstevel@tonic-gate { 384*7c478bd9Sstevel@tonic-gate proc_t *p = curproc; 385*7c478bd9Sstevel@tonic-gate struct as *as = curproc->p_as; 386*7c478bd9Sstevel@tonic-gate struct watched_page *pwp, *next; 387*7c478bd9Sstevel@tonic-gate struct seg *seg; 388*7c478bd9Sstevel@tonic-gate caddr_t vaddr; 389*7c478bd9Sstevel@tonic-gate uint_t prot; 390*7c478bd9Sstevel@tonic-gate int err, retrycnt; 391*7c478bd9Sstevel@tonic-gate 392*7c478bd9Sstevel@tonic-gate if (p->p_wprot == NULL) 393*7c478bd9Sstevel@tonic-gate return; 394*7c478bd9Sstevel@tonic-gate 395*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&curproc->p_lock)); 396*7c478bd9Sstevel@tonic-gate 397*7c478bd9Sstevel@tonic-gate AS_LOCK_ENTER(as, &as->a_lock, RW_WRITER); 398*7c478bd9Sstevel@tonic-gate 399*7c478bd9Sstevel@tonic-gate pwp = p->p_wprot; 400*7c478bd9Sstevel@tonic-gate while (pwp != NULL) { 401*7c478bd9Sstevel@tonic-gate 402*7c478bd9Sstevel@tonic-gate vaddr = pwp->wp_vaddr; 403*7c478bd9Sstevel@tonic-gate retrycnt = 0; 404*7c478bd9Sstevel@tonic-gate retry: 405*7c478bd9Sstevel@tonic-gate ASSERT(pwp->wp_flags & WP_SETPROT); 406*7c478bd9Sstevel@tonic-gate if ((seg = as_segat(as, vaddr)) != NULL && 407*7c478bd9Sstevel@tonic-gate !(pwp->wp_flags & WP_NOWATCH)) { 408*7c478bd9Sstevel@tonic-gate prot = pwp->wp_prot; 409*7c478bd9Sstevel@tonic-gate err = SEGOP_SETPROT(seg, vaddr, PAGESIZE, prot); 410*7c478bd9Sstevel@tonic-gate if (err == IE_RETRY) { 411*7c478bd9Sstevel@tonic-gate ASSERT(retrycnt == 0); 412*7c478bd9Sstevel@tonic-gate retrycnt++; 413*7c478bd9Sstevel@tonic-gate goto retry; 414*7c478bd9Sstevel@tonic-gate } 415*7c478bd9Sstevel@tonic-gate } 416*7c478bd9Sstevel@tonic-gate 417*7c478bd9Sstevel@tonic-gate next = pwp->wp_list; 418*7c478bd9Sstevel@tonic-gate 419*7c478bd9Sstevel@tonic-gate if (pwp->wp_read + pwp->wp_write + pwp->wp_exec == 0) { 420*7c478bd9Sstevel@tonic-gate /* 421*7c478bd9Sstevel@tonic-gate * No watched areas remain in this page. 422*7c478bd9Sstevel@tonic-gate * Free the watched_page structure. 423*7c478bd9Sstevel@tonic-gate */ 424*7c478bd9Sstevel@tonic-gate avl_remove(&as->a_wpage, pwp); 425*7c478bd9Sstevel@tonic-gate kmem_free(pwp, sizeof (struct watched_page)); 426*7c478bd9Sstevel@tonic-gate } else { 427*7c478bd9Sstevel@tonic-gate pwp->wp_flags &= ~WP_SETPROT; 428*7c478bd9Sstevel@tonic-gate } 429*7c478bd9Sstevel@tonic-gate 430*7c478bd9Sstevel@tonic-gate pwp = next; 431*7c478bd9Sstevel@tonic-gate } 432*7c478bd9Sstevel@tonic-gate p->p_wprot = NULL; 433*7c478bd9Sstevel@tonic-gate 434*7c478bd9Sstevel@tonic-gate AS_LOCK_EXIT(as, &as->a_lock); 435*7c478bd9Sstevel@tonic-gate } 436*7c478bd9Sstevel@tonic-gate 437*7c478bd9Sstevel@tonic-gate 438*7c478bd9Sstevel@tonic-gate 439*7c478bd9Sstevel@tonic-gate /* Must be called with as lock held */ 440*7c478bd9Sstevel@tonic-gate int 441*7c478bd9Sstevel@tonic-gate pr_is_watchpage_as(caddr_t addr, enum seg_rw rw, struct as *as) 442*7c478bd9Sstevel@tonic-gate { 443*7c478bd9Sstevel@tonic-gate register struct watched_page *pwp; 444*7c478bd9Sstevel@tonic-gate struct watched_page tpw; 445*7c478bd9Sstevel@tonic-gate uint_t prot; 446*7c478bd9Sstevel@tonic-gate int rv = 0; 447*7c478bd9Sstevel@tonic-gate 448*7c478bd9Sstevel@tonic-gate switch (rw) { 449*7c478bd9Sstevel@tonic-gate case S_READ: 450*7c478bd9Sstevel@tonic-gate case S_WRITE: 451*7c478bd9Sstevel@tonic-gate case S_EXEC: 452*7c478bd9Sstevel@tonic-gate break; 453*7c478bd9Sstevel@tonic-gate default: 454*7c478bd9Sstevel@tonic-gate return (0); 455*7c478bd9Sstevel@tonic-gate } 456*7c478bd9Sstevel@tonic-gate 457*7c478bd9Sstevel@tonic-gate /* 458*7c478bd9Sstevel@tonic-gate * as->a_wpage can only be modified while the process is totally 459*7c478bd9Sstevel@tonic-gate * stopped. We need, and should use, no locks here. 460*7c478bd9Sstevel@tonic-gate */ 461*7c478bd9Sstevel@tonic-gate if (as != &kas && avl_numnodes(&as->a_wpage) != 0) { 462*7c478bd9Sstevel@tonic-gate tpw.wp_vaddr = (caddr_t)((uintptr_t)addr & (uintptr_t)PAGEMASK); 463*7c478bd9Sstevel@tonic-gate pwp = avl_find(&as->a_wpage, &tpw, NULL); 464*7c478bd9Sstevel@tonic-gate if (pwp != NULL) { 465*7c478bd9Sstevel@tonic-gate ASSERT(addr >= pwp->wp_vaddr && 466*7c478bd9Sstevel@tonic-gate addr < pwp->wp_vaddr + PAGESIZE); 467*7c478bd9Sstevel@tonic-gate if (pwp->wp_oprot != 0) { 468*7c478bd9Sstevel@tonic-gate prot = pwp->wp_prot; 469*7c478bd9Sstevel@tonic-gate switch (rw) { 470*7c478bd9Sstevel@tonic-gate case S_READ: 471*7c478bd9Sstevel@tonic-gate rv = ((prot & (PROT_USER|PROT_READ)) 472*7c478bd9Sstevel@tonic-gate != (PROT_USER|PROT_READ)); 473*7c478bd9Sstevel@tonic-gate break; 474*7c478bd9Sstevel@tonic-gate case S_WRITE: 475*7c478bd9Sstevel@tonic-gate rv = ((prot & (PROT_USER|PROT_WRITE)) 476*7c478bd9Sstevel@tonic-gate != (PROT_USER|PROT_WRITE)); 477*7c478bd9Sstevel@tonic-gate break; 478*7c478bd9Sstevel@tonic-gate case S_EXEC: 479*7c478bd9Sstevel@tonic-gate rv = ((prot & (PROT_USER|PROT_EXEC)) 480*7c478bd9Sstevel@tonic-gate != (PROT_USER|PROT_EXEC)); 481*7c478bd9Sstevel@tonic-gate break; 482*7c478bd9Sstevel@tonic-gate default: 483*7c478bd9Sstevel@tonic-gate /* can't happen! */ 484*7c478bd9Sstevel@tonic-gate break; 485*7c478bd9Sstevel@tonic-gate } 486*7c478bd9Sstevel@tonic-gate } 487*7c478bd9Sstevel@tonic-gate } 488*7c478bd9Sstevel@tonic-gate } 489*7c478bd9Sstevel@tonic-gate 490*7c478bd9Sstevel@tonic-gate return (rv); 491*7c478bd9Sstevel@tonic-gate } 492*7c478bd9Sstevel@tonic-gate 493*7c478bd9Sstevel@tonic-gate 494*7c478bd9Sstevel@tonic-gate /* 495*7c478bd9Sstevel@tonic-gate * trap() calls here to determine if a fault is in a watched page. 496*7c478bd9Sstevel@tonic-gate * We return nonzero if this is true and the load/store would fail. 497*7c478bd9Sstevel@tonic-gate */ 498*7c478bd9Sstevel@tonic-gate int 499*7c478bd9Sstevel@tonic-gate pr_is_watchpage(caddr_t addr, enum seg_rw rw) 500*7c478bd9Sstevel@tonic-gate { 501*7c478bd9Sstevel@tonic-gate struct as *as = curproc->p_as; 502*7c478bd9Sstevel@tonic-gate int rv; 503*7c478bd9Sstevel@tonic-gate 504*7c478bd9Sstevel@tonic-gate if ((as == &kas) || avl_numnodes(&as->a_wpage) == 0) 505*7c478bd9Sstevel@tonic-gate return (0); 506*7c478bd9Sstevel@tonic-gate 507*7c478bd9Sstevel@tonic-gate /* Grab the lock because of XHAT (see comment in pr_mappage()) */ 508*7c478bd9Sstevel@tonic-gate AS_LOCK_ENTER(as, &as->a_lock, RW_READER); 509*7c478bd9Sstevel@tonic-gate rv = pr_is_watchpage_as(addr, rw, as); 510*7c478bd9Sstevel@tonic-gate AS_LOCK_EXIT(as, &as->a_lock); 511*7c478bd9Sstevel@tonic-gate 512*7c478bd9Sstevel@tonic-gate return (rv); 513*7c478bd9Sstevel@tonic-gate } 514*7c478bd9Sstevel@tonic-gate 515*7c478bd9Sstevel@tonic-gate 516*7c478bd9Sstevel@tonic-gate 517*7c478bd9Sstevel@tonic-gate /* 518*7c478bd9Sstevel@tonic-gate * trap() calls here to determine if a fault is a watchpoint. 519*7c478bd9Sstevel@tonic-gate */ 520*7c478bd9Sstevel@tonic-gate int 521*7c478bd9Sstevel@tonic-gate pr_is_watchpoint(caddr_t *paddr, int *pta, size_t size, size_t *plen, 522*7c478bd9Sstevel@tonic-gate enum seg_rw rw) 523*7c478bd9Sstevel@tonic-gate { 524*7c478bd9Sstevel@tonic-gate proc_t *p = curproc; 525*7c478bd9Sstevel@tonic-gate caddr_t addr = *paddr; 526*7c478bd9Sstevel@tonic-gate caddr_t eaddr = addr + size; 527*7c478bd9Sstevel@tonic-gate register struct watched_area *pwa; 528*7c478bd9Sstevel@tonic-gate struct watched_area twa; 529*7c478bd9Sstevel@tonic-gate int rv = 0; 530*7c478bd9Sstevel@tonic-gate int ta = 0; 531*7c478bd9Sstevel@tonic-gate size_t len = 0; 532*7c478bd9Sstevel@tonic-gate 533*7c478bd9Sstevel@tonic-gate switch (rw) { 534*7c478bd9Sstevel@tonic-gate case S_READ: 535*7c478bd9Sstevel@tonic-gate case S_WRITE: 536*7c478bd9Sstevel@tonic-gate case S_EXEC: 537*7c478bd9Sstevel@tonic-gate break; 538*7c478bd9Sstevel@tonic-gate default: 539*7c478bd9Sstevel@tonic-gate *pta = 0; 540*7c478bd9Sstevel@tonic-gate return (0); 541*7c478bd9Sstevel@tonic-gate } 542*7c478bd9Sstevel@tonic-gate 543*7c478bd9Sstevel@tonic-gate /* 544*7c478bd9Sstevel@tonic-gate * p->p_warea is protected by p->p_lock. 545*7c478bd9Sstevel@tonic-gate */ 546*7c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 547*7c478bd9Sstevel@tonic-gate 548*7c478bd9Sstevel@tonic-gate /* BEGIN CSTYLED */ 549*7c478bd9Sstevel@tonic-gate /* 550*7c478bd9Sstevel@tonic-gate * This loop is somewhat complicated because the fault region can span 551*7c478bd9Sstevel@tonic-gate * multiple watched areas. For example: 552*7c478bd9Sstevel@tonic-gate * 553*7c478bd9Sstevel@tonic-gate * addr eaddr 554*7c478bd9Sstevel@tonic-gate * +-----------------+ 555*7c478bd9Sstevel@tonic-gate * | fault region | 556*7c478bd9Sstevel@tonic-gate * +-------+--------+----+---+------------+ 557*7c478bd9Sstevel@tonic-gate * | prot not right | | prot correct | 558*7c478bd9Sstevel@tonic-gate * +----------------+ +----------------+ 559*7c478bd9Sstevel@tonic-gate * wa_vaddr wa_eaddr 560*7c478bd9Sstevel@tonic-gate * wa_vaddr wa_eaddr 561*7c478bd9Sstevel@tonic-gate * 562*7c478bd9Sstevel@tonic-gate * We start at the area greater than or equal to the starting address. 563*7c478bd9Sstevel@tonic-gate * As long as some portion of the fault region overlaps the current 564*7c478bd9Sstevel@tonic-gate * area, we continue checking permissions until we find an appropriate 565*7c478bd9Sstevel@tonic-gate * match. 566*7c478bd9Sstevel@tonic-gate */ 567*7c478bd9Sstevel@tonic-gate /* END CSTYLED */ 568*7c478bd9Sstevel@tonic-gate twa.wa_vaddr = addr; 569*7c478bd9Sstevel@tonic-gate twa.wa_eaddr = eaddr; 570*7c478bd9Sstevel@tonic-gate 571*7c478bd9Sstevel@tonic-gate for (pwa = pr_find_watched_area(p, &twa, NULL); 572*7c478bd9Sstevel@tonic-gate pwa != NULL && eaddr > pwa->wa_vaddr && addr < pwa->wa_eaddr; 573*7c478bd9Sstevel@tonic-gate pwa = AVL_NEXT(&p->p_warea, pwa)) { 574*7c478bd9Sstevel@tonic-gate 575*7c478bd9Sstevel@tonic-gate switch (rw) { 576*7c478bd9Sstevel@tonic-gate case S_READ: 577*7c478bd9Sstevel@tonic-gate if (pwa->wa_flags & WA_READ) 578*7c478bd9Sstevel@tonic-gate rv = TRAP_RWATCH; 579*7c478bd9Sstevel@tonic-gate break; 580*7c478bd9Sstevel@tonic-gate case S_WRITE: 581*7c478bd9Sstevel@tonic-gate if (pwa->wa_flags & WA_WRITE) 582*7c478bd9Sstevel@tonic-gate rv = TRAP_WWATCH; 583*7c478bd9Sstevel@tonic-gate break; 584*7c478bd9Sstevel@tonic-gate case S_EXEC: 585*7c478bd9Sstevel@tonic-gate if (pwa->wa_flags & WA_EXEC) 586*7c478bd9Sstevel@tonic-gate rv = TRAP_XWATCH; 587*7c478bd9Sstevel@tonic-gate break; 588*7c478bd9Sstevel@tonic-gate default: 589*7c478bd9Sstevel@tonic-gate /* can't happen */ 590*7c478bd9Sstevel@tonic-gate break; 591*7c478bd9Sstevel@tonic-gate } 592*7c478bd9Sstevel@tonic-gate 593*7c478bd9Sstevel@tonic-gate /* 594*7c478bd9Sstevel@tonic-gate * If protections didn't match, check the next watched 595*7c478bd9Sstevel@tonic-gate * area 596*7c478bd9Sstevel@tonic-gate */ 597*7c478bd9Sstevel@tonic-gate if (rv != 0) { 598*7c478bd9Sstevel@tonic-gate if (addr < pwa->wa_vaddr) 599*7c478bd9Sstevel@tonic-gate addr = pwa->wa_vaddr; 600*7c478bd9Sstevel@tonic-gate len = pwa->wa_eaddr - addr; 601*7c478bd9Sstevel@tonic-gate if (pwa->wa_flags & WA_TRAPAFTER) 602*7c478bd9Sstevel@tonic-gate ta = 1; 603*7c478bd9Sstevel@tonic-gate break; 604*7c478bd9Sstevel@tonic-gate } 605*7c478bd9Sstevel@tonic-gate } 606*7c478bd9Sstevel@tonic-gate 607*7c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 608*7c478bd9Sstevel@tonic-gate 609*7c478bd9Sstevel@tonic-gate *paddr = addr; 610*7c478bd9Sstevel@tonic-gate *pta = ta; 611*7c478bd9Sstevel@tonic-gate if (plen != NULL) 612*7c478bd9Sstevel@tonic-gate *plen = len; 613*7c478bd9Sstevel@tonic-gate return (rv); 614*7c478bd9Sstevel@tonic-gate } 615*7c478bd9Sstevel@tonic-gate 616*7c478bd9Sstevel@tonic-gate /* 617*7c478bd9Sstevel@tonic-gate * Set up to perform a single-step at user level for the 618*7c478bd9Sstevel@tonic-gate * case of a trapafter watchpoint. Called from trap(). 619*7c478bd9Sstevel@tonic-gate */ 620*7c478bd9Sstevel@tonic-gate void 621*7c478bd9Sstevel@tonic-gate do_watch_step(caddr_t vaddr, size_t sz, enum seg_rw rw, 622*7c478bd9Sstevel@tonic-gate int watchcode, greg_t pc) 623*7c478bd9Sstevel@tonic-gate { 624*7c478bd9Sstevel@tonic-gate register klwp_t *lwp = ttolwp(curthread); 625*7c478bd9Sstevel@tonic-gate struct lwp_watch *pw = &lwp->lwp_watch[rw_to_index(rw)]; 626*7c478bd9Sstevel@tonic-gate 627*7c478bd9Sstevel@tonic-gate /* 628*7c478bd9Sstevel@tonic-gate * Check to see if we are already performing this special 629*7c478bd9Sstevel@tonic-gate * watchpoint single-step. We must not do pr_mappage() twice. 630*7c478bd9Sstevel@tonic-gate */ 631*7c478bd9Sstevel@tonic-gate 632*7c478bd9Sstevel@tonic-gate /* special check for two read traps on the same instruction */ 633*7c478bd9Sstevel@tonic-gate if (rw == S_READ && pw->wpaddr != NULL && 634*7c478bd9Sstevel@tonic-gate !(pw->wpaddr <= vaddr && vaddr < pw->wpaddr + pw->wpsize)) { 635*7c478bd9Sstevel@tonic-gate ASSERT(lwp->lwp_watchtrap != 0); 636*7c478bd9Sstevel@tonic-gate pw++; /* use the extra S_READ struct */ 637*7c478bd9Sstevel@tonic-gate } 638*7c478bd9Sstevel@tonic-gate 639*7c478bd9Sstevel@tonic-gate if (pw->wpaddr != NULL) { 640*7c478bd9Sstevel@tonic-gate ASSERT(lwp->lwp_watchtrap != 0); 641*7c478bd9Sstevel@tonic-gate ASSERT(pw->wpaddr <= vaddr && vaddr < pw->wpaddr + pw->wpsize); 642*7c478bd9Sstevel@tonic-gate if (pw->wpcode == 0) { 643*7c478bd9Sstevel@tonic-gate pw->wpcode = watchcode; 644*7c478bd9Sstevel@tonic-gate pw->wppc = pc; 645*7c478bd9Sstevel@tonic-gate } 646*7c478bd9Sstevel@tonic-gate } else { 647*7c478bd9Sstevel@tonic-gate int mapped = pr_mappage(vaddr, sz, rw, 0); 648*7c478bd9Sstevel@tonic-gate prstep(lwp, 1); 649*7c478bd9Sstevel@tonic-gate lwp->lwp_watchtrap = 1; 650*7c478bd9Sstevel@tonic-gate pw->wpaddr = vaddr; 651*7c478bd9Sstevel@tonic-gate pw->wpsize = sz; 652*7c478bd9Sstevel@tonic-gate pw->wpcode = watchcode; 653*7c478bd9Sstevel@tonic-gate pw->wpmapped = mapped; 654*7c478bd9Sstevel@tonic-gate pw->wppc = pc; 655*7c478bd9Sstevel@tonic-gate } 656*7c478bd9Sstevel@tonic-gate } 657*7c478bd9Sstevel@tonic-gate 658*7c478bd9Sstevel@tonic-gate /* 659*7c478bd9Sstevel@tonic-gate * Undo the effects of do_watch_step(). 660*7c478bd9Sstevel@tonic-gate * Called from trap() after the single-step is finished. 661*7c478bd9Sstevel@tonic-gate * Also called from issig_forreal() and stop() with a NULL 662*7c478bd9Sstevel@tonic-gate * argument to avoid having these things set more than once. 663*7c478bd9Sstevel@tonic-gate */ 664*7c478bd9Sstevel@tonic-gate int 665*7c478bd9Sstevel@tonic-gate undo_watch_step(k_siginfo_t *sip) 666*7c478bd9Sstevel@tonic-gate { 667*7c478bd9Sstevel@tonic-gate register klwp_t *lwp = ttolwp(curthread); 668*7c478bd9Sstevel@tonic-gate int fault = 0; 669*7c478bd9Sstevel@tonic-gate 670*7c478bd9Sstevel@tonic-gate if (lwp->lwp_watchtrap) { 671*7c478bd9Sstevel@tonic-gate struct lwp_watch *pw = lwp->lwp_watch; 672*7c478bd9Sstevel@tonic-gate int i; 673*7c478bd9Sstevel@tonic-gate 674*7c478bd9Sstevel@tonic-gate for (i = 0; i < 4; i++, pw++) { 675*7c478bd9Sstevel@tonic-gate if (pw->wpaddr == NULL) 676*7c478bd9Sstevel@tonic-gate continue; 677*7c478bd9Sstevel@tonic-gate if (pw->wpmapped) 678*7c478bd9Sstevel@tonic-gate pr_unmappage(pw->wpaddr, pw->wpsize, S_rw[i], 679*7c478bd9Sstevel@tonic-gate 0); 680*7c478bd9Sstevel@tonic-gate if (pw->wpcode != 0) { 681*7c478bd9Sstevel@tonic-gate if (sip != NULL) { 682*7c478bd9Sstevel@tonic-gate sip->si_signo = SIGTRAP; 683*7c478bd9Sstevel@tonic-gate sip->si_code = pw->wpcode; 684*7c478bd9Sstevel@tonic-gate sip->si_addr = pw->wpaddr; 685*7c478bd9Sstevel@tonic-gate sip->si_trapafter = 1; 686*7c478bd9Sstevel@tonic-gate sip->si_pc = (caddr_t)pw->wppc; 687*7c478bd9Sstevel@tonic-gate } 688*7c478bd9Sstevel@tonic-gate fault = FLTWATCH; 689*7c478bd9Sstevel@tonic-gate pw->wpcode = 0; 690*7c478bd9Sstevel@tonic-gate } 691*7c478bd9Sstevel@tonic-gate pw->wpaddr = NULL; 692*7c478bd9Sstevel@tonic-gate pw->wpsize = 0; 693*7c478bd9Sstevel@tonic-gate pw->wpmapped = 0; 694*7c478bd9Sstevel@tonic-gate } 695*7c478bd9Sstevel@tonic-gate lwp->lwp_watchtrap = 0; 696*7c478bd9Sstevel@tonic-gate } 697*7c478bd9Sstevel@tonic-gate 698*7c478bd9Sstevel@tonic-gate return (fault); 699*7c478bd9Sstevel@tonic-gate } 700*7c478bd9Sstevel@tonic-gate 701*7c478bd9Sstevel@tonic-gate /* 702*7c478bd9Sstevel@tonic-gate * Handle a watchpoint that occurs while doing copyin() 703*7c478bd9Sstevel@tonic-gate * or copyout() in a system call. 704*7c478bd9Sstevel@tonic-gate * Return non-zero if the fault or signal is cleared 705*7c478bd9Sstevel@tonic-gate * by a debugger while the lwp is stopped. 706*7c478bd9Sstevel@tonic-gate */ 707*7c478bd9Sstevel@tonic-gate static int 708*7c478bd9Sstevel@tonic-gate sys_watchpoint(caddr_t addr, int watchcode, int ta) 709*7c478bd9Sstevel@tonic-gate { 710*7c478bd9Sstevel@tonic-gate extern greg_t getuserpc(void); /* XXX header file */ 711*7c478bd9Sstevel@tonic-gate k_sigset_t smask; 712*7c478bd9Sstevel@tonic-gate register proc_t *p = ttoproc(curthread); 713*7c478bd9Sstevel@tonic-gate register klwp_t *lwp = ttolwp(curthread); 714*7c478bd9Sstevel@tonic-gate register sigqueue_t *sqp; 715*7c478bd9Sstevel@tonic-gate int rval; 716*7c478bd9Sstevel@tonic-gate 717*7c478bd9Sstevel@tonic-gate /* assert no locks are held */ 718*7c478bd9Sstevel@tonic-gate /* ASSERT(curthread->t_nlocks == 0); */ 719*7c478bd9Sstevel@tonic-gate 720*7c478bd9Sstevel@tonic-gate sqp = kmem_zalloc(sizeof (sigqueue_t), KM_SLEEP); 721*7c478bd9Sstevel@tonic-gate sqp->sq_info.si_signo = SIGTRAP; 722*7c478bd9Sstevel@tonic-gate sqp->sq_info.si_code = watchcode; 723*7c478bd9Sstevel@tonic-gate sqp->sq_info.si_addr = addr; 724*7c478bd9Sstevel@tonic-gate sqp->sq_info.si_trapafter = ta; 725*7c478bd9Sstevel@tonic-gate sqp->sq_info.si_pc = (caddr_t)getuserpc(); 726*7c478bd9Sstevel@tonic-gate 727*7c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 728*7c478bd9Sstevel@tonic-gate 729*7c478bd9Sstevel@tonic-gate /* this will be tested and cleared by the caller */ 730*7c478bd9Sstevel@tonic-gate lwp->lwp_sysabort = 0; 731*7c478bd9Sstevel@tonic-gate 732*7c478bd9Sstevel@tonic-gate if (prismember(&p->p_fltmask, FLTWATCH)) { 733*7c478bd9Sstevel@tonic-gate lwp->lwp_curflt = (uchar_t)FLTWATCH; 734*7c478bd9Sstevel@tonic-gate lwp->lwp_siginfo = sqp->sq_info; 735*7c478bd9Sstevel@tonic-gate stop(PR_FAULTED, FLTWATCH); 736*7c478bd9Sstevel@tonic-gate if (lwp->lwp_curflt == 0) { 737*7c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 738*7c478bd9Sstevel@tonic-gate kmem_free(sqp, sizeof (sigqueue_t)); 739*7c478bd9Sstevel@tonic-gate return (1); 740*7c478bd9Sstevel@tonic-gate } 741*7c478bd9Sstevel@tonic-gate lwp->lwp_curflt = 0; 742*7c478bd9Sstevel@tonic-gate } 743*7c478bd9Sstevel@tonic-gate 744*7c478bd9Sstevel@tonic-gate /* 745*7c478bd9Sstevel@tonic-gate * post the SIGTRAP signal. 746*7c478bd9Sstevel@tonic-gate * Block all other signals so we only stop showing SIGTRAP. 747*7c478bd9Sstevel@tonic-gate */ 748*7c478bd9Sstevel@tonic-gate if (signal_is_blocked(curthread, SIGTRAP) || 749*7c478bd9Sstevel@tonic-gate sigismember(&p->p_ignore, SIGTRAP)) { 750*7c478bd9Sstevel@tonic-gate /* SIGTRAP is blocked or ignored, forget the rest. */ 751*7c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 752*7c478bd9Sstevel@tonic-gate kmem_free(sqp, sizeof (sigqueue_t)); 753*7c478bd9Sstevel@tonic-gate return (0); 754*7c478bd9Sstevel@tonic-gate } 755*7c478bd9Sstevel@tonic-gate sigdelq(p, curthread, SIGTRAP); 756*7c478bd9Sstevel@tonic-gate sigaddqa(p, curthread, sqp); 757*7c478bd9Sstevel@tonic-gate schedctl_finish_sigblock(curthread); 758*7c478bd9Sstevel@tonic-gate smask = curthread->t_hold; 759*7c478bd9Sstevel@tonic-gate sigfillset(&curthread->t_hold); 760*7c478bd9Sstevel@tonic-gate sigdiffset(&curthread->t_hold, &cantmask); 761*7c478bd9Sstevel@tonic-gate sigdelset(&curthread->t_hold, SIGTRAP); 762*7c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 763*7c478bd9Sstevel@tonic-gate 764*7c478bd9Sstevel@tonic-gate rval = ((ISSIG_FAST(curthread, lwp, p, FORREAL))? 0 : 1); 765*7c478bd9Sstevel@tonic-gate 766*7c478bd9Sstevel@tonic-gate /* restore the original signal mask */ 767*7c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 768*7c478bd9Sstevel@tonic-gate curthread->t_hold = smask; 769*7c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 770*7c478bd9Sstevel@tonic-gate 771*7c478bd9Sstevel@tonic-gate return (rval); 772*7c478bd9Sstevel@tonic-gate } 773*7c478bd9Sstevel@tonic-gate 774*7c478bd9Sstevel@tonic-gate /* 775*7c478bd9Sstevel@tonic-gate * Wrappers for the copyin()/copyout() functions to deal 776*7c478bd9Sstevel@tonic-gate * with watchpoints that fire while in system calls. 777*7c478bd9Sstevel@tonic-gate */ 778*7c478bd9Sstevel@tonic-gate 779*7c478bd9Sstevel@tonic-gate static int 780*7c478bd9Sstevel@tonic-gate watch_xcopyin(const void *uaddr, void *kaddr, size_t count) 781*7c478bd9Sstevel@tonic-gate { 782*7c478bd9Sstevel@tonic-gate klwp_t *lwp = ttolwp(curthread); 783*7c478bd9Sstevel@tonic-gate caddr_t watch_uaddr = (caddr_t)uaddr; 784*7c478bd9Sstevel@tonic-gate caddr_t watch_kaddr = (caddr_t)kaddr; 785*7c478bd9Sstevel@tonic-gate int error = 0; 786*7c478bd9Sstevel@tonic-gate label_t ljb; 787*7c478bd9Sstevel@tonic-gate size_t part; 788*7c478bd9Sstevel@tonic-gate int mapped; 789*7c478bd9Sstevel@tonic-gate 790*7c478bd9Sstevel@tonic-gate while (count && error == 0) { 791*7c478bd9Sstevel@tonic-gate int watchcode; 792*7c478bd9Sstevel@tonic-gate caddr_t vaddr; 793*7c478bd9Sstevel@tonic-gate size_t len; 794*7c478bd9Sstevel@tonic-gate int ta; 795*7c478bd9Sstevel@tonic-gate 796*7c478bd9Sstevel@tonic-gate if ((part = PAGESIZE - 797*7c478bd9Sstevel@tonic-gate (((uintptr_t)uaddr) & PAGEOFFSET)) > count) 798*7c478bd9Sstevel@tonic-gate part = count; 799*7c478bd9Sstevel@tonic-gate 800*7c478bd9Sstevel@tonic-gate if (!pr_is_watchpage(watch_uaddr, S_READ)) 801*7c478bd9Sstevel@tonic-gate watchcode = 0; 802*7c478bd9Sstevel@tonic-gate else { 803*7c478bd9Sstevel@tonic-gate vaddr = watch_uaddr; 804*7c478bd9Sstevel@tonic-gate watchcode = pr_is_watchpoint(&vaddr, &ta, 805*7c478bd9Sstevel@tonic-gate part, &len, S_READ); 806*7c478bd9Sstevel@tonic-gate if (watchcode && ta == 0) 807*7c478bd9Sstevel@tonic-gate part = vaddr - watch_uaddr; 808*7c478bd9Sstevel@tonic-gate } 809*7c478bd9Sstevel@tonic-gate 810*7c478bd9Sstevel@tonic-gate /* 811*7c478bd9Sstevel@tonic-gate * Copy the initial part, up to a watched address, if any. 812*7c478bd9Sstevel@tonic-gate */ 813*7c478bd9Sstevel@tonic-gate if (part != 0) { 814*7c478bd9Sstevel@tonic-gate mapped = pr_mappage(watch_uaddr, part, S_READ, 1); 815*7c478bd9Sstevel@tonic-gate if (on_fault(&ljb)) 816*7c478bd9Sstevel@tonic-gate error = EFAULT; 817*7c478bd9Sstevel@tonic-gate else 818*7c478bd9Sstevel@tonic-gate copyin_noerr(watch_uaddr, watch_kaddr, part); 819*7c478bd9Sstevel@tonic-gate no_fault(); 820*7c478bd9Sstevel@tonic-gate if (mapped) 821*7c478bd9Sstevel@tonic-gate pr_unmappage(watch_uaddr, part, S_READ, 1); 822*7c478bd9Sstevel@tonic-gate watch_uaddr += part; 823*7c478bd9Sstevel@tonic-gate watch_kaddr += part; 824*7c478bd9Sstevel@tonic-gate count -= part; 825*7c478bd9Sstevel@tonic-gate } 826*7c478bd9Sstevel@tonic-gate /* 827*7c478bd9Sstevel@tonic-gate * If trapafter was specified, then copy through the 828*7c478bd9Sstevel@tonic-gate * watched area before taking the watchpoint trap. 829*7c478bd9Sstevel@tonic-gate */ 830*7c478bd9Sstevel@tonic-gate while (count && watchcode && ta && len > part && error == 0) { 831*7c478bd9Sstevel@tonic-gate len -= part; 832*7c478bd9Sstevel@tonic-gate if ((part = PAGESIZE) > count) 833*7c478bd9Sstevel@tonic-gate part = count; 834*7c478bd9Sstevel@tonic-gate if (part > len) 835*7c478bd9Sstevel@tonic-gate part = len; 836*7c478bd9Sstevel@tonic-gate mapped = pr_mappage(watch_uaddr, part, S_READ, 1); 837*7c478bd9Sstevel@tonic-gate if (on_fault(&ljb)) 838*7c478bd9Sstevel@tonic-gate error = EFAULT; 839*7c478bd9Sstevel@tonic-gate else 840*7c478bd9Sstevel@tonic-gate copyin_noerr(watch_uaddr, watch_kaddr, part); 841*7c478bd9Sstevel@tonic-gate no_fault(); 842*7c478bd9Sstevel@tonic-gate if (mapped) 843*7c478bd9Sstevel@tonic-gate pr_unmappage(watch_uaddr, part, S_READ, 1); 844*7c478bd9Sstevel@tonic-gate watch_uaddr += part; 845*7c478bd9Sstevel@tonic-gate watch_kaddr += part; 846*7c478bd9Sstevel@tonic-gate count -= part; 847*7c478bd9Sstevel@tonic-gate } 848*7c478bd9Sstevel@tonic-gate 849*7c478bd9Sstevel@tonic-gate error: 850*7c478bd9Sstevel@tonic-gate /* if we hit a watched address, do the watchpoint logic */ 851*7c478bd9Sstevel@tonic-gate if (watchcode && 852*7c478bd9Sstevel@tonic-gate (!sys_watchpoint(vaddr, watchcode, ta) || 853*7c478bd9Sstevel@tonic-gate lwp->lwp_sysabort)) { 854*7c478bd9Sstevel@tonic-gate lwp->lwp_sysabort = 0; 855*7c478bd9Sstevel@tonic-gate error = EFAULT; 856*7c478bd9Sstevel@tonic-gate break; 857*7c478bd9Sstevel@tonic-gate } 858*7c478bd9Sstevel@tonic-gate } 859*7c478bd9Sstevel@tonic-gate 860*7c478bd9Sstevel@tonic-gate return (error); 861*7c478bd9Sstevel@tonic-gate } 862*7c478bd9Sstevel@tonic-gate 863*7c478bd9Sstevel@tonic-gate static int 864*7c478bd9Sstevel@tonic-gate watch_copyin(const void *kaddr, void *uaddr, size_t count) 865*7c478bd9Sstevel@tonic-gate { 866*7c478bd9Sstevel@tonic-gate return (watch_xcopyin(kaddr, uaddr, count) ? -1 : 0); 867*7c478bd9Sstevel@tonic-gate } 868*7c478bd9Sstevel@tonic-gate 869*7c478bd9Sstevel@tonic-gate 870*7c478bd9Sstevel@tonic-gate static int 871*7c478bd9Sstevel@tonic-gate watch_xcopyout(const void *kaddr, void *uaddr, size_t count) 872*7c478bd9Sstevel@tonic-gate { 873*7c478bd9Sstevel@tonic-gate klwp_t *lwp = ttolwp(curthread); 874*7c478bd9Sstevel@tonic-gate caddr_t watch_uaddr = (caddr_t)uaddr; 875*7c478bd9Sstevel@tonic-gate caddr_t watch_kaddr = (caddr_t)kaddr; 876*7c478bd9Sstevel@tonic-gate int error = 0; 877*7c478bd9Sstevel@tonic-gate label_t ljb; 878*7c478bd9Sstevel@tonic-gate 879*7c478bd9Sstevel@tonic-gate while (count && error == 0) { 880*7c478bd9Sstevel@tonic-gate int watchcode; 881*7c478bd9Sstevel@tonic-gate caddr_t vaddr; 882*7c478bd9Sstevel@tonic-gate size_t part; 883*7c478bd9Sstevel@tonic-gate size_t len; 884*7c478bd9Sstevel@tonic-gate int ta; 885*7c478bd9Sstevel@tonic-gate int mapped; 886*7c478bd9Sstevel@tonic-gate 887*7c478bd9Sstevel@tonic-gate if ((part = PAGESIZE - 888*7c478bd9Sstevel@tonic-gate (((uintptr_t)uaddr) & PAGEOFFSET)) > count) 889*7c478bd9Sstevel@tonic-gate part = count; 890*7c478bd9Sstevel@tonic-gate 891*7c478bd9Sstevel@tonic-gate if (!pr_is_watchpage(watch_uaddr, S_WRITE)) 892*7c478bd9Sstevel@tonic-gate watchcode = 0; 893*7c478bd9Sstevel@tonic-gate else { 894*7c478bd9Sstevel@tonic-gate vaddr = watch_uaddr; 895*7c478bd9Sstevel@tonic-gate watchcode = pr_is_watchpoint(&vaddr, &ta, 896*7c478bd9Sstevel@tonic-gate part, &len, S_WRITE); 897*7c478bd9Sstevel@tonic-gate if (watchcode) { 898*7c478bd9Sstevel@tonic-gate if (ta == 0) 899*7c478bd9Sstevel@tonic-gate part = vaddr - watch_uaddr; 900*7c478bd9Sstevel@tonic-gate else { 901*7c478bd9Sstevel@tonic-gate len += vaddr - watch_uaddr; 902*7c478bd9Sstevel@tonic-gate if (part > len) 903*7c478bd9Sstevel@tonic-gate part = len; 904*7c478bd9Sstevel@tonic-gate } 905*7c478bd9Sstevel@tonic-gate } 906*7c478bd9Sstevel@tonic-gate } 907*7c478bd9Sstevel@tonic-gate 908*7c478bd9Sstevel@tonic-gate /* 909*7c478bd9Sstevel@tonic-gate * Copy the initial part, up to a watched address, if any. 910*7c478bd9Sstevel@tonic-gate */ 911*7c478bd9Sstevel@tonic-gate if (part != 0) { 912*7c478bd9Sstevel@tonic-gate mapped = pr_mappage(watch_uaddr, part, S_WRITE, 1); 913*7c478bd9Sstevel@tonic-gate if (on_fault(&ljb)) 914*7c478bd9Sstevel@tonic-gate error = EFAULT; 915*7c478bd9Sstevel@tonic-gate else 916*7c478bd9Sstevel@tonic-gate copyout_noerr(watch_kaddr, watch_uaddr, part); 917*7c478bd9Sstevel@tonic-gate no_fault(); 918*7c478bd9Sstevel@tonic-gate if (mapped) 919*7c478bd9Sstevel@tonic-gate pr_unmappage(watch_uaddr, part, S_WRITE, 1); 920*7c478bd9Sstevel@tonic-gate watch_uaddr += part; 921*7c478bd9Sstevel@tonic-gate watch_kaddr += part; 922*7c478bd9Sstevel@tonic-gate count -= part; 923*7c478bd9Sstevel@tonic-gate } 924*7c478bd9Sstevel@tonic-gate 925*7c478bd9Sstevel@tonic-gate /* 926*7c478bd9Sstevel@tonic-gate * If trapafter was specified, then copy through the 927*7c478bd9Sstevel@tonic-gate * watched area before taking the watchpoint trap. 928*7c478bd9Sstevel@tonic-gate */ 929*7c478bd9Sstevel@tonic-gate while (count && watchcode && ta && len > part && error == 0) { 930*7c478bd9Sstevel@tonic-gate len -= part; 931*7c478bd9Sstevel@tonic-gate if ((part = PAGESIZE) > count) 932*7c478bd9Sstevel@tonic-gate part = count; 933*7c478bd9Sstevel@tonic-gate if (part > len) 934*7c478bd9Sstevel@tonic-gate part = len; 935*7c478bd9Sstevel@tonic-gate mapped = pr_mappage(watch_uaddr, part, S_WRITE, 1); 936*7c478bd9Sstevel@tonic-gate if (on_fault(&ljb)) 937*7c478bd9Sstevel@tonic-gate error = EFAULT; 938*7c478bd9Sstevel@tonic-gate else 939*7c478bd9Sstevel@tonic-gate copyout_noerr(watch_kaddr, watch_uaddr, part); 940*7c478bd9Sstevel@tonic-gate no_fault(); 941*7c478bd9Sstevel@tonic-gate if (mapped) 942*7c478bd9Sstevel@tonic-gate pr_unmappage(watch_uaddr, part, S_WRITE, 1); 943*7c478bd9Sstevel@tonic-gate watch_uaddr += part; 944*7c478bd9Sstevel@tonic-gate watch_kaddr += part; 945*7c478bd9Sstevel@tonic-gate count -= part; 946*7c478bd9Sstevel@tonic-gate } 947*7c478bd9Sstevel@tonic-gate 948*7c478bd9Sstevel@tonic-gate /* if we hit a watched address, do the watchpoint logic */ 949*7c478bd9Sstevel@tonic-gate if (watchcode && 950*7c478bd9Sstevel@tonic-gate (!sys_watchpoint(vaddr, watchcode, ta) || 951*7c478bd9Sstevel@tonic-gate lwp->lwp_sysabort)) { 952*7c478bd9Sstevel@tonic-gate lwp->lwp_sysabort = 0; 953*7c478bd9Sstevel@tonic-gate error = EFAULT; 954*7c478bd9Sstevel@tonic-gate break; 955*7c478bd9Sstevel@tonic-gate } 956*7c478bd9Sstevel@tonic-gate } 957*7c478bd9Sstevel@tonic-gate 958*7c478bd9Sstevel@tonic-gate return (error); 959*7c478bd9Sstevel@tonic-gate } 960*7c478bd9Sstevel@tonic-gate 961*7c478bd9Sstevel@tonic-gate static int 962*7c478bd9Sstevel@tonic-gate watch_copyout(const void *kaddr, void *uaddr, size_t count) 963*7c478bd9Sstevel@tonic-gate { 964*7c478bd9Sstevel@tonic-gate return (watch_xcopyout(kaddr, uaddr, count) ? -1 : 0); 965*7c478bd9Sstevel@tonic-gate } 966*7c478bd9Sstevel@tonic-gate 967*7c478bd9Sstevel@tonic-gate static int 968*7c478bd9Sstevel@tonic-gate watch_copyinstr( 969*7c478bd9Sstevel@tonic-gate const char *uaddr, 970*7c478bd9Sstevel@tonic-gate char *kaddr, 971*7c478bd9Sstevel@tonic-gate size_t maxlength, 972*7c478bd9Sstevel@tonic-gate size_t *lencopied) 973*7c478bd9Sstevel@tonic-gate { 974*7c478bd9Sstevel@tonic-gate klwp_t *lwp = ttolwp(curthread); 975*7c478bd9Sstevel@tonic-gate size_t resid; 976*7c478bd9Sstevel@tonic-gate int error = 0; 977*7c478bd9Sstevel@tonic-gate label_t ljb; 978*7c478bd9Sstevel@tonic-gate 979*7c478bd9Sstevel@tonic-gate if ((resid = maxlength) == 0) 980*7c478bd9Sstevel@tonic-gate return (ENAMETOOLONG); 981*7c478bd9Sstevel@tonic-gate 982*7c478bd9Sstevel@tonic-gate while (resid && error == 0) { 983*7c478bd9Sstevel@tonic-gate int watchcode; 984*7c478bd9Sstevel@tonic-gate caddr_t vaddr; 985*7c478bd9Sstevel@tonic-gate size_t part; 986*7c478bd9Sstevel@tonic-gate size_t len; 987*7c478bd9Sstevel@tonic-gate size_t size; 988*7c478bd9Sstevel@tonic-gate int ta; 989*7c478bd9Sstevel@tonic-gate int mapped; 990*7c478bd9Sstevel@tonic-gate 991*7c478bd9Sstevel@tonic-gate if ((part = PAGESIZE - 992*7c478bd9Sstevel@tonic-gate (((uintptr_t)uaddr) & PAGEOFFSET)) > resid) 993*7c478bd9Sstevel@tonic-gate part = resid; 994*7c478bd9Sstevel@tonic-gate 995*7c478bd9Sstevel@tonic-gate if (!pr_is_watchpage((caddr_t)uaddr, S_READ)) 996*7c478bd9Sstevel@tonic-gate watchcode = 0; 997*7c478bd9Sstevel@tonic-gate else { 998*7c478bd9Sstevel@tonic-gate vaddr = (caddr_t)uaddr; 999*7c478bd9Sstevel@tonic-gate watchcode = pr_is_watchpoint(&vaddr, &ta, 1000*7c478bd9Sstevel@tonic-gate part, &len, S_READ); 1001*7c478bd9Sstevel@tonic-gate if (watchcode) { 1002*7c478bd9Sstevel@tonic-gate if (ta == 0) 1003*7c478bd9Sstevel@tonic-gate part = vaddr - uaddr; 1004*7c478bd9Sstevel@tonic-gate else { 1005*7c478bd9Sstevel@tonic-gate len += vaddr - uaddr; 1006*7c478bd9Sstevel@tonic-gate if (part > len) 1007*7c478bd9Sstevel@tonic-gate part = len; 1008*7c478bd9Sstevel@tonic-gate } 1009*7c478bd9Sstevel@tonic-gate } 1010*7c478bd9Sstevel@tonic-gate } 1011*7c478bd9Sstevel@tonic-gate 1012*7c478bd9Sstevel@tonic-gate /* 1013*7c478bd9Sstevel@tonic-gate * Copy the initial part, up to a watched address, if any. 1014*7c478bd9Sstevel@tonic-gate */ 1015*7c478bd9Sstevel@tonic-gate if (part != 0) { 1016*7c478bd9Sstevel@tonic-gate mapped = pr_mappage((caddr_t)uaddr, part, S_READ, 1); 1017*7c478bd9Sstevel@tonic-gate if (on_fault(&ljb)) 1018*7c478bd9Sstevel@tonic-gate error = EFAULT; 1019*7c478bd9Sstevel@tonic-gate else 1020*7c478bd9Sstevel@tonic-gate error = copyinstr_noerr(uaddr, kaddr, part, 1021*7c478bd9Sstevel@tonic-gate &size); 1022*7c478bd9Sstevel@tonic-gate no_fault(); 1023*7c478bd9Sstevel@tonic-gate if (mapped) 1024*7c478bd9Sstevel@tonic-gate pr_unmappage((caddr_t)uaddr, part, S_READ, 1); 1025*7c478bd9Sstevel@tonic-gate uaddr += size; 1026*7c478bd9Sstevel@tonic-gate kaddr += size; 1027*7c478bd9Sstevel@tonic-gate resid -= size; 1028*7c478bd9Sstevel@tonic-gate if (error == ENAMETOOLONG && resid > 0) 1029*7c478bd9Sstevel@tonic-gate error = 0; 1030*7c478bd9Sstevel@tonic-gate if (error != 0 || (watchcode && 1031*7c478bd9Sstevel@tonic-gate (uaddr < vaddr || kaddr[-1] == '\0'))) 1032*7c478bd9Sstevel@tonic-gate break; /* didn't reach the watched area */ 1033*7c478bd9Sstevel@tonic-gate } 1034*7c478bd9Sstevel@tonic-gate 1035*7c478bd9Sstevel@tonic-gate /* 1036*7c478bd9Sstevel@tonic-gate * If trapafter was specified, then copy through the 1037*7c478bd9Sstevel@tonic-gate * watched area before taking the watchpoint trap. 1038*7c478bd9Sstevel@tonic-gate */ 1039*7c478bd9Sstevel@tonic-gate while (resid && watchcode && ta && len > part && error == 0 && 1040*7c478bd9Sstevel@tonic-gate size == part && kaddr[-1] != '\0') { 1041*7c478bd9Sstevel@tonic-gate len -= part; 1042*7c478bd9Sstevel@tonic-gate if ((part = PAGESIZE) > resid) 1043*7c478bd9Sstevel@tonic-gate part = resid; 1044*7c478bd9Sstevel@tonic-gate if (part > len) 1045*7c478bd9Sstevel@tonic-gate part = len; 1046*7c478bd9Sstevel@tonic-gate mapped = pr_mappage((caddr_t)uaddr, part, S_READ, 1); 1047*7c478bd9Sstevel@tonic-gate if (on_fault(&ljb)) 1048*7c478bd9Sstevel@tonic-gate error = EFAULT; 1049*7c478bd9Sstevel@tonic-gate else 1050*7c478bd9Sstevel@tonic-gate error = copyinstr_noerr(uaddr, kaddr, part, 1051*7c478bd9Sstevel@tonic-gate &size); 1052*7c478bd9Sstevel@tonic-gate no_fault(); 1053*7c478bd9Sstevel@tonic-gate if (mapped) 1054*7c478bd9Sstevel@tonic-gate pr_unmappage((caddr_t)uaddr, part, S_READ, 1); 1055*7c478bd9Sstevel@tonic-gate uaddr += size; 1056*7c478bd9Sstevel@tonic-gate kaddr += size; 1057*7c478bd9Sstevel@tonic-gate resid -= size; 1058*7c478bd9Sstevel@tonic-gate if (error == ENAMETOOLONG && resid > 0) 1059*7c478bd9Sstevel@tonic-gate error = 0; 1060*7c478bd9Sstevel@tonic-gate } 1061*7c478bd9Sstevel@tonic-gate 1062*7c478bd9Sstevel@tonic-gate /* if we hit a watched address, do the watchpoint logic */ 1063*7c478bd9Sstevel@tonic-gate if (watchcode && 1064*7c478bd9Sstevel@tonic-gate (!sys_watchpoint(vaddr, watchcode, ta) || 1065*7c478bd9Sstevel@tonic-gate lwp->lwp_sysabort)) { 1066*7c478bd9Sstevel@tonic-gate lwp->lwp_sysabort = 0; 1067*7c478bd9Sstevel@tonic-gate error = EFAULT; 1068*7c478bd9Sstevel@tonic-gate break; 1069*7c478bd9Sstevel@tonic-gate } 1070*7c478bd9Sstevel@tonic-gate 1071*7c478bd9Sstevel@tonic-gate if (error == 0 && part != 0 && 1072*7c478bd9Sstevel@tonic-gate (size < part || kaddr[-1] == '\0')) 1073*7c478bd9Sstevel@tonic-gate break; 1074*7c478bd9Sstevel@tonic-gate } 1075*7c478bd9Sstevel@tonic-gate 1076*7c478bd9Sstevel@tonic-gate if (error != EFAULT && lencopied) 1077*7c478bd9Sstevel@tonic-gate *lencopied = maxlength - resid; 1078*7c478bd9Sstevel@tonic-gate return (error); 1079*7c478bd9Sstevel@tonic-gate } 1080*7c478bd9Sstevel@tonic-gate 1081*7c478bd9Sstevel@tonic-gate static int 1082*7c478bd9Sstevel@tonic-gate watch_copyoutstr( 1083*7c478bd9Sstevel@tonic-gate const char *kaddr, 1084*7c478bd9Sstevel@tonic-gate char *uaddr, 1085*7c478bd9Sstevel@tonic-gate size_t maxlength, 1086*7c478bd9Sstevel@tonic-gate size_t *lencopied) 1087*7c478bd9Sstevel@tonic-gate { 1088*7c478bd9Sstevel@tonic-gate klwp_t *lwp = ttolwp(curthread); 1089*7c478bd9Sstevel@tonic-gate size_t resid; 1090*7c478bd9Sstevel@tonic-gate int error = 0; 1091*7c478bd9Sstevel@tonic-gate label_t ljb; 1092*7c478bd9Sstevel@tonic-gate 1093*7c478bd9Sstevel@tonic-gate if ((resid = maxlength) == 0) 1094*7c478bd9Sstevel@tonic-gate return (ENAMETOOLONG); 1095*7c478bd9Sstevel@tonic-gate 1096*7c478bd9Sstevel@tonic-gate while (resid && error == 0) { 1097*7c478bd9Sstevel@tonic-gate int watchcode; 1098*7c478bd9Sstevel@tonic-gate caddr_t vaddr; 1099*7c478bd9Sstevel@tonic-gate size_t part; 1100*7c478bd9Sstevel@tonic-gate size_t len; 1101*7c478bd9Sstevel@tonic-gate size_t size; 1102*7c478bd9Sstevel@tonic-gate int ta; 1103*7c478bd9Sstevel@tonic-gate int mapped; 1104*7c478bd9Sstevel@tonic-gate 1105*7c478bd9Sstevel@tonic-gate if ((part = PAGESIZE - 1106*7c478bd9Sstevel@tonic-gate (((uintptr_t)uaddr) & PAGEOFFSET)) > resid) 1107*7c478bd9Sstevel@tonic-gate part = resid; 1108*7c478bd9Sstevel@tonic-gate 1109*7c478bd9Sstevel@tonic-gate if (!pr_is_watchpage(uaddr, S_WRITE)) { 1110*7c478bd9Sstevel@tonic-gate watchcode = 0; 1111*7c478bd9Sstevel@tonic-gate } else { 1112*7c478bd9Sstevel@tonic-gate vaddr = uaddr; 1113*7c478bd9Sstevel@tonic-gate watchcode = pr_is_watchpoint(&vaddr, &ta, 1114*7c478bd9Sstevel@tonic-gate part, &len, S_WRITE); 1115*7c478bd9Sstevel@tonic-gate if (watchcode && ta == 0) 1116*7c478bd9Sstevel@tonic-gate part = vaddr - uaddr; 1117*7c478bd9Sstevel@tonic-gate } 1118*7c478bd9Sstevel@tonic-gate 1119*7c478bd9Sstevel@tonic-gate /* 1120*7c478bd9Sstevel@tonic-gate * Copy the initial part, up to a watched address, if any. 1121*7c478bd9Sstevel@tonic-gate */ 1122*7c478bd9Sstevel@tonic-gate if (part != 0) { 1123*7c478bd9Sstevel@tonic-gate mapped = pr_mappage(uaddr, part, S_WRITE, 1); 1124*7c478bd9Sstevel@tonic-gate if (on_fault(&ljb)) 1125*7c478bd9Sstevel@tonic-gate error = EFAULT; 1126*7c478bd9Sstevel@tonic-gate else 1127*7c478bd9Sstevel@tonic-gate error = copyoutstr_noerr(kaddr, uaddr, part, 1128*7c478bd9Sstevel@tonic-gate &size); 1129*7c478bd9Sstevel@tonic-gate no_fault(); 1130*7c478bd9Sstevel@tonic-gate if (mapped) 1131*7c478bd9Sstevel@tonic-gate pr_unmappage(uaddr, part, S_WRITE, 1); 1132*7c478bd9Sstevel@tonic-gate uaddr += size; 1133*7c478bd9Sstevel@tonic-gate kaddr += size; 1134*7c478bd9Sstevel@tonic-gate resid -= size; 1135*7c478bd9Sstevel@tonic-gate if (error == ENAMETOOLONG && resid > 0) 1136*7c478bd9Sstevel@tonic-gate error = 0; 1137*7c478bd9Sstevel@tonic-gate if (error != 0 || (watchcode && 1138*7c478bd9Sstevel@tonic-gate (uaddr < vaddr || kaddr[-1] == '\0'))) 1139*7c478bd9Sstevel@tonic-gate break; /* didn't reach the watched area */ 1140*7c478bd9Sstevel@tonic-gate } 1141*7c478bd9Sstevel@tonic-gate 1142*7c478bd9Sstevel@tonic-gate /* 1143*7c478bd9Sstevel@tonic-gate * If trapafter was specified, then copy through the 1144*7c478bd9Sstevel@tonic-gate * watched area before taking the watchpoint trap. 1145*7c478bd9Sstevel@tonic-gate */ 1146*7c478bd9Sstevel@tonic-gate while (resid && watchcode && ta && len > part && error == 0 && 1147*7c478bd9Sstevel@tonic-gate size == part && kaddr[-1] != '\0') { 1148*7c478bd9Sstevel@tonic-gate len -= part; 1149*7c478bd9Sstevel@tonic-gate if ((part = PAGESIZE) > resid) 1150*7c478bd9Sstevel@tonic-gate part = resid; 1151*7c478bd9Sstevel@tonic-gate if (part > len) 1152*7c478bd9Sstevel@tonic-gate part = len; 1153*7c478bd9Sstevel@tonic-gate mapped = pr_mappage(uaddr, part, S_WRITE, 1); 1154*7c478bd9Sstevel@tonic-gate if (on_fault(&ljb)) 1155*7c478bd9Sstevel@tonic-gate error = EFAULT; 1156*7c478bd9Sstevel@tonic-gate else 1157*7c478bd9Sstevel@tonic-gate error = copyoutstr_noerr(kaddr, uaddr, part, 1158*7c478bd9Sstevel@tonic-gate &size); 1159*7c478bd9Sstevel@tonic-gate no_fault(); 1160*7c478bd9Sstevel@tonic-gate if (mapped) 1161*7c478bd9Sstevel@tonic-gate pr_unmappage(uaddr, part, S_WRITE, 1); 1162*7c478bd9Sstevel@tonic-gate uaddr += size; 1163*7c478bd9Sstevel@tonic-gate kaddr += size; 1164*7c478bd9Sstevel@tonic-gate resid -= size; 1165*7c478bd9Sstevel@tonic-gate if (error == ENAMETOOLONG && resid > 0) 1166*7c478bd9Sstevel@tonic-gate error = 0; 1167*7c478bd9Sstevel@tonic-gate } 1168*7c478bd9Sstevel@tonic-gate 1169*7c478bd9Sstevel@tonic-gate /* if we hit a watched address, do the watchpoint logic */ 1170*7c478bd9Sstevel@tonic-gate if (watchcode && 1171*7c478bd9Sstevel@tonic-gate (!sys_watchpoint(vaddr, watchcode, ta) || 1172*7c478bd9Sstevel@tonic-gate lwp->lwp_sysabort)) { 1173*7c478bd9Sstevel@tonic-gate lwp->lwp_sysabort = 0; 1174*7c478bd9Sstevel@tonic-gate error = EFAULT; 1175*7c478bd9Sstevel@tonic-gate break; 1176*7c478bd9Sstevel@tonic-gate } 1177*7c478bd9Sstevel@tonic-gate 1178*7c478bd9Sstevel@tonic-gate if (error == 0 && part != 0 && 1179*7c478bd9Sstevel@tonic-gate (size < part || kaddr[-1] == '\0')) 1180*7c478bd9Sstevel@tonic-gate break; 1181*7c478bd9Sstevel@tonic-gate } 1182*7c478bd9Sstevel@tonic-gate 1183*7c478bd9Sstevel@tonic-gate if (error != EFAULT && lencopied) 1184*7c478bd9Sstevel@tonic-gate *lencopied = maxlength - resid; 1185*7c478bd9Sstevel@tonic-gate return (error); 1186*7c478bd9Sstevel@tonic-gate } 1187*7c478bd9Sstevel@tonic-gate 1188*7c478bd9Sstevel@tonic-gate typedef int (*fuword_func)(const void *, void *); 1189*7c478bd9Sstevel@tonic-gate 1190*7c478bd9Sstevel@tonic-gate /* 1191*7c478bd9Sstevel@tonic-gate * Generic form of watch_fuword8(), watch_fuword16(), etc. 1192*7c478bd9Sstevel@tonic-gate */ 1193*7c478bd9Sstevel@tonic-gate static int 1194*7c478bd9Sstevel@tonic-gate watch_fuword(const void *addr, void *dst, fuword_func func, size_t size) 1195*7c478bd9Sstevel@tonic-gate { 1196*7c478bd9Sstevel@tonic-gate klwp_t *lwp = ttolwp(curthread); 1197*7c478bd9Sstevel@tonic-gate int watchcode; 1198*7c478bd9Sstevel@tonic-gate caddr_t vaddr; 1199*7c478bd9Sstevel@tonic-gate int mapped; 1200*7c478bd9Sstevel@tonic-gate int rv = 0; 1201*7c478bd9Sstevel@tonic-gate int ta; 1202*7c478bd9Sstevel@tonic-gate label_t ljb; 1203*7c478bd9Sstevel@tonic-gate 1204*7c478bd9Sstevel@tonic-gate for (;;) { 1205*7c478bd9Sstevel@tonic-gate 1206*7c478bd9Sstevel@tonic-gate vaddr = (caddr_t)addr; 1207*7c478bd9Sstevel@tonic-gate watchcode = pr_is_watchpoint(&vaddr, &ta, size, NULL, S_READ); 1208*7c478bd9Sstevel@tonic-gate if (watchcode == 0 || ta != 0) { 1209*7c478bd9Sstevel@tonic-gate mapped = pr_mappage((caddr_t)addr, size, S_READ, 1); 1210*7c478bd9Sstevel@tonic-gate if (on_fault(&ljb)) 1211*7c478bd9Sstevel@tonic-gate rv = -1; 1212*7c478bd9Sstevel@tonic-gate else 1213*7c478bd9Sstevel@tonic-gate (*func)(addr, dst); 1214*7c478bd9Sstevel@tonic-gate no_fault(); 1215*7c478bd9Sstevel@tonic-gate if (mapped) 1216*7c478bd9Sstevel@tonic-gate pr_unmappage((caddr_t)addr, size, S_READ, 1); 1217*7c478bd9Sstevel@tonic-gate } 1218*7c478bd9Sstevel@tonic-gate if (watchcode && 1219*7c478bd9Sstevel@tonic-gate (!sys_watchpoint(vaddr, watchcode, ta) || 1220*7c478bd9Sstevel@tonic-gate lwp->lwp_sysabort)) { 1221*7c478bd9Sstevel@tonic-gate lwp->lwp_sysabort = 0; 1222*7c478bd9Sstevel@tonic-gate rv = -1; 1223*7c478bd9Sstevel@tonic-gate break; 1224*7c478bd9Sstevel@tonic-gate } 1225*7c478bd9Sstevel@tonic-gate if (watchcode == 0 || ta != 0) 1226*7c478bd9Sstevel@tonic-gate break; 1227*7c478bd9Sstevel@tonic-gate } 1228*7c478bd9Sstevel@tonic-gate 1229*7c478bd9Sstevel@tonic-gate return (rv); 1230*7c478bd9Sstevel@tonic-gate } 1231*7c478bd9Sstevel@tonic-gate 1232*7c478bd9Sstevel@tonic-gate static int 1233*7c478bd9Sstevel@tonic-gate watch_fuword8(const void *addr, uint8_t *dst) 1234*7c478bd9Sstevel@tonic-gate { 1235*7c478bd9Sstevel@tonic-gate return (watch_fuword(addr, dst, (fuword_func)fuword8_noerr, 1236*7c478bd9Sstevel@tonic-gate sizeof (*dst))); 1237*7c478bd9Sstevel@tonic-gate } 1238*7c478bd9Sstevel@tonic-gate 1239*7c478bd9Sstevel@tonic-gate static int 1240*7c478bd9Sstevel@tonic-gate watch_fuword16(const void *addr, uint16_t *dst) 1241*7c478bd9Sstevel@tonic-gate { 1242*7c478bd9Sstevel@tonic-gate return (watch_fuword(addr, dst, (fuword_func)fuword16_noerr, 1243*7c478bd9Sstevel@tonic-gate sizeof (*dst))); 1244*7c478bd9Sstevel@tonic-gate } 1245*7c478bd9Sstevel@tonic-gate 1246*7c478bd9Sstevel@tonic-gate static int 1247*7c478bd9Sstevel@tonic-gate watch_fuword32(const void *addr, uint32_t *dst) 1248*7c478bd9Sstevel@tonic-gate { 1249*7c478bd9Sstevel@tonic-gate return (watch_fuword(addr, dst, (fuword_func)fuword32_noerr, 1250*7c478bd9Sstevel@tonic-gate sizeof (*dst))); 1251*7c478bd9Sstevel@tonic-gate } 1252*7c478bd9Sstevel@tonic-gate 1253*7c478bd9Sstevel@tonic-gate #ifdef _LP64 1254*7c478bd9Sstevel@tonic-gate static int 1255*7c478bd9Sstevel@tonic-gate watch_fuword64(const void *addr, uint64_t *dst) 1256*7c478bd9Sstevel@tonic-gate { 1257*7c478bd9Sstevel@tonic-gate return (watch_fuword(addr, dst, (fuword_func)fuword64_noerr, 1258*7c478bd9Sstevel@tonic-gate sizeof (*dst))); 1259*7c478bd9Sstevel@tonic-gate } 1260*7c478bd9Sstevel@tonic-gate #endif 1261*7c478bd9Sstevel@tonic-gate 1262*7c478bd9Sstevel@tonic-gate 1263*7c478bd9Sstevel@tonic-gate static int 1264*7c478bd9Sstevel@tonic-gate watch_suword8(void *addr, uint8_t value) 1265*7c478bd9Sstevel@tonic-gate { 1266*7c478bd9Sstevel@tonic-gate klwp_t *lwp = ttolwp(curthread); 1267*7c478bd9Sstevel@tonic-gate int watchcode; 1268*7c478bd9Sstevel@tonic-gate caddr_t vaddr; 1269*7c478bd9Sstevel@tonic-gate int mapped; 1270*7c478bd9Sstevel@tonic-gate int rv = 0; 1271*7c478bd9Sstevel@tonic-gate int ta; 1272*7c478bd9Sstevel@tonic-gate label_t ljb; 1273*7c478bd9Sstevel@tonic-gate 1274*7c478bd9Sstevel@tonic-gate for (;;) { 1275*7c478bd9Sstevel@tonic-gate 1276*7c478bd9Sstevel@tonic-gate vaddr = (caddr_t)addr; 1277*7c478bd9Sstevel@tonic-gate watchcode = pr_is_watchpoint(&vaddr, &ta, sizeof (value), NULL, 1278*7c478bd9Sstevel@tonic-gate S_WRITE); 1279*7c478bd9Sstevel@tonic-gate if (watchcode == 0 || ta != 0) { 1280*7c478bd9Sstevel@tonic-gate mapped = pr_mappage((caddr_t)addr, sizeof (value), 1281*7c478bd9Sstevel@tonic-gate S_WRITE, 1); 1282*7c478bd9Sstevel@tonic-gate if (on_fault(&ljb)) 1283*7c478bd9Sstevel@tonic-gate rv = -1; 1284*7c478bd9Sstevel@tonic-gate else 1285*7c478bd9Sstevel@tonic-gate suword8_noerr(addr, value); 1286*7c478bd9Sstevel@tonic-gate no_fault(); 1287*7c478bd9Sstevel@tonic-gate if (mapped) 1288*7c478bd9Sstevel@tonic-gate pr_unmappage((caddr_t)addr, sizeof (value), 1289*7c478bd9Sstevel@tonic-gate S_WRITE, 1); 1290*7c478bd9Sstevel@tonic-gate } 1291*7c478bd9Sstevel@tonic-gate if (watchcode && 1292*7c478bd9Sstevel@tonic-gate (!sys_watchpoint(vaddr, watchcode, ta) || 1293*7c478bd9Sstevel@tonic-gate lwp->lwp_sysabort)) { 1294*7c478bd9Sstevel@tonic-gate lwp->lwp_sysabort = 0; 1295*7c478bd9Sstevel@tonic-gate rv = -1; 1296*7c478bd9Sstevel@tonic-gate break; 1297*7c478bd9Sstevel@tonic-gate } 1298*7c478bd9Sstevel@tonic-gate if (watchcode == 0 || ta != 0) 1299*7c478bd9Sstevel@tonic-gate break; 1300*7c478bd9Sstevel@tonic-gate } 1301*7c478bd9Sstevel@tonic-gate 1302*7c478bd9Sstevel@tonic-gate return (rv); 1303*7c478bd9Sstevel@tonic-gate } 1304*7c478bd9Sstevel@tonic-gate 1305*7c478bd9Sstevel@tonic-gate static int 1306*7c478bd9Sstevel@tonic-gate watch_suword16(void *addr, uint16_t value) 1307*7c478bd9Sstevel@tonic-gate { 1308*7c478bd9Sstevel@tonic-gate klwp_t *lwp = ttolwp(curthread); 1309*7c478bd9Sstevel@tonic-gate int watchcode; 1310*7c478bd9Sstevel@tonic-gate caddr_t vaddr; 1311*7c478bd9Sstevel@tonic-gate int mapped; 1312*7c478bd9Sstevel@tonic-gate int rv = 0; 1313*7c478bd9Sstevel@tonic-gate int ta; 1314*7c478bd9Sstevel@tonic-gate label_t ljb; 1315*7c478bd9Sstevel@tonic-gate 1316*7c478bd9Sstevel@tonic-gate for (;;) { 1317*7c478bd9Sstevel@tonic-gate 1318*7c478bd9Sstevel@tonic-gate vaddr = (caddr_t)addr; 1319*7c478bd9Sstevel@tonic-gate watchcode = pr_is_watchpoint(&vaddr, &ta, sizeof (value), NULL, 1320*7c478bd9Sstevel@tonic-gate S_WRITE); 1321*7c478bd9Sstevel@tonic-gate if (watchcode == 0 || ta != 0) { 1322*7c478bd9Sstevel@tonic-gate mapped = pr_mappage((caddr_t)addr, sizeof (value), 1323*7c478bd9Sstevel@tonic-gate S_WRITE, 1); 1324*7c478bd9Sstevel@tonic-gate if (on_fault(&ljb)) 1325*7c478bd9Sstevel@tonic-gate rv = -1; 1326*7c478bd9Sstevel@tonic-gate else 1327*7c478bd9Sstevel@tonic-gate suword16_noerr(addr, value); 1328*7c478bd9Sstevel@tonic-gate no_fault(); 1329*7c478bd9Sstevel@tonic-gate if (mapped) 1330*7c478bd9Sstevel@tonic-gate pr_unmappage((caddr_t)addr, sizeof (value), 1331*7c478bd9Sstevel@tonic-gate S_WRITE, 1); 1332*7c478bd9Sstevel@tonic-gate } 1333*7c478bd9Sstevel@tonic-gate if (watchcode && 1334*7c478bd9Sstevel@tonic-gate (!sys_watchpoint(vaddr, watchcode, ta) || 1335*7c478bd9Sstevel@tonic-gate lwp->lwp_sysabort)) { 1336*7c478bd9Sstevel@tonic-gate lwp->lwp_sysabort = 0; 1337*7c478bd9Sstevel@tonic-gate rv = -1; 1338*7c478bd9Sstevel@tonic-gate break; 1339*7c478bd9Sstevel@tonic-gate } 1340*7c478bd9Sstevel@tonic-gate if (watchcode == 0 || ta != 0) 1341*7c478bd9Sstevel@tonic-gate break; 1342*7c478bd9Sstevel@tonic-gate } 1343*7c478bd9Sstevel@tonic-gate 1344*7c478bd9Sstevel@tonic-gate return (rv); 1345*7c478bd9Sstevel@tonic-gate } 1346*7c478bd9Sstevel@tonic-gate 1347*7c478bd9Sstevel@tonic-gate static int 1348*7c478bd9Sstevel@tonic-gate watch_suword32(void *addr, uint32_t value) 1349*7c478bd9Sstevel@tonic-gate { 1350*7c478bd9Sstevel@tonic-gate klwp_t *lwp = ttolwp(curthread); 1351*7c478bd9Sstevel@tonic-gate int watchcode; 1352*7c478bd9Sstevel@tonic-gate caddr_t vaddr; 1353*7c478bd9Sstevel@tonic-gate int mapped; 1354*7c478bd9Sstevel@tonic-gate int rv = 0; 1355*7c478bd9Sstevel@tonic-gate int ta; 1356*7c478bd9Sstevel@tonic-gate label_t ljb; 1357*7c478bd9Sstevel@tonic-gate 1358*7c478bd9Sstevel@tonic-gate for (;;) { 1359*7c478bd9Sstevel@tonic-gate 1360*7c478bd9Sstevel@tonic-gate vaddr = (caddr_t)addr; 1361*7c478bd9Sstevel@tonic-gate watchcode = pr_is_watchpoint(&vaddr, &ta, sizeof (value), NULL, 1362*7c478bd9Sstevel@tonic-gate S_WRITE); 1363*7c478bd9Sstevel@tonic-gate if (watchcode == 0 || ta != 0) { 1364*7c478bd9Sstevel@tonic-gate mapped = pr_mappage((caddr_t)addr, sizeof (value), 1365*7c478bd9Sstevel@tonic-gate S_WRITE, 1); 1366*7c478bd9Sstevel@tonic-gate if (on_fault(&ljb)) 1367*7c478bd9Sstevel@tonic-gate rv = -1; 1368*7c478bd9Sstevel@tonic-gate else 1369*7c478bd9Sstevel@tonic-gate suword32_noerr(addr, value); 1370*7c478bd9Sstevel@tonic-gate no_fault(); 1371*7c478bd9Sstevel@tonic-gate if (mapped) 1372*7c478bd9Sstevel@tonic-gate pr_unmappage((caddr_t)addr, sizeof (value), 1373*7c478bd9Sstevel@tonic-gate S_WRITE, 1); 1374*7c478bd9Sstevel@tonic-gate } 1375*7c478bd9Sstevel@tonic-gate if (watchcode && 1376*7c478bd9Sstevel@tonic-gate (!sys_watchpoint(vaddr, watchcode, ta) || 1377*7c478bd9Sstevel@tonic-gate lwp->lwp_sysabort)) { 1378*7c478bd9Sstevel@tonic-gate lwp->lwp_sysabort = 0; 1379*7c478bd9Sstevel@tonic-gate rv = -1; 1380*7c478bd9Sstevel@tonic-gate break; 1381*7c478bd9Sstevel@tonic-gate } 1382*7c478bd9Sstevel@tonic-gate if (watchcode == 0 || ta != 0) 1383*7c478bd9Sstevel@tonic-gate break; 1384*7c478bd9Sstevel@tonic-gate } 1385*7c478bd9Sstevel@tonic-gate 1386*7c478bd9Sstevel@tonic-gate return (rv); 1387*7c478bd9Sstevel@tonic-gate } 1388*7c478bd9Sstevel@tonic-gate 1389*7c478bd9Sstevel@tonic-gate #ifdef _LP64 1390*7c478bd9Sstevel@tonic-gate static int 1391*7c478bd9Sstevel@tonic-gate watch_suword64(void *addr, uint64_t value) 1392*7c478bd9Sstevel@tonic-gate { 1393*7c478bd9Sstevel@tonic-gate klwp_t *lwp = ttolwp(curthread); 1394*7c478bd9Sstevel@tonic-gate int watchcode; 1395*7c478bd9Sstevel@tonic-gate caddr_t vaddr; 1396*7c478bd9Sstevel@tonic-gate int mapped; 1397*7c478bd9Sstevel@tonic-gate int rv = 0; 1398*7c478bd9Sstevel@tonic-gate int ta; 1399*7c478bd9Sstevel@tonic-gate label_t ljb; 1400*7c478bd9Sstevel@tonic-gate 1401*7c478bd9Sstevel@tonic-gate for (;;) { 1402*7c478bd9Sstevel@tonic-gate 1403*7c478bd9Sstevel@tonic-gate vaddr = (caddr_t)addr; 1404*7c478bd9Sstevel@tonic-gate watchcode = pr_is_watchpoint(&vaddr, &ta, sizeof (value), NULL, 1405*7c478bd9Sstevel@tonic-gate S_WRITE); 1406*7c478bd9Sstevel@tonic-gate if (watchcode == 0 || ta != 0) { 1407*7c478bd9Sstevel@tonic-gate mapped = pr_mappage((caddr_t)addr, sizeof (value), 1408*7c478bd9Sstevel@tonic-gate S_WRITE, 1); 1409*7c478bd9Sstevel@tonic-gate if (on_fault(&ljb)) 1410*7c478bd9Sstevel@tonic-gate rv = -1; 1411*7c478bd9Sstevel@tonic-gate else 1412*7c478bd9Sstevel@tonic-gate suword64_noerr(addr, value); 1413*7c478bd9Sstevel@tonic-gate no_fault(); 1414*7c478bd9Sstevel@tonic-gate if (mapped) 1415*7c478bd9Sstevel@tonic-gate pr_unmappage((caddr_t)addr, sizeof (value), 1416*7c478bd9Sstevel@tonic-gate S_WRITE, 1); 1417*7c478bd9Sstevel@tonic-gate } 1418*7c478bd9Sstevel@tonic-gate if (watchcode && 1419*7c478bd9Sstevel@tonic-gate (!sys_watchpoint(vaddr, watchcode, ta) || 1420*7c478bd9Sstevel@tonic-gate lwp->lwp_sysabort)) { 1421*7c478bd9Sstevel@tonic-gate lwp->lwp_sysabort = 0; 1422*7c478bd9Sstevel@tonic-gate rv = -1; 1423*7c478bd9Sstevel@tonic-gate break; 1424*7c478bd9Sstevel@tonic-gate } 1425*7c478bd9Sstevel@tonic-gate if (watchcode == 0 || ta != 0) 1426*7c478bd9Sstevel@tonic-gate break; 1427*7c478bd9Sstevel@tonic-gate } 1428*7c478bd9Sstevel@tonic-gate 1429*7c478bd9Sstevel@tonic-gate return (rv); 1430*7c478bd9Sstevel@tonic-gate } 1431*7c478bd9Sstevel@tonic-gate #endif /* _LP64 */ 1432*7c478bd9Sstevel@tonic-gate 1433*7c478bd9Sstevel@tonic-gate /* 1434*7c478bd9Sstevel@tonic-gate * Check for watched addresses in the given address space. 1435*7c478bd9Sstevel@tonic-gate * Return 1 if this is true, otherwise 0. 1436*7c478bd9Sstevel@tonic-gate */ 1437*7c478bd9Sstevel@tonic-gate static int 1438*7c478bd9Sstevel@tonic-gate pr_is_watched(caddr_t base, size_t len, int rw) 1439*7c478bd9Sstevel@tonic-gate { 1440*7c478bd9Sstevel@tonic-gate caddr_t saddr = (caddr_t)((uintptr_t)base & (uintptr_t)PAGEMASK); 1441*7c478bd9Sstevel@tonic-gate caddr_t eaddr = base + len; 1442*7c478bd9Sstevel@tonic-gate caddr_t paddr; 1443*7c478bd9Sstevel@tonic-gate 1444*7c478bd9Sstevel@tonic-gate for (paddr = saddr; paddr < eaddr; paddr += PAGESIZE) { 1445*7c478bd9Sstevel@tonic-gate if (pr_is_watchpage(paddr, rw)) 1446*7c478bd9Sstevel@tonic-gate return (1); 1447*7c478bd9Sstevel@tonic-gate } 1448*7c478bd9Sstevel@tonic-gate 1449*7c478bd9Sstevel@tonic-gate return (0); 1450*7c478bd9Sstevel@tonic-gate } 1451*7c478bd9Sstevel@tonic-gate 1452*7c478bd9Sstevel@tonic-gate /* 1453*7c478bd9Sstevel@tonic-gate * Wrapper for the physio() function. 1454*7c478bd9Sstevel@tonic-gate * Splits one uio operation with multiple iovecs into uio operations with 1455*7c478bd9Sstevel@tonic-gate * only one iovecs to do the watchpoint handling separately for each iovecs. 1456*7c478bd9Sstevel@tonic-gate */ 1457*7c478bd9Sstevel@tonic-gate static int 1458*7c478bd9Sstevel@tonic-gate watch_physio(int (*strat)(struct buf *), struct buf *bp, dev_t dev, 1459*7c478bd9Sstevel@tonic-gate int rw, void (*mincnt)(struct buf *), struct uio *uio) 1460*7c478bd9Sstevel@tonic-gate { 1461*7c478bd9Sstevel@tonic-gate struct uio auio; 1462*7c478bd9Sstevel@tonic-gate struct iovec *iov; 1463*7c478bd9Sstevel@tonic-gate caddr_t base; 1464*7c478bd9Sstevel@tonic-gate size_t len; 1465*7c478bd9Sstevel@tonic-gate int seg_rw; 1466*7c478bd9Sstevel@tonic-gate int error = 0; 1467*7c478bd9Sstevel@tonic-gate 1468*7c478bd9Sstevel@tonic-gate if (uio->uio_segflg == UIO_SYSSPACE) 1469*7c478bd9Sstevel@tonic-gate return (default_physio(strat, bp, dev, rw, mincnt, uio)); 1470*7c478bd9Sstevel@tonic-gate 1471*7c478bd9Sstevel@tonic-gate seg_rw = (rw == B_READ) ? S_WRITE : S_READ; 1472*7c478bd9Sstevel@tonic-gate 1473*7c478bd9Sstevel@tonic-gate while (uio->uio_iovcnt > 0) { 1474*7c478bd9Sstevel@tonic-gate if (uio->uio_resid == 0) { 1475*7c478bd9Sstevel@tonic-gate /* 1476*7c478bd9Sstevel@tonic-gate * Make sure to return the uio structure with the 1477*7c478bd9Sstevel@tonic-gate * same values as default_physio() does. 1478*7c478bd9Sstevel@tonic-gate */ 1479*7c478bd9Sstevel@tonic-gate uio->uio_iov++; 1480*7c478bd9Sstevel@tonic-gate uio->uio_iovcnt--; 1481*7c478bd9Sstevel@tonic-gate continue; 1482*7c478bd9Sstevel@tonic-gate } 1483*7c478bd9Sstevel@tonic-gate 1484*7c478bd9Sstevel@tonic-gate iov = uio->uio_iov; 1485*7c478bd9Sstevel@tonic-gate len = MIN(iov->iov_len, uio->uio_resid); 1486*7c478bd9Sstevel@tonic-gate 1487*7c478bd9Sstevel@tonic-gate auio.uio_iovcnt = 1; 1488*7c478bd9Sstevel@tonic-gate auio.uio_iov = iov; 1489*7c478bd9Sstevel@tonic-gate auio.uio_resid = len; 1490*7c478bd9Sstevel@tonic-gate auio.uio_loffset = uio->uio_loffset; 1491*7c478bd9Sstevel@tonic-gate auio.uio_llimit = uio->uio_llimit; 1492*7c478bd9Sstevel@tonic-gate auio.uio_fmode = uio->uio_fmode; 1493*7c478bd9Sstevel@tonic-gate auio.uio_extflg = uio->uio_extflg; 1494*7c478bd9Sstevel@tonic-gate auio.uio_segflg = uio->uio_segflg; 1495*7c478bd9Sstevel@tonic-gate 1496*7c478bd9Sstevel@tonic-gate base = iov->iov_base; 1497*7c478bd9Sstevel@tonic-gate 1498*7c478bd9Sstevel@tonic-gate if (!pr_is_watched(base, len, seg_rw)) { 1499*7c478bd9Sstevel@tonic-gate /* 1500*7c478bd9Sstevel@tonic-gate * The given memory references don't cover a 1501*7c478bd9Sstevel@tonic-gate * watched page. 1502*7c478bd9Sstevel@tonic-gate */ 1503*7c478bd9Sstevel@tonic-gate error = default_physio(strat, bp, dev, rw, mincnt, 1504*7c478bd9Sstevel@tonic-gate &auio); 1505*7c478bd9Sstevel@tonic-gate 1506*7c478bd9Sstevel@tonic-gate /* Update uio with values from auio. */ 1507*7c478bd9Sstevel@tonic-gate len -= auio.uio_resid; 1508*7c478bd9Sstevel@tonic-gate uio->uio_resid -= len; 1509*7c478bd9Sstevel@tonic-gate uio->uio_loffset += len; 1510*7c478bd9Sstevel@tonic-gate 1511*7c478bd9Sstevel@tonic-gate /* 1512*7c478bd9Sstevel@tonic-gate * Return if an error occurred or not all data 1513*7c478bd9Sstevel@tonic-gate * was copied. 1514*7c478bd9Sstevel@tonic-gate */ 1515*7c478bd9Sstevel@tonic-gate if (auio.uio_resid || error) 1516*7c478bd9Sstevel@tonic-gate break; 1517*7c478bd9Sstevel@tonic-gate uio->uio_iov++; 1518*7c478bd9Sstevel@tonic-gate uio->uio_iovcnt--; 1519*7c478bd9Sstevel@tonic-gate } else { 1520*7c478bd9Sstevel@tonic-gate int mapped, watchcode, ta; 1521*7c478bd9Sstevel@tonic-gate caddr_t vaddr = base; 1522*7c478bd9Sstevel@tonic-gate klwp_t *lwp = ttolwp(curthread); 1523*7c478bd9Sstevel@tonic-gate 1524*7c478bd9Sstevel@tonic-gate watchcode = pr_is_watchpoint(&vaddr, &ta, len, 1525*7c478bd9Sstevel@tonic-gate NULL, seg_rw); 1526*7c478bd9Sstevel@tonic-gate 1527*7c478bd9Sstevel@tonic-gate if (watchcode == 0 || ta != 0) { 1528*7c478bd9Sstevel@tonic-gate /* 1529*7c478bd9Sstevel@tonic-gate * Do the io if the given memory references 1530*7c478bd9Sstevel@tonic-gate * don't cover a watched area (watchcode=0) 1531*7c478bd9Sstevel@tonic-gate * or if WA_TRAPAFTER was specified. 1532*7c478bd9Sstevel@tonic-gate */ 1533*7c478bd9Sstevel@tonic-gate mapped = pr_mappage(base, len, seg_rw, 1); 1534*7c478bd9Sstevel@tonic-gate error = default_physio(strat, bp, dev, rw, 1535*7c478bd9Sstevel@tonic-gate mincnt, &auio); 1536*7c478bd9Sstevel@tonic-gate if (mapped) 1537*7c478bd9Sstevel@tonic-gate pr_unmappage(base, len, seg_rw, 1); 1538*7c478bd9Sstevel@tonic-gate 1539*7c478bd9Sstevel@tonic-gate len -= auio.uio_resid; 1540*7c478bd9Sstevel@tonic-gate uio->uio_resid -= len; 1541*7c478bd9Sstevel@tonic-gate uio->uio_loffset += len; 1542*7c478bd9Sstevel@tonic-gate } 1543*7c478bd9Sstevel@tonic-gate 1544*7c478bd9Sstevel@tonic-gate /* 1545*7c478bd9Sstevel@tonic-gate * If we hit a watched address, do the watchpoint logic. 1546*7c478bd9Sstevel@tonic-gate */ 1547*7c478bd9Sstevel@tonic-gate if (watchcode && 1548*7c478bd9Sstevel@tonic-gate (!sys_watchpoint(vaddr, watchcode, ta) || 1549*7c478bd9Sstevel@tonic-gate lwp->lwp_sysabort)) { 1550*7c478bd9Sstevel@tonic-gate lwp->lwp_sysabort = 0; 1551*7c478bd9Sstevel@tonic-gate return (EFAULT); 1552*7c478bd9Sstevel@tonic-gate } 1553*7c478bd9Sstevel@tonic-gate 1554*7c478bd9Sstevel@tonic-gate /* 1555*7c478bd9Sstevel@tonic-gate * Check for errors from default_physio(). 1556*7c478bd9Sstevel@tonic-gate */ 1557*7c478bd9Sstevel@tonic-gate if (watchcode == 0 || ta != 0) { 1558*7c478bd9Sstevel@tonic-gate if (auio.uio_resid || error) 1559*7c478bd9Sstevel@tonic-gate break; 1560*7c478bd9Sstevel@tonic-gate uio->uio_iov++; 1561*7c478bd9Sstevel@tonic-gate uio->uio_iovcnt--; 1562*7c478bd9Sstevel@tonic-gate } 1563*7c478bd9Sstevel@tonic-gate } 1564*7c478bd9Sstevel@tonic-gate } 1565*7c478bd9Sstevel@tonic-gate 1566*7c478bd9Sstevel@tonic-gate return (error); 1567*7c478bd9Sstevel@tonic-gate } 1568*7c478bd9Sstevel@tonic-gate 1569*7c478bd9Sstevel@tonic-gate int 1570*7c478bd9Sstevel@tonic-gate wa_compare(const void *a, const void *b) 1571*7c478bd9Sstevel@tonic-gate { 1572*7c478bd9Sstevel@tonic-gate const watched_area_t *pa = a; 1573*7c478bd9Sstevel@tonic-gate const watched_area_t *pb = b; 1574*7c478bd9Sstevel@tonic-gate 1575*7c478bd9Sstevel@tonic-gate if (pa->wa_vaddr < pb->wa_vaddr) 1576*7c478bd9Sstevel@tonic-gate return (-1); 1577*7c478bd9Sstevel@tonic-gate else if (pa->wa_vaddr > pb->wa_vaddr) 1578*7c478bd9Sstevel@tonic-gate return (1); 1579*7c478bd9Sstevel@tonic-gate else 1580*7c478bd9Sstevel@tonic-gate return (0); 1581*7c478bd9Sstevel@tonic-gate } 1582*7c478bd9Sstevel@tonic-gate 1583*7c478bd9Sstevel@tonic-gate int 1584*7c478bd9Sstevel@tonic-gate wp_compare(const void *a, const void *b) 1585*7c478bd9Sstevel@tonic-gate { 1586*7c478bd9Sstevel@tonic-gate const watched_page_t *pa = a; 1587*7c478bd9Sstevel@tonic-gate const watched_page_t *pb = b; 1588*7c478bd9Sstevel@tonic-gate 1589*7c478bd9Sstevel@tonic-gate if (pa->wp_vaddr < pb->wp_vaddr) 1590*7c478bd9Sstevel@tonic-gate return (-1); 1591*7c478bd9Sstevel@tonic-gate else if (pa->wp_vaddr > pb->wp_vaddr) 1592*7c478bd9Sstevel@tonic-gate return (1); 1593*7c478bd9Sstevel@tonic-gate else 1594*7c478bd9Sstevel@tonic-gate return (0); 1595*7c478bd9Sstevel@tonic-gate } 1596*7c478bd9Sstevel@tonic-gate 1597*7c478bd9Sstevel@tonic-gate /* 1598*7c478bd9Sstevel@tonic-gate * Given an address range, finds the first watched area which overlaps some or 1599*7c478bd9Sstevel@tonic-gate * all of the range. 1600*7c478bd9Sstevel@tonic-gate */ 1601*7c478bd9Sstevel@tonic-gate watched_area_t * 1602*7c478bd9Sstevel@tonic-gate pr_find_watched_area(proc_t *p, watched_area_t *pwa, avl_index_t *where) 1603*7c478bd9Sstevel@tonic-gate { 1604*7c478bd9Sstevel@tonic-gate caddr_t vaddr = pwa->wa_vaddr; 1605*7c478bd9Sstevel@tonic-gate caddr_t eaddr = pwa->wa_eaddr; 1606*7c478bd9Sstevel@tonic-gate watched_area_t *wap; 1607*7c478bd9Sstevel@tonic-gate avl_index_t real_where; 1608*7c478bd9Sstevel@tonic-gate 1609*7c478bd9Sstevel@tonic-gate /* First, check if there is an exact match. */ 1610*7c478bd9Sstevel@tonic-gate wap = avl_find(&p->p_warea, pwa, &real_where); 1611*7c478bd9Sstevel@tonic-gate 1612*7c478bd9Sstevel@tonic-gate 1613*7c478bd9Sstevel@tonic-gate /* Check to see if we overlap with the previous area. */ 1614*7c478bd9Sstevel@tonic-gate if (wap == NULL) { 1615*7c478bd9Sstevel@tonic-gate wap = avl_nearest(&p->p_warea, real_where, AVL_BEFORE); 1616*7c478bd9Sstevel@tonic-gate if (wap != NULL && 1617*7c478bd9Sstevel@tonic-gate (vaddr >= wap->wa_eaddr || eaddr <= wap->wa_vaddr)) 1618*7c478bd9Sstevel@tonic-gate wap = NULL; 1619*7c478bd9Sstevel@tonic-gate } 1620*7c478bd9Sstevel@tonic-gate 1621*7c478bd9Sstevel@tonic-gate /* Try the next area. */ 1622*7c478bd9Sstevel@tonic-gate if (wap == NULL) { 1623*7c478bd9Sstevel@tonic-gate wap = avl_nearest(&p->p_warea, real_where, AVL_AFTER); 1624*7c478bd9Sstevel@tonic-gate if (wap != NULL && 1625*7c478bd9Sstevel@tonic-gate (vaddr >= wap->wa_eaddr || eaddr <= wap->wa_vaddr)) 1626*7c478bd9Sstevel@tonic-gate wap = NULL; 1627*7c478bd9Sstevel@tonic-gate } 1628*7c478bd9Sstevel@tonic-gate 1629*7c478bd9Sstevel@tonic-gate if (where) 1630*7c478bd9Sstevel@tonic-gate *where = real_where; 1631*7c478bd9Sstevel@tonic-gate 1632*7c478bd9Sstevel@tonic-gate return (wap); 1633*7c478bd9Sstevel@tonic-gate } 1634*7c478bd9Sstevel@tonic-gate 1635*7c478bd9Sstevel@tonic-gate void 1636*7c478bd9Sstevel@tonic-gate watch_enable(kthread_id_t t) 1637*7c478bd9Sstevel@tonic-gate { 1638*7c478bd9Sstevel@tonic-gate t->t_proc_flag |= TP_WATCHPT; 1639*7c478bd9Sstevel@tonic-gate install_copyops(t, &watch_copyops); 1640*7c478bd9Sstevel@tonic-gate } 1641*7c478bd9Sstevel@tonic-gate 1642*7c478bd9Sstevel@tonic-gate void 1643*7c478bd9Sstevel@tonic-gate watch_disable(kthread_id_t t) 1644*7c478bd9Sstevel@tonic-gate { 1645*7c478bd9Sstevel@tonic-gate t->t_proc_flag &= ~TP_WATCHPT; 1646*7c478bd9Sstevel@tonic-gate remove_copyops(t); 1647*7c478bd9Sstevel@tonic-gate } 1648*7c478bd9Sstevel@tonic-gate 1649*7c478bd9Sstevel@tonic-gate int 1650*7c478bd9Sstevel@tonic-gate copyin_nowatch(const void *uaddr, void *kaddr, size_t len) 1651*7c478bd9Sstevel@tonic-gate { 1652*7c478bd9Sstevel@tonic-gate int watched, ret; 1653*7c478bd9Sstevel@tonic-gate 1654*7c478bd9Sstevel@tonic-gate watched = watch_disable_addr(uaddr, len, S_READ); 1655*7c478bd9Sstevel@tonic-gate ret = copyin(uaddr, kaddr, len); 1656*7c478bd9Sstevel@tonic-gate if (watched) 1657*7c478bd9Sstevel@tonic-gate watch_enable_addr(uaddr, len, S_READ); 1658*7c478bd9Sstevel@tonic-gate 1659*7c478bd9Sstevel@tonic-gate return (ret); 1660*7c478bd9Sstevel@tonic-gate } 1661*7c478bd9Sstevel@tonic-gate 1662*7c478bd9Sstevel@tonic-gate int 1663*7c478bd9Sstevel@tonic-gate copyout_nowatch(const void *kaddr, void *uaddr, size_t len) 1664*7c478bd9Sstevel@tonic-gate { 1665*7c478bd9Sstevel@tonic-gate int watched, ret; 1666*7c478bd9Sstevel@tonic-gate 1667*7c478bd9Sstevel@tonic-gate watched = watch_disable_addr(uaddr, len, S_WRITE); 1668*7c478bd9Sstevel@tonic-gate ret = copyout(kaddr, uaddr, len); 1669*7c478bd9Sstevel@tonic-gate if (watched) 1670*7c478bd9Sstevel@tonic-gate watch_enable_addr(uaddr, len, S_WRITE); 1671*7c478bd9Sstevel@tonic-gate 1672*7c478bd9Sstevel@tonic-gate return (ret); 1673*7c478bd9Sstevel@tonic-gate } 1674*7c478bd9Sstevel@tonic-gate 1675*7c478bd9Sstevel@tonic-gate #ifdef _LP64 1676*7c478bd9Sstevel@tonic-gate int 1677*7c478bd9Sstevel@tonic-gate fuword64_nowatch(const void *addr, uint64_t *value) 1678*7c478bd9Sstevel@tonic-gate { 1679*7c478bd9Sstevel@tonic-gate int watched, ret; 1680*7c478bd9Sstevel@tonic-gate 1681*7c478bd9Sstevel@tonic-gate watched = watch_disable_addr(addr, sizeof (*value), S_READ); 1682*7c478bd9Sstevel@tonic-gate ret = fuword64(addr, value); 1683*7c478bd9Sstevel@tonic-gate if (watched) 1684*7c478bd9Sstevel@tonic-gate watch_enable_addr(addr, sizeof (*value), S_READ); 1685*7c478bd9Sstevel@tonic-gate 1686*7c478bd9Sstevel@tonic-gate return (ret); 1687*7c478bd9Sstevel@tonic-gate } 1688*7c478bd9Sstevel@tonic-gate #endif 1689*7c478bd9Sstevel@tonic-gate 1690*7c478bd9Sstevel@tonic-gate int 1691*7c478bd9Sstevel@tonic-gate fuword32_nowatch(const void *addr, uint32_t *value) 1692*7c478bd9Sstevel@tonic-gate { 1693*7c478bd9Sstevel@tonic-gate int watched, ret; 1694*7c478bd9Sstevel@tonic-gate 1695*7c478bd9Sstevel@tonic-gate watched = watch_disable_addr(addr, sizeof (*value), S_READ); 1696*7c478bd9Sstevel@tonic-gate ret = fuword32(addr, value); 1697*7c478bd9Sstevel@tonic-gate if (watched) 1698*7c478bd9Sstevel@tonic-gate watch_enable_addr(addr, sizeof (*value), S_READ); 1699*7c478bd9Sstevel@tonic-gate 1700*7c478bd9Sstevel@tonic-gate return (ret); 1701*7c478bd9Sstevel@tonic-gate } 1702*7c478bd9Sstevel@tonic-gate 1703*7c478bd9Sstevel@tonic-gate #ifdef _LP64 1704*7c478bd9Sstevel@tonic-gate int 1705*7c478bd9Sstevel@tonic-gate suword64_nowatch(void *addr, uint64_t value) 1706*7c478bd9Sstevel@tonic-gate { 1707*7c478bd9Sstevel@tonic-gate int watched, ret; 1708*7c478bd9Sstevel@tonic-gate 1709*7c478bd9Sstevel@tonic-gate watched = watch_disable_addr(addr, sizeof (value), S_WRITE); 1710*7c478bd9Sstevel@tonic-gate ret = suword64(addr, value); 1711*7c478bd9Sstevel@tonic-gate if (watched) 1712*7c478bd9Sstevel@tonic-gate watch_enable_addr(addr, sizeof (value), S_WRITE); 1713*7c478bd9Sstevel@tonic-gate 1714*7c478bd9Sstevel@tonic-gate return (ret); 1715*7c478bd9Sstevel@tonic-gate } 1716*7c478bd9Sstevel@tonic-gate #endif 1717*7c478bd9Sstevel@tonic-gate 1718*7c478bd9Sstevel@tonic-gate int 1719*7c478bd9Sstevel@tonic-gate suword32_nowatch(void *addr, uint32_t value) 1720*7c478bd9Sstevel@tonic-gate { 1721*7c478bd9Sstevel@tonic-gate int watched, ret; 1722*7c478bd9Sstevel@tonic-gate 1723*7c478bd9Sstevel@tonic-gate watched = watch_disable_addr(addr, sizeof (value), S_WRITE); 1724*7c478bd9Sstevel@tonic-gate ret = suword32(addr, value); 1725*7c478bd9Sstevel@tonic-gate if (watched) 1726*7c478bd9Sstevel@tonic-gate watch_enable_addr(addr, sizeof (value), S_WRITE); 1727*7c478bd9Sstevel@tonic-gate 1728*7c478bd9Sstevel@tonic-gate return (ret); 1729*7c478bd9Sstevel@tonic-gate } 1730*7c478bd9Sstevel@tonic-gate 1731*7c478bd9Sstevel@tonic-gate int 1732*7c478bd9Sstevel@tonic-gate watch_disable_addr(const void *addr, size_t len, enum seg_rw rw) 1733*7c478bd9Sstevel@tonic-gate { 1734*7c478bd9Sstevel@tonic-gate if (pr_watch_active(curproc)) 1735*7c478bd9Sstevel@tonic-gate return (pr_mappage((caddr_t)addr, len, rw, 1)); 1736*7c478bd9Sstevel@tonic-gate return (0); 1737*7c478bd9Sstevel@tonic-gate } 1738*7c478bd9Sstevel@tonic-gate 1739*7c478bd9Sstevel@tonic-gate void 1740*7c478bd9Sstevel@tonic-gate watch_enable_addr(const void *addr, size_t len, enum seg_rw rw) 1741*7c478bd9Sstevel@tonic-gate { 1742*7c478bd9Sstevel@tonic-gate if (pr_watch_active(curproc)) 1743*7c478bd9Sstevel@tonic-gate pr_unmappage((caddr_t)addr, len, rw, 1); 1744*7c478bd9Sstevel@tonic-gate } 1745