]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - sys/cddl/dev/dtrace/amd64/dtrace_isa.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.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 (fp->f_retaddr == (long)dtrace_invop_callsite) {
353                         /*
354                          * In the case of amd64, we will use the pointer to the
355                          * regs structure that was pushed when we took the
356                          * trap.  To get this structure, we must increment
357                          * beyond the frame structure, and then again beyond
358                          * the calling RIP stored in dtrace_invop().  If the
359                          * argument that we're seeking is passed on the stack,
360                          * we'll pull the true stack pointer out of the saved
361                          * registers and decrement our argument by the number
362                          * of arguments passed in registers; if the argument
363                          * we're seeking is passed in regsiters, we can just
364                          * load it directly.
365                          */
366                         struct reg *rp = (struct reg *)((uintptr_t)&fp[1] +
367                             sizeof (uintptr_t));
368
369                         if (arg <= inreg) {
370                                 stack = (uintptr_t *)&rp->r_rdi;
371                         } else {
372                                 stack = (uintptr_t *)(rp->r_rsp);
373                                 arg -= inreg;
374                         }
375                         goto load;
376                 }
377
378         }
379
380         /*
381          * We know that we did not come through a trap to get into
382          * dtrace_probe() -- the provider simply called dtrace_probe()
383          * directly.  As this is the case, we need to shift the argument
384          * that we're looking for:  the probe ID is the first argument to
385          * dtrace_probe(), so the argument n will actually be found where
386          * one would expect to find argument (n + 1).
387          */
388         arg++;
389
390         if (arg <= inreg) {
391                 /*
392                  * This shouldn't happen.  If the argument is passed in a
393                  * register then it should have been, well, passed in a
394                  * register...
395                  */
396                 DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
397                 return (0);
398         }
399
400         arg -= (inreg + 1);
401         stack = (uintptr_t *)fp + 2;
402
403 load:
404         DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
405         val = stack[arg];
406         DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT);
407
408         return (val);
409         return (0);
410 }
411
412 int
413 dtrace_getstackdepth(int aframes)
414 {
415         int depth = 0;
416         struct amd64_frame *frame;
417         vm_offset_t rbp;
418
419         aframes++;
420         rbp = dtrace_getfp();
421         frame = (struct amd64_frame *)rbp;
422         depth++;
423         for(;;) {
424                 if (!INKERNEL((long) frame))
425                         break;
426                 if (!INKERNEL((long) frame->f_frame))
427                         break;
428                 depth++;
429                 if (frame->f_frame <= frame ||
430                     (vm_offset_t)frame->f_frame >=
431                     (vm_offset_t)rbp + KSTACK_PAGES * PAGE_SIZE)
432                         break;
433                 frame = frame->f_frame;
434         }
435         if (depth < aframes)
436                 return 0;
437         else
438                 return depth - aframes;
439 }
440
441 ulong_t
442 dtrace_getreg(struct trapframe *rp, uint_t reg)
443 {
444         /* This table is dependent on reg.d. */
445         int regmap[] = {
446                 REG_GS,         /* 0  GS */
447                 REG_FS,         /* 1  FS */
448                 REG_ES,         /* 2  ES */
449                 REG_DS,         /* 3  DS */
450                 REG_RDI,        /* 4  EDI */
451                 REG_RSI,        /* 5  ESI */
452                 REG_RBP,        /* 6  EBP, REG_FP */
453                 REG_RSP,        /* 7  ESP */
454                 REG_RBX,        /* 8  EBX, REG_R1 */
455                 REG_RDX,        /* 9  EDX */
456                 REG_RCX,        /* 10 ECX */
457                 REG_RAX,        /* 11 EAX, REG_R0 */
458                 REG_TRAPNO,     /* 12 TRAPNO */
459                 REG_ERR,        /* 13 ERR */
460                 REG_RIP,        /* 14 EIP, REG_PC */
461                 REG_CS,         /* 15 CS */
462                 REG_RFL,        /* 16 EFL, REG_PS */
463                 REG_RSP,        /* 17 UESP, REG_SP */
464                 REG_SS          /* 18 SS */
465         };
466
467         if (reg <= SS) {
468                 if (reg >= sizeof (regmap) / sizeof (int)) {
469                         DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
470                         return (0);
471                 }
472
473                 reg = regmap[reg];
474         } else {
475                 /* This is dependent on reg.d. */
476                 reg -= SS + 1;
477         }
478
479         switch (reg) {
480         case REG_RDI:
481                 return (rp->tf_rdi);
482         case REG_RSI:
483                 return (rp->tf_rsi);
484         case REG_RDX:
485                 return (rp->tf_rdx);
486         case REG_RCX:
487                 return (rp->tf_rcx);
488         case REG_R8:
489                 return (rp->tf_r8);
490         case REG_R9:
491                 return (rp->tf_r9);
492         case REG_RAX:
493                 return (rp->tf_rax);
494         case REG_RBX:
495                 return (rp->tf_rbx);
496         case REG_RBP:
497                 return (rp->tf_rbp);
498         case REG_R10:
499                 return (rp->tf_r10);
500         case REG_R11:
501                 return (rp->tf_r11);
502         case REG_R12:
503                 return (rp->tf_r12);
504         case REG_R13:
505                 return (rp->tf_r13);
506         case REG_R14:
507                 return (rp->tf_r14);
508         case REG_R15:
509                 return (rp->tf_r15);
510         case REG_DS:
511                 return (rp->tf_ds);
512         case REG_ES:
513                 return (rp->tf_es);
514         case REG_FS:
515                 return (rp->tf_fs);
516         case REG_GS:
517                 return (rp->tf_gs);
518         case REG_TRAPNO:
519                 return (rp->tf_trapno);
520         case REG_ERR:
521                 return (rp->tf_err);
522         case REG_RIP:
523                 return (rp->tf_rip);
524         case REG_CS:
525                 return (rp->tf_cs);
526         case REG_SS:
527                 return (rp->tf_ss);
528         case REG_RFL:
529                 return (rp->tf_rflags);
530         case REG_RSP:
531                 return (rp->tf_rsp);
532         default:
533                 DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
534                 return (0);
535         }
536 }
537
538 static int
539 dtrace_copycheck(uintptr_t uaddr, uintptr_t kaddr, size_t size)
540 {
541         ASSERT(INKERNEL(kaddr) && kaddr + size >= kaddr);
542
543         if (uaddr + size > VM_MAXUSER_ADDRESS || uaddr + size < uaddr) {
544                 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
545                 cpu_core[curcpu].cpuc_dtrace_illval = uaddr;
546                 return (0);
547         }
548
549         return (1);
550 }
551
552 void
553 dtrace_copyin(uintptr_t uaddr, uintptr_t kaddr, size_t size,
554     volatile uint16_t *flags)
555 {
556         if (dtrace_copycheck(uaddr, kaddr, size))
557                 dtrace_copy(uaddr, kaddr, size);
558 }
559
560 void
561 dtrace_copyout(uintptr_t kaddr, uintptr_t uaddr, size_t size,
562     volatile uint16_t *flags)
563 {
564         if (dtrace_copycheck(uaddr, kaddr, size))
565                 dtrace_copy(kaddr, uaddr, size);
566 }
567
568 void
569 dtrace_copyinstr(uintptr_t uaddr, uintptr_t kaddr, size_t size,
570     volatile uint16_t *flags)
571 {
572         if (dtrace_copycheck(uaddr, kaddr, size))
573                 dtrace_copystr(uaddr, kaddr, size, flags);
574 }
575
576 void
577 dtrace_copyoutstr(uintptr_t kaddr, uintptr_t uaddr, size_t size,
578     volatile uint16_t *flags)
579 {
580         if (dtrace_copycheck(uaddr, kaddr, size))
581                 dtrace_copystr(kaddr, uaddr, size, flags);
582 }
583
584 uint8_t
585 dtrace_fuword8(void *uaddr)
586 {
587         if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
588                 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
589                 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
590                 return (0);
591         }
592         return (dtrace_fuword8_nocheck(uaddr));
593 }
594
595 uint16_t
596 dtrace_fuword16(void *uaddr)
597 {
598         if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
599                 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
600                 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
601                 return (0);
602         }
603         return (dtrace_fuword16_nocheck(uaddr));
604 }
605
606 uint32_t
607 dtrace_fuword32(void *uaddr)
608 {
609         if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
610                 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
611                 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
612                 return (0);
613         }
614         return (dtrace_fuword32_nocheck(uaddr));
615 }
616
617 uint64_t
618 dtrace_fuword64(void *uaddr)
619 {
620         if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
621                 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
622                 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
623                 return (0);
624         }
625         return (dtrace_fuword64_nocheck(uaddr));
626 }