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