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