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/reg.h>
43 #include <machine/stack.h>
46 #include <vm/vm_param.h>
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
57 #define OFFSET 4 /* Account for the TOC reload slot */
58 #define FRAME_OFFSET 48
61 #define FRAME_OFFSET 8
64 #define INKERNEL(x) (((x) <= VM_MAX_KERNEL_ADDRESS && \
65 (x) >= VM_MIN_KERNEL_ADDRESS) || \
66 (PMAP_HAS_DMAP && (x) >= DMAP_BASE_ADDRESS && \
67 (x) <= DMAP_MAX_ADDRESS))
70 dtrace_sp_inkernel(uintptr_t sp)
72 struct trapframe *frame;
75 /* Not within the kernel, or not aligned. */
76 if (!INKERNEL(sp) || (sp & 0xf) != 0)
79 callpc = *(vm_offset_t *)(sp + RETURN_OFFSET64);
81 callpc = *(vm_offset_t *)(sp + RETURN_OFFSET);
83 if ((callpc & 3) || (callpc < 0x100))
87 * trapexit() and asttrapexit() are sentinels
88 * for kernel stack tracing.
90 if (callpc + OFFSET == (vm_offset_t) &trapexit ||
91 callpc + OFFSET == (vm_offset_t) &asttrapexit) {
92 frame = (struct trapframe *)(sp + FRAME_OFFSET);
94 return ((frame->srr1 & PSL_PR) == 0);
101 dtrace_next_sp_pc(uintptr_t sp, uintptr_t *nsp, uintptr_t *pc)
104 struct trapframe *frame;
107 callpc = *(vm_offset_t *)(sp + RETURN_OFFSET64);
109 callpc = *(vm_offset_t *)(sp + RETURN_OFFSET);
113 * trapexit() and asttrapexit() are sentinels
114 * for kernel stack tracing.
116 if ((callpc + OFFSET == (vm_offset_t) &trapexit ||
117 callpc + OFFSET == (vm_offset_t) &asttrapexit)) {
118 /* Access the trap frame */
119 frame = (struct trapframe *)(sp + FRAME_OFFSET);
122 *nsp = frame->fixreg[1];
129 *nsp = *(uintptr_t *)sp;
135 dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes,
141 pc_t caller = (pc_t) solaris_cpu[curcpu].cpu_dtrace_caller;
145 pcstack[depth++] = (pc_t) intrpc;
149 sp = (uintptr_t)__builtin_frame_address(0);
151 while (depth < pcstack_limit) {
155 if (!dtrace_sp_inkernel(sp))
158 dtrace_next_sp_pc(osp, &sp, &callpc);
162 if ((aframes == 0) && (caller != 0)) {
163 pcstack[depth++] = caller;
167 pcstack[depth++] = callpc;
171 for (; depth < pcstack_limit; depth++) {
177 dtrace_getustack_common(uint64_t *pcstack, int pcstack_limit, uintptr_t pc,
183 ASSERT(pcstack == NULL || pcstack_limit > 0);
187 if (pcstack != NULL) {
188 *pcstack++ = (uint64_t)pc;
190 if (pcstack_limit <= 0)
197 if (SV_PROC_FLAG(p, SV_ILP32)) {
198 pc = dtrace_fuword32((void *)(sp + RETURN_OFFSET));
199 sp = dtrace_fuword32((void *)sp);
202 pc = dtrace_fuword64((void *)(sp + RETURN_OFFSET64));
203 sp = dtrace_fuword64((void *)sp);
211 dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit)
214 struct trapframe *tf;
216 volatile uint16_t *flags =
217 (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags;
220 if (*flags & CPU_DTRACE_FAULT)
223 if (pcstack_limit <= 0)
227 * If there's no user context we still need to zero the stack.
229 if (p == NULL || (tf = curthread->td_frame) == NULL)
232 *pcstack++ = (uint64_t)p->p_pid;
235 if (pcstack_limit <= 0)
241 if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {
243 * In an entry probe. The frame pointer has not yet been
244 * pushed (that happens in the function prologue). The
245 * best approach is to add the current pc as a missing top
246 * of stack and back the pc up to the caller, which is stored
247 * at the current stack pointer address since the call
248 * instruction puts it there right before the branch.
251 *pcstack++ = (uint64_t)pc;
253 if (pcstack_limit <= 0)
259 n = dtrace_getustack_common(pcstack, pcstack_limit, pc, sp);
261 ASSERT(n <= pcstack_limit);
267 while (pcstack_limit-- > 0)
272 dtrace_getustackdepth(void)
275 struct trapframe *tf;
279 if (p == NULL || (tf = curthread->td_frame) == NULL)
282 if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_FAULT))
288 if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {
290 * In an entry probe. The frame pointer has not yet been
291 * pushed (that happens in the function prologue). The
292 * best approach is to add the current pc as a missing top
293 * of stack and back the pc up to the caller, which is stored
294 * at the current stack pointer address since the call
295 * instruction puts it there right before the branch.
298 if (SV_PROC_FLAG(p, SV_ILP32)) {
299 pc = dtrace_fuword32((void *) sp);
302 pc = dtrace_fuword64((void *) sp);
306 n += dtrace_getustack_common(NULL, 0, pc, sp);
312 dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit)
315 struct trapframe *tf;
317 volatile uint16_t *flags =
318 (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags;
319 #ifdef notyet /* XXX signal stack */
320 uintptr_t oldcontext;
324 if (*flags & CPU_DTRACE_FAULT)
327 if (pcstack_limit <= 0)
331 * If there's no user context we still need to zero the stack.
333 if (p == NULL || (tf = curthread->td_frame) == NULL)
336 *pcstack++ = (uint64_t)p->p_pid;
339 if (pcstack_limit <= 0)
345 #ifdef notyet /* XXX signal stack */
346 oldcontext = lwp->lwp_oldcontext;
347 s1 = sizeof (struct xframe) + 2 * sizeof (long);
348 s2 = s1 + sizeof (siginfo_t);
351 if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {
352 *pcstack++ = (uint64_t)pc;
355 if (pcstack_limit <= 0)
358 if (SV_PROC_FLAG(p, SV_ILP32)) {
359 pc = dtrace_fuword32((void *)sp);
362 pc = dtrace_fuword64((void *)sp);
367 *pcstack++ = (uint64_t)pc;
370 if (pcstack_limit <= 0)
376 #ifdef notyet /* XXX signal stack */
377 if (oldcontext == sp + s1 || oldcontext == sp + s2) {
378 ucontext_t *ucp = (ucontext_t *)oldcontext;
379 greg_t *gregs = ucp->uc_mcontext.gregs;
381 sp = dtrace_fulword(&gregs[REG_FP]);
382 pc = dtrace_fulword(&gregs[REG_PC]);
384 oldcontext = dtrace_fulword(&ucp->uc_link);
388 if (SV_PROC_FLAG(p, SV_ILP32)) {
389 pc = dtrace_fuword32((void *)(sp + RETURN_OFFSET));
390 sp = dtrace_fuword32((void *)sp);
393 pc = dtrace_fuword64((void *)(sp + RETURN_OFFSET64));
394 sp = dtrace_fuword64((void *)sp);
399 * This is totally bogus: if we faulted, we're going to clear
400 * the fault and break. This is to deal with the apparently
401 * broken Java stacks on x86.
403 if (*flags & CPU_DTRACE_FAULT) {
404 *flags &= ~CPU_DTRACE_FAULT;
410 while (pcstack_limit-- > 0)
416 dtrace_getarg(int arg, int aframes)
419 uintptr_t *fp = (uintptr_t *)__builtin_frame_address(0);
424 * A total of 8 arguments are passed via registers; any argument with
425 * index of 7 or lower is therefore in a register.
429 for (i = 1; i <= aframes; i++) {
430 fp = (uintptr_t *)*fp;
433 * On ppc32 trapexit() is the immediately following label. On
434 * ppc64 AIM trapexit() follows a nop.
437 if ((long)(fp[2]) + 4 == (long)trapexit) {
439 if ((long)(fp[1]) == (long)trapexit) {
442 * In the case of powerpc, we will use the pointer to the regs
443 * structure that was pushed when we took the trap. To get this
444 * structure, we must increment beyond the frame structure. If the
445 * argument that we're seeking is passed on the stack, we'll pull
446 * the true stack pointer out of the saved registers and decrement
447 * our argument by the number of arguments passed in registers; if
448 * the argument we're seeking is passed in regsiters, we can just
452 struct reg *rp = (struct reg *)((uintptr_t)fp[0] + 48);
454 struct reg *rp = (struct reg *)((uintptr_t)fp[0] + 8);
458 stack = &rp->fixreg[3];
460 stack = (uintptr_t *)(rp->fixreg[1]);
469 * We know that we did not come through a trap to get into
470 * dtrace_probe() -- the provider simply called dtrace_probe()
471 * directly. As this is the case, we need to shift the argument
472 * that we're looking for: the probe ID is the first argument to
473 * dtrace_probe(), so the argument n will actually be found where
474 * one would expect to find argument (n + 1).
480 * This shouldn't happen. If the argument is passed in a
481 * register then it should have been, well, passed in a
484 DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
492 DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
494 DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT);
500 dtrace_getstackdepth(int aframes)
507 sp = (uintptr_t)__builtin_frame_address(0);
512 if (!dtrace_sp_inkernel(sp))
517 dtrace_next_sp_pc(sp, &sp, NULL);
522 return (depth - aframes);
526 dtrace_getreg(struct trapframe *rp, uint_t reg)
529 return (rp->fixreg[reg]);
547 DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
553 dtrace_copycheck(uintptr_t uaddr, uintptr_t kaddr, size_t size)
555 ASSERT(INKERNEL(kaddr) && kaddr + size >= kaddr);
557 if (uaddr + size > VM_MAXUSER_ADDRESS || uaddr + size < uaddr) {
558 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
559 cpu_core[curcpu].cpuc_dtrace_illval = uaddr;
567 dtrace_copyin(uintptr_t uaddr, uintptr_t kaddr, size_t size,
568 volatile uint16_t *flags)
570 if (dtrace_copycheck(uaddr, kaddr, size))
571 if (copyin((const void *)uaddr, (void *)kaddr, size)) {
572 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
573 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
578 dtrace_copyout(uintptr_t kaddr, uintptr_t uaddr, size_t size,
579 volatile uint16_t *flags)
581 if (dtrace_copycheck(uaddr, kaddr, size)) {
582 if (copyout((const void *)kaddr, (void *)uaddr, size)) {
583 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
584 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
590 dtrace_copyinstr(uintptr_t uaddr, uintptr_t kaddr, size_t size,
591 volatile uint16_t *flags)
596 if (dtrace_copycheck(uaddr, kaddr, size)) {
597 error = copyinstr((const void *)uaddr, (void *)kaddr,
600 /* ENAMETOOLONG is not a fault condition. */
601 if (error && error != ENAMETOOLONG) {
602 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
603 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
609 * The bulk of this function could be replaced to match dtrace_copyinstr()
610 * if we ever implement a copyoutstr().
613 dtrace_copyoutstr(uintptr_t kaddr, uintptr_t uaddr, size_t size,
614 volatile uint16_t *flags)
618 if (dtrace_copycheck(uaddr, kaddr, size)) {
619 len = strlen((const char *)kaddr);
623 if (copyout((const void *)kaddr, (void *)uaddr, len)) {
624 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
625 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
631 dtrace_fuword8(void *uaddr)
633 if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
634 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
635 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
638 return (fubyte(uaddr));
642 dtrace_fuword16(void *uaddr)
646 if (dtrace_copycheck((uintptr_t)uaddr, (uintptr_t)&ret, sizeof(ret))) {
647 if (copyin((const void *)uaddr, (void *)&ret, sizeof(ret))) {
648 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
649 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
656 dtrace_fuword32(void *uaddr)
658 if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
659 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
660 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
663 return (fuword32(uaddr));
667 dtrace_fuword64(void *uaddr)
671 if (dtrace_copycheck((uintptr_t)uaddr, (uintptr_t)&ret, sizeof(ret))) {
672 if (copyin((const void *)uaddr, (void *)&ret, sizeof(ret))) {
673 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
674 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
681 dtrace_fulword(void *uaddr)
685 if (dtrace_copycheck((uintptr_t)uaddr, (uintptr_t)&ret, sizeof(ret))) {
686 if (copyin((const void *)uaddr, (void *)&ret, sizeof(ret))) {
687 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
688 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;