xref: /onnv-gate/usr/src/uts/sun4/os/dtrace_subr.c (revision 3446:5903aece022d)
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