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