10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
52179Sahl * Common Development and Distribution License (the "License").
62179Sahl * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
212179Sahl
220Sstevel@tonic-gate /*
23*3446Smrj * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
240Sstevel@tonic-gate * Use is subject to license terms.
250Sstevel@tonic-gate */
260Sstevel@tonic-gate
270Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
280Sstevel@tonic-gate
290Sstevel@tonic-gate #include <sys/dtrace.h>
300Sstevel@tonic-gate #include <sys/fasttrap.h>
310Sstevel@tonic-gate #include <sys/x_call.h>
320Sstevel@tonic-gate #include <sys/atomic.h>
330Sstevel@tonic-gate #include <sys/machsystm.h>
340Sstevel@tonic-gate
350Sstevel@tonic-gate static void
dtrace_xcall_func(uint64_t arg1,uint64_t arg2)360Sstevel@tonic-gate dtrace_xcall_func(uint64_t arg1, uint64_t arg2)
370Sstevel@tonic-gate {
380Sstevel@tonic-gate (*(dtrace_xcall_t)arg1)((void *)(arg2));
390Sstevel@tonic-gate }
400Sstevel@tonic-gate
410Sstevel@tonic-gate void
dtrace_xcall(processorid_t cpu,dtrace_xcall_t func,void * arg)420Sstevel@tonic-gate dtrace_xcall(processorid_t cpu, dtrace_xcall_t func, void *arg)
430Sstevel@tonic-gate {
440Sstevel@tonic-gate if (cpu == DTRACE_CPUALL) {
450Sstevel@tonic-gate xc_all(dtrace_xcall_func, (uint64_t)func, (uint64_t)arg);
460Sstevel@tonic-gate } else {
470Sstevel@tonic-gate xc_one(cpu, dtrace_xcall_func, (uint64_t)func, (uint64_t)arg);
480Sstevel@tonic-gate }
490Sstevel@tonic-gate }
500Sstevel@tonic-gate
510Sstevel@tonic-gate /*ARGSUSED*/
520Sstevel@tonic-gate static void
dtrace_sync_func(uint64_t arg1,uint64_t arg2)530Sstevel@tonic-gate dtrace_sync_func(uint64_t arg1, uint64_t arg2)
540Sstevel@tonic-gate {
550Sstevel@tonic-gate membar_consumer();
560Sstevel@tonic-gate }
570Sstevel@tonic-gate
580Sstevel@tonic-gate void
dtrace_sync(void)590Sstevel@tonic-gate dtrace_sync(void)
600Sstevel@tonic-gate {
610Sstevel@tonic-gate membar_producer();
620Sstevel@tonic-gate xc_all(dtrace_sync_func, 0, 0);
630Sstevel@tonic-gate }
640Sstevel@tonic-gate
650Sstevel@tonic-gate void
dtrace_toxic_ranges(void (* func)(uintptr_t base,uintptr_t limit))660Sstevel@tonic-gate dtrace_toxic_ranges(void (*func)(uintptr_t base, uintptr_t limit))
670Sstevel@tonic-gate {
680Sstevel@tonic-gate (*func)(PIOMAPBASE, PIOMAPBASE + PIOMAPSIZE);
690Sstevel@tonic-gate (*func)(OFW_START_ADDR, OFW_END_ADDR);
700Sstevel@tonic-gate
710Sstevel@tonic-gate if (hole_end > hole_start)
720Sstevel@tonic-gate (*func)((uintptr_t)hole_start, (uintptr_t)hole_end);
730Sstevel@tonic-gate }
740Sstevel@tonic-gate
750Sstevel@tonic-gate int (*dtrace_pid_probe_ptr)(struct regs *);
760Sstevel@tonic-gate
770Sstevel@tonic-gate void
dtrace_pid_probe(struct regs * rp)780Sstevel@tonic-gate dtrace_pid_probe(struct regs *rp)
790Sstevel@tonic-gate {
800Sstevel@tonic-gate krwlock_t *rwp = &CPU->cpu_ft_lock;
810Sstevel@tonic-gate uint32_t instr;
820Sstevel@tonic-gate
830Sstevel@tonic-gate /*
840Sstevel@tonic-gate * This trap should only be invoked if there's a corresponding
850Sstevel@tonic-gate * enabled dtrace probe. If there isn't, send SIGILL as though
860Sstevel@tonic-gate * the process had executed an invalid trap instruction.
870Sstevel@tonic-gate */
880Sstevel@tonic-gate rw_enter(rwp, RW_READER);
890Sstevel@tonic-gate if (dtrace_pid_probe_ptr != NULL && (*dtrace_pid_probe_ptr)(rp) == 0) {
900Sstevel@tonic-gate rw_exit(rwp);
910Sstevel@tonic-gate return;
920Sstevel@tonic-gate }
930Sstevel@tonic-gate rw_exit(rwp);
940Sstevel@tonic-gate
950Sstevel@tonic-gate /*
960Sstevel@tonic-gate * It is possible that we were preempted after entering the kernel,
970Sstevel@tonic-gate * and the tracepoint was removed. If it appears that the process hit
980Sstevel@tonic-gate * our reserved trap instruction, we call send SIGILL just as though
990Sstevel@tonic-gate * the user had executed an unused trap instruction.
1000Sstevel@tonic-gate */
1010Sstevel@tonic-gate if (fuword32((void *)rp->r_pc, &instr) != 0 ||
1020Sstevel@tonic-gate instr == FASTTRAP_INSTR) {
1030Sstevel@tonic-gate sigqueue_t *sqp = kmem_zalloc(sizeof (sigqueue_t), KM_SLEEP);
1040Sstevel@tonic-gate proc_t *p = curproc;
1050Sstevel@tonic-gate
1060Sstevel@tonic-gate sqp->sq_info.si_signo = SIGILL;
1070Sstevel@tonic-gate sqp->sq_info.si_code = ILL_ILLTRP;
1080Sstevel@tonic-gate sqp->sq_info.si_addr = (caddr_t)rp->r_pc;
1090Sstevel@tonic-gate sqp->sq_info.si_trapno = 0x38;
1100Sstevel@tonic-gate
1110Sstevel@tonic-gate mutex_enter(&p->p_lock);
1120Sstevel@tonic-gate sigaddqa(p, curthread, sqp);
1130Sstevel@tonic-gate mutex_exit(&p->p_lock);
1140Sstevel@tonic-gate aston(curthread);
1150Sstevel@tonic-gate }
1160Sstevel@tonic-gate }
1170Sstevel@tonic-gate
1180Sstevel@tonic-gate int (*dtrace_return_probe_ptr)(struct regs *);
1190Sstevel@tonic-gate
1200Sstevel@tonic-gate void
dtrace_return_probe(struct regs * rp)1210Sstevel@tonic-gate dtrace_return_probe(struct regs *rp)
1220Sstevel@tonic-gate {
1230Sstevel@tonic-gate krwlock_t *rwp;
1240Sstevel@tonic-gate uintptr_t npc = curthread->t_dtrace_npc;
1250Sstevel@tonic-gate uint8_t step = curthread->t_dtrace_step;
1260Sstevel@tonic-gate uint8_t ret = curthread->t_dtrace_ret;
1270Sstevel@tonic-gate
1280Sstevel@tonic-gate if (curthread->t_dtrace_ast) {
1290Sstevel@tonic-gate aston(curthread);
1300Sstevel@tonic-gate curthread->t_sig_check = 1;
1310Sstevel@tonic-gate }
1320Sstevel@tonic-gate
1330Sstevel@tonic-gate /*
1340Sstevel@tonic-gate * Clear all user tracing flags.
1350Sstevel@tonic-gate */
1360Sstevel@tonic-gate curthread->t_dtrace_ft = 0;
1370Sstevel@tonic-gate
1380Sstevel@tonic-gate /*
1390Sstevel@tonic-gate * If we weren't expecting to take a return probe trap, kill the
1400Sstevel@tonic-gate * process as though it had just executed an unassigned trap
1410Sstevel@tonic-gate * instruction.
1420Sstevel@tonic-gate */
1430Sstevel@tonic-gate if (step == 0) {
1440Sstevel@tonic-gate tsignal(curthread, SIGILL);
1450Sstevel@tonic-gate return;
1460Sstevel@tonic-gate }
1470Sstevel@tonic-gate
1480Sstevel@tonic-gate ASSERT(rp->r_npc == rp->r_pc + 4);
1490Sstevel@tonic-gate
1500Sstevel@tonic-gate /*
1510Sstevel@tonic-gate * If we hit this trap unrelated to a return probe, we're just here
1520Sstevel@tonic-gate * to reset the AST flag since we deferred a signal until after we
1530Sstevel@tonic-gate * logically single-stepped the instruction we copied out.
1540Sstevel@tonic-gate */
1550Sstevel@tonic-gate if (ret == 0) {
1560Sstevel@tonic-gate rp->r_pc = npc;
1570Sstevel@tonic-gate rp->r_npc = npc + 4;
1580Sstevel@tonic-gate return;
1590Sstevel@tonic-gate }
1600Sstevel@tonic-gate
1610Sstevel@tonic-gate /*
1620Sstevel@tonic-gate * We need to wait until after we've called the dtrace_return_probe_ptr
1630Sstevel@tonic-gate * function pointer to set %pc and %npc.
1640Sstevel@tonic-gate */
1650Sstevel@tonic-gate rwp = &CPU->cpu_ft_lock;
1660Sstevel@tonic-gate rw_enter(rwp, RW_READER);
1670Sstevel@tonic-gate if (dtrace_return_probe_ptr != NULL)
1680Sstevel@tonic-gate (void) (*dtrace_return_probe_ptr)(rp);
1690Sstevel@tonic-gate rw_exit(rwp);
1700Sstevel@tonic-gate rp->r_pc = npc;
1710Sstevel@tonic-gate rp->r_npc = npc + 4;
1720Sstevel@tonic-gate }
1730Sstevel@tonic-gate
1740Sstevel@tonic-gate void
dtrace_safe_synchronous_signal(void)1750Sstevel@tonic-gate dtrace_safe_synchronous_signal(void)
1760Sstevel@tonic-gate {
1770Sstevel@tonic-gate kthread_t *t = curthread;
1780Sstevel@tonic-gate struct regs *rp = lwptoregs(ttolwp(t));
1790Sstevel@tonic-gate
1800Sstevel@tonic-gate ASSERT(t->t_dtrace_on);
1810Sstevel@tonic-gate
1820Sstevel@tonic-gate /*
1830Sstevel@tonic-gate * If we're not actively tracing an instruction, turn off tracing
1840Sstevel@tonic-gate * flags. If the instruction we copied out caused a synchronous
1850Sstevel@tonic-gate * trap, reset the pc and npc back to their original values and turn
1860Sstevel@tonic-gate * off the flags.
1870Sstevel@tonic-gate */
1880Sstevel@tonic-gate if (rp->r_pc != t->t_dtrace_scrpc && rp->r_pc != t->t_dtrace_astpc &&
1890Sstevel@tonic-gate rp->r_npc != t->t_dtrace_astpc) {
1900Sstevel@tonic-gate t->t_dtrace_ft = 0;
1910Sstevel@tonic-gate } else if (rp->r_pc == t->t_dtrace_scrpc) {
1920Sstevel@tonic-gate rp->r_pc = t->t_dtrace_pc;
1930Sstevel@tonic-gate rp->r_npc = t->t_dtrace_npc;
1940Sstevel@tonic-gate t->t_dtrace_ft = 0;
1950Sstevel@tonic-gate }
1960Sstevel@tonic-gate }
1970Sstevel@tonic-gate
1980Sstevel@tonic-gate int
dtrace_safe_defer_signal(void)1990Sstevel@tonic-gate dtrace_safe_defer_signal(void)
2000Sstevel@tonic-gate {
2010Sstevel@tonic-gate kthread_t *t = curthread;
2020Sstevel@tonic-gate struct regs *rp = lwptoregs(ttolwp(t));
2030Sstevel@tonic-gate
2040Sstevel@tonic-gate ASSERT(t->t_dtrace_on);
2050Sstevel@tonic-gate
2060Sstevel@tonic-gate /*
2070Sstevel@tonic-gate * If we're not actively tracing an instruction, turn off tracing
2080Sstevel@tonic-gate * flags.
2090Sstevel@tonic-gate */
2100Sstevel@tonic-gate if (rp->r_pc != t->t_dtrace_scrpc && rp->r_pc != t->t_dtrace_astpc &&
2110Sstevel@tonic-gate rp->r_npc != t->t_dtrace_astpc) {
2120Sstevel@tonic-gate t->t_dtrace_ft = 0;
2130Sstevel@tonic-gate return (0);
2140Sstevel@tonic-gate }
2150Sstevel@tonic-gate
2160Sstevel@tonic-gate /*
2170Sstevel@tonic-gate * Otherwise, make sure we'll return to the kernel after executing
2180Sstevel@tonic-gate * the instruction we copied out.
2190Sstevel@tonic-gate */
2200Sstevel@tonic-gate if (!t->t_dtrace_step) {
2210Sstevel@tonic-gate ASSERT(rp->r_pc == t->t_dtrace_scrpc);
2220Sstevel@tonic-gate rp->r_npc = t->t_dtrace_astpc;
2230Sstevel@tonic-gate t->t_dtrace_step = 1;
2240Sstevel@tonic-gate }
2250Sstevel@tonic-gate
2260Sstevel@tonic-gate t->t_dtrace_ast = 1;
2270Sstevel@tonic-gate
2280Sstevel@tonic-gate return (1);
2290Sstevel@tonic-gate }
230*3446Smrj
231*3446Smrj /*
232*3446Smrj * Additional artificial frames for the machine type. For SPARC, we're already
233*3446Smrj * accounted for, so return 0.
234*3446Smrj */
235*3446Smrj int
dtrace_mach_aframes(void)236*3446Smrj dtrace_mach_aframes(void)
237*3446Smrj {
238*3446Smrj return (0);
239*3446Smrj }
240