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 /*
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26 #include <sys/cdefs.h>
27
28 #include <sys/param.h>
29 #include <sys/systm.h>
30 #include <sys/dtrace_impl.h>
31 #include <sys/kernel.h>
32 #include <sys/stack.h>
33 #include <sys/pcpu.h>
34
35 #include <machine/frame.h>
36 #include <machine/md_var.h>
37 #include <machine/pcb.h>
38 #include <machine/stack.h>
39
40 #include <vm/vm.h>
41 #include <vm/vm_param.h>
42 #include <vm/pmap.h>
43
44 #include "regset.h"
45
46 extern uintptr_t kernbase;
47 uintptr_t kernelbase = (uintptr_t) &kernbase;
48
49 uint8_t dtrace_fuword8_nocheck(void *);
50 uint16_t dtrace_fuword16_nocheck(void *);
51 uint32_t dtrace_fuword32_nocheck(void *);
52 uint64_t dtrace_fuword64_nocheck(void *);
53
54 int dtrace_ustackdepth_max = 2048;
55
56 void
dtrace_getpcstack(pc_t * pcstack,int pcstack_limit,int aframes,uint32_t * intrpc)57 dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes,
58 uint32_t *intrpc)
59 {
60 int depth = 0;
61 register_t ebp;
62 struct i386_frame *frame;
63 vm_offset_t callpc;
64 pc_t caller = (pc_t) solaris_cpu[curcpu].cpu_dtrace_caller;
65
66 if (intrpc != 0)
67 pcstack[depth++] = (pc_t) intrpc;
68
69 aframes++;
70
71 __asm __volatile("movl %%ebp,%0" : "=r" (ebp));
72
73 frame = (struct i386_frame *)ebp;
74 while (depth < pcstack_limit) {
75 if (!kstack_contains(curthread, (vm_offset_t)frame,
76 sizeof(*frame)))
77 break;
78
79 callpc = frame->f_retaddr;
80
81 if (!INKERNEL(callpc))
82 break;
83
84 if (aframes > 0) {
85 aframes--;
86 if ((aframes == 0) && (caller != 0)) {
87 pcstack[depth++] = caller;
88 }
89 }
90 else {
91 pcstack[depth++] = callpc;
92 }
93
94 if (frame->f_frame <= frame)
95 break;
96 frame = frame->f_frame;
97 }
98
99 for (; depth < pcstack_limit; depth++) {
100 pcstack[depth] = 0;
101 }
102 }
103
104 static int
dtrace_getustack_common(uint64_t * pcstack,int pcstack_limit,uintptr_t pc,uintptr_t sp)105 dtrace_getustack_common(uint64_t *pcstack, int pcstack_limit, uintptr_t pc,
106 uintptr_t sp)
107 {
108 #ifdef notyet
109 proc_t *p = curproc;
110 uintptr_t oldcontext = lwp->lwp_oldcontext; /* XXX signal stack. */
111 size_t s1, s2;
112 #endif
113 uintptr_t oldsp;
114 volatile uint16_t *flags =
115 (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags;
116 int ret = 0;
117
118 ASSERT(pcstack == NULL || pcstack_limit > 0);
119 ASSERT(dtrace_ustackdepth_max > 0);
120
121 #ifdef notyet /* XXX signal stack. */
122 if (p->p_model == DATAMODEL_NATIVE) {
123 s1 = sizeof (struct frame) + 2 * sizeof (long);
124 s2 = s1 + sizeof (siginfo_t);
125 } else {
126 s1 = sizeof (struct frame32) + 3 * sizeof (int);
127 s2 = s1 + sizeof (siginfo32_t);
128 }
129 #endif
130
131 while (pc != 0) {
132 /*
133 * We limit the number of times we can go around this
134 * loop to account for a circular stack.
135 */
136 if (ret++ >= dtrace_ustackdepth_max) {
137 *flags |= CPU_DTRACE_BADSTACK;
138 cpu_core[curcpu].cpuc_dtrace_illval = sp;
139 break;
140 }
141
142 if (pcstack != NULL) {
143 *pcstack++ = (uint64_t)pc;
144 pcstack_limit--;
145 if (pcstack_limit <= 0)
146 break;
147 }
148
149 if (sp == 0)
150 break;
151
152 oldsp = sp;
153
154 #ifdef notyet /* XXX signal stack. */
155 if (oldcontext == sp + s1 || oldcontext == sp + s2) {
156 if (p->p_model == DATAMODEL_NATIVE) {
157 ucontext_t *ucp = (ucontext_t *)oldcontext;
158 greg_t *gregs = ucp->uc_mcontext.gregs;
159
160 sp = dtrace_fulword(&gregs[REG_FP]);
161 pc = dtrace_fulword(&gregs[REG_PC]);
162
163 oldcontext = dtrace_fulword(&ucp->uc_link);
164 } else {
165 ucontext32_t *ucp = (ucontext32_t *)oldcontext;
166 greg32_t *gregs = ucp->uc_mcontext.gregs;
167
168 sp = dtrace_fuword32(&gregs[EBP]);
169 pc = dtrace_fuword32(&gregs[EIP]);
170
171 oldcontext = dtrace_fuword32(&ucp->uc_link);
172 }
173 } else {
174 if (p->p_model == DATAMODEL_NATIVE) {
175 struct frame *fr = (struct frame *)sp;
176
177 pc = dtrace_fulword(&fr->fr_savpc);
178 sp = dtrace_fulword(&fr->fr_savfp);
179 } else {
180 struct frame32 *fr = (struct frame32 *)sp;
181
182 pc = dtrace_fuword32(&fr->fr_savpc);
183 sp = dtrace_fuword32(&fr->fr_savfp);
184 }
185 }
186 #else
187 pc = dtrace_fuword32((void *)(sp +
188 offsetof(struct i386_frame, f_retaddr)));
189 sp = dtrace_fuword32((void *)sp);
190 #endif /* ! notyet */
191
192 if (sp == oldsp) {
193 *flags |= CPU_DTRACE_BADSTACK;
194 cpu_core[curcpu].cpuc_dtrace_illval = sp;
195 break;
196 }
197
198 /*
199 * This is totally bogus: if we faulted, we're going to clear
200 * the fault and break. This is to deal with the apparently
201 * broken Java stacks on x86.
202 */
203 if (*flags & CPU_DTRACE_FAULT) {
204 *flags &= ~CPU_DTRACE_FAULT;
205 break;
206 }
207 }
208
209 return (ret);
210 }
211
212 void
dtrace_getupcstack(uint64_t * pcstack,int pcstack_limit)213 dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit)
214 {
215 proc_t *p = curproc;
216 struct trapframe *tf;
217 uintptr_t pc, sp, fp;
218 volatile uint16_t *flags =
219 (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags;
220 int n;
221
222 if (*flags & CPU_DTRACE_FAULT)
223 return;
224
225 if (pcstack_limit <= 0)
226 return;
227
228 /*
229 * If there's no user context we still need to zero the stack.
230 */
231 if (p == NULL || (tf = curthread->td_frame) == NULL)
232 goto zero;
233
234 *pcstack++ = (uint64_t)p->p_pid;
235 pcstack_limit--;
236
237 if (pcstack_limit <= 0)
238 return;
239
240 pc = tf->tf_eip;
241 fp = tf->tf_ebp;
242 sp = tf->tf_esp;
243
244 if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {
245 /*
246 * In an entry probe. The frame pointer has not yet been
247 * pushed (that happens in the function prologue). The
248 * best approach is to add the current pc as a missing top
249 * of stack and back the pc up to the caller, which is stored
250 * at the current stack pointer address since the call
251 * instruction puts it there right before the branch.
252 */
253
254 *pcstack++ = (uint64_t)pc;
255 pcstack_limit--;
256 if (pcstack_limit <= 0)
257 return;
258
259 pc = dtrace_fuword32((void *) sp);
260 }
261
262 n = dtrace_getustack_common(pcstack, pcstack_limit, pc, sp);
263 ASSERT(n >= 0);
264 ASSERT(n <= pcstack_limit);
265
266 pcstack += n;
267 pcstack_limit -= n;
268
269 zero:
270 while (pcstack_limit-- > 0)
271 *pcstack++ = 0;
272 }
273
274 int
dtrace_getustackdepth(void)275 dtrace_getustackdepth(void)
276 {
277 proc_t *p = curproc;
278 struct trapframe *tf;
279 uintptr_t pc, fp, sp;
280 int n = 0;
281
282 if (p == NULL || (tf = curthread->td_frame) == NULL)
283 return (0);
284
285 if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_FAULT))
286 return (-1);
287
288 pc = tf->tf_eip;
289 fp = tf->tf_ebp;
290 sp = tf->tf_esp;
291
292 if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {
293 /*
294 * In an entry probe. The frame pointer has not yet been
295 * pushed (that happens in the function prologue). The
296 * best approach is to add the current pc as a missing top
297 * of stack and back the pc up to the caller, which is stored
298 * at the current stack pointer address since the call
299 * instruction puts it there right before the branch.
300 */
301
302 pc = dtrace_fuword32((void *) sp);
303 n++;
304 }
305
306 n += dtrace_getustack_common(NULL, 0, pc, fp);
307
308 return (n);
309 }
310
311 void
dtrace_getufpstack(uint64_t * pcstack,uint64_t * fpstack,int pcstack_limit)312 dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit)
313 {
314 proc_t *p = curproc;
315 struct trapframe *tf;
316 uintptr_t pc, sp, fp;
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;
321 size_t s1, s2;
322 #endif
323
324 if (*flags & CPU_DTRACE_FAULT)
325 return;
326
327 if (pcstack_limit <= 0)
328 return;
329
330 /*
331 * If there's no user context we still need to zero the stack.
332 */
333 if (p == NULL || (tf = curthread->td_frame) == NULL)
334 goto zero;
335
336 *pcstack++ = (uint64_t)p->p_pid;
337 pcstack_limit--;
338
339 if (pcstack_limit <= 0)
340 return;
341
342 pc = tf->tf_eip;
343 fp = tf->tf_ebp;
344 sp = tf->tf_esp;
345
346 #ifdef notyet /* XXX signal stack */
347 oldcontext = lwp->lwp_oldcontext;
348
349 if (p->p_model == DATAMODEL_NATIVE) {
350 s1 = sizeof (struct frame) + 2 * sizeof (long);
351 s2 = s1 + sizeof (siginfo_t);
352 } else {
353 s1 = sizeof (struct frame32) + 3 * sizeof (int);
354 s2 = s1 + sizeof (siginfo32_t);
355 }
356 #endif
357
358 if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {
359 *pcstack++ = (uint64_t)pc;
360 *fpstack++ = 0;
361 pcstack_limit--;
362 if (pcstack_limit <= 0)
363 return;
364
365 pc = dtrace_fuword32((void *)sp);
366 }
367
368 while (pc != 0) {
369 *pcstack++ = (uint64_t)pc;
370 *fpstack++ = fp;
371 pcstack_limit--;
372 if (pcstack_limit <= 0)
373 break;
374
375 if (fp == 0)
376 break;
377
378 #ifdef notyet /* XXX signal stack */
379 if (oldcontext == sp + s1 || oldcontext == sp + s2) {
380 if (p->p_model == DATAMODEL_NATIVE) {
381 ucontext_t *ucp = (ucontext_t *)oldcontext;
382 greg_t *gregs = ucp->uc_mcontext.gregs;
383
384 sp = dtrace_fulword(&gregs[REG_FP]);
385 pc = dtrace_fulword(&gregs[REG_PC]);
386
387 oldcontext = dtrace_fulword(&ucp->uc_link);
388 } else {
389 ucontext_t *ucp = (ucontext_t *)oldcontext;
390 greg_t *gregs = ucp->uc_mcontext.gregs;
391
392 sp = dtrace_fuword32(&gregs[EBP]);
393 pc = dtrace_fuword32(&gregs[EIP]);
394
395 oldcontext = dtrace_fuword32(&ucp->uc_link);
396 }
397 } else
398 #endif /* XXX */
399 {
400 pc = dtrace_fuword32((void *)(fp +
401 offsetof(struct i386_frame, f_retaddr)));
402 fp = dtrace_fuword32((void *)fp);
403 }
404
405 /*
406 * This is totally bogus: if we faulted, we're going to clear
407 * the fault and break. This is to deal with the apparently
408 * broken Java stacks on x86.
409 */
410 if (*flags & CPU_DTRACE_FAULT) {
411 *flags &= ~CPU_DTRACE_FAULT;
412 break;
413 }
414 }
415
416 zero:
417 while (pcstack_limit-- > 0)
418 *pcstack++ = 0;
419 }
420
421 uint64_t
dtrace_getarg(int arg,int aframes)422 dtrace_getarg(int arg, int aframes)
423 {
424 struct trapframe *frame;
425 struct i386_frame *fp = (struct i386_frame *)dtrace_getfp();
426 uintptr_t *stack, val;
427 int i;
428
429 for (i = 1; i <= aframes; i++) {
430 fp = fp->f_frame;
431
432 if (roundup2(fp->f_retaddr, 4) ==
433 (long)dtrace_invop_callsite) {
434 /*
435 * If we pass through the invalid op handler, we will
436 * use the trap frame pointer that it pushed on the
437 * stack as the second argument to dtrace_invop() as
438 * the pointer to the stack. When using this stack, we
439 * must skip the third argument to dtrace_invop(),
440 * which is included in the i386_frame.
441 */
442 frame = (struct trapframe *)(((uintptr_t **)&fp[1])[0]);
443 /*
444 * Skip the three hardware-saved registers and the
445 * return address.
446 */
447 stack = (uintptr_t *)frame->tf_isp + 4;
448 goto load;
449 }
450
451 }
452
453 /*
454 * We know that we did not come through a trap to get into
455 * dtrace_probe() -- the provider simply called dtrace_probe()
456 * directly. As this is the case, we need to shift the argument
457 * that we're looking for: the probe ID is the first argument to
458 * dtrace_probe(), so the argument n will actually be found where
459 * one would expect to find argument (n + 1).
460 */
461 arg++;
462
463 stack = (uintptr_t *)fp + 2;
464
465 load:
466 DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
467 val = stack[arg];
468 DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT);
469
470 return (val);
471 }
472
473 int
dtrace_getstackdepth(int aframes)474 dtrace_getstackdepth(int aframes)
475 {
476 int depth = 0;
477 struct i386_frame *frame;
478 vm_offset_t ebp;
479
480 aframes++;
481 ebp = dtrace_getfp();
482 frame = (struct i386_frame *)ebp;
483 depth++;
484 for(;;) {
485 if (!kstack_contains(curthread, (vm_offset_t)frame,
486 sizeof(*frame)))
487 break;
488 depth++;
489 if (frame->f_frame <= frame)
490 break;
491 frame = frame->f_frame;
492 }
493 if (depth < aframes)
494 return 0;
495 else
496 return depth - aframes;
497 }
498
499 ulong_t
dtrace_getreg(struct trapframe * frame,uint_t reg)500 dtrace_getreg(struct trapframe *frame, uint_t reg)
501 {
502 struct pcb *pcb;
503 int regmap[] = { /* Order is dependent on reg.d */
504 REG_GS, /* 0 GS */
505 REG_FS, /* 1 FS */
506 REG_ES, /* 2 ES */
507 REG_DS, /* 3 DS */
508 REG_RDI, /* 4 EDI */
509 REG_RSI, /* 5 ESI */
510 REG_RBP, /* 6 EBP, REG_FP */
511 REG_RSP, /* 7 ESP */
512 REG_RBX, /* 8 EBX */
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 */
519 REG_CS, /* 15 CS */
520 REG_RFL, /* 16 EFL, REG_PS */
521 REG_RSP, /* 17 UESP, REG_SP */
522 REG_SS /* 18 SS */
523 };
524
525 if (reg > SS) {
526 DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
527 return (0);
528 }
529
530 if (reg >= sizeof (regmap) / sizeof (int)) {
531 DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
532 return (0);
533 }
534
535 reg = regmap[reg];
536
537 switch(reg) {
538 case REG_GS:
539 if ((pcb = curthread->td_pcb) == NULL) {
540 DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
541 return (0);
542 }
543 return (pcb->pcb_gs);
544 case REG_FS:
545 return (frame->tf_fs);
546 case REG_ES:
547 return (frame->tf_es);
548 case REG_DS:
549 return (frame->tf_ds);
550 case REG_RDI:
551 return (frame->tf_edi);
552 case REG_RSI:
553 return (frame->tf_esi);
554 case REG_RBP:
555 return (frame->tf_ebp);
556 case REG_RSP:
557 return (frame->tf_isp);
558 case REG_RBX:
559 return (frame->tf_ebx);
560 case REG_RCX:
561 return (frame->tf_ecx);
562 case REG_RAX:
563 return (frame->tf_eax);
564 case REG_TRAPNO:
565 return (frame->tf_trapno);
566 case REG_ERR:
567 return (frame->tf_err);
568 case REG_RIP:
569 return (frame->tf_eip);
570 case REG_CS:
571 return (frame->tf_cs);
572 case REG_RFL:
573 return (frame->tf_eflags);
574 #if 0
575 case REG_RSP:
576 return (frame->tf_esp);
577 #endif
578 case REG_SS:
579 return (frame->tf_ss);
580 default:
581 DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
582 return (0);
583 }
584 }
585
586 static int
dtrace_copycheck(uintptr_t uaddr,uintptr_t kaddr,size_t size)587 dtrace_copycheck(uintptr_t uaddr, uintptr_t kaddr, size_t size)
588 {
589 ASSERT(kaddr >= kernelbase && kaddr + size >= kaddr);
590
591 if (uaddr + size >= kernelbase || uaddr + size < uaddr) {
592 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
593 cpu_core[curcpu].cpuc_dtrace_illval = uaddr;
594 return (0);
595 }
596
597 return (1);
598 }
599
600 void
dtrace_copyin(uintptr_t uaddr,uintptr_t kaddr,size_t size,volatile uint16_t * flags)601 dtrace_copyin(uintptr_t uaddr, uintptr_t kaddr, size_t size,
602 volatile uint16_t *flags)
603 {
604 if (dtrace_copycheck(uaddr, kaddr, size))
605 dtrace_copy(uaddr, kaddr, size);
606 }
607
608 void
dtrace_copyout(uintptr_t kaddr,uintptr_t uaddr,size_t size,volatile uint16_t * flags)609 dtrace_copyout(uintptr_t kaddr, uintptr_t uaddr, size_t size,
610 volatile uint16_t *flags)
611 {
612 if (dtrace_copycheck(uaddr, kaddr, size))
613 dtrace_copy(kaddr, uaddr, size);
614 }
615
616 void
dtrace_copyinstr(uintptr_t uaddr,uintptr_t kaddr,size_t size,volatile uint16_t * flags)617 dtrace_copyinstr(uintptr_t uaddr, uintptr_t kaddr, size_t size,
618 volatile uint16_t *flags)
619 {
620 if (dtrace_copycheck(uaddr, kaddr, size))
621 dtrace_copystr(uaddr, kaddr, size, flags);
622 }
623
624 void
dtrace_copyoutstr(uintptr_t kaddr,uintptr_t uaddr,size_t size,volatile uint16_t * flags)625 dtrace_copyoutstr(uintptr_t kaddr, uintptr_t uaddr, size_t size,
626 volatile uint16_t *flags)
627 {
628 if (dtrace_copycheck(uaddr, kaddr, size))
629 dtrace_copystr(kaddr, uaddr, size, flags);
630 }
631
632 uint8_t
dtrace_fuword8(void * uaddr)633 dtrace_fuword8(void *uaddr)
634 {
635 if ((uintptr_t)uaddr >= kernelbase) {
636 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
637 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
638 return (0);
639 }
640 return (dtrace_fuword8_nocheck(uaddr));
641 }
642
643 uint16_t
dtrace_fuword16(void * uaddr)644 dtrace_fuword16(void *uaddr)
645 {
646 if ((uintptr_t)uaddr >= kernelbase) {
647 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
648 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
649 return (0);
650 }
651 return (dtrace_fuword16_nocheck(uaddr));
652 }
653
654 uint32_t
dtrace_fuword32(void * uaddr)655 dtrace_fuword32(void *uaddr)
656 {
657 if ((uintptr_t)uaddr >= kernelbase) {
658 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
659 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
660 return (0);
661 }
662 return (dtrace_fuword32_nocheck(uaddr));
663 }
664
665 uint64_t
dtrace_fuword64(void * uaddr)666 dtrace_fuword64(void *uaddr)
667 {
668 if ((uintptr_t)uaddr >= kernelbase) {
669 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
670 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
671 return (0);
672 }
673 return (dtrace_fuword64_nocheck(uaddr));
674 }
675