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