]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - sys/cddl/dev/dtrace/i386/dtrace_isa.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / sys / cddl / dev / dtrace / i386 / dtrace_isa.c
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  * $FreeBSD$
23  */
24 /*
25  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
26  * Use is subject to license terms.
27  */
28 #include <sys/cdefs.h>
29
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/kernel.h>
33 #include <sys/stack.h>
34 #include <sys/pcpu.h>
35
36 #include <machine/frame.h>
37 #include <machine/md_var.h>
38 #include <machine/pcb.h>
39 #include <machine/stack.h>
40
41 #include <vm/vm.h>
42 #include <vm/vm_param.h>
43 #include <vm/pmap.h>
44
45 #include "regset.h"
46
47 extern uintptr_t kernbase;
48 uintptr_t kernelbase = (uintptr_t) &kernbase;
49
50 #define INKERNEL(va) (((vm_offset_t)(va)) >= USRSTACK && \
51          ((vm_offset_t)(va)) < VM_MAX_KERNEL_ADDRESS)
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
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[curcpu].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_PAGES * PAGE_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
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[curcpu].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
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[curcpu].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 = curthread->td_frame) == 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, sp);
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
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 = curthread->td_frame) == 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
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[curcpu].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 = curthread->td_frame) == 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
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         /*
432          * We know that we did not come through a trap to get into
433          * dtrace_probe() -- the provider simply called dtrace_probe()
434          * directly.  As this is the case, we need to shift the argument
435          * that we're looking for:  the probe ID is the first argument to
436          * dtrace_probe(), so the argument n will actually be found where
437          * one would expect to find argument (n + 1).
438          */
439         arg++;
440
441         stack = (uintptr_t *)&fp[1];
442
443 load:
444         DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
445         val = stack[arg];
446         DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT);
447
448         return (val);
449 }
450
451 int
452 dtrace_getstackdepth(int aframes)
453 {
454         int depth = 0;
455         struct i386_frame *frame;
456         vm_offset_t ebp;
457
458         aframes++;
459         ebp = dtrace_getfp();
460         frame = (struct i386_frame *)ebp;
461         depth++;
462         for(;;) {
463                 if (!INKERNEL((long) frame))
464                         break;
465                 if (!INKERNEL((long) frame->f_frame))
466                         break;
467                 depth++;
468                 if (frame->f_frame <= frame ||
469                     (vm_offset_t)frame->f_frame >=
470                     (vm_offset_t)ebp + KSTACK_PAGES * PAGE_SIZE)
471                         break;
472                 frame = frame->f_frame;
473         }
474         if (depth < aframes)
475                 return 0;
476         else
477                 return depth - aframes;
478 }
479
480 ulong_t
481 dtrace_getreg(struct trapframe *rp, uint_t reg)
482 {
483         struct pcb *pcb;
484         int regmap[] = {  /* Order is dependent on reg.d */
485                 REG_GS,         /* 0  GS */
486                 REG_FS,         /* 1  FS */
487                 REG_ES,         /* 2  ES */
488                 REG_DS,         /* 3  DS */
489                 REG_RDI,        /* 4  EDI */
490                 REG_RSI,        /* 5  ESI */
491                 REG_RBP,        /* 6  EBP, REG_FP */
492                 REG_RSP,        /* 7  ESP */
493                 REG_RBX,        /* 8  EBX */
494                 REG_RDX,        /* 9  EDX, REG_R1 */
495                 REG_RCX,        /* 10 ECX */
496                 REG_RAX,        /* 11 EAX, REG_R0 */
497                 REG_TRAPNO,     /* 12 TRAPNO */
498                 REG_ERR,        /* 13 ERR */
499                 REG_RIP,        /* 14 EIP, REG_PC */
500                 REG_CS,         /* 15 CS */
501                 REG_RFL,        /* 16 EFL, REG_PS */
502                 REG_RSP,        /* 17 UESP, REG_SP */
503                 REG_SS          /* 18 SS */
504         };
505
506         if (reg > SS) {
507                 DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
508                 return (0);
509         }
510
511         if (reg >= sizeof (regmap) / sizeof (int)) {
512                 DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
513                 return (0);
514         }
515
516         reg = regmap[reg];
517
518         switch(reg) {
519         case REG_GS:
520                 if ((pcb = curthread->td_pcb) == NULL) {
521                         DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
522                         return (0);
523                 }
524                 return (pcb->pcb_gs);
525         case REG_FS:
526                 return (rp->tf_fs);
527         case REG_ES:
528                 return (rp->tf_es);
529         case REG_DS:
530                 return (rp->tf_ds);
531         case REG_RDI:
532                 return (rp->tf_edi);
533         case REG_RSI:
534                 return (rp->tf_esi);
535         case REG_RBP:
536                 return (rp->tf_ebp);
537         case REG_RSP:
538                 return (rp->tf_isp);
539         case REG_RBX:
540                 return (rp->tf_ebx);
541         case REG_RCX:
542                 return (rp->tf_ecx);
543         case REG_RAX:
544                 return (rp->tf_eax);
545         case REG_TRAPNO:
546                 return (rp->tf_trapno);
547         case REG_ERR:
548                 return (rp->tf_err);
549         case REG_RIP:
550                 return (rp->tf_eip);
551         case REG_CS:
552                 return (rp->tf_cs);
553         case REG_RFL:
554                 return (rp->tf_eflags);
555 #if 0
556         case REG_RSP:
557                 return (rp->tf_esp);
558 #endif
559         case REG_SS:
560                 return (rp->tf_ss);
561         default:
562                 DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
563                 return (0);
564         }
565 }
566
567 static int
568 dtrace_copycheck(uintptr_t uaddr, uintptr_t kaddr, size_t size)
569 {
570         ASSERT(kaddr >= kernelbase && kaddr + size >= kaddr);
571
572         if (uaddr + size >= kernelbase || uaddr + size < uaddr) {
573                 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
574                 cpu_core[curcpu].cpuc_dtrace_illval = uaddr;
575                 return (0);
576         }
577
578         return (1);
579 }
580
581 void
582 dtrace_copyin(uintptr_t uaddr, uintptr_t kaddr, size_t size,
583     volatile uint16_t *flags)
584 {
585         if (dtrace_copycheck(uaddr, kaddr, size))
586                 dtrace_copy(uaddr, kaddr, size);
587 }
588
589 void
590 dtrace_copyout(uintptr_t kaddr, uintptr_t uaddr, size_t size,
591     volatile uint16_t *flags)
592 {
593         if (dtrace_copycheck(uaddr, kaddr, size))
594                 dtrace_copy(kaddr, uaddr, size);
595 }
596
597 void
598 dtrace_copyinstr(uintptr_t uaddr, uintptr_t kaddr, size_t size,
599     volatile uint16_t *flags)
600 {
601         if (dtrace_copycheck(uaddr, kaddr, size))
602                 dtrace_copystr(uaddr, kaddr, size, flags);
603 }
604
605 void
606 dtrace_copyoutstr(uintptr_t kaddr, uintptr_t uaddr, size_t size,
607     volatile uint16_t *flags)
608 {
609         if (dtrace_copycheck(uaddr, kaddr, size))
610                 dtrace_copystr(kaddr, uaddr, size, flags);
611 }
612
613 uint8_t
614 dtrace_fuword8(void *uaddr)
615 {
616         if ((uintptr_t)uaddr >= kernelbase) {
617                 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
618                 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
619                 return (0);
620         }
621         return (dtrace_fuword8_nocheck(uaddr));
622 }
623
624 uint16_t
625 dtrace_fuword16(void *uaddr)
626 {
627         if ((uintptr_t)uaddr >= kernelbase) {
628                 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
629                 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
630                 return (0);
631         }
632         return (dtrace_fuword16_nocheck(uaddr));
633 }
634
635 uint32_t
636 dtrace_fuword32(void *uaddr)
637 {
638         if ((uintptr_t)uaddr >= kernelbase) {
639                 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
640                 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
641                 return (0);
642         }
643         return (dtrace_fuword32_nocheck(uaddr));
644 }
645
646 uint64_t
647 dtrace_fuword64(void *uaddr)
648 {
649         if ((uintptr_t)uaddr >= kernelbase) {
650                 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
651                 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
652                 return (0);
653         }
654         return (dtrace_fuword64_nocheck(uaddr));
655 }