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