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/pcb.h>
39 #include <machine/stack.h>
42 #include <vm/vm_param.h>
47 extern uintptr_t kernbase;
48 uintptr_t kernelbase = (uintptr_t) &kernbase;
50 uint8_t dtrace_fuword8_nocheck(void *);
51 uint16_t dtrace_fuword16_nocheck(void *);
52 uint32_t dtrace_fuword32_nocheck(void *);
53 uint64_t dtrace_fuword64_nocheck(void *);
55 int dtrace_ustackdepth_max = 2048;
58 dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes,
63 struct i386_frame *frame;
65 pc_t caller = (pc_t) solaris_cpu[curcpu].cpu_dtrace_caller;
68 pcstack[depth++] = (pc_t) intrpc;
72 __asm __volatile("movl %%ebp,%0" : "=r" (ebp));
74 frame = (struct i386_frame *)ebp;
75 while (depth < pcstack_limit) {
79 callpc = frame->f_retaddr;
81 if (!INKERNEL(callpc))
86 if ((aframes == 0) && (caller != 0)) {
87 pcstack[depth++] = caller;
91 pcstack[depth++] = callpc;
94 if (frame->f_frame <= frame ||
95 (vm_offset_t)frame->f_frame >= curthread->td_kstack +
96 curthread->td_kstack_pages * PAGE_SIZE)
98 frame = frame->f_frame;
101 for (; depth < pcstack_limit; depth++) {
107 dtrace_getustack_common(uint64_t *pcstack, int pcstack_limit, uintptr_t pc,
112 uintptr_t oldcontext = lwp->lwp_oldcontext; /* XXX signal stack. */
116 volatile uint16_t *flags =
117 (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags;
120 ASSERT(pcstack == NULL || pcstack_limit > 0);
121 ASSERT(dtrace_ustackdepth_max > 0);
123 #ifdef notyet /* XXX signal stack. */
124 if (p->p_model == DATAMODEL_NATIVE) {
125 s1 = sizeof (struct frame) + 2 * sizeof (long);
126 s2 = s1 + sizeof (siginfo_t);
128 s1 = sizeof (struct frame32) + 3 * sizeof (int);
129 s2 = s1 + sizeof (siginfo32_t);
135 * We limit the number of times we can go around this
136 * loop to account for a circular stack.
138 if (ret++ >= dtrace_ustackdepth_max) {
139 *flags |= CPU_DTRACE_BADSTACK;
140 cpu_core[curcpu].cpuc_dtrace_illval = sp;
144 if (pcstack != NULL) {
145 *pcstack++ = (uint64_t)pc;
147 if (pcstack_limit <= 0)
156 #ifdef notyet /* XXX signal stack. */
157 if (oldcontext == sp + s1 || oldcontext == sp + s2) {
158 if (p->p_model == DATAMODEL_NATIVE) {
159 ucontext_t *ucp = (ucontext_t *)oldcontext;
160 greg_t *gregs = ucp->uc_mcontext.gregs;
162 sp = dtrace_fulword(&gregs[REG_FP]);
163 pc = dtrace_fulword(&gregs[REG_PC]);
165 oldcontext = dtrace_fulword(&ucp->uc_link);
167 ucontext32_t *ucp = (ucontext32_t *)oldcontext;
168 greg32_t *gregs = ucp->uc_mcontext.gregs;
170 sp = dtrace_fuword32(&gregs[EBP]);
171 pc = dtrace_fuword32(&gregs[EIP]);
173 oldcontext = dtrace_fuword32(&ucp->uc_link);
176 if (p->p_model == DATAMODEL_NATIVE) {
177 struct frame *fr = (struct frame *)sp;
179 pc = dtrace_fulword(&fr->fr_savpc);
180 sp = dtrace_fulword(&fr->fr_savfp);
182 struct frame32 *fr = (struct frame32 *)sp;
184 pc = dtrace_fuword32(&fr->fr_savpc);
185 sp = dtrace_fuword32(&fr->fr_savfp);
189 pc = dtrace_fuword32((void *)(sp +
190 offsetof(struct i386_frame, f_retaddr)));
191 sp = dtrace_fuword32((void *)sp);
192 #endif /* ! notyet */
195 *flags |= CPU_DTRACE_BADSTACK;
196 cpu_core[curcpu].cpuc_dtrace_illval = sp;
201 * This is totally bogus: if we faulted, we're going to clear
202 * the fault and break. This is to deal with the apparently
203 * broken Java stacks on x86.
205 if (*flags & CPU_DTRACE_FAULT) {
206 *flags &= ~CPU_DTRACE_FAULT;
215 dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit)
218 struct trapframe *tf;
219 uintptr_t pc, sp, fp;
220 volatile uint16_t *flags =
221 (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags;
224 if (*flags & CPU_DTRACE_FAULT)
227 if (pcstack_limit <= 0)
231 * If there's no user context we still need to zero the stack.
233 if (p == NULL || (tf = curthread->td_frame) == NULL)
236 *pcstack++ = (uint64_t)p->p_pid;
239 if (pcstack_limit <= 0)
246 if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {
248 * In an entry probe. The frame pointer has not yet been
249 * pushed (that happens in the function prologue). The
250 * best approach is to add the current pc as a missing top
251 * of stack and back the pc up to the caller, which is stored
252 * at the current stack pointer address since the call
253 * instruction puts it there right before the branch.
256 *pcstack++ = (uint64_t)pc;
258 if (pcstack_limit <= 0)
261 pc = dtrace_fuword32((void *) sp);
264 n = dtrace_getustack_common(pcstack, pcstack_limit, pc, sp);
266 ASSERT(n <= pcstack_limit);
272 while (pcstack_limit-- > 0)
277 dtrace_getustackdepth(void)
280 struct trapframe *tf;
281 uintptr_t pc, fp, sp;
284 if (p == NULL || (tf = curthread->td_frame) == NULL)
287 if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_FAULT))
294 if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {
296 * In an entry probe. The frame pointer has not yet been
297 * pushed (that happens in the function prologue). The
298 * best approach is to add the current pc as a missing top
299 * of stack and back the pc up to the caller, which is stored
300 * at the current stack pointer address since the call
301 * instruction puts it there right before the branch.
304 pc = dtrace_fuword32((void *) sp);
308 n += dtrace_getustack_common(NULL, 0, pc, fp);
314 dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit)
317 struct trapframe *tf;
318 uintptr_t pc, sp, fp;
319 volatile uint16_t *flags =
320 (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags;
321 #ifdef notyet /* XXX signal stack */
322 uintptr_t oldcontext;
326 if (*flags & CPU_DTRACE_FAULT)
329 if (pcstack_limit <= 0)
333 * If there's no user context we still need to zero the stack.
335 if (p == NULL || (tf = curthread->td_frame) == NULL)
338 *pcstack++ = (uint64_t)p->p_pid;
341 if (pcstack_limit <= 0)
348 #ifdef notyet /* XXX signal stack */
349 oldcontext = lwp->lwp_oldcontext;
351 if (p->p_model == DATAMODEL_NATIVE) {
352 s1 = sizeof (struct frame) + 2 * sizeof (long);
353 s2 = s1 + sizeof (siginfo_t);
355 s1 = sizeof (struct frame32) + 3 * sizeof (int);
356 s2 = s1 + sizeof (siginfo32_t);
360 if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {
361 *pcstack++ = (uint64_t)pc;
364 if (pcstack_limit <= 0)
367 pc = dtrace_fuword32((void *)sp);
371 *pcstack++ = (uint64_t)pc;
374 if (pcstack_limit <= 0)
380 #ifdef notyet /* XXX signal stack */
381 if (oldcontext == sp + s1 || oldcontext == sp + s2) {
382 if (p->p_model == DATAMODEL_NATIVE) {
383 ucontext_t *ucp = (ucontext_t *)oldcontext;
384 greg_t *gregs = ucp->uc_mcontext.gregs;
386 sp = dtrace_fulword(&gregs[REG_FP]);
387 pc = dtrace_fulword(&gregs[REG_PC]);
389 oldcontext = dtrace_fulword(&ucp->uc_link);
391 ucontext_t *ucp = (ucontext_t *)oldcontext;
392 greg_t *gregs = ucp->uc_mcontext.gregs;
394 sp = dtrace_fuword32(&gregs[EBP]);
395 pc = dtrace_fuword32(&gregs[EIP]);
397 oldcontext = dtrace_fuword32(&ucp->uc_link);
402 pc = dtrace_fuword32((void *)(fp +
403 offsetof(struct i386_frame, f_retaddr)));
404 fp = dtrace_fuword32((void *)fp);
408 * This is totally bogus: if we faulted, we're going to clear
409 * the fault and break. This is to deal with the apparently
410 * broken Java stacks on x86.
412 if (*flags & CPU_DTRACE_FAULT) {
413 *flags &= ~CPU_DTRACE_FAULT;
419 while (pcstack_limit-- > 0)
424 dtrace_getarg(int arg, int aframes)
427 struct i386_frame *fp = (struct i386_frame *)dtrace_getfp();
431 for (i = 1; i <= aframes; i++) {
434 if (P2ROUNDUP(fp->f_retaddr, 4) ==
435 (long)dtrace_invop_callsite) {
437 * If we pass through the invalid op handler, we will
438 * use the pointer that it passed to the stack as the
439 * second argument to dtrace_invop() as the pointer to
440 * the stack. When using this stack, we must step
441 * beyond the EIP/RIP that was pushed when the trap was
442 * taken -- hence the "+ 1" below.
444 stack = ((uintptr_t **)&fp[1])[0] + 1;
451 * We know that we did not come through a trap to get into
452 * dtrace_probe() -- the provider simply called dtrace_probe()
453 * directly. As this is the case, we need to shift the argument
454 * that we're looking for: the probe ID is the first argument to
455 * dtrace_probe(), so the argument n will actually be found where
456 * one would expect to find argument (n + 1).
460 stack = (uintptr_t *)fp + 2;
463 DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
465 DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT);
471 dtrace_getstackdepth(int aframes)
474 struct i386_frame *frame;
478 ebp = dtrace_getfp();
479 frame = (struct i386_frame *)ebp;
482 if (!INKERNEL((long) frame))
484 if (!INKERNEL((long) frame->f_frame))
487 if (frame->f_frame <= frame ||
488 (vm_offset_t)frame->f_frame >= curthread->td_kstack +
489 curthread->td_kstack_pages * PAGE_SIZE)
491 frame = frame->f_frame;
496 return depth - aframes;
500 dtrace_getreg(struct trapframe *rp, uint_t reg)
503 int regmap[] = { /* Order is dependent on reg.d */
510 REG_RBP, /* 6 EBP, REG_FP */
513 REG_RDX, /* 9 EDX, REG_R1 */
514 REG_RCX, /* 10 ECX */
515 REG_RAX, /* 11 EAX, REG_R0 */
516 REG_TRAPNO, /* 12 TRAPNO */
517 REG_ERR, /* 13 ERR */
518 REG_RIP, /* 14 EIP, REG_PC */
520 REG_RFL, /* 16 EFL, REG_PS */
521 REG_RSP, /* 17 UESP, REG_SP */
526 DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
530 if (reg >= sizeof (regmap) / sizeof (int)) {
531 DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
539 if ((pcb = curthread->td_pcb) == NULL) {
540 DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
543 return (pcb->pcb_gs);
565 return (rp->tf_trapno);
573 return (rp->tf_eflags);
581 DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
587 dtrace_copycheck(uintptr_t uaddr, uintptr_t kaddr, size_t size)
589 ASSERT(kaddr >= kernelbase && kaddr + size >= kaddr);
591 if (uaddr + size >= kernelbase || uaddr + size < uaddr) {
592 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
593 cpu_core[curcpu].cpuc_dtrace_illval = uaddr;
601 dtrace_copyin(uintptr_t uaddr, uintptr_t kaddr, size_t size,
602 volatile uint16_t *flags)
604 if (dtrace_copycheck(uaddr, kaddr, size))
605 dtrace_copy(uaddr, kaddr, size);
609 dtrace_copyout(uintptr_t kaddr, uintptr_t uaddr, size_t size,
610 volatile uint16_t *flags)
612 if (dtrace_copycheck(uaddr, kaddr, size))
613 dtrace_copy(kaddr, uaddr, size);
617 dtrace_copyinstr(uintptr_t uaddr, uintptr_t kaddr, size_t size,
618 volatile uint16_t *flags)
620 if (dtrace_copycheck(uaddr, kaddr, size))
621 dtrace_copystr(uaddr, kaddr, size, flags);
625 dtrace_copyoutstr(uintptr_t kaddr, uintptr_t uaddr, size_t size,
626 volatile uint16_t *flags)
628 if (dtrace_copycheck(uaddr, kaddr, size))
629 dtrace_copystr(kaddr, uaddr, size, flags);
633 dtrace_fuword8(void *uaddr)
635 if ((uintptr_t)uaddr >= kernelbase) {
636 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
637 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
640 return (dtrace_fuword8_nocheck(uaddr));
644 dtrace_fuword16(void *uaddr)
646 if ((uintptr_t)uaddr >= kernelbase) {
647 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
648 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
651 return (dtrace_fuword16_nocheck(uaddr));
655 dtrace_fuword32(void *uaddr)
657 if ((uintptr_t)uaddr >= kernelbase) {
658 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
659 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
662 return (dtrace_fuword32_nocheck(uaddr));
666 dtrace_fuword64(void *uaddr)
668 if ((uintptr_t)uaddr >= kernelbase) {
669 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
670 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
673 return (dtrace_fuword64_nocheck(uaddr));