xref: /illumos-gate/usr/src/uts/sun4/os/dtrace_subr.c (revision ae115bc7)
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
5f498645aSahl  * Common Development and Distribution License (the "License").
6f498645aSahl  * 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  */
21f498645aSahl 
227c478bd9Sstevel@tonic-gate /*
23*ae115bc7Smrj  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate #include <sys/dtrace.h>
307c478bd9Sstevel@tonic-gate #include <sys/fasttrap.h>
317c478bd9Sstevel@tonic-gate #include <sys/x_call.h>
327c478bd9Sstevel@tonic-gate #include <sys/atomic.h>
337c478bd9Sstevel@tonic-gate #include <sys/machsystm.h>
347c478bd9Sstevel@tonic-gate 
357c478bd9Sstevel@tonic-gate static void
dtrace_xcall_func(uint64_t arg1,uint64_t arg2)367c478bd9Sstevel@tonic-gate dtrace_xcall_func(uint64_t arg1, uint64_t arg2)
377c478bd9Sstevel@tonic-gate {
387c478bd9Sstevel@tonic-gate 	(*(dtrace_xcall_t)arg1)((void *)(arg2));
397c478bd9Sstevel@tonic-gate }
407c478bd9Sstevel@tonic-gate 
417c478bd9Sstevel@tonic-gate void
dtrace_xcall(processorid_t cpu,dtrace_xcall_t func,void * arg)427c478bd9Sstevel@tonic-gate dtrace_xcall(processorid_t cpu, dtrace_xcall_t func, void *arg)
437c478bd9Sstevel@tonic-gate {
447c478bd9Sstevel@tonic-gate 	if (cpu == DTRACE_CPUALL) {
457c478bd9Sstevel@tonic-gate 		xc_all(dtrace_xcall_func, (uint64_t)func, (uint64_t)arg);
467c478bd9Sstevel@tonic-gate 	} else {
477c478bd9Sstevel@tonic-gate 		xc_one(cpu, dtrace_xcall_func, (uint64_t)func, (uint64_t)arg);
487c478bd9Sstevel@tonic-gate 	}
497c478bd9Sstevel@tonic-gate }
507c478bd9Sstevel@tonic-gate 
517c478bd9Sstevel@tonic-gate /*ARGSUSED*/
527c478bd9Sstevel@tonic-gate static void
dtrace_sync_func(uint64_t arg1,uint64_t arg2)537c478bd9Sstevel@tonic-gate dtrace_sync_func(uint64_t arg1, uint64_t arg2)
547c478bd9Sstevel@tonic-gate {
557c478bd9Sstevel@tonic-gate 	membar_consumer();
567c478bd9Sstevel@tonic-gate }
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate void
dtrace_sync(void)597c478bd9Sstevel@tonic-gate dtrace_sync(void)
607c478bd9Sstevel@tonic-gate {
617c478bd9Sstevel@tonic-gate 	membar_producer();
627c478bd9Sstevel@tonic-gate 	xc_all(dtrace_sync_func, 0, 0);
637c478bd9Sstevel@tonic-gate }
647c478bd9Sstevel@tonic-gate 
657c478bd9Sstevel@tonic-gate void
dtrace_toxic_ranges(void (* func)(uintptr_t base,uintptr_t limit))667c478bd9Sstevel@tonic-gate dtrace_toxic_ranges(void (*func)(uintptr_t base, uintptr_t limit))
677c478bd9Sstevel@tonic-gate {
687c478bd9Sstevel@tonic-gate 	(*func)(PIOMAPBASE, PIOMAPBASE + PIOMAPSIZE);
697c478bd9Sstevel@tonic-gate 	(*func)(OFW_START_ADDR, OFW_END_ADDR);
707c478bd9Sstevel@tonic-gate 
717c478bd9Sstevel@tonic-gate 	if (hole_end > hole_start)
727c478bd9Sstevel@tonic-gate 		(*func)((uintptr_t)hole_start, (uintptr_t)hole_end);
737c478bd9Sstevel@tonic-gate }
747c478bd9Sstevel@tonic-gate 
757c478bd9Sstevel@tonic-gate int (*dtrace_pid_probe_ptr)(struct regs *);
767c478bd9Sstevel@tonic-gate 
777c478bd9Sstevel@tonic-gate void
dtrace_pid_probe(struct regs * rp)787c478bd9Sstevel@tonic-gate dtrace_pid_probe(struct regs *rp)
797c478bd9Sstevel@tonic-gate {
807c478bd9Sstevel@tonic-gate 	krwlock_t *rwp = &CPU->cpu_ft_lock;
817c478bd9Sstevel@tonic-gate 	uint32_t instr;
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate 	/*
847c478bd9Sstevel@tonic-gate 	 * This trap should only be invoked if there's a corresponding
857c478bd9Sstevel@tonic-gate 	 * enabled dtrace probe. If there isn't, send SIGILL as though
867c478bd9Sstevel@tonic-gate 	 * the process had executed an invalid trap instruction.
877c478bd9Sstevel@tonic-gate 	 */
887c478bd9Sstevel@tonic-gate 	rw_enter(rwp, RW_READER);
897c478bd9Sstevel@tonic-gate 	if (dtrace_pid_probe_ptr != NULL && (*dtrace_pid_probe_ptr)(rp) == 0) {
907c478bd9Sstevel@tonic-gate 		rw_exit(rwp);
917c478bd9Sstevel@tonic-gate 		return;
927c478bd9Sstevel@tonic-gate 	}
937c478bd9Sstevel@tonic-gate 	rw_exit(rwp);
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate 	/*
967c478bd9Sstevel@tonic-gate 	 * It is possible that we were preempted after entering the kernel,
977c478bd9Sstevel@tonic-gate 	 * and the tracepoint was removed. If it appears that the process hit
987c478bd9Sstevel@tonic-gate 	 * our reserved trap instruction, we call send SIGILL just as though
997c478bd9Sstevel@tonic-gate 	 * the user had executed an unused trap instruction.
1007c478bd9Sstevel@tonic-gate 	 */
1017c478bd9Sstevel@tonic-gate 	if (fuword32((void *)rp->r_pc, &instr) != 0 ||
1027c478bd9Sstevel@tonic-gate 	    instr == FASTTRAP_INSTR) {
1037c478bd9Sstevel@tonic-gate 		sigqueue_t *sqp = kmem_zalloc(sizeof (sigqueue_t), KM_SLEEP);
1047c478bd9Sstevel@tonic-gate 		proc_t *p = curproc;
1057c478bd9Sstevel@tonic-gate 
1067c478bd9Sstevel@tonic-gate 		sqp->sq_info.si_signo = SIGILL;
1077c478bd9Sstevel@tonic-gate 		sqp->sq_info.si_code = ILL_ILLTRP;
1087c478bd9Sstevel@tonic-gate 		sqp->sq_info.si_addr = (caddr_t)rp->r_pc;
1097c478bd9Sstevel@tonic-gate 		sqp->sq_info.si_trapno = 0x38;
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
1127c478bd9Sstevel@tonic-gate 		sigaddqa(p, curthread, sqp);
1137c478bd9Sstevel@tonic-gate 		mutex_exit(&p->p_lock);
1147c478bd9Sstevel@tonic-gate 		aston(curthread);
1157c478bd9Sstevel@tonic-gate 	}
1167c478bd9Sstevel@tonic-gate }
1177c478bd9Sstevel@tonic-gate 
1187c478bd9Sstevel@tonic-gate int (*dtrace_return_probe_ptr)(struct regs *);
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate void
dtrace_return_probe(struct regs * rp)1217c478bd9Sstevel@tonic-gate dtrace_return_probe(struct regs *rp)
1227c478bd9Sstevel@tonic-gate {
1237c478bd9Sstevel@tonic-gate 	krwlock_t *rwp;
1247c478bd9Sstevel@tonic-gate 	uintptr_t npc = curthread->t_dtrace_npc;
1257c478bd9Sstevel@tonic-gate 	uint8_t step = curthread->t_dtrace_step;
1267c478bd9Sstevel@tonic-gate 	uint8_t ret = curthread->t_dtrace_ret;
1277c478bd9Sstevel@tonic-gate 
1287c478bd9Sstevel@tonic-gate 	if (curthread->t_dtrace_ast) {
1297c478bd9Sstevel@tonic-gate 		aston(curthread);
1307c478bd9Sstevel@tonic-gate 		curthread->t_sig_check = 1;
1317c478bd9Sstevel@tonic-gate 	}
1327c478bd9Sstevel@tonic-gate 
1337c478bd9Sstevel@tonic-gate 	/*
1347c478bd9Sstevel@tonic-gate 	 * Clear all user tracing flags.
1357c478bd9Sstevel@tonic-gate 	 */
1367c478bd9Sstevel@tonic-gate 	curthread->t_dtrace_ft = 0;
1377c478bd9Sstevel@tonic-gate 
1387c478bd9Sstevel@tonic-gate 	/*
1397c478bd9Sstevel@tonic-gate 	 * If we weren't expecting to take a return probe trap, kill the
1407c478bd9Sstevel@tonic-gate 	 * process as though it had just executed an unassigned trap
1417c478bd9Sstevel@tonic-gate 	 * instruction.
1427c478bd9Sstevel@tonic-gate 	 */
1437c478bd9Sstevel@tonic-gate 	if (step == 0) {
1447c478bd9Sstevel@tonic-gate 		tsignal(curthread, SIGILL);
1457c478bd9Sstevel@tonic-gate 		return;
1467c478bd9Sstevel@tonic-gate 	}
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate 	ASSERT(rp->r_npc == rp->r_pc + 4);
1497c478bd9Sstevel@tonic-gate 
1507c478bd9Sstevel@tonic-gate 	/*
1517c478bd9Sstevel@tonic-gate 	 * If we hit this trap unrelated to a return probe, we're just here
1527c478bd9Sstevel@tonic-gate 	 * to reset the AST flag since we deferred a signal until after we
1537c478bd9Sstevel@tonic-gate 	 * logically single-stepped the instruction we copied out.
1547c478bd9Sstevel@tonic-gate 	 */
1557c478bd9Sstevel@tonic-gate 	if (ret == 0) {
1567c478bd9Sstevel@tonic-gate 		rp->r_pc = npc;
1577c478bd9Sstevel@tonic-gate 		rp->r_npc = npc + 4;
1587c478bd9Sstevel@tonic-gate 		return;
1597c478bd9Sstevel@tonic-gate 	}
1607c478bd9Sstevel@tonic-gate 
1617c478bd9Sstevel@tonic-gate 	/*
1627c478bd9Sstevel@tonic-gate 	 * We need to wait until after we've called the dtrace_return_probe_ptr
1637c478bd9Sstevel@tonic-gate 	 * function pointer to set %pc and %npc.
1647c478bd9Sstevel@tonic-gate 	 */
1657c478bd9Sstevel@tonic-gate 	rwp = &CPU->cpu_ft_lock;
1667c478bd9Sstevel@tonic-gate 	rw_enter(rwp, RW_READER);
1677c478bd9Sstevel@tonic-gate 	if (dtrace_return_probe_ptr != NULL)
1687c478bd9Sstevel@tonic-gate 		(void) (*dtrace_return_probe_ptr)(rp);
1697c478bd9Sstevel@tonic-gate 	rw_exit(rwp);
1707c478bd9Sstevel@tonic-gate 	rp->r_pc = npc;
1717c478bd9Sstevel@tonic-gate 	rp->r_npc = npc + 4;
1727c478bd9Sstevel@tonic-gate }
1737c478bd9Sstevel@tonic-gate 
1747c478bd9Sstevel@tonic-gate void
dtrace_safe_synchronous_signal(void)1757c478bd9Sstevel@tonic-gate dtrace_safe_synchronous_signal(void)
1767c478bd9Sstevel@tonic-gate {
1777c478bd9Sstevel@tonic-gate 	kthread_t *t = curthread;
1787c478bd9Sstevel@tonic-gate 	struct regs *rp = lwptoregs(ttolwp(t));
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate 	ASSERT(t->t_dtrace_on);
1817c478bd9Sstevel@tonic-gate 
1827c478bd9Sstevel@tonic-gate 	/*
1837c478bd9Sstevel@tonic-gate 	 * If we're not actively tracing an instruction, turn off tracing
1847c478bd9Sstevel@tonic-gate 	 * flags. If the instruction we copied out caused a synchronous
1857c478bd9Sstevel@tonic-gate 	 * trap, reset the pc and npc back to their original values and turn
1867c478bd9Sstevel@tonic-gate 	 * off the flags.
1877c478bd9Sstevel@tonic-gate 	 */
1887c478bd9Sstevel@tonic-gate 	if (rp->r_pc != t->t_dtrace_scrpc && rp->r_pc != t->t_dtrace_astpc &&
1897c478bd9Sstevel@tonic-gate 	    rp->r_npc != t->t_dtrace_astpc) {
1907c478bd9Sstevel@tonic-gate 		t->t_dtrace_ft = 0;
1917c478bd9Sstevel@tonic-gate 	} else if (rp->r_pc == t->t_dtrace_scrpc) {
1927c478bd9Sstevel@tonic-gate 		rp->r_pc = t->t_dtrace_pc;
1937c478bd9Sstevel@tonic-gate 		rp->r_npc = t->t_dtrace_npc;
1947c478bd9Sstevel@tonic-gate 		t->t_dtrace_ft = 0;
1957c478bd9Sstevel@tonic-gate 	}
1967c478bd9Sstevel@tonic-gate }
1977c478bd9Sstevel@tonic-gate 
1987c478bd9Sstevel@tonic-gate int
dtrace_safe_defer_signal(void)1997c478bd9Sstevel@tonic-gate dtrace_safe_defer_signal(void)
2007c478bd9Sstevel@tonic-gate {
2017c478bd9Sstevel@tonic-gate 	kthread_t *t = curthread;
2027c478bd9Sstevel@tonic-gate 	struct regs *rp = lwptoregs(ttolwp(t));
2037c478bd9Sstevel@tonic-gate 
2047c478bd9Sstevel@tonic-gate 	ASSERT(t->t_dtrace_on);
2057c478bd9Sstevel@tonic-gate 
2067c478bd9Sstevel@tonic-gate 	/*
2077c478bd9Sstevel@tonic-gate 	 * If we're not actively tracing an instruction, turn off tracing
2087c478bd9Sstevel@tonic-gate 	 * flags.
2097c478bd9Sstevel@tonic-gate 	 */
2107c478bd9Sstevel@tonic-gate 	if (rp->r_pc != t->t_dtrace_scrpc && rp->r_pc != t->t_dtrace_astpc &&
2117c478bd9Sstevel@tonic-gate 	    rp->r_npc != t->t_dtrace_astpc) {
2127c478bd9Sstevel@tonic-gate 		t->t_dtrace_ft = 0;
2137c478bd9Sstevel@tonic-gate 		return (0);
2147c478bd9Sstevel@tonic-gate 	}
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate 	/*
2177c478bd9Sstevel@tonic-gate 	 * Otherwise, make sure we'll return to the kernel after executing
2187c478bd9Sstevel@tonic-gate 	 * the instruction we copied out.
2197c478bd9Sstevel@tonic-gate 	 */
2207c478bd9Sstevel@tonic-gate 	if (!t->t_dtrace_step) {
2217c478bd9Sstevel@tonic-gate 		ASSERT(rp->r_pc == t->t_dtrace_scrpc);
2227c478bd9Sstevel@tonic-gate 		rp->r_npc = t->t_dtrace_astpc;
2237c478bd9Sstevel@tonic-gate 		t->t_dtrace_step = 1;
2247c478bd9Sstevel@tonic-gate 	}
2257c478bd9Sstevel@tonic-gate 
2267c478bd9Sstevel@tonic-gate 	t->t_dtrace_ast = 1;
2277c478bd9Sstevel@tonic-gate 
2287c478bd9Sstevel@tonic-gate 	return (1);
2297c478bd9Sstevel@tonic-gate }
230*ae115bc7Smrj 
231*ae115bc7Smrj /*
232*ae115bc7Smrj  * Additional artificial frames for the machine type. For SPARC, we're already
233*ae115bc7Smrj  * accounted for, so return 0.
234*ae115bc7Smrj  */
235*ae115bc7Smrj int
dtrace_mach_aframes(void)236*ae115bc7Smrj dtrace_mach_aframes(void)
237*ae115bc7Smrj {
238*ae115bc7Smrj 	return (0);
239*ae115bc7Smrj }
240