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 5ae115bc7Smrj * Common Development and Distribution License (the "License"). 6ae115bc7Smrj * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 21*07a48826SRoger A. Faulkner 227c478bd9Sstevel@tonic-gate /* 23*07a48826SRoger A. Faulkner * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 287c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 297c478bd9Sstevel@tonic-gate 307c478bd9Sstevel@tonic-gate #include <sys/types.h> 317c478bd9Sstevel@tonic-gate #include <sys/t_lock.h> 327c478bd9Sstevel@tonic-gate #include <sys/param.h> 337c478bd9Sstevel@tonic-gate #include <sys/cred.h> 347c478bd9Sstevel@tonic-gate #include <sys/debug.h> 357c478bd9Sstevel@tonic-gate #include <sys/inline.h> 367c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 377c478bd9Sstevel@tonic-gate #include <sys/proc.h> 387c478bd9Sstevel@tonic-gate #include <sys/regset.h> 397c478bd9Sstevel@tonic-gate #include <sys/privregs.h> 407c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 417c478bd9Sstevel@tonic-gate #include <sys/systm.h> 427c478bd9Sstevel@tonic-gate #include <sys/vfs.h> 437c478bd9Sstevel@tonic-gate #include <sys/vnode.h> 447c478bd9Sstevel@tonic-gate #include <sys/psw.h> 457c478bd9Sstevel@tonic-gate #include <sys/pcb.h> 467c478bd9Sstevel@tonic-gate #include <sys/buf.h> 477c478bd9Sstevel@tonic-gate #include <sys/signal.h> 487c478bd9Sstevel@tonic-gate #include <sys/user.h> 497c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h> 507c478bd9Sstevel@tonic-gate 517c478bd9Sstevel@tonic-gate #include <sys/fault.h> 527c478bd9Sstevel@tonic-gate #include <sys/syscall.h> 537c478bd9Sstevel@tonic-gate #include <sys/procfs.h> 547c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 557c478bd9Sstevel@tonic-gate #include <sys/stack.h> 567c478bd9Sstevel@tonic-gate #include <sys/debugreg.h> 577c478bd9Sstevel@tonic-gate #include <sys/copyops.h> 587c478bd9Sstevel@tonic-gate 597c478bd9Sstevel@tonic-gate #include <sys/vmem.h> 607c478bd9Sstevel@tonic-gate #include <sys/mman.h> 617c478bd9Sstevel@tonic-gate #include <sys/vmparam.h> 627c478bd9Sstevel@tonic-gate #include <sys/fp.h> 637c478bd9Sstevel@tonic-gate #include <sys/archsystm.h> 647c478bd9Sstevel@tonic-gate #include <sys/vmsystm.h> 657c478bd9Sstevel@tonic-gate #include <vm/hat.h> 667c478bd9Sstevel@tonic-gate #include <vm/as.h> 677c478bd9Sstevel@tonic-gate #include <vm/seg.h> 687c478bd9Sstevel@tonic-gate #include <vm/seg_kmem.h> 697c478bd9Sstevel@tonic-gate #include <vm/seg_kp.h> 707c478bd9Sstevel@tonic-gate #include <vm/page.h> 717c478bd9Sstevel@tonic-gate 727c478bd9Sstevel@tonic-gate #include <sys/sysi86.h> 737c478bd9Sstevel@tonic-gate 747c478bd9Sstevel@tonic-gate #include <fs/proc/prdata.h> 757c478bd9Sstevel@tonic-gate 767c478bd9Sstevel@tonic-gate int prnwatch = 10000; /* maximum number of watched areas */ 777c478bd9Sstevel@tonic-gate 787c478bd9Sstevel@tonic-gate /* 797c478bd9Sstevel@tonic-gate * Force a thread into the kernel if it is not already there. 807c478bd9Sstevel@tonic-gate * This is a no-op on uniprocessors. 817c478bd9Sstevel@tonic-gate */ 827c478bd9Sstevel@tonic-gate /* ARGSUSED */ 837c478bd9Sstevel@tonic-gate void 847c478bd9Sstevel@tonic-gate prpokethread(kthread_t *t) 857c478bd9Sstevel@tonic-gate { 867c478bd9Sstevel@tonic-gate if (t->t_state == TS_ONPROC && t->t_cpu != CPU) 877c478bd9Sstevel@tonic-gate poke_cpu(t->t_cpu->cpu_id); 887c478bd9Sstevel@tonic-gate } 897c478bd9Sstevel@tonic-gate 907c478bd9Sstevel@tonic-gate /* 917c478bd9Sstevel@tonic-gate * Return general registers. 927c478bd9Sstevel@tonic-gate */ 937c478bd9Sstevel@tonic-gate void 947c478bd9Sstevel@tonic-gate prgetprregs(klwp_t *lwp, prgregset_t prp) 957c478bd9Sstevel@tonic-gate { 967c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&lwptoproc(lwp)->p_lock)); 977c478bd9Sstevel@tonic-gate 987c478bd9Sstevel@tonic-gate getgregs(lwp, prp); 997c478bd9Sstevel@tonic-gate } 1007c478bd9Sstevel@tonic-gate 1017c478bd9Sstevel@tonic-gate /* 1027c478bd9Sstevel@tonic-gate * Set general registers. 1037c478bd9Sstevel@tonic-gate * (Note: This can be an alias to setgregs().) 1047c478bd9Sstevel@tonic-gate */ 1057c478bd9Sstevel@tonic-gate void 1067c478bd9Sstevel@tonic-gate prsetprregs(klwp_t *lwp, prgregset_t prp, int initial) 1077c478bd9Sstevel@tonic-gate { 1087c478bd9Sstevel@tonic-gate if (initial) /* set initial values */ 1097c478bd9Sstevel@tonic-gate lwptoregs(lwp)->r_ps = PSL_USER; 1107c478bd9Sstevel@tonic-gate (void) setgregs(lwp, prp); 1117c478bd9Sstevel@tonic-gate } 1127c478bd9Sstevel@tonic-gate 1137c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 1147c478bd9Sstevel@tonic-gate 1157c478bd9Sstevel@tonic-gate /* 1167c478bd9Sstevel@tonic-gate * Convert prgregset32 to native prgregset 1177c478bd9Sstevel@tonic-gate */ 1187c478bd9Sstevel@tonic-gate void 1197c478bd9Sstevel@tonic-gate prgregset_32ton(klwp_t *lwp, prgregset32_t src, prgregset_t dst) 1207c478bd9Sstevel@tonic-gate { 1217c478bd9Sstevel@tonic-gate struct regs *rp = lwptoregs(lwp); 1227c478bd9Sstevel@tonic-gate 1237c478bd9Sstevel@tonic-gate dst[REG_GSBASE] = lwp->lwp_pcb.pcb_gsbase; 1247c478bd9Sstevel@tonic-gate dst[REG_FSBASE] = lwp->lwp_pcb.pcb_fsbase; 1257c478bd9Sstevel@tonic-gate 1267c478bd9Sstevel@tonic-gate dst[REG_DS] = (uint16_t)src[DS]; 1277c478bd9Sstevel@tonic-gate dst[REG_ES] = (uint16_t)src[ES]; 1287c478bd9Sstevel@tonic-gate 1297c478bd9Sstevel@tonic-gate dst[REG_GS] = (uint16_t)src[GS]; 1307c478bd9Sstevel@tonic-gate dst[REG_FS] = (uint16_t)src[FS]; 1317c478bd9Sstevel@tonic-gate dst[REG_SS] = (uint16_t)src[SS]; 1327c478bd9Sstevel@tonic-gate dst[REG_RSP] = (uint32_t)src[UESP]; 1337c478bd9Sstevel@tonic-gate dst[REG_RFL] = 1347c478bd9Sstevel@tonic-gate (rp->r_ps & ~PSL_USERMASK) | (src[EFL] & PSL_USERMASK); 1357c478bd9Sstevel@tonic-gate dst[REG_CS] = (uint16_t)src[CS]; 1367c478bd9Sstevel@tonic-gate dst[REG_RIP] = (uint32_t)src[EIP]; 1377c478bd9Sstevel@tonic-gate dst[REG_ERR] = (uint32_t)src[ERR]; 1387c478bd9Sstevel@tonic-gate dst[REG_TRAPNO] = (uint32_t)src[TRAPNO]; 1397c478bd9Sstevel@tonic-gate dst[REG_RAX] = (uint32_t)src[EAX]; 1407c478bd9Sstevel@tonic-gate dst[REG_RCX] = (uint32_t)src[ECX]; 1417c478bd9Sstevel@tonic-gate dst[REG_RDX] = (uint32_t)src[EDX]; 1427c478bd9Sstevel@tonic-gate dst[REG_RBX] = (uint32_t)src[EBX]; 1437c478bd9Sstevel@tonic-gate dst[REG_RBP] = (uint32_t)src[EBP]; 1447c478bd9Sstevel@tonic-gate dst[REG_RSI] = (uint32_t)src[ESI]; 1457c478bd9Sstevel@tonic-gate dst[REG_RDI] = (uint32_t)src[EDI]; 1467c478bd9Sstevel@tonic-gate dst[REG_R8] = dst[REG_R9] = dst[REG_R10] = dst[REG_R11] = 1477c478bd9Sstevel@tonic-gate dst[REG_R12] = dst[REG_R13] = dst[REG_R14] = dst[REG_R15] = 0; 1487c478bd9Sstevel@tonic-gate } 1497c478bd9Sstevel@tonic-gate 1507c478bd9Sstevel@tonic-gate /* 1517c478bd9Sstevel@tonic-gate * Return 32-bit general registers 1527c478bd9Sstevel@tonic-gate */ 1537c478bd9Sstevel@tonic-gate void 1547c478bd9Sstevel@tonic-gate prgetprregs32(klwp_t *lwp, prgregset32_t prp) 1557c478bd9Sstevel@tonic-gate { 1567c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&lwptoproc(lwp)->p_lock)); 1577c478bd9Sstevel@tonic-gate getgregs32(lwp, prp); 1587c478bd9Sstevel@tonic-gate } 1597c478bd9Sstevel@tonic-gate 1607c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */ 1617c478bd9Sstevel@tonic-gate 1627c478bd9Sstevel@tonic-gate /* 1637c478bd9Sstevel@tonic-gate * Get the syscall return values for the lwp. 1647c478bd9Sstevel@tonic-gate */ 1657c478bd9Sstevel@tonic-gate int 1667c478bd9Sstevel@tonic-gate prgetrvals(klwp_t *lwp, long *rval1, long *rval2) 1677c478bd9Sstevel@tonic-gate { 1687c478bd9Sstevel@tonic-gate struct regs *r = lwptoregs(lwp); 1697c478bd9Sstevel@tonic-gate 1707c478bd9Sstevel@tonic-gate if (r->r_ps & PS_C) 1717c478bd9Sstevel@tonic-gate return (r->r_r0); 1727c478bd9Sstevel@tonic-gate if (lwp->lwp_eosys == JUSTRETURN) { 1737c478bd9Sstevel@tonic-gate *rval1 = 0; 1747c478bd9Sstevel@tonic-gate *rval2 = 0; 1757c478bd9Sstevel@tonic-gate } else if (lwp_getdatamodel(lwp) != DATAMODEL_NATIVE) { 1767c478bd9Sstevel@tonic-gate /* 1777c478bd9Sstevel@tonic-gate * XX64 Not sure we -really- need to do this, because the 1787c478bd9Sstevel@tonic-gate * syscall return already masks off the bottom values ..? 1797c478bd9Sstevel@tonic-gate */ 1807c478bd9Sstevel@tonic-gate *rval1 = r->r_r0 & (uint32_t)0xffffffffu; 1817c478bd9Sstevel@tonic-gate *rval2 = r->r_r1 & (uint32_t)0xffffffffu; 1827c478bd9Sstevel@tonic-gate } else { 1837c478bd9Sstevel@tonic-gate *rval1 = r->r_r0; 1847c478bd9Sstevel@tonic-gate *rval2 = r->r_r1; 1857c478bd9Sstevel@tonic-gate } 1867c478bd9Sstevel@tonic-gate return (0); 1877c478bd9Sstevel@tonic-gate } 1887c478bd9Sstevel@tonic-gate 1897c478bd9Sstevel@tonic-gate /* 1907c478bd9Sstevel@tonic-gate * Does the system support floating-point, either through hardware 1917c478bd9Sstevel@tonic-gate * or by trapping and emulating floating-point machine instructions? 1927c478bd9Sstevel@tonic-gate */ 1937c478bd9Sstevel@tonic-gate int 1947c478bd9Sstevel@tonic-gate prhasfp(void) 1957c478bd9Sstevel@tonic-gate { 1967c478bd9Sstevel@tonic-gate extern int fp_kind; 1977c478bd9Sstevel@tonic-gate 1987c478bd9Sstevel@tonic-gate return (fp_kind != FP_NO); 1997c478bd9Sstevel@tonic-gate } 2007c478bd9Sstevel@tonic-gate 2017c478bd9Sstevel@tonic-gate /* 2027c478bd9Sstevel@tonic-gate * Get floating-point registers. 2037c478bd9Sstevel@tonic-gate */ 2047c478bd9Sstevel@tonic-gate void 2057c478bd9Sstevel@tonic-gate prgetprfpregs(klwp_t *lwp, prfpregset_t *pfp) 2067c478bd9Sstevel@tonic-gate { 2077c478bd9Sstevel@tonic-gate bzero(pfp, sizeof (prfpregset_t)); 2087c478bd9Sstevel@tonic-gate getfpregs(lwp, pfp); 2097c478bd9Sstevel@tonic-gate } 2107c478bd9Sstevel@tonic-gate 2117c478bd9Sstevel@tonic-gate #if defined(_SYSCALL32_IMPL) 2127c478bd9Sstevel@tonic-gate void 2137c478bd9Sstevel@tonic-gate prgetprfpregs32(klwp_t *lwp, prfpregset32_t *pfp) 2147c478bd9Sstevel@tonic-gate { 2157c478bd9Sstevel@tonic-gate bzero(pfp, sizeof (*pfp)); 2167c478bd9Sstevel@tonic-gate getfpregs32(lwp, pfp); 2177c478bd9Sstevel@tonic-gate } 2187c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */ 2197c478bd9Sstevel@tonic-gate 2207c478bd9Sstevel@tonic-gate /* 2217c478bd9Sstevel@tonic-gate * Set floating-point registers. 2227c478bd9Sstevel@tonic-gate * (Note: This can be an alias to setfpregs().) 2237c478bd9Sstevel@tonic-gate */ 2247c478bd9Sstevel@tonic-gate void 2257c478bd9Sstevel@tonic-gate prsetprfpregs(klwp_t *lwp, prfpregset_t *pfp) 2267c478bd9Sstevel@tonic-gate { 2277c478bd9Sstevel@tonic-gate setfpregs(lwp, pfp); 2287c478bd9Sstevel@tonic-gate } 2297c478bd9Sstevel@tonic-gate 2307c478bd9Sstevel@tonic-gate #if defined(_SYSCALL32_IMPL) 2317c478bd9Sstevel@tonic-gate void 2327c478bd9Sstevel@tonic-gate prsetprfpregs32(klwp_t *lwp, prfpregset32_t *pfp) 2337c478bd9Sstevel@tonic-gate { 2347c478bd9Sstevel@tonic-gate setfpregs32(lwp, pfp); 2357c478bd9Sstevel@tonic-gate } 2367c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */ 2377c478bd9Sstevel@tonic-gate 2387c478bd9Sstevel@tonic-gate /* 2397c478bd9Sstevel@tonic-gate * Does the system support extra register state? 2407c478bd9Sstevel@tonic-gate */ 2417c478bd9Sstevel@tonic-gate /* ARGSUSED */ 2427c478bd9Sstevel@tonic-gate int 2437c478bd9Sstevel@tonic-gate prhasx(proc_t *p) 2447c478bd9Sstevel@tonic-gate { 2457c478bd9Sstevel@tonic-gate return (0); 2467c478bd9Sstevel@tonic-gate } 2477c478bd9Sstevel@tonic-gate 2487c478bd9Sstevel@tonic-gate /* 2497c478bd9Sstevel@tonic-gate * Get the size of the extra registers. 2507c478bd9Sstevel@tonic-gate */ 2517c478bd9Sstevel@tonic-gate /* ARGSUSED */ 2527c478bd9Sstevel@tonic-gate int 2537c478bd9Sstevel@tonic-gate prgetprxregsize(proc_t *p) 2547c478bd9Sstevel@tonic-gate { 2557c478bd9Sstevel@tonic-gate return (0); 2567c478bd9Sstevel@tonic-gate } 2577c478bd9Sstevel@tonic-gate 2587c478bd9Sstevel@tonic-gate /* 2597c478bd9Sstevel@tonic-gate * Get extra registers. 2607c478bd9Sstevel@tonic-gate */ 2617c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2627c478bd9Sstevel@tonic-gate void 2637c478bd9Sstevel@tonic-gate prgetprxregs(klwp_t *lwp, caddr_t prx) 2647c478bd9Sstevel@tonic-gate { 2657c478bd9Sstevel@tonic-gate /* no extra registers */ 2667c478bd9Sstevel@tonic-gate } 2677c478bd9Sstevel@tonic-gate 2687c478bd9Sstevel@tonic-gate /* 2697c478bd9Sstevel@tonic-gate * Set extra registers. 2707c478bd9Sstevel@tonic-gate */ 2717c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2727c478bd9Sstevel@tonic-gate void 2737c478bd9Sstevel@tonic-gate prsetprxregs(klwp_t *lwp, caddr_t prx) 2747c478bd9Sstevel@tonic-gate { 2757c478bd9Sstevel@tonic-gate /* no extra registers */ 2767c478bd9Sstevel@tonic-gate } 2777c478bd9Sstevel@tonic-gate 2787c478bd9Sstevel@tonic-gate /* 2797c478bd9Sstevel@tonic-gate * Return the base (lower limit) of the process stack. 2807c478bd9Sstevel@tonic-gate */ 2817c478bd9Sstevel@tonic-gate caddr_t 2827c478bd9Sstevel@tonic-gate prgetstackbase(proc_t *p) 2837c478bd9Sstevel@tonic-gate { 2847c478bd9Sstevel@tonic-gate return (p->p_usrstack - p->p_stksize); 2857c478bd9Sstevel@tonic-gate } 2867c478bd9Sstevel@tonic-gate 2877c478bd9Sstevel@tonic-gate /* 2887c478bd9Sstevel@tonic-gate * Return the "addr" field for pr_addr in prpsinfo_t. 2897c478bd9Sstevel@tonic-gate * This is a vestige of the past, so whatever we return is OK. 2907c478bd9Sstevel@tonic-gate */ 2917c478bd9Sstevel@tonic-gate caddr_t 2927c478bd9Sstevel@tonic-gate prgetpsaddr(proc_t *p) 2937c478bd9Sstevel@tonic-gate { 2947c478bd9Sstevel@tonic-gate return ((caddr_t)p); 2957c478bd9Sstevel@tonic-gate } 2967c478bd9Sstevel@tonic-gate 2977c478bd9Sstevel@tonic-gate /* 2987c478bd9Sstevel@tonic-gate * Arrange to single-step the lwp. 2997c478bd9Sstevel@tonic-gate */ 3007c478bd9Sstevel@tonic-gate void 3017c478bd9Sstevel@tonic-gate prstep(klwp_t *lwp, int watchstep) 3027c478bd9Sstevel@tonic-gate { 3037c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&lwptoproc(lwp)->p_lock)); 3047c478bd9Sstevel@tonic-gate 30565a89a64Smarx /* 30665a89a64Smarx * flag LWP so that its r_efl trace bit (PS_T) will be set on 30765a89a64Smarx * next return to usermode. 30865a89a64Smarx */ 30965a89a64Smarx lwp->lwp_pcb.pcb_flags |= REQUEST_STEP; 31065a89a64Smarx lwp->lwp_pcb.pcb_flags &= ~REQUEST_NOSTEP; 31165a89a64Smarx 3127c478bd9Sstevel@tonic-gate if (watchstep) 3137c478bd9Sstevel@tonic-gate lwp->lwp_pcb.pcb_flags |= WATCH_STEP; 3147c478bd9Sstevel@tonic-gate else 3157c478bd9Sstevel@tonic-gate lwp->lwp_pcb.pcb_flags |= NORMAL_STEP; 3167c478bd9Sstevel@tonic-gate 31765a89a64Smarx aston(lwptot(lwp)); /* let trap() set PS_T in rp->r_efl */ 3187c478bd9Sstevel@tonic-gate } 3197c478bd9Sstevel@tonic-gate 3207c478bd9Sstevel@tonic-gate /* 3217c478bd9Sstevel@tonic-gate * Undo prstep(). 3227c478bd9Sstevel@tonic-gate */ 3237c478bd9Sstevel@tonic-gate void 3247c478bd9Sstevel@tonic-gate prnostep(klwp_t *lwp) 3257c478bd9Sstevel@tonic-gate { 3267c478bd9Sstevel@tonic-gate ASSERT(ttolwp(curthread) == lwp || 3277c478bd9Sstevel@tonic-gate MUTEX_NOT_HELD(&lwptoproc(lwp)->p_lock)); 3287c478bd9Sstevel@tonic-gate 32965a89a64Smarx /* 33065a89a64Smarx * flag LWP so that its r_efl trace bit (PS_T) will be cleared on 33165a89a64Smarx * next return to usermode. 33265a89a64Smarx */ 33365a89a64Smarx lwp->lwp_pcb.pcb_flags |= REQUEST_NOSTEP; 33465a89a64Smarx 33565a89a64Smarx lwp->lwp_pcb.pcb_flags &= 33665a89a64Smarx ~(REQUEST_STEP|NORMAL_STEP|WATCH_STEP|DEBUG_PENDING); 33765a89a64Smarx 33865a89a64Smarx aston(lwptot(lwp)); /* let trap() clear PS_T in rp->r_efl */ 3397c478bd9Sstevel@tonic-gate } 3407c478bd9Sstevel@tonic-gate 3417c478bd9Sstevel@tonic-gate /* 3427c478bd9Sstevel@tonic-gate * Return non-zero if a single-step is in effect. 3437c478bd9Sstevel@tonic-gate */ 3447c478bd9Sstevel@tonic-gate int 3457c478bd9Sstevel@tonic-gate prisstep(klwp_t *lwp) 3467c478bd9Sstevel@tonic-gate { 3477c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&lwptoproc(lwp)->p_lock)); 3487c478bd9Sstevel@tonic-gate 3497c478bd9Sstevel@tonic-gate return ((lwp->lwp_pcb.pcb_flags & 3507c478bd9Sstevel@tonic-gate (NORMAL_STEP|WATCH_STEP|DEBUG_PENDING)) != 0); 3517c478bd9Sstevel@tonic-gate } 3527c478bd9Sstevel@tonic-gate 3537c478bd9Sstevel@tonic-gate /* 3547c478bd9Sstevel@tonic-gate * Set the PC to the specified virtual address. 3557c478bd9Sstevel@tonic-gate */ 3567c478bd9Sstevel@tonic-gate void 3577c478bd9Sstevel@tonic-gate prsvaddr(klwp_t *lwp, caddr_t vaddr) 3587c478bd9Sstevel@tonic-gate { 3597c478bd9Sstevel@tonic-gate struct regs *r = lwptoregs(lwp); 3607c478bd9Sstevel@tonic-gate 3617c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&lwptoproc(lwp)->p_lock)); 3627c478bd9Sstevel@tonic-gate 3637c478bd9Sstevel@tonic-gate r->r_pc = (uintptr_t)vaddr; 3647c478bd9Sstevel@tonic-gate } 3657c478bd9Sstevel@tonic-gate 3667c478bd9Sstevel@tonic-gate /* 3677c478bd9Sstevel@tonic-gate * Map address "addr" in address space "as" into a kernel virtual address. 3687c478bd9Sstevel@tonic-gate * The memory is guaranteed to be resident and locked down. 3697c478bd9Sstevel@tonic-gate */ 3707c478bd9Sstevel@tonic-gate caddr_t 3717c478bd9Sstevel@tonic-gate prmapin(struct as *as, caddr_t addr, int writing) 3727c478bd9Sstevel@tonic-gate { 3737c478bd9Sstevel@tonic-gate page_t *pp; 3747c478bd9Sstevel@tonic-gate caddr_t kaddr; 3757c478bd9Sstevel@tonic-gate pfn_t pfnum; 3767c478bd9Sstevel@tonic-gate 3777c478bd9Sstevel@tonic-gate /* 3787c478bd9Sstevel@tonic-gate * XXX - Because of past mistakes, we have bits being returned 3797c478bd9Sstevel@tonic-gate * by getpfnum that are actually the page type bits of the pte. 3807c478bd9Sstevel@tonic-gate * When the object we are trying to map is a memory page with 3817c478bd9Sstevel@tonic-gate * a page structure everything is ok and we can use the optimal 3827c478bd9Sstevel@tonic-gate * method, ppmapin. Otherwise, we have to do something special. 3837c478bd9Sstevel@tonic-gate */ 3847c478bd9Sstevel@tonic-gate pfnum = hat_getpfnum(as->a_hat, addr); 3857c478bd9Sstevel@tonic-gate if (pf_is_memory(pfnum)) { 3867c478bd9Sstevel@tonic-gate pp = page_numtopp_nolock(pfnum); 3877c478bd9Sstevel@tonic-gate if (pp != NULL) { 3887c478bd9Sstevel@tonic-gate ASSERT(PAGE_LOCKED(pp)); 3897c478bd9Sstevel@tonic-gate kaddr = ppmapin(pp, writing ? 3907c478bd9Sstevel@tonic-gate (PROT_READ | PROT_WRITE) : PROT_READ, (caddr_t)-1); 3917c478bd9Sstevel@tonic-gate return (kaddr + ((uintptr_t)addr & PAGEOFFSET)); 3927c478bd9Sstevel@tonic-gate } 3937c478bd9Sstevel@tonic-gate } 3947c478bd9Sstevel@tonic-gate 3957c478bd9Sstevel@tonic-gate /* 3967c478bd9Sstevel@tonic-gate * Oh well, we didn't have a page struct for the object we were 3977c478bd9Sstevel@tonic-gate * trying to map in; ppmapin doesn't handle devices, but allocating a 3987c478bd9Sstevel@tonic-gate * heap address allows ppmapout to free virtual space when done. 3997c478bd9Sstevel@tonic-gate */ 4007c478bd9Sstevel@tonic-gate kaddr = vmem_alloc(heap_arena, PAGESIZE, VM_SLEEP); 4017c478bd9Sstevel@tonic-gate 4027c478bd9Sstevel@tonic-gate hat_devload(kas.a_hat, kaddr, MMU_PAGESIZE, pfnum, 4037c478bd9Sstevel@tonic-gate writing ? (PROT_READ | PROT_WRITE) : PROT_READ, 0); 4047c478bd9Sstevel@tonic-gate 4057c478bd9Sstevel@tonic-gate return (kaddr + ((uintptr_t)addr & PAGEOFFSET)); 4067c478bd9Sstevel@tonic-gate } 4077c478bd9Sstevel@tonic-gate 4087c478bd9Sstevel@tonic-gate /* 4097c478bd9Sstevel@tonic-gate * Unmap address "addr" in address space "as"; inverse of prmapin(). 4107c478bd9Sstevel@tonic-gate */ 4117c478bd9Sstevel@tonic-gate /* ARGSUSED */ 4127c478bd9Sstevel@tonic-gate void 4137c478bd9Sstevel@tonic-gate prmapout(struct as *as, caddr_t addr, caddr_t vaddr, int writing) 4147c478bd9Sstevel@tonic-gate { 4157c478bd9Sstevel@tonic-gate extern void ppmapout(caddr_t); 4167c478bd9Sstevel@tonic-gate 4177c478bd9Sstevel@tonic-gate vaddr = (caddr_t)((uintptr_t)vaddr & PAGEMASK); 4187c478bd9Sstevel@tonic-gate ppmapout(vaddr); 4197c478bd9Sstevel@tonic-gate } 4207c478bd9Sstevel@tonic-gate 4217c478bd9Sstevel@tonic-gate /* 4227c478bd9Sstevel@tonic-gate * Make sure the lwp is in an orderly state 4237c478bd9Sstevel@tonic-gate * for inspection by a debugger through /proc. 424*07a48826SRoger A. Faulkner * 425*07a48826SRoger A. Faulkner * This needs to be called only once while the current thread remains in the 426*07a48826SRoger A. Faulkner * kernel and needs to be called while holding no resources (mutex locks, etc). 427*07a48826SRoger A. Faulkner * 428*07a48826SRoger A. Faulkner * As a hedge against these conditions, if prstop() is called repeatedly 429*07a48826SRoger A. Faulkner * before prunstop() is called, it does nothing and just returns. 430*07a48826SRoger A. Faulkner * 431*07a48826SRoger A. Faulkner * prunstop() must be called before the thread returns to user level. 4327c478bd9Sstevel@tonic-gate */ 4337c478bd9Sstevel@tonic-gate /* ARGSUSED */ 4347c478bd9Sstevel@tonic-gate void 4357c478bd9Sstevel@tonic-gate prstop(int why, int what) 4367c478bd9Sstevel@tonic-gate { 4377c478bd9Sstevel@tonic-gate klwp_t *lwp = ttolwp(curthread); 4387c478bd9Sstevel@tonic-gate struct regs *r = lwptoregs(lwp); 4397c478bd9Sstevel@tonic-gate 440*07a48826SRoger A. Faulkner if (lwp->lwp_pcb.pcb_flags & PRSTOP_CALLED) 441*07a48826SRoger A. Faulkner return; 442*07a48826SRoger A. Faulkner 4437c478bd9Sstevel@tonic-gate /* 4448548bf79Snr123932 * Make sure we don't deadlock on a recursive call 4458548bf79Snr123932 * to prstop(). stop() tests the lwp_nostop flag. 4467c478bd9Sstevel@tonic-gate */ 4478548bf79Snr123932 ASSERT(lwp->lwp_nostop == 0); 4488548bf79Snr123932 lwp->lwp_nostop = 1; 4497c478bd9Sstevel@tonic-gate 4507c478bd9Sstevel@tonic-gate if (copyin_nowatch((caddr_t)r->r_pc, &lwp->lwp_pcb.pcb_instr, 4517c478bd9Sstevel@tonic-gate sizeof (lwp->lwp_pcb.pcb_instr)) == 0) 4527c478bd9Sstevel@tonic-gate lwp->lwp_pcb.pcb_flags |= INSTR_VALID; 4537c478bd9Sstevel@tonic-gate else { 4547c478bd9Sstevel@tonic-gate lwp->lwp_pcb.pcb_flags &= ~INSTR_VALID; 4557c478bd9Sstevel@tonic-gate lwp->lwp_pcb.pcb_instr = 0; 4567c478bd9Sstevel@tonic-gate } 4577c478bd9Sstevel@tonic-gate 4587c478bd9Sstevel@tonic-gate (void) save_syscall_args(); 4598548bf79Snr123932 ASSERT(lwp->lwp_nostop == 1); 4608548bf79Snr123932 lwp->lwp_nostop = 0; 461*07a48826SRoger A. Faulkner 462*07a48826SRoger A. Faulkner lwp->lwp_pcb.pcb_flags |= PRSTOP_CALLED; 463*07a48826SRoger A. Faulkner aston(curthread); /* so prunstop() will be called */ 464*07a48826SRoger A. Faulkner } 465*07a48826SRoger A. Faulkner 466*07a48826SRoger A. Faulkner /* 467*07a48826SRoger A. Faulkner * Inform prstop() that it should do its work again 468*07a48826SRoger A. Faulkner * the next time it is called. 469*07a48826SRoger A. Faulkner */ 470*07a48826SRoger A. Faulkner void 471*07a48826SRoger A. Faulkner prunstop(void) 472*07a48826SRoger A. Faulkner { 473*07a48826SRoger A. Faulkner ttolwp(curthread)->lwp_pcb.pcb_flags &= ~PRSTOP_CALLED; 4747c478bd9Sstevel@tonic-gate } 4757c478bd9Sstevel@tonic-gate 4767c478bd9Sstevel@tonic-gate /* 4777c478bd9Sstevel@tonic-gate * Fetch the user-level instruction on which the lwp is stopped. 4787c478bd9Sstevel@tonic-gate * It was saved by the lwp itself, in prstop(). 4797c478bd9Sstevel@tonic-gate * Return non-zero if the instruction is valid. 4807c478bd9Sstevel@tonic-gate */ 4817c478bd9Sstevel@tonic-gate int 4827c478bd9Sstevel@tonic-gate prfetchinstr(klwp_t *lwp, ulong_t *ip) 4837c478bd9Sstevel@tonic-gate { 4847c478bd9Sstevel@tonic-gate *ip = (ulong_t)(instr_t)lwp->lwp_pcb.pcb_instr; 4857c478bd9Sstevel@tonic-gate return (lwp->lwp_pcb.pcb_flags & INSTR_VALID); 4867c478bd9Sstevel@tonic-gate } 4877c478bd9Sstevel@tonic-gate 4887c478bd9Sstevel@tonic-gate /* 4897c478bd9Sstevel@tonic-gate * Called from trap() when a load or store instruction 4907c478bd9Sstevel@tonic-gate * falls in a watched page but is not a watchpoint. 4917c478bd9Sstevel@tonic-gate * We emulate the instruction in the kernel. 4927c478bd9Sstevel@tonic-gate */ 4937c478bd9Sstevel@tonic-gate /* ARGSUSED */ 4947c478bd9Sstevel@tonic-gate int 4957c478bd9Sstevel@tonic-gate pr_watch_emul(struct regs *rp, caddr_t addr, enum seg_rw rw) 4967c478bd9Sstevel@tonic-gate { 4977c478bd9Sstevel@tonic-gate #ifdef SOMEDAY 4987c478bd9Sstevel@tonic-gate int res; 4997c478bd9Sstevel@tonic-gate proc_t *p = curproc; 5007c478bd9Sstevel@tonic-gate char *badaddr = (caddr_t)(-1); 5017c478bd9Sstevel@tonic-gate int mapped; 5027c478bd9Sstevel@tonic-gate 5037c478bd9Sstevel@tonic-gate /* prevent recursive calls to pr_watch_emul() */ 5047c478bd9Sstevel@tonic-gate ASSERT(!(curthread->t_flag & T_WATCHPT)); 5057c478bd9Sstevel@tonic-gate curthread->t_flag |= T_WATCHPT; 5067c478bd9Sstevel@tonic-gate 5077c478bd9Sstevel@tonic-gate watch_disable_addr(addr, 8, rw); 5087c478bd9Sstevel@tonic-gate res = do_unaligned(rp, &badaddr); 5097c478bd9Sstevel@tonic-gate watch_enable_addr(addr, 8, rw); 5107c478bd9Sstevel@tonic-gate 5117c478bd9Sstevel@tonic-gate curthread->t_flag &= ~T_WATCHPT; 5127c478bd9Sstevel@tonic-gate if (res == SIMU_SUCCESS) { 5137c478bd9Sstevel@tonic-gate /* adjust the pc */ 5147c478bd9Sstevel@tonic-gate return (1); 5157c478bd9Sstevel@tonic-gate } 5167c478bd9Sstevel@tonic-gate #endif 5177c478bd9Sstevel@tonic-gate return (0); 5187c478bd9Sstevel@tonic-gate } 5197c478bd9Sstevel@tonic-gate 5207c478bd9Sstevel@tonic-gate /* 5217c478bd9Sstevel@tonic-gate * Return the number of active entries in the local descriptor table. 5227c478bd9Sstevel@tonic-gate */ 5237c478bd9Sstevel@tonic-gate int 5247c478bd9Sstevel@tonic-gate prnldt(proc_t *p) 5257c478bd9Sstevel@tonic-gate { 5267c478bd9Sstevel@tonic-gate int limit, i, n; 5277c478bd9Sstevel@tonic-gate user_desc_t *udp; 5287c478bd9Sstevel@tonic-gate 5297c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&p->p_ldtlock)); 5307c478bd9Sstevel@tonic-gate 5317c478bd9Sstevel@tonic-gate /* 532ddece0baSsethg * Currently 64 bit processes cannot have private LDTs. 5337c478bd9Sstevel@tonic-gate */ 534ddece0baSsethg ASSERT(p->p_model != DATAMODEL_LP64 || p->p_ldt == NULL); 5357c478bd9Sstevel@tonic-gate 5367c478bd9Sstevel@tonic-gate if (p->p_ldt == NULL) 5377c478bd9Sstevel@tonic-gate return (0); 5387c478bd9Sstevel@tonic-gate n = 0; 5397c478bd9Sstevel@tonic-gate limit = p->p_ldtlimit; 5407c478bd9Sstevel@tonic-gate ASSERT(limit >= 0 && limit < MAXNLDT); 5417c478bd9Sstevel@tonic-gate 5427c478bd9Sstevel@tonic-gate /* 5437c478bd9Sstevel@tonic-gate * Count all present user descriptors. 5447c478bd9Sstevel@tonic-gate */ 5457c478bd9Sstevel@tonic-gate for (i = LDT_UDBASE, udp = &p->p_ldt[i]; i <= limit; i++, udp++) 5467c478bd9Sstevel@tonic-gate if (udp->usd_type != 0 || udp->usd_dpl != 0 || udp->usd_p != 0) 5477c478bd9Sstevel@tonic-gate n++; 5487c478bd9Sstevel@tonic-gate return (n); 5497c478bd9Sstevel@tonic-gate } 5507c478bd9Sstevel@tonic-gate 5517c478bd9Sstevel@tonic-gate /* 5527c478bd9Sstevel@tonic-gate * Fetch the active entries from the local descriptor table. 5537c478bd9Sstevel@tonic-gate */ 5547c478bd9Sstevel@tonic-gate void 5557c478bd9Sstevel@tonic-gate prgetldt(proc_t *p, struct ssd *ssd) 5567c478bd9Sstevel@tonic-gate { 5577c478bd9Sstevel@tonic-gate int i, limit; 5587c478bd9Sstevel@tonic-gate user_desc_t *udp; 5597c478bd9Sstevel@tonic-gate 5607c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&p->p_ldtlock)); 5617c478bd9Sstevel@tonic-gate 5627c478bd9Sstevel@tonic-gate if (p->p_ldt == NULL) 5637c478bd9Sstevel@tonic-gate return; 5647c478bd9Sstevel@tonic-gate 5657c478bd9Sstevel@tonic-gate limit = p->p_ldtlimit; 5667c478bd9Sstevel@tonic-gate ASSERT(limit >= 0 && limit < MAXNLDT); 5677c478bd9Sstevel@tonic-gate 5687c478bd9Sstevel@tonic-gate /* 5697c478bd9Sstevel@tonic-gate * All present user descriptors. 5707c478bd9Sstevel@tonic-gate */ 5717c478bd9Sstevel@tonic-gate for (i = LDT_UDBASE, udp = &p->p_ldt[i]; i <= limit; i++, udp++) 5727c478bd9Sstevel@tonic-gate if (udp->usd_type != 0 || udp->usd_dpl != 0 || 5737c478bd9Sstevel@tonic-gate udp->usd_p != 0) 5747c478bd9Sstevel@tonic-gate usd_to_ssd(udp, ssd++, SEL_LDT(i)); 5757c478bd9Sstevel@tonic-gate } 576