c6f5742f90
o uregs (sson@) o ustack (sson@) o /dev/dtrace/helper device (needed for USDT probes) The work done by me was: Sponsored by: The FreeBSD Foundation
656 lines
14 KiB
C
656 lines
14 KiB
C
/*
|
|
* CDDL HEADER START
|
|
*
|
|
* The contents of this file are subject to the terms of the
|
|
* Common Development and Distribution License, Version 1.0 only
|
|
* (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
|
|
* or http://www.opensolaris.org/os/licensing.
|
|
* 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
|
|
*
|
|
* $FreeBSD$
|
|
*/
|
|
/*
|
|
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
|
|
* Use is subject to license terms.
|
|
*/
|
|
#include <sys/cdefs.h>
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/systm.h>
|
|
#include <sys/kernel.h>
|
|
#include <sys/stack.h>
|
|
#include <sys/pcpu.h>
|
|
|
|
#include <machine/frame.h>
|
|
#include <machine/md_var.h>
|
|
#include <machine/pcb.h>
|
|
#include <machine/stack.h>
|
|
|
|
#include <vm/vm.h>
|
|
#include <vm/vm_param.h>
|
|
#include <vm/pmap.h>
|
|
|
|
#include "regset.h"
|
|
|
|
extern uintptr_t kernbase;
|
|
uintptr_t kernelbase = (uintptr_t) &kernbase;
|
|
|
|
#define INKERNEL(va) (((vm_offset_t)(va)) >= USRSTACK && \
|
|
((vm_offset_t)(va)) < VM_MAX_KERNEL_ADDRESS)
|
|
|
|
uint8_t dtrace_fuword8_nocheck(void *);
|
|
uint16_t dtrace_fuword16_nocheck(void *);
|
|
uint32_t dtrace_fuword32_nocheck(void *);
|
|
uint64_t dtrace_fuword64_nocheck(void *);
|
|
|
|
void
|
|
dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes,
|
|
uint32_t *intrpc)
|
|
{
|
|
int depth = 0;
|
|
register_t ebp;
|
|
struct i386_frame *frame;
|
|
vm_offset_t callpc;
|
|
pc_t caller = (pc_t) solaris_cpu[curcpu].cpu_dtrace_caller;
|
|
|
|
if (intrpc != 0)
|
|
pcstack[depth++] = (pc_t) intrpc;
|
|
|
|
aframes++;
|
|
|
|
__asm __volatile("movl %%ebp,%0" : "=r" (ebp));
|
|
|
|
frame = (struct i386_frame *)ebp;
|
|
while (depth < pcstack_limit) {
|
|
if (!INKERNEL(frame))
|
|
break;
|
|
|
|
callpc = frame->f_retaddr;
|
|
|
|
if (!INKERNEL(callpc))
|
|
break;
|
|
|
|
if (aframes > 0) {
|
|
aframes--;
|
|
if ((aframes == 0) && (caller != 0)) {
|
|
pcstack[depth++] = caller;
|
|
}
|
|
}
|
|
else {
|
|
pcstack[depth++] = callpc;
|
|
}
|
|
|
|
if (frame->f_frame <= frame ||
|
|
(vm_offset_t)frame->f_frame >=
|
|
(vm_offset_t)ebp + KSTACK_PAGES * PAGE_SIZE)
|
|
break;
|
|
frame = frame->f_frame;
|
|
}
|
|
|
|
for (; depth < pcstack_limit; depth++) {
|
|
pcstack[depth] = 0;
|
|
}
|
|
}
|
|
|
|
static int
|
|
dtrace_getustack_common(uint64_t *pcstack, int pcstack_limit, uintptr_t pc,
|
|
uintptr_t sp)
|
|
{
|
|
#ifdef notyet
|
|
proc_t *p = curproc;
|
|
uintptr_t oldcontext = lwp->lwp_oldcontext; /* XXX signal stack. */
|
|
size_t s1, s2;
|
|
#endif
|
|
volatile uint16_t *flags =
|
|
(volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags;
|
|
int ret = 0;
|
|
|
|
ASSERT(pcstack == NULL || pcstack_limit > 0);
|
|
|
|
#ifdef notyet /* XXX signal stack. */
|
|
if (p->p_model == DATAMODEL_NATIVE) {
|
|
s1 = sizeof (struct frame) + 2 * sizeof (long);
|
|
s2 = s1 + sizeof (siginfo_t);
|
|
} else {
|
|
s1 = sizeof (struct frame32) + 3 * sizeof (int);
|
|
s2 = s1 + sizeof (siginfo32_t);
|
|
}
|
|
#endif
|
|
|
|
while (pc != 0) {
|
|
ret++;
|
|
if (pcstack != NULL) {
|
|
*pcstack++ = (uint64_t)pc;
|
|
pcstack_limit--;
|
|
if (pcstack_limit <= 0)
|
|
break;
|
|
}
|
|
|
|
if (sp == 0)
|
|
break;
|
|
|
|
#ifdef notyet /* XXX signal stack. */
|
|
if (oldcontext == sp + s1 || oldcontext == sp + s2) {
|
|
if (p->p_model == DATAMODEL_NATIVE) {
|
|
ucontext_t *ucp = (ucontext_t *)oldcontext;
|
|
greg_t *gregs = ucp->uc_mcontext.gregs;
|
|
|
|
sp = dtrace_fulword(&gregs[REG_FP]);
|
|
pc = dtrace_fulword(&gregs[REG_PC]);
|
|
|
|
oldcontext = dtrace_fulword(&ucp->uc_link);
|
|
} else {
|
|
ucontext32_t *ucp = (ucontext32_t *)oldcontext;
|
|
greg32_t *gregs = ucp->uc_mcontext.gregs;
|
|
|
|
sp = dtrace_fuword32(&gregs[EBP]);
|
|
pc = dtrace_fuword32(&gregs[EIP]);
|
|
|
|
oldcontext = dtrace_fuword32(&ucp->uc_link);
|
|
}
|
|
} else {
|
|
if (p->p_model == DATAMODEL_NATIVE) {
|
|
struct frame *fr = (struct frame *)sp;
|
|
|
|
pc = dtrace_fulword(&fr->fr_savpc);
|
|
sp = dtrace_fulword(&fr->fr_savfp);
|
|
} else {
|
|
struct frame32 *fr = (struct frame32 *)sp;
|
|
|
|
pc = dtrace_fuword32(&fr->fr_savpc);
|
|
sp = dtrace_fuword32(&fr->fr_savfp);
|
|
}
|
|
}
|
|
#else
|
|
pc = dtrace_fuword32((void *)(sp +
|
|
offsetof(struct i386_frame, f_retaddr)));
|
|
sp = dtrace_fuword32((void *)sp);
|
|
#endif /* ! notyet */
|
|
|
|
/*
|
|
* This is totally bogus: if we faulted, we're going to clear
|
|
* the fault and break. This is to deal with the apparently
|
|
* broken Java stacks on x86.
|
|
*/
|
|
if (*flags & CPU_DTRACE_FAULT) {
|
|
*flags &= ~CPU_DTRACE_FAULT;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return (ret);
|
|
}
|
|
|
|
void
|
|
dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit)
|
|
{
|
|
proc_t *p = curproc;
|
|
struct trapframe *tf;
|
|
uintptr_t pc, sp, fp;
|
|
volatile uint16_t *flags =
|
|
(volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags;
|
|
int n;
|
|
|
|
if (*flags & CPU_DTRACE_FAULT)
|
|
return;
|
|
|
|
if (pcstack_limit <= 0)
|
|
return;
|
|
|
|
/*
|
|
* If there's no user context we still need to zero the stack.
|
|
*/
|
|
if (p == NULL || (tf = curthread->td_frame) == NULL)
|
|
goto zero;
|
|
|
|
*pcstack++ = (uint64_t)p->p_pid;
|
|
pcstack_limit--;
|
|
|
|
if (pcstack_limit <= 0)
|
|
return;
|
|
|
|
pc = tf->tf_eip;
|
|
fp = tf->tf_ebp;
|
|
sp = tf->tf_esp;
|
|
|
|
if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {
|
|
/*
|
|
* In an entry probe. The frame pointer has not yet been
|
|
* pushed (that happens in the function prologue). The
|
|
* best approach is to add the current pc as a missing top
|
|
* of stack and back the pc up to the caller, which is stored
|
|
* at the current stack pointer address since the call
|
|
* instruction puts it there right before the branch.
|
|
*/
|
|
|
|
*pcstack++ = (uint64_t)pc;
|
|
pcstack_limit--;
|
|
if (pcstack_limit <= 0)
|
|
return;
|
|
|
|
pc = dtrace_fuword32((void *) sp);
|
|
}
|
|
|
|
n = dtrace_getustack_common(pcstack, pcstack_limit, pc, sp);
|
|
ASSERT(n >= 0);
|
|
ASSERT(n <= pcstack_limit);
|
|
|
|
pcstack += n;
|
|
pcstack_limit -= n;
|
|
|
|
zero:
|
|
while (pcstack_limit-- > 0)
|
|
*pcstack++ = 0;
|
|
}
|
|
|
|
int
|
|
dtrace_getustackdepth(void)
|
|
{
|
|
proc_t *p = curproc;
|
|
struct trapframe *tf;
|
|
uintptr_t pc, fp, sp;
|
|
int n = 0;
|
|
|
|
if (p == NULL || (tf = curthread->td_frame) == NULL)
|
|
return (0);
|
|
|
|
if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_FAULT))
|
|
return (-1);
|
|
|
|
pc = tf->tf_eip;
|
|
fp = tf->tf_ebp;
|
|
sp = tf->tf_esp;
|
|
|
|
if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {
|
|
/*
|
|
* In an entry probe. The frame pointer has not yet been
|
|
* pushed (that happens in the function prologue). The
|
|
* best approach is to add the current pc as a missing top
|
|
* of stack and back the pc up to the caller, which is stored
|
|
* at the current stack pointer address since the call
|
|
* instruction puts it there right before the branch.
|
|
*/
|
|
|
|
pc = dtrace_fuword32((void *) sp);
|
|
n++;
|
|
}
|
|
|
|
n += dtrace_getustack_common(NULL, 0, pc, fp);
|
|
|
|
return (n);
|
|
}
|
|
|
|
void
|
|
dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit)
|
|
{
|
|
proc_t *p = curproc;
|
|
struct trapframe *tf;
|
|
uintptr_t pc, sp, fp;
|
|
volatile uint16_t *flags =
|
|
(volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags;
|
|
#ifdef notyet /* XXX signal stack */
|
|
uintptr_t oldcontext;
|
|
size_t s1, s2;
|
|
#endif
|
|
|
|
if (*flags & CPU_DTRACE_FAULT)
|
|
return;
|
|
|
|
if (pcstack_limit <= 0)
|
|
return;
|
|
|
|
/*
|
|
* If there's no user context we still need to zero the stack.
|
|
*/
|
|
if (p == NULL || (tf = curthread->td_frame) == NULL)
|
|
goto zero;
|
|
|
|
*pcstack++ = (uint64_t)p->p_pid;
|
|
pcstack_limit--;
|
|
|
|
if (pcstack_limit <= 0)
|
|
return;
|
|
|
|
pc = tf->tf_eip;
|
|
fp = tf->tf_ebp;
|
|
sp = tf->tf_esp;
|
|
|
|
#ifdef notyet /* XXX signal stack */
|
|
oldcontext = lwp->lwp_oldcontext;
|
|
|
|
if (p->p_model == DATAMODEL_NATIVE) {
|
|
s1 = sizeof (struct frame) + 2 * sizeof (long);
|
|
s2 = s1 + sizeof (siginfo_t);
|
|
} else {
|
|
s1 = sizeof (struct frame32) + 3 * sizeof (int);
|
|
s2 = s1 + sizeof (siginfo32_t);
|
|
}
|
|
#endif
|
|
|
|
if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {
|
|
*pcstack++ = (uint64_t)pc;
|
|
*fpstack++ = 0;
|
|
pcstack_limit--;
|
|
if (pcstack_limit <= 0)
|
|
return;
|
|
|
|
pc = dtrace_fuword32((void *)sp);
|
|
}
|
|
|
|
while (pc != 0) {
|
|
*pcstack++ = (uint64_t)pc;
|
|
*fpstack++ = fp;
|
|
pcstack_limit--;
|
|
if (pcstack_limit <= 0)
|
|
break;
|
|
|
|
if (fp == 0)
|
|
break;
|
|
|
|
#ifdef notyet /* XXX signal stack */
|
|
if (oldcontext == sp + s1 || oldcontext == sp + s2) {
|
|
if (p->p_model == DATAMODEL_NATIVE) {
|
|
ucontext_t *ucp = (ucontext_t *)oldcontext;
|
|
greg_t *gregs = ucp->uc_mcontext.gregs;
|
|
|
|
sp = dtrace_fulword(&gregs[REG_FP]);
|
|
pc = dtrace_fulword(&gregs[REG_PC]);
|
|
|
|
oldcontext = dtrace_fulword(&ucp->uc_link);
|
|
} else {
|
|
ucontext_t *ucp = (ucontext_t *)oldcontext;
|
|
greg_t *gregs = ucp->uc_mcontext.gregs;
|
|
|
|
sp = dtrace_fuword32(&gregs[EBP]);
|
|
pc = dtrace_fuword32(&gregs[EIP]);
|
|
|
|
oldcontext = dtrace_fuword32(&ucp->uc_link);
|
|
}
|
|
} else
|
|
#endif /* XXX */
|
|
{
|
|
pc = dtrace_fuword32((void *)(fp +
|
|
offsetof(struct i386_frame, f_retaddr)));
|
|
fp = dtrace_fuword32((void *)fp);
|
|
}
|
|
|
|
/*
|
|
* This is totally bogus: if we faulted, we're going to clear
|
|
* the fault and break. This is to deal with the apparently
|
|
* broken Java stacks on x86.
|
|
*/
|
|
if (*flags & CPU_DTRACE_FAULT) {
|
|
*flags &= ~CPU_DTRACE_FAULT;
|
|
break;
|
|
}
|
|
}
|
|
|
|
zero:
|
|
while (pcstack_limit-- > 0)
|
|
*pcstack++ = 0;
|
|
}
|
|
|
|
uint64_t
|
|
dtrace_getarg(int arg, int aframes)
|
|
{
|
|
uintptr_t val;
|
|
struct i386_frame *fp = (struct i386_frame *)dtrace_getfp();
|
|
uintptr_t *stack;
|
|
int i;
|
|
|
|
for (i = 1; i <= aframes; i++) {
|
|
fp = fp->f_frame;
|
|
|
|
if (fp->f_retaddr == (long)dtrace_invop_callsite) {
|
|
/*
|
|
* If we pass through the invalid op handler, we will
|
|
* use the pointer that it passed to the stack as the
|
|
* second argument to dtrace_invop() as the pointer to
|
|
* the stack. When using this stack, we must step
|
|
* beyond the EIP/RIP that was pushed when the trap was
|
|
* taken -- hence the "+ 1" below.
|
|
*/
|
|
stack = ((uintptr_t **)&fp[1])[1] + 1;
|
|
goto load;
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
* We know that we did not come through a trap to get into
|
|
* dtrace_probe() -- the provider simply called dtrace_probe()
|
|
* directly. As this is the case, we need to shift the argument
|
|
* that we're looking for: the probe ID is the first argument to
|
|
* dtrace_probe(), so the argument n will actually be found where
|
|
* one would expect to find argument (n + 1).
|
|
*/
|
|
arg++;
|
|
|
|
stack = (uintptr_t *)&fp[1];
|
|
|
|
load:
|
|
DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
|
|
val = stack[arg];
|
|
DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT);
|
|
|
|
return (val);
|
|
}
|
|
|
|
int
|
|
dtrace_getstackdepth(int aframes)
|
|
{
|
|
int depth = 0;
|
|
struct i386_frame *frame;
|
|
vm_offset_t ebp;
|
|
|
|
aframes++;
|
|
ebp = dtrace_getfp();
|
|
frame = (struct i386_frame *)ebp;
|
|
depth++;
|
|
for(;;) {
|
|
if (!INKERNEL((long) frame))
|
|
break;
|
|
if (!INKERNEL((long) frame->f_frame))
|
|
break;
|
|
depth++;
|
|
if (frame->f_frame <= frame ||
|
|
(vm_offset_t)frame->f_frame >=
|
|
(vm_offset_t)ebp + KSTACK_PAGES * PAGE_SIZE)
|
|
break;
|
|
frame = frame->f_frame;
|
|
}
|
|
if (depth < aframes)
|
|
return 0;
|
|
else
|
|
return depth - aframes;
|
|
}
|
|
|
|
ulong_t
|
|
dtrace_getreg(struct trapframe *rp, uint_t reg)
|
|
{
|
|
struct pcb *pcb;
|
|
int regmap[] = { /* Order is dependent on reg.d */
|
|
REG_GS, /* 0 GS */
|
|
REG_FS, /* 1 FS */
|
|
REG_ES, /* 2 ES */
|
|
REG_DS, /* 3 DS */
|
|
REG_RDI, /* 4 EDI */
|
|
REG_RSI, /* 5 ESI */
|
|
REG_RBP, /* 6 EBP, REG_FP */
|
|
REG_RSP, /* 7 ESP */
|
|
REG_RBX, /* 8 EBX */
|
|
REG_RDX, /* 9 EDX, REG_R1 */
|
|
REG_RCX, /* 10 ECX */
|
|
REG_RAX, /* 11 EAX, REG_R0 */
|
|
REG_TRAPNO, /* 12 TRAPNO */
|
|
REG_ERR, /* 13 ERR */
|
|
REG_RIP, /* 14 EIP, REG_PC */
|
|
REG_CS, /* 15 CS */
|
|
REG_RFL, /* 16 EFL, REG_PS */
|
|
REG_RSP, /* 17 UESP, REG_SP */
|
|
REG_SS /* 18 SS */
|
|
};
|
|
|
|
if (reg > SS) {
|
|
DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
|
|
return (0);
|
|
}
|
|
|
|
if (reg >= sizeof (regmap) / sizeof (int)) {
|
|
DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
|
|
return (0);
|
|
}
|
|
|
|
reg = regmap[reg];
|
|
|
|
switch(reg) {
|
|
case REG_GS:
|
|
if ((pcb = curthread->td_pcb) == NULL) {
|
|
DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
|
|
return (0);
|
|
}
|
|
return (pcb->pcb_gs);
|
|
case REG_FS:
|
|
return (rp->tf_fs);
|
|
case REG_ES:
|
|
return (rp->tf_es);
|
|
case REG_DS:
|
|
return (rp->tf_ds);
|
|
case REG_RDI:
|
|
return (rp->tf_edi);
|
|
case REG_RSI:
|
|
return (rp->tf_esi);
|
|
case REG_RBP:
|
|
return (rp->tf_ebp);
|
|
case REG_RSP:
|
|
return (rp->tf_isp);
|
|
case REG_RBX:
|
|
return (rp->tf_ebx);
|
|
case REG_RCX:
|
|
return (rp->tf_ecx);
|
|
case REG_RAX:
|
|
return (rp->tf_eax);
|
|
case REG_TRAPNO:
|
|
return (rp->tf_trapno);
|
|
case REG_ERR:
|
|
return (rp->tf_err);
|
|
case REG_RIP:
|
|
return (rp->tf_eip);
|
|
case REG_CS:
|
|
return (rp->tf_cs);
|
|
case REG_RFL:
|
|
return (rp->tf_eflags);
|
|
#if 0
|
|
case REG_RSP:
|
|
return (rp->tf_esp);
|
|
#endif
|
|
case REG_SS:
|
|
return (rp->tf_ss);
|
|
default:
|
|
DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
|
|
return (0);
|
|
}
|
|
}
|
|
|
|
static int
|
|
dtrace_copycheck(uintptr_t uaddr, uintptr_t kaddr, size_t size)
|
|
{
|
|
ASSERT(kaddr >= kernelbase && kaddr + size >= kaddr);
|
|
|
|
if (uaddr + size >= kernelbase || uaddr + size < uaddr) {
|
|
DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
|
|
cpu_core[curcpu].cpuc_dtrace_illval = uaddr;
|
|
return (0);
|
|
}
|
|
|
|
return (1);
|
|
}
|
|
|
|
void
|
|
dtrace_copyin(uintptr_t uaddr, uintptr_t kaddr, size_t size,
|
|
volatile uint16_t *flags)
|
|
{
|
|
if (dtrace_copycheck(uaddr, kaddr, size))
|
|
dtrace_copy(uaddr, kaddr, size);
|
|
}
|
|
|
|
void
|
|
dtrace_copyout(uintptr_t kaddr, uintptr_t uaddr, size_t size,
|
|
volatile uint16_t *flags)
|
|
{
|
|
if (dtrace_copycheck(uaddr, kaddr, size))
|
|
dtrace_copy(kaddr, uaddr, size);
|
|
}
|
|
|
|
void
|
|
dtrace_copyinstr(uintptr_t uaddr, uintptr_t kaddr, size_t size,
|
|
volatile uint16_t *flags)
|
|
{
|
|
if (dtrace_copycheck(uaddr, kaddr, size))
|
|
dtrace_copystr(uaddr, kaddr, size, flags);
|
|
}
|
|
|
|
void
|
|
dtrace_copyoutstr(uintptr_t kaddr, uintptr_t uaddr, size_t size,
|
|
volatile uint16_t *flags)
|
|
{
|
|
if (dtrace_copycheck(uaddr, kaddr, size))
|
|
dtrace_copystr(kaddr, uaddr, size, flags);
|
|
}
|
|
|
|
uint8_t
|
|
dtrace_fuword8(void *uaddr)
|
|
{
|
|
if ((uintptr_t)uaddr >= kernelbase) {
|
|
DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
|
|
cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
|
|
return (0);
|
|
}
|
|
return (dtrace_fuword8_nocheck(uaddr));
|
|
}
|
|
|
|
uint16_t
|
|
dtrace_fuword16(void *uaddr)
|
|
{
|
|
if ((uintptr_t)uaddr >= kernelbase) {
|
|
DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
|
|
cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
|
|
return (0);
|
|
}
|
|
return (dtrace_fuword16_nocheck(uaddr));
|
|
}
|
|
|
|
uint32_t
|
|
dtrace_fuword32(void *uaddr)
|
|
{
|
|
if ((uintptr_t)uaddr >= kernelbase) {
|
|
DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
|
|
cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
|
|
return (0);
|
|
}
|
|
return (dtrace_fuword32_nocheck(uaddr));
|
|
}
|
|
|
|
uint64_t
|
|
dtrace_fuword64(void *uaddr)
|
|
{
|
|
if ((uintptr_t)uaddr >= kernelbase) {
|
|
DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
|
|
cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
|
|
return (0);
|
|
}
|
|
return (dtrace_fuword64_nocheck(uaddr));
|
|
}
|