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