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