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