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]
25 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
26 * Use is subject to license terms.
28 #include <sys/cdefs.h>
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/kernel.h>
33 #include <sys/stack.h>
36 #include <machine/frame.h>
37 #include <machine/md_var.h>
38 #include <machine/reg.h>
39 #include <machine/stack.h>
40 #include <x86/ifunc.h>
43 #include <vm/vm_param.h>
48 uint8_t dtrace_fuword8_nocheck(void *);
49 uint16_t dtrace_fuword16_nocheck(void *);
50 uint32_t dtrace_fuword32_nocheck(void *);
51 uint64_t dtrace_fuword64_nocheck(void *);
53 int dtrace_ustackdepth_max = 2048;
56 dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes,
62 struct amd64_frame *frame;
64 pc_t caller = (pc_t) solaris_cpu[curcpu].cpu_dtrace_caller;
67 pcstack[depth++] = (pc_t) intrpc;
71 __asm __volatile("movq %%rbp,%0" : "=r" (rbp));
73 frame = (struct amd64_frame *)rbp;
75 while (depth < pcstack_limit) {
76 if (!INKERNEL((long) frame))
79 if ((vm_offset_t)frame >=
80 td->td_kstack + ptoa(td->td_kstack_pages) ||
81 (vm_offset_t)frame < td->td_kstack)
84 callpc = frame->f_retaddr;
86 if (!INKERNEL(callpc))
91 if ((aframes == 0) && (caller != 0)) {
92 pcstack[depth++] = caller;
95 pcstack[depth++] = callpc;
98 if ((vm_offset_t)frame->f_frame <= (vm_offset_t)frame)
100 frame = frame->f_frame;
103 for (; depth < pcstack_limit; depth++) {
109 dtrace_getustack_common(uint64_t *pcstack, int pcstack_limit, uintptr_t pc,
113 volatile uint16_t *flags =
114 (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags;
117 ASSERT(pcstack == NULL || pcstack_limit > 0);
118 ASSERT(dtrace_ustackdepth_max > 0);
122 * We limit the number of times we can go around this
123 * loop to account for a circular stack.
125 if (ret++ >= dtrace_ustackdepth_max) {
126 *flags |= CPU_DTRACE_BADSTACK;
127 cpu_core[curcpu].cpuc_dtrace_illval = sp;
131 if (pcstack != NULL) {
132 *pcstack++ = (uint64_t)pc;
134 if (pcstack_limit <= 0)
143 pc = dtrace_fuword64((void *)(sp +
144 offsetof(struct amd64_frame, f_retaddr)));
145 sp = dtrace_fuword64((void *)sp);
148 *flags |= CPU_DTRACE_BADSTACK;
149 cpu_core[curcpu].cpuc_dtrace_illval = sp;
154 * This is totally bogus: if we faulted, we're going to clear
155 * the fault and break. This is to deal with the apparently
156 * broken Java stacks on x86.
158 if (*flags & CPU_DTRACE_FAULT) {
159 *flags &= ~CPU_DTRACE_FAULT;
168 dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit)
171 struct trapframe *tf;
172 uintptr_t pc, sp, fp;
173 volatile uint16_t *flags =
174 (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags;
177 if (*flags & CPU_DTRACE_FAULT)
180 if (pcstack_limit <= 0)
184 * If there's no user context we still need to zero the stack.
186 if (p == NULL || (tf = curthread->td_frame) == NULL)
189 *pcstack++ = (uint64_t)p->p_pid;
192 if (pcstack_limit <= 0)
199 if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {
201 * In an entry probe. The frame pointer has not yet been
202 * pushed (that happens in the function prologue). The
203 * best approach is to add the current pc as a missing top
204 * of stack and back the pc up to the caller, which is stored
205 * at the current stack pointer address since the call
206 * instruction puts it there right before the branch.
209 *pcstack++ = (uint64_t)pc;
211 if (pcstack_limit <= 0)
214 pc = dtrace_fuword64((void *) sp);
217 n = dtrace_getustack_common(pcstack, pcstack_limit, pc, fp);
219 ASSERT(n <= pcstack_limit);
225 while (pcstack_limit-- > 0)
230 dtrace_getustackdepth(void)
233 struct trapframe *tf;
234 uintptr_t pc, fp, sp;
237 if (p == NULL || (tf = curthread->td_frame) == NULL)
240 if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_FAULT))
247 if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {
249 * In an entry probe. The frame pointer has not yet been
250 * pushed (that happens in the function prologue). The
251 * best approach is to add the current pc as a missing top
252 * of stack and back the pc up to the caller, which is stored
253 * at the current stack pointer address since the call
254 * instruction puts it there right before the branch.
257 pc = dtrace_fuword64((void *) sp);
261 n += dtrace_getustack_common(NULL, 0, pc, fp);
267 dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit)
270 struct trapframe *tf;
271 uintptr_t pc, sp, fp;
272 volatile uint16_t *flags =
273 (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags;
274 #ifdef notyet /* XXX signal stack */
275 uintptr_t oldcontext;
279 if (*flags & CPU_DTRACE_FAULT)
282 if (pcstack_limit <= 0)
286 * If there's no user context we still need to zero the stack.
288 if (p == NULL || (tf = curthread->td_frame) == NULL)
291 *pcstack++ = (uint64_t)p->p_pid;
294 if (pcstack_limit <= 0)
301 #ifdef notyet /* XXX signal stack */
302 oldcontext = lwp->lwp_oldcontext;
303 s1 = sizeof (struct xframe) + 2 * sizeof (long);
304 s2 = s1 + sizeof (siginfo_t);
307 if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {
308 *pcstack++ = (uint64_t)pc;
311 if (pcstack_limit <= 0)
314 pc = dtrace_fuword64((void *)sp);
318 *pcstack++ = (uint64_t)pc;
321 if (pcstack_limit <= 0)
327 #ifdef notyet /* XXX signal stack */
328 if (oldcontext == sp + s1 || oldcontext == sp + s2) {
329 ucontext_t *ucp = (ucontext_t *)oldcontext;
330 greg_t *gregs = ucp->uc_mcontext.gregs;
332 sp = dtrace_fulword(&gregs[REG_FP]);
333 pc = dtrace_fulword(&gregs[REG_PC]);
335 oldcontext = dtrace_fulword(&ucp->uc_link);
339 pc = dtrace_fuword64((void *)(fp +
340 offsetof(struct amd64_frame, f_retaddr)));
341 fp = dtrace_fuword64((void *)fp);
345 * This is totally bogus: if we faulted, we're going to clear
346 * the fault and break. This is to deal with the apparently
347 * broken Java stacks on x86.
349 if (*flags & CPU_DTRACE_FAULT) {
350 *flags &= ~CPU_DTRACE_FAULT;
356 while (pcstack_limit-- > 0)
362 dtrace_getarg(int arg, int aframes)
365 struct amd64_frame *fp = (struct amd64_frame *)dtrace_getfp();
370 * A total of 6 arguments are passed via registers; any argument with
371 * index of 5 or lower is therefore in a register.
375 for (i = 1; i <= aframes; i++) {
378 if (P2ROUNDUP(fp->f_retaddr, 16) ==
379 (long)dtrace_invop_callsite) {
381 * In the case of amd64, we will use the pointer to the
382 * regs structure that was pushed when we took the
383 * trap. To get this structure, we must increment
384 * beyond the frame structure, and then again beyond
385 * the calling RIP stored in dtrace_invop(). If the
386 * argument that we're seeking is passed on the stack,
387 * we'll pull the true stack pointer out of the saved
388 * registers and decrement our argument by the number
389 * of arguments passed in registers; if the argument
390 * we're seeking is passed in registers, we can just
393 struct trapframe *tf = (struct trapframe *)&fp[1];
398 stack = (uintptr_t *)&tf->tf_rdi;
401 stack = (uintptr_t *)&tf->tf_rsi;
404 stack = (uintptr_t *)&tf->tf_rdx;
407 stack = (uintptr_t *)&tf->tf_rcx;
410 stack = (uintptr_t *)&tf->tf_r8;
413 stack = (uintptr_t *)&tf->tf_r9;
418 stack = (uintptr_t *)(tf->tf_rsp);
427 * We know that we did not come through a trap to get into
428 * dtrace_probe() -- the provider simply called dtrace_probe()
429 * directly. As this is the case, we need to shift the argument
430 * that we're looking for: the probe ID is the first argument to
431 * dtrace_probe(), so the argument n will actually be found where
432 * one would expect to find argument (n + 1).
438 * This shouldn't happen. If the argument is passed in a
439 * register then it should have been, well, passed in a
442 DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
447 stack = (uintptr_t *)&fp[1];
450 DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
452 DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT);
458 dtrace_getstackdepth(int aframes)
461 struct amd64_frame *frame;
465 rbp = dtrace_getfp();
466 frame = (struct amd64_frame *)rbp;
469 if (!INKERNEL((long) frame))
471 if (!INKERNEL((long) frame->f_frame))
474 if (frame->f_frame <= frame ||
475 (vm_offset_t)frame->f_frame >= curthread->td_kstack +
476 curthread->td_kstack_pages * PAGE_SIZE)
478 frame = frame->f_frame;
483 return depth - aframes;
487 dtrace_getreg(struct trapframe *rp, uint_t reg)
489 /* This table is dependent on reg.d. */
497 REG_RBP, /* 6 EBP, REG_FP */
499 REG_RBX, /* 8 EBX, REG_R1 */
501 REG_RCX, /* 10 ECX */
502 REG_RAX, /* 11 EAX, REG_R0 */
503 REG_TRAPNO, /* 12 TRAPNO */
504 REG_ERR, /* 13 ERR */
505 REG_RIP, /* 14 EIP, REG_PC */
507 REG_RFL, /* 16 EFL, REG_PS */
508 REG_RSP, /* 17 UESP, REG_SP */
517 if (reg >= sizeof (regmap) / sizeof (int)) {
518 DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
524 /* This is dependent on reg.d. */
572 return (rp->tf_trapno);
582 return (rp->tf_rflags);
586 DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
592 dtrace_copycheck(uintptr_t uaddr, uintptr_t kaddr, size_t size)
594 ASSERT(INKERNEL(kaddr) && kaddr + size >= kaddr);
596 if (uaddr + size > VM_MAXUSER_ADDRESS || uaddr + size < uaddr) {
597 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
598 cpu_core[curcpu].cpuc_dtrace_illval = uaddr;
606 dtrace_copyin(uintptr_t uaddr, uintptr_t kaddr, size_t size,
607 volatile uint16_t *flags)
609 if (dtrace_copycheck(uaddr, kaddr, size))
610 dtrace_copy(uaddr, kaddr, size);
614 dtrace_copyout(uintptr_t kaddr, uintptr_t uaddr, size_t size,
615 volatile uint16_t *flags)
617 if (dtrace_copycheck(uaddr, kaddr, size))
618 dtrace_copy(kaddr, uaddr, size);
622 dtrace_copyinstr(uintptr_t uaddr, uintptr_t kaddr, size_t size,
623 volatile uint16_t *flags)
625 if (dtrace_copycheck(uaddr, kaddr, size))
626 dtrace_copystr(uaddr, kaddr, size, flags);
630 dtrace_copyoutstr(uintptr_t kaddr, uintptr_t uaddr, size_t size,
631 volatile uint16_t *flags)
633 if (dtrace_copycheck(uaddr, kaddr, size))
634 dtrace_copystr(kaddr, uaddr, size, flags);
638 dtrace_fuword8(void *uaddr)
640 if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
641 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
642 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
645 return (dtrace_fuword8_nocheck(uaddr));
649 dtrace_fuword16(void *uaddr)
651 if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
652 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
653 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
656 return (dtrace_fuword16_nocheck(uaddr));
660 dtrace_fuword32(void *uaddr)
662 if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
663 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
664 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
667 return (dtrace_fuword32_nocheck(uaddr));
671 dtrace_fuword64(void *uaddr)
673 if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
674 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
675 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
678 return (dtrace_fuword64_nocheck(uaddr));
682 * ifunc resolvers for SMAP support
684 void dtrace_copy_nosmap(uintptr_t, uintptr_t, size_t);
685 void dtrace_copy_smap(uintptr_t, uintptr_t, size_t);
686 DEFINE_IFUNC(, void, dtrace_copy, (uintptr_t, uintptr_t, size_t))
689 return ((cpu_stdext_feature & CPUID_STDEXT_SMAP) != 0 ?
690 dtrace_copy_smap : dtrace_copy_nosmap);
693 void dtrace_copystr_nosmap(uintptr_t, uintptr_t, size_t, volatile uint16_t *);
694 void dtrace_copystr_smap(uintptr_t, uintptr_t, size_t, volatile uint16_t *);
695 DEFINE_IFUNC(, void, dtrace_copystr, (uintptr_t, uintptr_t, size_t,
696 volatile uint16_t *))
699 return ((cpu_stdext_feature & CPUID_STDEXT_SMAP) != 0 ?
700 dtrace_copystr_smap : dtrace_copystr_nosmap);
703 uintptr_t dtrace_fulword_nosmap(void *);
704 uintptr_t dtrace_fulword_smap(void *);
705 DEFINE_IFUNC(, uintptr_t, dtrace_fulword, (void *))
708 return ((cpu_stdext_feature & CPUID_STDEXT_SMAP) != 0 ?
709 dtrace_fulword_smap : dtrace_fulword_nosmap);
712 uint8_t dtrace_fuword8_nocheck_nosmap(void *);
713 uint8_t dtrace_fuword8_nocheck_smap(void *);
714 DEFINE_IFUNC(, uint8_t, dtrace_fuword8_nocheck, (void *))
717 return ((cpu_stdext_feature & CPUID_STDEXT_SMAP) != 0 ?
718 dtrace_fuword8_nocheck_smap : dtrace_fuword8_nocheck_nosmap);
721 uint16_t dtrace_fuword16_nocheck_nosmap(void *);
722 uint16_t dtrace_fuword16_nocheck_smap(void *);
723 DEFINE_IFUNC(, uint16_t, dtrace_fuword16_nocheck, (void *))
726 return ((cpu_stdext_feature & CPUID_STDEXT_SMAP) != 0 ?
727 dtrace_fuword16_nocheck_smap : dtrace_fuword16_nocheck_nosmap);
730 uint32_t dtrace_fuword32_nocheck_nosmap(void *);
731 uint32_t dtrace_fuword32_nocheck_smap(void *);
732 DEFINE_IFUNC(, uint32_t, dtrace_fuword32_nocheck, (void *))
735 return ((cpu_stdext_feature & CPUID_STDEXT_SMAP) != 0 ?
736 dtrace_fuword32_nocheck_smap : dtrace_fuword32_nocheck_nosmap);
739 uint64_t dtrace_fuword64_nocheck_nosmap(void *);
740 uint64_t dtrace_fuword64_nocheck_smap(void *);
741 DEFINE_IFUNC(, uint64_t, dtrace_fuword64_nocheck, (void *))
744 return ((cpu_stdext_feature & CPUID_STDEXT_SMAP) != 0 ?
745 dtrace_fuword64_nocheck_smap : dtrace_fuword64_nocheck_nosmap);