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