14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync/*
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * CDDL HEADER START
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync *
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * The contents of this file are subject to the terms of the
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * Common Development and Distribution License (the "License").
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * You may not use this file except in compliance with the License.
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync *
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * or http://www.opensolaris.org/os/licensing.
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * See the License for the specific language governing permissions
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * and limitations under the License.
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync *
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * When distributing Covered Code, include this CDDL HEADER in each
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * If applicable, add the following below this CDDL HEADER, with the
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * fields enclosed by brackets "[]" replaced with your own identifying
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * information: Portions Copyright [yyyy] [name of copyright owner]
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync *
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * CDDL HEADER END
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync */
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync/*
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * Use is subject to license terms.
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync */
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync#include <sys/dtrace.h>
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync#include <sys/fasttrap.h>
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync#include <sys/x_call.h>
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync#include <sys/cmn_err.h>
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync#include <sys/trap.h>
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync#include <sys/psw.h>
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync#include <sys/privregs.h>
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync#include <sys/machsystm.h>
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync#include <vm/seg_kmem.h>
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsynctypedef struct dtrace_invop_hdlr {
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync int (*dtih_func)(uintptr_t, uintptr_t *, uintptr_t);
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync struct dtrace_invop_hdlr *dtih_next;
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync} dtrace_invop_hdlr_t;
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsyncdtrace_invop_hdlr_t *dtrace_invop_hdlr;
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsyncint
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsyncdtrace_invop(uintptr_t addr, uintptr_t *stack, uintptr_t eax)
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync{
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync dtrace_invop_hdlr_t *hdlr;
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync int rval;
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync for (hdlr = dtrace_invop_hdlr; hdlr != NULL; hdlr = hdlr->dtih_next) {
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync if ((rval = hdlr->dtih_func(addr, stack, eax)) != 0)
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync return (rval);
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync }
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync return (0);
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync}
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsyncvoid
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsyncdtrace_invop_add(int (*func)(uintptr_t, uintptr_t *, uintptr_t))
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync{
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync dtrace_invop_hdlr_t *hdlr;
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync hdlr = kmem_alloc(sizeof (dtrace_invop_hdlr_t), KM_SLEEP);
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync hdlr->dtih_func = func;
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync hdlr->dtih_next = dtrace_invop_hdlr;
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync dtrace_invop_hdlr = hdlr;
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync}
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsyncvoid
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsyncdtrace_invop_remove(int (*func)(uintptr_t, uintptr_t *, uintptr_t))
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync{
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync dtrace_invop_hdlr_t *hdlr = dtrace_invop_hdlr, *prev = NULL;
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync for (;;) {
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync if (hdlr == NULL)
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync panic("attempt to remove non-existent invop handler");
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync if (hdlr->dtih_func == func)
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync break;
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync prev = hdlr;
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync hdlr = hdlr->dtih_next;
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync }
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync if (prev == NULL) {
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync ASSERT(dtrace_invop_hdlr == hdlr);
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync dtrace_invop_hdlr = hdlr->dtih_next;
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync } else {
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync ASSERT(dtrace_invop_hdlr != hdlr);
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync prev->dtih_next = hdlr->dtih_next;
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync }
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync kmem_free(hdlr, sizeof (dtrace_invop_hdlr_t));
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync}
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsyncint
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsyncdtrace_getipl(void)
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync{
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync return (CPU->cpu_pri);
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync}
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync/*ARGSUSED*/
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsyncvoid
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsyncdtrace_toxic_ranges(void (*func)(uintptr_t base, uintptr_t limit))
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync{
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync#ifdef __amd64
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync extern uintptr_t toxic_addr;
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync extern size_t toxic_size;
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync (*func)(0, _userlimit);
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync if (hole_end > hole_start)
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync (*func)(hole_start, hole_end);
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync (*func)(toxic_addr, toxic_addr + toxic_size);
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync#else
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync extern void *device_arena_contains(void *, size_t, size_t *);
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync caddr_t vaddr;
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync size_t len;
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync for (vaddr = (caddr_t)kernelbase; vaddr < (caddr_t)KERNEL_TEXT;
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync vaddr += len) {
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync len = (caddr_t)KERNEL_TEXT - vaddr;
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync vaddr = device_arena_contains(vaddr, len, &len);
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync if (vaddr == NULL)
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync break;
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync (*func)((uintptr_t)vaddr, (uintptr_t)vaddr + len);
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync }
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync#endif
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync (*func)(0, _userlimit);
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync}
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsyncstatic int
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsyncdtrace_xcall_func(dtrace_xcall_t func, void *arg)
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync{
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync (*func)(arg);
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync return (0);
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync}
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync/*ARGSUSED*/
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsyncvoid
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsyncdtrace_xcall(processorid_t cpu, dtrace_xcall_t func, void *arg)
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync{
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync cpuset_t set;
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync CPUSET_ZERO(set);
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync if (cpu == DTRACE_CPUALL) {
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync CPUSET_ALL(set);
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync } else {
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync CPUSET_ADD(set, cpu);
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync }
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync kpreempt_disable();
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync xc_sync((xc_arg_t)func, (xc_arg_t)arg, 0, CPUSET2BV(set),
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync (xc_func_t)dtrace_xcall_func);
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync kpreempt_enable();
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync}
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsyncvoid
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsyncdtrace_sync_func(void)
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync{}
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsyncvoid
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsyncdtrace_sync(void)
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync{
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync dtrace_xcall(DTRACE_CPUALL, (dtrace_xcall_t)dtrace_sync_func, NULL);
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync}
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsyncint (*dtrace_pid_probe_ptr)(struct regs *);
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsyncint (*dtrace_return_probe_ptr)(struct regs *);
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsyncvoid
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsyncdtrace_user_probe(struct regs *rp, caddr_t addr, processorid_t cpuid)
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync{
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync krwlock_t *rwp;
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync proc_t *p = curproc;
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync extern void trap(struct regs *, caddr_t, processorid_t);
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync if (USERMODE(rp->r_cs) || (rp->r_ps & PS_VM)) {
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync if (curthread->t_cred != p->p_cred) {
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync cred_t *oldcred = curthread->t_cred;
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync /*
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * DTrace accesses t_cred in probe context. t_cred
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * must always be either NULL, or point to a valid,
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * allocated cred structure.
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync */
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync curthread->t_cred = crgetcred();
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync crfree(oldcred);
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync }
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync }
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync if (rp->r_trapno == T_DTRACE_RET) {
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync uint8_t step = curthread->t_dtrace_step;
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync uint8_t ret = curthread->t_dtrace_ret;
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync uintptr_t npc = curthread->t_dtrace_npc;
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync if (curthread->t_dtrace_ast) {
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync aston(curthread);
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync curthread->t_sig_check = 1;
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync }
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync /*
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * Clear all user tracing flags.
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync */
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync curthread->t_dtrace_ft = 0;
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync /*
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * If we weren't expecting to take a return probe trap, kill
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * the process as though it had just executed an unassigned
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * trap instruction.
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync */
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync if (step == 0) {
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync tsignal(curthread, SIGILL);
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync return;
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync }
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync /*
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * If we hit this trap unrelated to a return probe, we're
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * just here to reset the AST flag since we deferred a signal
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * until after we logically single-stepped the instruction we
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * copied out.
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync */
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync if (ret == 0) {
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync rp->r_pc = npc;
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync return;
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync }
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync /*
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * We need to wait until after we've called the
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * dtrace_return_probe_ptr function pointer to set %pc.
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync */
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync rwp = &CPU->cpu_ft_lock;
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync rw_enter(rwp, RW_READER);
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync if (dtrace_return_probe_ptr != NULL)
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync (void) (*dtrace_return_probe_ptr)(rp);
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync rw_exit(rwp);
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync rp->r_pc = npc;
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync } else if (rp->r_trapno == T_BPTFLT) {
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync uint8_t instr, instr2;
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync caddr_t linearpc;
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync rwp = &CPU->cpu_ft_lock;
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync /*
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * The DTrace fasttrap provider uses the breakpoint trap
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * (int 3). We let DTrace take the first crack at handling
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * this trap; if it's not a probe that DTrace knowns about,
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * we call into the trap() routine to handle it like a
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * breakpoint placed by a conventional debugger.
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync */
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync rw_enter(rwp, RW_READER);
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync if (dtrace_pid_probe_ptr != NULL &&
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync (*dtrace_pid_probe_ptr)(rp) == 0) {
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync rw_exit(rwp);
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync return;
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync }
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync rw_exit(rwp);
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync if (dtrace_linear_pc(rp, p, &linearpc) != 0) {
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync trap(rp, addr, cpuid);
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync return;
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync }
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync /*
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * If the instruction that caused the breakpoint trap doesn't
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * look like an int 3 anymore, it may be that this tracepoint
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * was removed just after the user thread executed it. In
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * that case, return to user land to retry the instuction.
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * Note that we assume the length of the instruction to retry
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * is 1 byte because that's the length of FASTTRAP_INSTR.
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * We check for r_pc > 0 and > 2 so that we don't have to
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * deal with segment wraparound.
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync */
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync if (rp->r_pc > 0 && fuword8(linearpc - 1, &instr) == 0 &&
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync instr != FASTTRAP_INSTR &&
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync (instr != 3 || (rp->r_pc >= 2 &&
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync (fuword8(linearpc - 2, &instr2) != 0 || instr2 != 0xCD)))) {
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync rp->r_pc--;
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync return;
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync }
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync trap(rp, addr, cpuid);
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync } else {
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync trap(rp, addr, cpuid);
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync }
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync}
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsyncvoid
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsyncdtrace_safe_synchronous_signal(void)
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync{
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync kthread_t *t = curthread;
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync struct regs *rp = lwptoregs(ttolwp(t));
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync size_t isz = t->t_dtrace_npc - t->t_dtrace_pc;
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync ASSERT(t->t_dtrace_on);
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync /*
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * If we're not in the range of scratch addresses, we're not actually
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * tracing user instructions so turn off the flags. If the instruction
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * we copied out caused a synchonous trap, reset the pc back to its
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * original value and turn off the flags.
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync */
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync if (rp->r_pc < t->t_dtrace_scrpc ||
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync rp->r_pc > t->t_dtrace_astpc + isz) {
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync t->t_dtrace_ft = 0;
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync } else if (rp->r_pc == t->t_dtrace_scrpc ||
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync rp->r_pc == t->t_dtrace_astpc) {
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync rp->r_pc = t->t_dtrace_pc;
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync t->t_dtrace_ft = 0;
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync }
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync}
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsyncint
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsyncdtrace_safe_defer_signal(void)
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync{
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync kthread_t *t = curthread;
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync struct regs *rp = lwptoregs(ttolwp(t));
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync size_t isz = t->t_dtrace_npc - t->t_dtrace_pc;
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync ASSERT(t->t_dtrace_on);
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync /*
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * If we're not in the range of scratch addresses, we're not actually
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * tracing user instructions so turn off the flags.
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync */
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync if (rp->r_pc < t->t_dtrace_scrpc ||
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync rp->r_pc > t->t_dtrace_astpc + isz) {
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync t->t_dtrace_ft = 0;
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync return (0);
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync }
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync /*
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * If we've executed the original instruction, but haven't performed
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * the jmp back to t->t_dtrace_npc or the clean up of any registers
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * used to emulate %rip-relative instructions in 64-bit mode, do that
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * here and take the signal right away. We detect this condition by
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * seeing if the program counter is the range [scrpc + isz, astpc).
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync */
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync if (t->t_dtrace_astpc - rp->r_pc <
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync t->t_dtrace_astpc - t->t_dtrace_scrpc - isz) {
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync#ifdef __amd64
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync /*
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * If there is a scratch register and we're on the
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * instruction immediately after the modified instruction,
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * restore the value of that scratch register.
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync */
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync if (t->t_dtrace_reg != 0 &&
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync rp->r_pc == t->t_dtrace_scrpc + isz) {
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync switch (t->t_dtrace_reg) {
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync case REG_RAX:
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync rp->r_rax = t->t_dtrace_regv;
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync break;
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync case REG_RCX:
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync rp->r_rcx = t->t_dtrace_regv;
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync break;
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync case REG_R8:
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync rp->r_r8 = t->t_dtrace_regv;
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync break;
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync case REG_R9:
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync rp->r_r9 = t->t_dtrace_regv;
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync break;
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync }
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync }
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync#endif
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync rp->r_pc = t->t_dtrace_npc;
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync t->t_dtrace_ft = 0;
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync return (0);
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync }
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync /*
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * Otherwise, make sure we'll return to the kernel after executing
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * the copied out instruction and defer the signal.
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync */
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync if (!t->t_dtrace_step) {
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync ASSERT(rp->r_pc < t->t_dtrace_astpc);
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync rp->r_pc += t->t_dtrace_astpc - t->t_dtrace_scrpc;
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync t->t_dtrace_step = 1;
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync }
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync t->t_dtrace_ast = 1;
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync return (1);
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync}
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync/*
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * Additional artificial frames for the machine type. For i86pc, we're already
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * accounted for, so return 0. On the hypervisor, we have an additional frame
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync * (xen_callback_handler).
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync */
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsyncint
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsyncdtrace_mach_aframes(void)
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync{
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync#ifdef __xpv
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync return (1);
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync#else
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync return (0);
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync#endif
14ea49401f3c8c61422aefbda43809e275f60c6cvboxsync}