]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/cddl/dev/dtrace/powerpc/dtrace_isa.c
Fix the stack tracing for dtrace/powerpc.
[FreeBSD/FreeBSD.git] / sys / cddl / dev / dtrace / powerpc / 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  * Portions Copyright 2012,2013 Justin Hibbits <jhibbits@freebsd.org>
23  *
24  * $FreeBSD$
25  */
26 /*
27  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
28  * Use is subject to license terms.
29  */
30 #include <sys/cdefs.h>
31
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/kernel.h>
35 #include <sys/stack.h>
36 #include <sys/sysent.h>
37 #include <sys/pcpu.h>
38
39 #include <machine/frame.h>
40 #include <machine/md_var.h>
41 #include <machine/reg.h>
42 #include <machine/stack.h>
43
44 #include <vm/vm.h>
45 #include <vm/vm_param.h>
46 #include <vm/pmap.h>
47
48 #include "regset.h"
49
50 /* Offset to the LR Save word (ppc32) */
51 #define RETURN_OFFSET   4
52 /* Offset to LR Save word (ppc64).  CR Save area sits between back chain and LR */
53 #define RETURN_OFFSET64 16
54
55 #ifdef __powerpc64__
56 #define OFFSET 4 /* Account for the TOC reload slot */
57 #else
58 #define OFFSET 0
59 #endif
60
61 #define INKERNEL(x)     ((x) <= VM_MAX_KERNEL_ADDRESS && \
62                 (x) >= VM_MIN_KERNEL_ADDRESS)
63
64 static __inline int
65 dtrace_sp_inkernel(uintptr_t sp, int aframes)
66 {
67         vm_offset_t callpc;
68
69 #ifdef __powerpc64__
70         callpc = *(vm_offset_t *)(sp + RETURN_OFFSET64);
71 #else
72         callpc = *(vm_offset_t *)(sp + RETURN_OFFSET);
73 #endif
74         if ((callpc & 3) || (callpc < 0x100))
75                 return (0);
76
77         /*
78          * trapexit() and asttrapexit() are sentinels
79          * for kernel stack tracing.
80          *
81          * Special-case this for 'aframes == 0', because fbt sets aframes to the
82          * trap callchain depth, so we want to break out of it.
83          */
84         if ((callpc + OFFSET == (vm_offset_t) &trapexit ||
85             callpc + OFFSET == (vm_offset_t) &asttrapexit) &&
86             aframes != 0)
87                 return (0);
88
89         return (1);
90 }
91
92 static __inline uintptr_t
93 dtrace_next_sp(uintptr_t sp)
94 {
95         vm_offset_t callpc;
96
97 #ifdef __powerpc64__
98         callpc = *(vm_offset_t *)(sp + RETURN_OFFSET64);
99 #else
100         callpc = *(vm_offset_t *)(sp + RETURN_OFFSET);
101 #endif
102
103         /*
104          * trapexit() and asttrapexit() are sentinels
105          * for kernel stack tracing.
106          *
107          * Special-case this for 'aframes == 0', because fbt sets aframes to the
108          * trap callchain depth, so we want to break out of it.
109          */
110         if ((callpc + OFFSET == (vm_offset_t) &trapexit ||
111             callpc + OFFSET == (vm_offset_t) &asttrapexit))
112             /* Access the trap frame */
113 #ifdef __powerpc64__
114                 return (*(uintptr_t *)sp + 48 + sizeof(register_t));
115 #else
116                 return (*(uintptr_t *)sp + 8 + sizeof(register_t));
117 #endif
118
119         return (*(uintptr_t*)sp);
120 }
121
122 static __inline uintptr_t
123 dtrace_get_pc(uintptr_t sp)
124 {
125         vm_offset_t callpc;
126
127 #ifdef __powerpc64__
128         callpc = *(vm_offset_t *)(sp + RETURN_OFFSET64);
129 #else
130         callpc = *(vm_offset_t *)(sp + RETURN_OFFSET);
131 #endif
132
133         /*
134          * trapexit() and asttrapexit() are sentinels
135          * for kernel stack tracing.
136          *
137          * Special-case this for 'aframes == 0', because fbt sets aframes to the
138          * trap callchain depth, so we want to break out of it.
139          */
140         if ((callpc + OFFSET == (vm_offset_t) &trapexit ||
141             callpc + OFFSET == (vm_offset_t) &asttrapexit))
142             /* Access the trap frame */
143 #ifdef __powerpc64__
144                 return (*(uintptr_t *)sp + 48 + offsetof(struct trapframe, lr));
145 #else
146                 return (*(uintptr_t *)sp + 8 + offsetof(struct trapframe, lr));
147 #endif
148
149         return (callpc);
150 }
151
152 greg_t
153 dtrace_getfp(void)
154 {
155         return (greg_t)__builtin_frame_address(0);
156 }
157
158 void
159 dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes,
160     uint32_t *intrpc)
161 {
162         int depth = 0;
163         uintptr_t osp, sp;
164         vm_offset_t callpc;
165         pc_t caller = (pc_t) solaris_cpu[curcpu].cpu_dtrace_caller;
166
167         osp = PAGE_SIZE;
168         if (intrpc != 0)
169                 pcstack[depth++] = (pc_t) intrpc;
170
171         aframes++;
172
173         sp = dtrace_getfp();
174
175         while (depth < pcstack_limit) {
176                 if (sp <= osp)
177                         break;
178
179                 if (!dtrace_sp_inkernel(sp, aframes))
180                         break;
181                 callpc = dtrace_get_pc(sp);
182
183                 if (aframes > 0) {
184                         aframes--;
185                         if ((aframes == 0) && (caller != 0)) {
186                                 pcstack[depth++] = caller;
187                         }
188                 }
189                 else {
190                         pcstack[depth++] = callpc;
191                 }
192
193                 osp = sp;
194                 sp = dtrace_next_sp(sp);
195         }
196
197         for (; depth < pcstack_limit; depth++) {
198                 pcstack[depth] = 0;
199         }
200 }
201
202 static int
203 dtrace_getustack_common(uint64_t *pcstack, int pcstack_limit, uintptr_t pc,
204     uintptr_t sp)
205 {
206         proc_t *p = curproc;
207         int ret = 0;
208
209         ASSERT(pcstack == NULL || pcstack_limit > 0);
210
211         while (pc != 0) {
212                 ret++;
213                 if (pcstack != NULL) {
214                         *pcstack++ = (uint64_t)pc;
215                         pcstack_limit--;
216                         if (pcstack_limit <= 0)
217                                 break;
218                 }
219
220                 if (sp == 0)
221                         break;
222
223                 if (SV_PROC_FLAG(p, SV_ILP32)) {
224                         pc = dtrace_fuword32((void *)(sp + RETURN_OFFSET));
225                         sp = dtrace_fuword32((void *)sp);
226                 }
227                 else {
228                         pc = dtrace_fuword64((void *)(sp + RETURN_OFFSET64));
229                         sp = dtrace_fuword64((void *)sp);
230                 }
231         }
232
233         return (ret);
234 }
235
236 void
237 dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit)
238 {
239         proc_t *p = curproc;
240         struct trapframe *tf;
241         uintptr_t pc, sp;
242         volatile uint16_t *flags =
243             (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags;
244         int n;
245
246         if (*flags & CPU_DTRACE_FAULT)
247                 return;
248
249         if (pcstack_limit <= 0)
250                 return;
251
252         /*
253          * If there's no user context we still need to zero the stack.
254          */
255         if (p == NULL || (tf = curthread->td_frame) == NULL)
256                 goto zero;
257
258         *pcstack++ = (uint64_t)p->p_pid;
259         pcstack_limit--;
260
261         if (pcstack_limit <= 0)
262                 return;
263
264         pc = tf->srr0;
265         sp = tf->fixreg[1];
266
267         if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {
268                 /* 
269                  * In an entry probe.  The frame pointer has not yet been
270                  * pushed (that happens in the function prologue).  The
271                  * best approach is to add the current pc as a missing top
272                  * of stack and back the pc up to the caller, which is stored
273                  * at the current stack pointer address since the call 
274                  * instruction puts it there right before the branch.
275                  */
276
277                 *pcstack++ = (uint64_t)pc;
278                 pcstack_limit--;
279                 if (pcstack_limit <= 0)
280                         return;
281
282                 pc = tf->lr;
283         }
284
285         n = dtrace_getustack_common(pcstack, pcstack_limit, pc, sp);
286         ASSERT(n >= 0);
287         ASSERT(n <= pcstack_limit);
288
289         pcstack += n;
290         pcstack_limit -= n;
291
292 zero:
293         while (pcstack_limit-- > 0)
294                 *pcstack++ = 0;
295 }
296
297 int
298 dtrace_getustackdepth(void)
299 {
300         proc_t *p = curproc;
301         struct trapframe *tf;
302         uintptr_t pc, sp;
303         int n = 0;
304
305         if (p == NULL || (tf = curthread->td_frame) == NULL)
306                 return (0);
307
308         if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_FAULT))
309                 return (-1);
310
311         pc = tf->srr0;
312         sp = tf->fixreg[1];
313
314         if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {
315                 /* 
316                  * In an entry probe.  The frame pointer has not yet been
317                  * pushed (that happens in the function prologue).  The
318                  * best approach is to add the current pc as a missing top
319                  * of stack and back the pc up to the caller, which is stored
320                  * at the current stack pointer address since the call 
321                  * instruction puts it there right before the branch.
322                  */
323
324                 if (SV_PROC_FLAG(p, SV_ILP32)) {
325                         pc = dtrace_fuword32((void *) sp);
326                 }
327                 else
328                         pc = dtrace_fuword64((void *) sp);
329                 n++;
330         }
331
332         n += dtrace_getustack_common(NULL, 0, pc, sp);
333
334         return (n);
335 }
336
337 void
338 dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit)
339 {
340         proc_t *p = curproc;
341         struct trapframe *tf;
342         uintptr_t pc, sp;
343         volatile uint16_t *flags =
344             (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags;
345 #ifdef notyet   /* XXX signal stack */
346         uintptr_t oldcontext;
347         size_t s1, s2;
348 #endif
349
350         if (*flags & CPU_DTRACE_FAULT)
351                 return;
352
353         if (pcstack_limit <= 0)
354                 return;
355
356         /*
357          * If there's no user context we still need to zero the stack.
358          */
359         if (p == NULL || (tf = curthread->td_frame) == NULL)
360                 goto zero;
361
362         *pcstack++ = (uint64_t)p->p_pid;
363         pcstack_limit--;
364
365         if (pcstack_limit <= 0)
366                 return;
367
368         pc = tf->srr0;
369         sp = tf->fixreg[1];
370
371 #ifdef notyet /* XXX signal stack */
372         oldcontext = lwp->lwp_oldcontext;
373         s1 = sizeof (struct xframe) + 2 * sizeof (long);
374         s2 = s1 + sizeof (siginfo_t);
375 #endif
376
377         if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {
378                 *pcstack++ = (uint64_t)pc;
379                 *fpstack++ = 0;
380                 pcstack_limit--;
381                 if (pcstack_limit <= 0)
382                         return;
383
384                 if (SV_PROC_FLAG(p, SV_ILP32)) {
385                         pc = dtrace_fuword32((void *)sp);
386                 }
387                 else {
388                         pc = dtrace_fuword64((void *)sp);
389                 }
390         }
391
392         while (pc != 0) {
393                 *pcstack++ = (uint64_t)pc;
394                 *fpstack++ = sp;
395                 pcstack_limit--;
396                 if (pcstack_limit <= 0)
397                         break;
398
399                 if (sp == 0)
400                         break;
401
402 #ifdef notyet /* XXX signal stack */
403                 if (oldcontext == sp + s1 || oldcontext == sp + s2) {
404                         ucontext_t *ucp = (ucontext_t *)oldcontext;
405                         greg_t *gregs = ucp->uc_mcontext.gregs;
406
407                         sp = dtrace_fulword(&gregs[REG_FP]);
408                         pc = dtrace_fulword(&gregs[REG_PC]);
409
410                         oldcontext = dtrace_fulword(&ucp->uc_link);
411                 } else
412 #endif /* XXX */
413                 {
414                         if (SV_PROC_FLAG(p, SV_ILP32)) {
415                                 pc = dtrace_fuword32((void *)(sp + RETURN_OFFSET));
416                                 sp = dtrace_fuword32((void *)sp);
417                         }
418                         else {
419                                 pc = dtrace_fuword64((void *)(sp + RETURN_OFFSET64));
420                                 sp = dtrace_fuword64((void *)sp);
421                         }
422                 }
423
424                 /*
425                  * This is totally bogus:  if we faulted, we're going to clear
426                  * the fault and break.  This is to deal with the apparently
427                  * broken Java stacks on x86.
428                  */
429                 if (*flags & CPU_DTRACE_FAULT) {
430                         *flags &= ~CPU_DTRACE_FAULT;
431                         break;
432                 }
433         }
434
435 zero:
436         while (pcstack_limit-- > 0)
437                 *pcstack++ = 0;
438 }
439
440 /*ARGSUSED*/
441 uint64_t
442 dtrace_getarg(int arg, int aframes)
443 {
444         uintptr_t val;
445         uintptr_t *fp = (uintptr_t *)dtrace_getfp();
446         uintptr_t *stack;
447         int i;
448
449         /*
450          * A total of 8 arguments are passed via registers; any argument with
451          * index of 7 or lower is therefore in a register.
452          */
453         int inreg = 7;
454
455         for (i = 1; i <= aframes; i++) {
456                 fp = (uintptr_t *)*fp;
457
458                 /*
459                  * On ppc32 AIM, and booke, trapexit() is the immediately following
460                  * label.  On ppc64 AIM trapexit() follows a nop.
461                  */
462 #ifdef __powerpc64__
463                 if ((long)(fp[2]) + 4 == (long)trapexit) {
464 #else
465                 if ((long)(fp[1]) == (long)trapexit) {
466 #endif
467                         /*
468                          * In the case of powerpc, we will use the pointer to the regs
469                          * structure that was pushed when we took the trap.  To get this
470                          * structure, we must increment beyond the frame structure.  If the
471                          * argument that we're seeking is passed on the stack, we'll pull
472                          * the true stack pointer out of the saved registers and decrement
473                          * our argument by the number of arguments passed in registers; if
474                          * the argument we're seeking is passed in regsiters, we can just
475                          * load it directly.
476                          */
477 #ifdef __powerpc64__
478                         struct reg *rp = (struct reg *)((uintptr_t)fp[0] + 48);
479 #else
480                         struct reg *rp = (struct reg *)((uintptr_t)fp[0] + 8);
481 #endif
482
483                         if (arg <= inreg) {
484                                 stack = &rp->fixreg[3];
485                         } else {
486                                 stack = (uintptr_t *)(rp->fixreg[1]);
487                                 arg -= inreg;
488                         }
489                         goto load;
490                 }
491
492         }
493
494         /*
495          * We know that we did not come through a trap to get into
496          * dtrace_probe() -- the provider simply called dtrace_probe()
497          * directly.  As this is the case, we need to shift the argument
498          * that we're looking for:  the probe ID is the first argument to
499          * dtrace_probe(), so the argument n will actually be found where
500          * one would expect to find argument (n + 1).
501          */
502         arg++;
503
504         if (arg <= inreg) {
505                 /*
506                  * This shouldn't happen.  If the argument is passed in a
507                  * register then it should have been, well, passed in a
508                  * register...
509                  */
510                 DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
511                 return (0);
512         }
513
514         arg -= (inreg + 1);
515         stack = fp + 2;
516
517 load:
518         DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
519         val = stack[arg];
520         DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT);
521
522         return (val);
523         return (0);
524 }
525
526 int
527 dtrace_getstackdepth(int aframes)
528 {
529         int depth = 0;
530         uintptr_t osp, sp;
531         vm_offset_t callpc;
532
533         osp = PAGE_SIZE;
534         aframes++;
535         sp = dtrace_getfp();
536         depth++;
537         for(;;) {
538                 if (sp <= osp)
539                         break;
540
541                 if (!dtrace_sp_inkernel(sp, aframes))
542                         break;
543
544                 if (aframes == 0)
545                         depth++;
546                 else
547                         aframes--;
548                 osp = sp;
549                 sp = *(uintptr_t *)sp;
550         }
551         if (depth < aframes)
552                 return (0);
553
554         return (depth);
555 }
556
557 ulong_t
558 dtrace_getreg(struct trapframe *rp, uint_t reg)
559 {
560         if (reg < 32)
561                 return (rp->fixreg[reg]);
562
563         switch (reg) {
564         case 33:
565                 return (rp->lr);
566         case 34:
567                 return (rp->cr);
568         case 35:
569                 return (rp->xer);
570         case 36:
571                 return (rp->ctr);
572         case 37:
573                 return (rp->srr0);
574         case 38:
575                 return (rp->srr1);
576         case 39:
577                 return (rp->exc);
578         default:
579                 DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
580                 return (0);
581         }
582 }
583
584 static int
585 dtrace_copycheck(uintptr_t uaddr, uintptr_t kaddr, size_t size)
586 {
587         ASSERT(INKERNEL(kaddr) && kaddr + size >= kaddr);
588
589         if (uaddr + size > VM_MAXUSER_ADDRESS || uaddr + size < uaddr) {
590                 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
591                 cpu_core[curcpu].cpuc_dtrace_illval = uaddr;
592                 return (0);
593         }
594
595         return (1);
596 }
597
598 void
599 dtrace_copyin(uintptr_t uaddr, uintptr_t kaddr, size_t size,
600     volatile uint16_t *flags)
601 {
602         if (dtrace_copycheck(uaddr, kaddr, size))
603                 if (copyin((const void *)uaddr, (void *)kaddr, size)) {
604                         DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
605                         cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
606                 }
607 }
608
609 void
610 dtrace_copyout(uintptr_t kaddr, uintptr_t uaddr, size_t size,
611     volatile uint16_t *flags)
612 {
613         if (dtrace_copycheck(uaddr, kaddr, size)) {
614                 if (copyout((const void *)kaddr, (void *)uaddr, size)) {
615                         DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
616                         cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
617                 }
618         }
619 }
620
621 void
622 dtrace_copyinstr(uintptr_t uaddr, uintptr_t kaddr, size_t size,
623     volatile uint16_t *flags)
624 {
625         size_t actual;
626         int    error;
627
628         if (dtrace_copycheck(uaddr, kaddr, size)) {
629                 error = copyinstr((const void *)uaddr, (void *)kaddr,
630                     size, &actual);
631                 
632                 /* ENAMETOOLONG is not a fault condition. */
633                 if (error && error != ENAMETOOLONG) {
634                         DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
635                         cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
636                 }
637         }
638 }
639
640 /*
641  * The bulk of this function could be replaced to match dtrace_copyinstr() 
642  * if we ever implement a copyoutstr().
643  */
644 void
645 dtrace_copyoutstr(uintptr_t kaddr, uintptr_t uaddr, size_t size,
646     volatile uint16_t *flags)
647 {
648         size_t len;
649
650         if (dtrace_copycheck(uaddr, kaddr, size)) {
651                 len = strlen((const char *)kaddr);
652                 if (len > size)
653                         len = size;
654
655                 if (copyout((const void *)kaddr, (void *)uaddr, len)) {
656                         DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
657                         cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
658                 }
659         }
660 }
661
662 uint8_t
663 dtrace_fuword8(void *uaddr)
664 {
665         if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
666                 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
667                 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
668                 return (0);
669         }
670         return (fubyte(uaddr));
671 }
672
673 uint16_t
674 dtrace_fuword16(void *uaddr)
675 {
676         uint16_t ret = 0;
677
678         if (dtrace_copycheck((uintptr_t)uaddr, (uintptr_t)&ret, sizeof(ret))) {
679                 if (copyin((const void *)uaddr, (void *)&ret, sizeof(ret))) {
680                         DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
681                         cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
682                 }
683         }
684         return ret;
685 }
686
687 uint32_t
688 dtrace_fuword32(void *uaddr)
689 {
690         if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
691                 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
692                 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
693                 return (0);
694         }
695         return (fuword32(uaddr));
696 }
697
698 uint64_t
699 dtrace_fuword64(void *uaddr)
700 {
701         uint64_t ret = 0;
702
703         if (dtrace_copycheck((uintptr_t)uaddr, (uintptr_t)&ret, sizeof(ret))) {
704                 if (copyin((const void *)uaddr, (void *)&ret, sizeof(ret))) {
705                         DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
706                         cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
707                 }
708         }
709         return ret;
710 }
711
712 uintptr_t
713 dtrace_fulword(void *uaddr)
714 {
715         uintptr_t ret = 0;
716
717         if (dtrace_copycheck((uintptr_t)uaddr, (uintptr_t)&ret, sizeof(ret))) {
718                 if (copyin((const void *)uaddr, (void *)&ret, sizeof(ret))) {
719                         DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
720                         cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
721                 }
722         }
723         return ret;
724 }