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
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.
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]
22 * Portions Copyright 2012,2013 Justin Hibbits <jhibbits@freebsd.org>
27 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
28 * Use is subject to license terms.
30 #include <sys/cdefs.h>
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>
39 #include <machine/frame.h>
40 #include <machine/md_var.h>
41 #include <machine/psl.h>
42 #include <machine/stack.h>
45 #include <vm/vm_param.h>
50 /* Offset to the LR Save word (ppc32) */
51 #define RETURN_OFFSET 4
52 /* Offset to LR Save word (ppc64). CR Save area sits between back chain and LR */
53 #define RETURN_OFFSET64 16
56 #define OFFSET 4 /* Account for the TOC reload slot */
57 #define FRAME_OFFSET 48
60 #define FRAME_OFFSET 8
63 #define INKERNEL(x) (((x) <= VM_MAX_KERNEL_ADDRESS && \
64 (x) >= VM_MIN_KERNEL_ADDRESS) || \
65 (PMAP_HAS_DMAP && (x) >= DMAP_BASE_ADDRESS && \
66 (x) <= DMAP_MAX_ADDRESS))
69 dtrace_sp_inkernel(uintptr_t sp)
71 struct trapframe *frame;
74 /* Not within the kernel, or not aligned. */
75 if (!INKERNEL(sp) || (sp & 0xf) != 0)
78 callpc = *(vm_offset_t *)(sp + RETURN_OFFSET64);
80 callpc = *(vm_offset_t *)(sp + RETURN_OFFSET);
82 if ((callpc & 3) || (callpc < 0x100))
86 * trapexit() and asttrapexit() are sentinels
87 * for kernel stack tracing.
89 if (callpc + OFFSET == (vm_offset_t) &trapexit ||
90 callpc + OFFSET == (vm_offset_t) &asttrapexit) {
91 frame = (struct trapframe *)(sp + FRAME_OFFSET);
93 return ((frame->srr1 & PSL_PR) == 0);
100 dtrace_next_sp_pc(uintptr_t sp, uintptr_t *nsp, uintptr_t *pc, uintptr_t *lr)
103 struct trapframe *frame;
105 if (lr != 0 && *lr != 0)
109 callpc = *(vm_offset_t *)(sp + RETURN_OFFSET64);
111 callpc = *(vm_offset_t *)(sp + RETURN_OFFSET);
115 * trapexit() and asttrapexit() are sentinels
116 * for kernel stack tracing.
118 if ((callpc + OFFSET == (vm_offset_t) &trapexit ||
119 callpc + OFFSET == (vm_offset_t) &asttrapexit)) {
120 /* Access the trap frame */
121 frame = (struct trapframe *)(sp + FRAME_OFFSET);
124 *nsp = frame->fixreg[1];
133 *nsp = *(uintptr_t *)sp;
136 /* lr is only valid for trap frames */
142 dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes,
146 uintptr_t osp, sp, lr = 0;
148 pc_t caller = (pc_t) solaris_cpu[curcpu].cpu_dtrace_caller;
152 pcstack[depth++] = (pc_t) intrpc;
156 sp = (uintptr_t)__builtin_frame_address(0);
158 while (depth < pcstack_limit) {
162 if (!dtrace_sp_inkernel(sp))
165 dtrace_next_sp_pc(osp, &sp, &callpc, &lr);
166 //printf("sp: %#lx, pc: %#lx, lr: %#lx\n", sp, callpc, lr);
170 if ((aframes == 0) && (caller != 0)) {
171 pcstack[depth++] = caller;
175 pcstack[depth++] = callpc;
179 for (; depth < pcstack_limit; depth++) {
185 dtrace_getustack_common(uint64_t *pcstack, int pcstack_limit, uintptr_t pc,
191 ASSERT(pcstack == NULL || pcstack_limit > 0);
195 if (pcstack != NULL) {
196 *pcstack++ = (uint64_t)pc;
198 if (pcstack_limit <= 0)
205 if (SV_PROC_FLAG(p, SV_ILP32)) {
206 pc = dtrace_fuword32((void *)(sp + RETURN_OFFSET));
207 sp = dtrace_fuword32((void *)sp);
210 pc = dtrace_fuword64((void *)(sp + RETURN_OFFSET64));
211 sp = dtrace_fuword64((void *)sp);
219 dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit)
222 struct trapframe *tf;
224 volatile uint16_t *flags =
225 (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags;
228 if (*flags & CPU_DTRACE_FAULT)
231 if (pcstack_limit <= 0)
235 * If there's no user context we still need to zero the stack.
237 if (p == NULL || (tf = curthread->td_frame) == NULL)
240 *pcstack++ = (uint64_t)p->p_pid;
243 if (pcstack_limit <= 0)
249 if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {
251 * In an entry probe. The frame pointer has not yet been
252 * pushed (that happens in the function prologue). The
253 * best approach is to add the current pc as a missing top
254 * of stack and back the pc up to the caller, which is stored
255 * at the current stack pointer address since the call
256 * instruction puts it there right before the branch.
259 *pcstack++ = (uint64_t)pc;
261 if (pcstack_limit <= 0)
267 n = dtrace_getustack_common(pcstack, pcstack_limit, pc, sp);
269 ASSERT(n <= pcstack_limit);
275 while (pcstack_limit-- > 0)
280 dtrace_getustackdepth(void)
283 struct trapframe *tf;
287 if (p == NULL || (tf = curthread->td_frame) == NULL)
290 if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_FAULT))
296 if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {
298 * In an entry probe. The frame pointer has not yet been
299 * pushed (that happens in the function prologue). The
300 * best approach is to add the current pc as a missing top
301 * of stack and back the pc up to the caller, which is stored
302 * at the current stack pointer address since the call
303 * instruction puts it there right before the branch.
306 if (SV_PROC_FLAG(p, SV_ILP32)) {
307 pc = dtrace_fuword32((void *) sp);
310 pc = dtrace_fuword64((void *) sp);
314 n += dtrace_getustack_common(NULL, 0, pc, sp);
320 dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit)
323 struct trapframe *tf;
325 volatile uint16_t *flags =
326 (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags;
327 #ifdef notyet /* XXX signal stack */
328 uintptr_t oldcontext;
332 if (*flags & CPU_DTRACE_FAULT)
335 if (pcstack_limit <= 0)
339 * If there's no user context we still need to zero the stack.
341 if (p == NULL || (tf = curthread->td_frame) == NULL)
344 *pcstack++ = (uint64_t)p->p_pid;
347 if (pcstack_limit <= 0)
353 #ifdef notyet /* XXX signal stack */
354 oldcontext = lwp->lwp_oldcontext;
355 s1 = sizeof (struct xframe) + 2 * sizeof (long);
356 s2 = s1 + sizeof (siginfo_t);
359 if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {
360 *pcstack++ = (uint64_t)pc;
363 if (pcstack_limit <= 0)
366 if (SV_PROC_FLAG(p, SV_ILP32)) {
367 pc = dtrace_fuword32((void *)sp);
370 pc = dtrace_fuword64((void *)sp);
375 *pcstack++ = (uint64_t)pc;
378 if (pcstack_limit <= 0)
384 #ifdef notyet /* XXX signal stack */
385 if (oldcontext == sp + s1 || oldcontext == sp + s2) {
386 ucontext_t *ucp = (ucontext_t *)oldcontext;
387 greg_t *gregs = ucp->uc_mcontext.gregs;
389 sp = dtrace_fulword(&gregs[REG_FP]);
390 pc = dtrace_fulword(&gregs[REG_PC]);
392 oldcontext = dtrace_fulword(&ucp->uc_link);
396 if (SV_PROC_FLAG(p, SV_ILP32)) {
397 pc = dtrace_fuword32((void *)(sp + RETURN_OFFSET));
398 sp = dtrace_fuword32((void *)sp);
401 pc = dtrace_fuword64((void *)(sp + RETURN_OFFSET64));
402 sp = dtrace_fuword64((void *)sp);
407 * This is totally bogus: if we faulted, we're going to clear
408 * the fault and break. This is to deal with the apparently
409 * broken Java stacks on x86.
411 if (*flags & CPU_DTRACE_FAULT) {
412 *flags &= ~CPU_DTRACE_FAULT;
418 while (pcstack_limit-- > 0)
424 dtrace_getarg(int arg, int aframes)
427 uintptr_t *fp = (uintptr_t *)__builtin_frame_address(0);
432 * A total of 8 arguments are passed via registers; any argument with
433 * index of 7 or lower is therefore in a register.
437 for (i = 1; i <= aframes; i++) {
438 fp = (uintptr_t *)*fp;
441 * On ppc32 trapexit() is the immediately following label. On
442 * ppc64 AIM trapexit() follows a nop.
445 if ((long)(fp[2]) + 4 == (long)trapexit) {
447 if ((long)(fp[1]) == (long)trapexit) {
450 * In the case of powerpc, we will use the pointer to the regs
451 * structure that was pushed when we took the trap. To get this
452 * structure, we must increment beyond the frame structure. If the
453 * argument that we're seeking is passed on the stack, we'll pull
454 * the true stack pointer out of the saved registers and decrement
455 * our argument by the number of arguments passed in registers; if
456 * the argument we're seeking is passed in regsiters, we can just
460 struct reg *rp = (struct reg *)((uintptr_t)fp[0] + 48);
462 struct reg *rp = (struct reg *)((uintptr_t)fp[0] + 8);
466 stack = &rp->fixreg[3];
468 stack = (uintptr_t *)(rp->fixreg[1]);
477 * We know that we did not come through a trap to get into
478 * dtrace_probe() -- the provider simply called dtrace_probe()
479 * directly. As this is the case, we need to shift the argument
480 * that we're looking for: the probe ID is the first argument to
481 * dtrace_probe(), so the argument n will actually be found where
482 * one would expect to find argument (n + 1).
488 * This shouldn't happen. If the argument is passed in a
489 * register then it should have been, well, passed in a
492 DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
500 DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
502 DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT);
508 dtrace_getstackdepth(int aframes)
515 sp = (uintptr_t)__builtin_frame_address(0);
520 if (!dtrace_sp_inkernel(sp))
525 dtrace_next_sp_pc(sp, &sp, NULL, NULL);
530 return (depth - aframes);
534 dtrace_getreg(struct trapframe *rp, uint_t reg)
537 return (rp->fixreg[reg]);
555 DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
561 dtrace_copycheck(uintptr_t uaddr, uintptr_t kaddr, size_t size)
563 ASSERT(INKERNEL(kaddr) && kaddr + size >= kaddr);
565 if (uaddr + size > VM_MAXUSER_ADDRESS || uaddr + size < uaddr) {
566 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
567 cpu_core[curcpu].cpuc_dtrace_illval = uaddr;
575 dtrace_copyin(uintptr_t uaddr, uintptr_t kaddr, size_t size,
576 volatile uint16_t *flags)
578 if (dtrace_copycheck(uaddr, kaddr, size))
579 if (copyin((const void *)uaddr, (void *)kaddr, size)) {
580 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
581 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
586 dtrace_copyout(uintptr_t kaddr, uintptr_t uaddr, size_t size,
587 volatile uint16_t *flags)
589 if (dtrace_copycheck(uaddr, kaddr, size)) {
590 if (copyout((const void *)kaddr, (void *)uaddr, size)) {
591 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
592 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
598 dtrace_copyinstr(uintptr_t uaddr, uintptr_t kaddr, size_t size,
599 volatile uint16_t *flags)
604 if (dtrace_copycheck(uaddr, kaddr, size)) {
605 error = copyinstr((const void *)uaddr, (void *)kaddr,
608 /* ENAMETOOLONG is not a fault condition. */
609 if (error && error != ENAMETOOLONG) {
610 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
611 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
617 * The bulk of this function could be replaced to match dtrace_copyinstr()
618 * if we ever implement a copyoutstr().
621 dtrace_copyoutstr(uintptr_t kaddr, uintptr_t uaddr, size_t size,
622 volatile uint16_t *flags)
626 if (dtrace_copycheck(uaddr, kaddr, size)) {
627 len = strlen((const char *)kaddr);
631 if (copyout((const void *)kaddr, (void *)uaddr, len)) {
632 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
633 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
639 dtrace_fuword8(void *uaddr)
641 if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
642 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
643 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
646 return (fubyte(uaddr));
650 dtrace_fuword16(void *uaddr)
654 if (dtrace_copycheck((uintptr_t)uaddr, (uintptr_t)&ret, sizeof(ret))) {
655 if (copyin((const void *)uaddr, (void *)&ret, sizeof(ret))) {
656 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
657 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
664 dtrace_fuword32(void *uaddr)
666 if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
667 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
668 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
671 return (fuword32(uaddr));
675 dtrace_fuword64(void *uaddr)
679 if (dtrace_copycheck((uintptr_t)uaddr, (uintptr_t)&ret, sizeof(ret))) {
680 if (copyin((const void *)uaddr, (void *)&ret, sizeof(ret))) {
681 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
682 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
689 dtrace_fulword(void *uaddr)
693 if (dtrace_copycheck((uintptr_t)uaddr, (uintptr_t)&ret, sizeof(ret))) {
694 if (copyin((const void *)uaddr, (void *)&ret, sizeof(ret))) {
695 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
696 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;