dtrace_subr.c revision 49048e7cecf159f9670295fa125e062ebd39bd57
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Copyright (c) 2011, Joyent, Inc. All rights reserved.
*/
#include <sys/fasttrap.h>
#include <sys/privregs.h>
#include <sys/machsystm.h>
#include <vm/seg_kmem.h>
typedef struct dtrace_invop_hdlr {
struct dtrace_invop_hdlr *dtih_next;
int
{
int rval;
return (rval);
}
return (0);
}
void
{
}
void
{
for (;;) {
panic("attempt to remove non-existent invop handler");
break;
}
} else {
}
}
int
dtrace_getipl(void)
{
}
/*ARGSUSED*/
void
{
#ifdef __amd64
extern uintptr_t toxic_addr;
extern size_t toxic_size;
(*func)(0, _userlimit);
if (hole_end > hole_start)
#else
break;
}
#endif
(*func)(0, _userlimit);
}
static int
{
return (0);
}
/*ARGSUSED*/
void
{
if (cpu == DTRACE_CPUALL) {
} else {
}
}
void
dtrace_sync_func(void)
{}
void
dtrace_sync(void)
{
}
int (*dtrace_pid_probe_ptr)(struct regs *);
int (*dtrace_return_probe_ptr)(struct regs *);
void
{
/*
* DTrace accesses t_cred in probe context. t_cred
* must always be either NULL, or point to a valid,
* allocated cred structure.
*/
}
}
if (curthread->t_dtrace_ast) {
}
/*
* Clear all user tracing flags.
*/
curthread->t_dtrace_ft = 0;
/*
* If we weren't expecting to take a return probe trap, kill
* the process as though it had just executed an unassigned
* trap instruction.
*/
if (step == 0) {
return;
}
/*
* If we hit this trap unrelated to a return probe, we're
* just here to reset the AST flag since we deferred a signal
* until after we logically single-stepped the instruction we
* copied out.
*/
if (ret == 0) {
return;
}
/*
* We need to wait until after we've called the
* dtrace_return_probe_ptr function pointer to set %pc.
*/
if (dtrace_return_probe_ptr != NULL)
(void) (*dtrace_return_probe_ptr)(rp);
/*
* The DTrace fasttrap provider uses the breakpoint trap
* (int 3). We let DTrace take the first crack at handling
* this trap; if it's not a probe that DTrace knowns about,
* we call into the trap() routine to handle it like a
* breakpoint placed by a conventional debugger.
*/
if (dtrace_pid_probe_ptr != NULL &&
(*dtrace_pid_probe_ptr)(rp) == 0) {
return;
}
return;
}
/*
* If the instruction that caused the breakpoint trap doesn't
* look like an int 3 anymore, it may be that this tracepoint
* was removed just after the user thread executed it. In
* that case, return to user land to retry the instuction.
* Note that we assume the length of the instruction to retry
* is 1 byte because that's the length of FASTTRAP_INSTR.
* We check for r_pc > 0 and > 2 so that we don't have to
* deal with segment wraparound.
*/
instr != FASTTRAP_INSTR &&
return;
}
} else {
}
}
void
{
ASSERT(t->t_dtrace_on);
/*
* If we're not in the range of scratch addresses, we're not actually
* tracing user instructions so turn off the flags. If the instruction
* we copied out caused a synchonous trap, reset the pc back to its
* original value and turn off the flags.
*/
t->t_dtrace_ft = 0;
t->t_dtrace_ft = 0;
}
}
int
dtrace_safe_defer_signal(void)
{
ASSERT(t->t_dtrace_on);
/*
* If we're not in the range of scratch addresses, we're not actually
* tracing user instructions so turn off the flags.
*/
t->t_dtrace_ft = 0;
return (0);
}
/*
* If we have executed the original instruction, but we have performed
* neither the jmp back to t->t_dtrace_npc nor the clean up of any
* registers used to emulate %rip-relative instructions in 64-bit mode,
* we'll save ourselves some effort by doing that here and taking the
* signal right away. We detect this condition by seeing if the program
* counter is the range [scrpc + isz, astpc).
*/
#ifdef __amd64
/*
* If there is a scratch register and we're on the
* instruction immediately after the modified instruction,
* restore the value of that scratch register.
*/
if (t->t_dtrace_reg != 0 &&
switch (t->t_dtrace_reg) {
case REG_RAX:
break;
case REG_RCX:
break;
case REG_R8:
break;
case REG_R9:
break;
}
}
#endif
t->t_dtrace_ft = 0;
return (0);
}
/*
* Otherwise, make sure we'll return to the kernel after executing
* the copied out instruction and defer the signal.
*/
if (!t->t_dtrace_step) {
t->t_dtrace_step = 1;
}
t->t_dtrace_ast = 1;
return (1);
}
/*
* Additional artificial frames for the machine type. For i86pc, we're already
* accounted for, so return 0. On the hypervisor, we have an additional frame
* (xen_callback_handler).
*/
int
dtrace_mach_aframes(void)
{
#ifdef __xpv
return (1);
#else
return (0);
#endif
}