xref: /freebsd/sys/cddl/dev/dtrace/powerpc/dtrace_isa.c (revision 47606b869eb149ebb7135d6594c3b9b9f05b9aed)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  *
22  * Portions Copyright 2012,2013 Justin Hibbits <jhibbits@freebsd.org>
23  *
24  * $FreeBSD$
25  */
26 /*
27  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
28  * Use is subject to license terms.
29  */
30 #include <sys/cdefs.h>
31 
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/kernel.h>
35 #include <sys/stack.h>
36 #include <sys/sysent.h>
37 #include <sys/pcpu.h>
38 
39 #include <machine/frame.h>
40 #include <machine/md_var.h>
41 #include <machine/psl.h>
42 #include <machine/reg.h>
43 #include <machine/stack.h>
44 
45 #include <vm/vm.h>
46 #include <vm/vm_param.h>
47 #include <vm/pmap.h>
48 
49 #include "regset.h"
50 
51 /* Offset to the LR Save word (ppc32) */
52 #define RETURN_OFFSET	4
53 /* Offset to LR Save word (ppc64).  CR Save area sits between back chain and LR */
54 #define RETURN_OFFSET64	16
55 
56 #ifdef __powerpc64__
57 #define OFFSET 4 /* Account for the TOC reload slot */
58 #define	FRAME_OFFSET	48
59 #else
60 #define OFFSET 0
61 #define	FRAME_OFFSET	8
62 #endif
63 
64 #define INKERNEL(x)	((x) <= VM_MAX_KERNEL_ADDRESS && \
65 		(x) >= VM_MIN_KERNEL_ADDRESS)
66 
67 static __inline int
68 dtrace_sp_inkernel(uintptr_t sp)
69 {
70 	struct trapframe *frame;
71 	vm_offset_t callpc;
72 
73 #ifdef __powerpc64__
74 	callpc = *(vm_offset_t *)(sp + RETURN_OFFSET64);
75 #else
76 	callpc = *(vm_offset_t *)(sp + RETURN_OFFSET);
77 #endif
78 	if ((callpc & 3) || (callpc < 0x100))
79 		return (0);
80 
81 	/*
82 	 * trapexit() and asttrapexit() are sentinels
83 	 * for kernel stack tracing.
84 	 */
85 	if (callpc + OFFSET == (vm_offset_t) &trapexit ||
86 	    callpc + OFFSET == (vm_offset_t) &asttrapexit) {
87 		if (sp == 0)
88 			return (0);
89 		frame = (struct trapframe *)(sp + FRAME_OFFSET);
90 
91 		return ((frame->srr1 & PSL_PR) == 0);
92 	}
93 
94 	return (1);
95 }
96 
97 static __inline uintptr_t
98 dtrace_next_sp(uintptr_t sp)
99 {
100 	vm_offset_t callpc;
101 	struct trapframe *frame;
102 
103 #ifdef __powerpc64__
104 	callpc = *(vm_offset_t *)(sp + RETURN_OFFSET64);
105 #else
106 	callpc = *(vm_offset_t *)(sp + RETURN_OFFSET);
107 #endif
108 
109 	/*
110 	 * trapexit() and asttrapexit() are sentinels
111 	 * for kernel stack tracing.
112 	 */
113 	if ((callpc + OFFSET == (vm_offset_t) &trapexit ||
114 	    callpc + OFFSET == (vm_offset_t) &asttrapexit)) {
115 		/* Access the trap frame */
116 		frame = (struct trapframe *)(sp + FRAME_OFFSET);
117 		return (*(uintptr_t *)(frame->fixreg[1]));
118 	}
119 
120 	return (*(uintptr_t*)sp);
121 }
122 
123 static __inline uintptr_t
124 dtrace_get_pc(uintptr_t sp)
125 {
126 	struct trapframe *frame;
127 	vm_offset_t callpc;
128 
129 #ifdef __powerpc64__
130 	callpc = *(vm_offset_t *)(sp + RETURN_OFFSET64);
131 #else
132 	callpc = *(vm_offset_t *)(sp + RETURN_OFFSET);
133 #endif
134 
135 	/*
136 	 * trapexit() and asttrapexit() are sentinels
137 	 * for kernel stack tracing.
138 	 */
139 	if ((callpc + OFFSET == (vm_offset_t) &trapexit ||
140 	    callpc + OFFSET == (vm_offset_t) &asttrapexit)) {
141 		/* Access the trap frame */
142 		frame = (struct trapframe *)(sp + FRAME_OFFSET);
143 		return (frame->srr0);
144 	}
145 
146 	return (callpc);
147 }
148 
149 greg_t
150 dtrace_getfp(void)
151 {
152 	return (greg_t)__builtin_frame_address(0);
153 }
154 
155 void
156 dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes,
157     uint32_t *intrpc)
158 {
159 	int depth = 0;
160 	uintptr_t osp, sp;
161 	vm_offset_t callpc;
162 	pc_t caller = (pc_t) solaris_cpu[curcpu].cpu_dtrace_caller;
163 
164 	osp = PAGE_SIZE;
165 	if (intrpc != 0)
166 		pcstack[depth++] = (pc_t) intrpc;
167 
168 	aframes++;
169 
170 	sp = dtrace_getfp();
171 
172 	while (depth < pcstack_limit) {
173 		if (sp <= osp)
174 			break;
175 
176 		if (!dtrace_sp_inkernel(sp))
177 			break;
178 		callpc = dtrace_get_pc(sp);
179 
180 		if (aframes > 0) {
181 			aframes--;
182 			if ((aframes == 0) && (caller != 0)) {
183 				pcstack[depth++] = caller;
184 			}
185 		}
186 		else {
187 			pcstack[depth++] = callpc;
188 		}
189 
190 		osp = sp;
191 		sp = dtrace_next_sp(sp);
192 	}
193 
194 	for (; depth < pcstack_limit; depth++) {
195 		pcstack[depth] = 0;
196 	}
197 }
198 
199 static int
200 dtrace_getustack_common(uint64_t *pcstack, int pcstack_limit, uintptr_t pc,
201     uintptr_t sp)
202 {
203 	proc_t *p = curproc;
204 	int ret = 0;
205 
206 	ASSERT(pcstack == NULL || pcstack_limit > 0);
207 
208 	while (pc != 0) {
209 		ret++;
210 		if (pcstack != NULL) {
211 			*pcstack++ = (uint64_t)pc;
212 			pcstack_limit--;
213 			if (pcstack_limit <= 0)
214 				break;
215 		}
216 
217 		if (sp == 0)
218 			break;
219 
220 		if (SV_PROC_FLAG(p, SV_ILP32)) {
221 			pc = dtrace_fuword32((void *)(sp + RETURN_OFFSET));
222 			sp = dtrace_fuword32((void *)sp);
223 		}
224 		else {
225 			pc = dtrace_fuword64((void *)(sp + RETURN_OFFSET64));
226 			sp = dtrace_fuword64((void *)sp);
227 		}
228 	}
229 
230 	return (ret);
231 }
232 
233 void
234 dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit)
235 {
236 	proc_t *p = curproc;
237 	struct trapframe *tf;
238 	uintptr_t pc, sp;
239 	volatile uint16_t *flags =
240 	    (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags;
241 	int n;
242 
243 	if (*flags & CPU_DTRACE_FAULT)
244 		return;
245 
246 	if (pcstack_limit <= 0)
247 		return;
248 
249 	/*
250 	 * If there's no user context we still need to zero the stack.
251 	 */
252 	if (p == NULL || (tf = curthread->td_frame) == NULL)
253 		goto zero;
254 
255 	*pcstack++ = (uint64_t)p->p_pid;
256 	pcstack_limit--;
257 
258 	if (pcstack_limit <= 0)
259 		return;
260 
261 	pc = tf->srr0;
262 	sp = tf->fixreg[1];
263 
264 	if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {
265 		/*
266 		 * In an entry probe.  The frame pointer has not yet been
267 		 * pushed (that happens in the function prologue).  The
268 		 * best approach is to add the current pc as a missing top
269 		 * of stack and back the pc up to the caller, which is stored
270 		 * at the current stack pointer address since the call
271 		 * instruction puts it there right before the branch.
272 		 */
273 
274 		*pcstack++ = (uint64_t)pc;
275 		pcstack_limit--;
276 		if (pcstack_limit <= 0)
277 			return;
278 
279 		pc = tf->lr;
280 	}
281 
282 	n = dtrace_getustack_common(pcstack, pcstack_limit, pc, sp);
283 	ASSERT(n >= 0);
284 	ASSERT(n <= pcstack_limit);
285 
286 	pcstack += n;
287 	pcstack_limit -= n;
288 
289 zero:
290 	while (pcstack_limit-- > 0)
291 		*pcstack++ = 0;
292 }
293 
294 int
295 dtrace_getustackdepth(void)
296 {
297 	proc_t *p = curproc;
298 	struct trapframe *tf;
299 	uintptr_t pc, sp;
300 	int n = 0;
301 
302 	if (p == NULL || (tf = curthread->td_frame) == NULL)
303 		return (0);
304 
305 	if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_FAULT))
306 		return (-1);
307 
308 	pc = tf->srr0;
309 	sp = tf->fixreg[1];
310 
311 	if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {
312 		/*
313 		 * In an entry probe.  The frame pointer has not yet been
314 		 * pushed (that happens in the function prologue).  The
315 		 * best approach is to add the current pc as a missing top
316 		 * of stack and back the pc up to the caller, which is stored
317 		 * at the current stack pointer address since the call
318 		 * instruction puts it there right before the branch.
319 		 */
320 
321 		if (SV_PROC_FLAG(p, SV_ILP32)) {
322 			pc = dtrace_fuword32((void *) sp);
323 		}
324 		else
325 			pc = dtrace_fuword64((void *) sp);
326 		n++;
327 	}
328 
329 	n += dtrace_getustack_common(NULL, 0, pc, sp);
330 
331 	return (n);
332 }
333 
334 void
335 dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit)
336 {
337 	proc_t *p = curproc;
338 	struct trapframe *tf;
339 	uintptr_t pc, sp;
340 	volatile uint16_t *flags =
341 	    (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags;
342 #ifdef notyet	/* XXX signal stack */
343 	uintptr_t oldcontext;
344 	size_t s1, s2;
345 #endif
346 
347 	if (*flags & CPU_DTRACE_FAULT)
348 		return;
349 
350 	if (pcstack_limit <= 0)
351 		return;
352 
353 	/*
354 	 * If there's no user context we still need to zero the stack.
355 	 */
356 	if (p == NULL || (tf = curthread->td_frame) == NULL)
357 		goto zero;
358 
359 	*pcstack++ = (uint64_t)p->p_pid;
360 	pcstack_limit--;
361 
362 	if (pcstack_limit <= 0)
363 		return;
364 
365 	pc = tf->srr0;
366 	sp = tf->fixreg[1];
367 
368 #ifdef notyet /* XXX signal stack */
369 	oldcontext = lwp->lwp_oldcontext;
370 	s1 = sizeof (struct xframe) + 2 * sizeof (long);
371 	s2 = s1 + sizeof (siginfo_t);
372 #endif
373 
374 	if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {
375 		*pcstack++ = (uint64_t)pc;
376 		*fpstack++ = 0;
377 		pcstack_limit--;
378 		if (pcstack_limit <= 0)
379 			return;
380 
381 		if (SV_PROC_FLAG(p, SV_ILP32)) {
382 			pc = dtrace_fuword32((void *)sp);
383 		}
384 		else {
385 			pc = dtrace_fuword64((void *)sp);
386 		}
387 	}
388 
389 	while (pc != 0) {
390 		*pcstack++ = (uint64_t)pc;
391 		*fpstack++ = sp;
392 		pcstack_limit--;
393 		if (pcstack_limit <= 0)
394 			break;
395 
396 		if (sp == 0)
397 			break;
398 
399 #ifdef notyet /* XXX signal stack */
400 		if (oldcontext == sp + s1 || oldcontext == sp + s2) {
401 			ucontext_t *ucp = (ucontext_t *)oldcontext;
402 			greg_t *gregs = ucp->uc_mcontext.gregs;
403 
404 			sp = dtrace_fulword(&gregs[REG_FP]);
405 			pc = dtrace_fulword(&gregs[REG_PC]);
406 
407 			oldcontext = dtrace_fulword(&ucp->uc_link);
408 		} else
409 #endif /* XXX */
410 		{
411 			if (SV_PROC_FLAG(p, SV_ILP32)) {
412 				pc = dtrace_fuword32((void *)(sp + RETURN_OFFSET));
413 				sp = dtrace_fuword32((void *)sp);
414 			}
415 			else {
416 				pc = dtrace_fuword64((void *)(sp + RETURN_OFFSET64));
417 				sp = dtrace_fuword64((void *)sp);
418 			}
419 		}
420 
421 		/*
422 		 * This is totally bogus:  if we faulted, we're going to clear
423 		 * the fault and break.  This is to deal with the apparently
424 		 * broken Java stacks on x86.
425 		 */
426 		if (*flags & CPU_DTRACE_FAULT) {
427 			*flags &= ~CPU_DTRACE_FAULT;
428 			break;
429 		}
430 	}
431 
432 zero:
433 	while (pcstack_limit-- > 0)
434 		*pcstack++ = 0;
435 }
436 
437 /*ARGSUSED*/
438 uint64_t
439 dtrace_getarg(int arg, int aframes)
440 {
441 	uintptr_t val;
442 	uintptr_t *fp = (uintptr_t *)dtrace_getfp();
443 	uintptr_t *stack;
444 	int i;
445 
446 	/*
447 	 * A total of 8 arguments are passed via registers; any argument with
448 	 * index of 7 or lower is therefore in a register.
449 	 */
450 	int inreg = 7;
451 
452 	for (i = 1; i <= aframes; i++) {
453 		fp = (uintptr_t *)*fp;
454 
455 		/*
456 		 * On ppc32 AIM, and booke, trapexit() is the immediately following
457 		 * label.  On ppc64 AIM trapexit() follows a nop.
458 		 */
459 #ifdef __powerpc64__
460 		if ((long)(fp[2]) + 4 == (long)trapexit) {
461 #else
462 		if ((long)(fp[1]) == (long)trapexit) {
463 #endif
464 			/*
465 			 * In the case of powerpc, we will use the pointer to the regs
466 			 * structure that was pushed when we took the trap.  To get this
467 			 * structure, we must increment beyond the frame structure.  If the
468 			 * argument that we're seeking is passed on the stack, we'll pull
469 			 * the true stack pointer out of the saved registers and decrement
470 			 * our argument by the number of arguments passed in registers; if
471 			 * the argument we're seeking is passed in regsiters, we can just
472 			 * load it directly.
473 			 */
474 #ifdef __powerpc64__
475 			struct reg *rp = (struct reg *)((uintptr_t)fp[0] + 48);
476 #else
477 			struct reg *rp = (struct reg *)((uintptr_t)fp[0] + 8);
478 #endif
479 
480 			if (arg <= inreg) {
481 				stack = &rp->fixreg[3];
482 			} else {
483 				stack = (uintptr_t *)(rp->fixreg[1]);
484 				arg -= inreg;
485 			}
486 			goto load;
487 		}
488 
489 	}
490 
491 	/*
492 	 * We know that we did not come through a trap to get into
493 	 * dtrace_probe() -- the provider simply called dtrace_probe()
494 	 * directly.  As this is the case, we need to shift the argument
495 	 * that we're looking for:  the probe ID is the first argument to
496 	 * dtrace_probe(), so the argument n will actually be found where
497 	 * one would expect to find argument (n + 1).
498 	 */
499 	arg++;
500 
501 	if (arg <= inreg) {
502 		/*
503 		 * This shouldn't happen.  If the argument is passed in a
504 		 * register then it should have been, well, passed in a
505 		 * register...
506 		 */
507 		DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
508 		return (0);
509 	}
510 
511 	arg -= (inreg + 1);
512 	stack = fp + 2;
513 
514 load:
515 	DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
516 	val = stack[arg];
517 	DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT);
518 
519 	return (val);
520 }
521 
522 int
523 dtrace_getstackdepth(int aframes)
524 {
525 	int depth = 0;
526 	uintptr_t osp, sp;
527 	vm_offset_t callpc;
528 
529 	osp = PAGE_SIZE;
530 	aframes++;
531 	sp = dtrace_getfp();
532 	depth++;
533 	for(;;) {
534 		if (sp <= osp)
535 			break;
536 
537 		if (!dtrace_sp_inkernel(sp))
538 			break;
539 
540 		if (aframes == 0)
541 			depth++;
542 		else
543 			aframes--;
544 		osp = sp;
545 		sp = dtrace_next_sp(sp);
546 	}
547 	if (depth < aframes)
548 		return (0);
549 
550 	return (depth);
551 }
552 
553 ulong_t
554 dtrace_getreg(struct trapframe *rp, uint_t reg)
555 {
556 	if (reg < 32)
557 		return (rp->fixreg[reg]);
558 
559 	switch (reg) {
560 	case 33:
561 		return (rp->lr);
562 	case 34:
563 		return (rp->cr);
564 	case 35:
565 		return (rp->xer);
566 	case 36:
567 		return (rp->ctr);
568 	case 37:
569 		return (rp->srr0);
570 	case 38:
571 		return (rp->srr1);
572 	case 39:
573 		return (rp->exc);
574 	default:
575 		DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
576 		return (0);
577 	}
578 }
579 
580 static int
581 dtrace_copycheck(uintptr_t uaddr, uintptr_t kaddr, size_t size)
582 {
583 	ASSERT(INKERNEL(kaddr) && kaddr + size >= kaddr);
584 
585 	if (uaddr + size > VM_MAXUSER_ADDRESS || uaddr + size < uaddr) {
586 		DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
587 		cpu_core[curcpu].cpuc_dtrace_illval = uaddr;
588 		return (0);
589 	}
590 
591 	return (1);
592 }
593 
594 void
595 dtrace_copyin(uintptr_t uaddr, uintptr_t kaddr, size_t size,
596     volatile uint16_t *flags)
597 {
598 	if (dtrace_copycheck(uaddr, kaddr, size))
599 		if (copyin((const void *)uaddr, (void *)kaddr, size)) {
600 			DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
601 			cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
602 		}
603 }
604 
605 void
606 dtrace_copyout(uintptr_t kaddr, uintptr_t uaddr, size_t size,
607     volatile uint16_t *flags)
608 {
609 	if (dtrace_copycheck(uaddr, kaddr, size)) {
610 		if (copyout((const void *)kaddr, (void *)uaddr, size)) {
611 			DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
612 			cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
613 		}
614 	}
615 }
616 
617 void
618 dtrace_copyinstr(uintptr_t uaddr, uintptr_t kaddr, size_t size,
619     volatile uint16_t *flags)
620 {
621 	size_t actual;
622 	int    error;
623 
624 	if (dtrace_copycheck(uaddr, kaddr, size)) {
625 		error = copyinstr((const void *)uaddr, (void *)kaddr,
626 		    size, &actual);
627 
628 		/* ENAMETOOLONG is not a fault condition. */
629 		if (error && error != ENAMETOOLONG) {
630 			DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
631 			cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
632 		}
633 	}
634 }
635 
636 /*
637  * The bulk of this function could be replaced to match dtrace_copyinstr()
638  * if we ever implement a copyoutstr().
639  */
640 void
641 dtrace_copyoutstr(uintptr_t kaddr, uintptr_t uaddr, size_t size,
642     volatile uint16_t *flags)
643 {
644 	size_t len;
645 
646 	if (dtrace_copycheck(uaddr, kaddr, size)) {
647 		len = strlen((const char *)kaddr);
648 		if (len > size)
649 			len = size;
650 
651 		if (copyout((const void *)kaddr, (void *)uaddr, len)) {
652 			DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
653 			cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
654 		}
655 	}
656 }
657 
658 uint8_t
659 dtrace_fuword8(void *uaddr)
660 {
661 	if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
662 		DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
663 		cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
664 		return (0);
665 	}
666 	return (fubyte(uaddr));
667 }
668 
669 uint16_t
670 dtrace_fuword16(void *uaddr)
671 {
672 	uint16_t ret = 0;
673 
674 	if (dtrace_copycheck((uintptr_t)uaddr, (uintptr_t)&ret, sizeof(ret))) {
675 		if (copyin((const void *)uaddr, (void *)&ret, sizeof(ret))) {
676 			DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
677 			cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
678 		}
679 	}
680 	return ret;
681 }
682 
683 uint32_t
684 dtrace_fuword32(void *uaddr)
685 {
686 	if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
687 		DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
688 		cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
689 		return (0);
690 	}
691 	return (fuword32(uaddr));
692 }
693 
694 uint64_t
695 dtrace_fuword64(void *uaddr)
696 {
697 	uint64_t ret = 0;
698 
699 	if (dtrace_copycheck((uintptr_t)uaddr, (uintptr_t)&ret, sizeof(ret))) {
700 		if (copyin((const void *)uaddr, (void *)&ret, sizeof(ret))) {
701 			DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
702 			cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
703 		}
704 	}
705 	return ret;
706 }
707 
708 uintptr_t
709 dtrace_fulword(void *uaddr)
710 {
711 	uintptr_t ret = 0;
712 
713 	if (dtrace_copycheck((uintptr_t)uaddr, (uintptr_t)&ret, sizeof(ret))) {
714 		if (copyin((const void *)uaddr, (void *)&ret, sizeof(ret))) {
715 			DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
716 			cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
717 		}
718 	}
719 	return ret;
720 }
721