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