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/kernel.h>
34
35 #include <mips/cpuregs.h>
36 #include <mips/frame.h>
37 #include <mips/locore.h>
38 #include <mips/reg.h>
39
40 #include <machine/db_machdep.h>
41 #include <machine/mips_opcode.h>
42 #include <ddb/db_sym.h>
43 #include <ddb/ddb.h>
44
45 #include "regset.h"
46
47 #ifdef __mips_n64
48 #define MIPS_IS_VALID_KERNELADDR(reg) ((((reg) & 3) == 0) && \
49 ((vm_offset_t)(reg) >= MIPS_XKPHYS_START))
50 #else
51 #define MIPS_IS_VALID_KERNELADDR(reg) ((((reg) & 3) == 0) && \
52 ((vm_offset_t)(reg) >= MIPS_KSEG0_START))
53 #endif
54
55 #ifdef __FreeBSD__
56 #define CURRENT_CPU curcpu
57 #define CURRENT_TRAPFRAME curthread->td_frame
58 #endif
59 #ifdef __NetBSD__
60 #define CURRENT_CPU cpu_index(curcpu())
61 #define CURRENT_TRAPFRAME curlwp->l_md.md_utf
62 #endif
63
64 #ifdef __FreeBSD__
65 #define KDBPEEK(va) kdbpeek((int *)(va))
66 #define KDBPEEKD(va) kdbpeekd((int *)(va))
67 #endif
68 #ifdef __NetBSD__
69 #define KDBPEEK(va) kdbrpeek((va), sizeof(int32_t))
70 #define KDBPEEKD(va) kdbrpeek((va), sizeof(int64_t))
71 #endif
72
73 #ifndef OP_BCOND
74 #define OP_BCOND OP_REGIMM
75 #endif
76
77 /*
78 * We need some reasonable default to prevent backtrace code
79 * from wandering too far
80 */
81 #define MAX_FUNCTION_SIZE 0x10000
82 #define MAX_PROLOGUE_SIZE 0x100
83
84 uint8_t dtrace_fuword8_nocheck(void *);
85 uint16_t dtrace_fuword16_nocheck(void *);
86 uint32_t dtrace_fuword32_nocheck(void *);
87 uint64_t dtrace_fuword64_nocheck(void *);
88
89 static int dtrace_next_frame(register_t *pc, register_t *sp, register_t *args, int *valid_args);
90 static int dtrace_next_uframe(register_t *pc, register_t *sp, register_t *ra);
91
92 void
dtrace_getpcstack(pc_t * pcstack,int pcstack_limit,int aframes,uint32_t * intrpc)93 dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes,
94 uint32_t *intrpc)
95 {
96 int depth = 0;
97 vm_offset_t callpc;
98 pc_t caller = (pc_t) solaris_cpu[CURRENT_CPU].cpu_dtrace_caller;
99 register_t sp, ra, pc;
100
101 if (intrpc != 0)
102 pcstack[depth++] = (pc_t) intrpc;
103
104 aframes++;
105
106 sp = (register_t)(intptr_t)__builtin_frame_address(0);
107 ra = (register_t)(intptr_t)__builtin_return_address(0);
108
109 __asm __volatile(
110 "nal\n"
111 " nop\n"
112 "move %0, $31\n" /* get ra */
113 "move $31, %1\n" /* restore ra */
114 : "=r" (pc)
115 : "r" (ra));
116
117 while (depth < pcstack_limit) {
118
119 callpc = pc;
120
121 if (aframes > 0) {
122 aframes--;
123 if ((aframes == 0) && (caller != 0)) {
124 pcstack[depth++] = caller;
125 }
126 }
127 else {
128 pcstack[depth++] = callpc;
129 }
130
131 if (dtrace_next_frame(&pc, &sp, NULL, NULL) < 0)
132 break;
133 }
134
135 for (; depth < pcstack_limit; depth++) {
136 pcstack[depth] = 0;
137 }
138 }
139
140 void
dtrace_getupcstack(uint64_t * pcstack,int pcstack_limit)141 dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit)
142 {
143 proc_t *p = curproc;
144 struct trapframe *tf;
145 register_t sp, ra, pc;
146 volatile uint16_t *flags =
147 (volatile uint16_t *)&cpu_core[CURRENT_CPU].cpuc_dtrace_flags;
148
149 if (*flags & CPU_DTRACE_FAULT)
150 return;
151
152 if (pcstack_limit <= 0)
153 return;
154
155 /*
156 * If there's no user context we still need to zero the stack.
157 */
158 if (p == NULL || (tf = CURRENT_TRAPFRAME) == NULL)
159 goto zero;
160
161 *pcstack++ = (uint64_t)p->p_pid;
162 pcstack_limit--;
163
164 if (pcstack_limit <= 0)
165 return;
166
167 pc = tf->tf_regs[_R_PC];
168 sp = tf->tf_regs[_R_SP];
169 ra = tf->tf_regs[_R_RA];
170 *pcstack++ = (uint64_t)pc;
171
172 /*
173 * Unwind, and unwind, and unwind
174 */
175 while (1) {
176 if (dtrace_next_uframe(&pc, &sp, &ra) < 0)
177 break;
178
179 *pcstack++ = pc;
180 pcstack_limit--;
181
182 if (pcstack_limit <= 0)
183 break;
184 }
185
186 zero:
187 while (pcstack_limit-- > 0)
188 *pcstack++ = 0;
189 }
190
191 int
dtrace_getustackdepth(void)192 dtrace_getustackdepth(void)
193 {
194 int n = 0;
195 proc_t *p = curproc;
196 struct trapframe *tf;
197 register_t sp, ra, pc;
198 volatile uint16_t *flags =
199 (volatile uint16_t *)&cpu_core[CURRENT_CPU].cpuc_dtrace_flags;
200
201 if (*flags & CPU_DTRACE_FAULT)
202 return (0);
203
204 if (p == NULL || (tf = CURRENT_TRAPFRAME) == NULL)
205 return (0);
206
207 pc = tf->tf_regs[_R_PC];
208 sp = tf->tf_regs[_R_SP];
209 ra = tf->tf_regs[_R_RA];
210 n++;
211
212 /*
213 * Unwind, and unwind, and unwind
214 */
215 while (1) {
216 if (dtrace_next_uframe(&pc, &sp, &ra) < 0)
217 break;
218 n++;
219 }
220
221 return (n);
222 }
223
224 void
dtrace_getufpstack(uint64_t * pcstack,uint64_t * fpstack,int pcstack_limit)225 dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit)
226 {
227 printf("IMPLEMENT ME: %s\n", __func__);
228 }
229
230 /*ARGSUSED*/
231 uint64_t
dtrace_getarg(int arg,int aframes)232 dtrace_getarg(int arg, int aframes)
233 {
234 int i;
235 register_t sp, ra, pc;
236 /* XXX: Fix this ugly code */
237 register_t args[8];
238 int valid[8];
239
240 sp = (register_t)(intptr_t)__builtin_frame_address(0);
241 ra = (register_t)(intptr_t)__builtin_return_address(0);
242
243 __asm __volatile(
244 "jal 99f\n"
245 "nop\n"
246 "99:\n"
247 "move %0, $31\n" /* get ra */
248 "move $31, %1\n" /* restore ra */
249 : "=r" (pc)
250 : "r" (ra));
251
252 for (i = 0; i <= aframes + 1; i++) {
253 if (dtrace_next_frame(&pc, &sp, args, valid) < 0) {
254 printf("%s: stack ends at frame #%d\n", __func__, i);
255 return (0);
256 }
257 }
258
259 if (arg < 8) {
260 if (valid[arg])
261 return (args[arg]);
262 else
263 printf("%s: request arg%d is not valid\n", __func__, arg);
264 }
265
266 return (0);
267 }
268
269 int
dtrace_getstackdepth(int aframes)270 dtrace_getstackdepth(int aframes)
271 {
272 register_t sp, ra, pc;
273 int depth = 0;
274
275 sp = (register_t)(intptr_t)__builtin_frame_address(0);
276 ra = (register_t)(intptr_t)__builtin_return_address(0);
277
278 __asm __volatile(
279 "jal 99f\n"
280 "nop\n"
281 "99:\n"
282 "move %0, $31\n" /* get ra */
283 "move $31, %1\n" /* restore ra */
284 : "=r" (pc)
285 : "r" (ra));
286
287 for (;;) {
288 if (dtrace_next_frame(&pc, &sp, NULL, NULL) < 0)
289 break;
290 depth++;
291 }
292
293 if (depth < aframes)
294 return 0;
295 else
296 return depth - aframes;
297 }
298
299 ulong_t
dtrace_getreg(struct trapframe * rp,uint_t reg)300 dtrace_getreg(struct trapframe *rp, uint_t reg)
301 {
302
303 return (0);
304 }
305
306 static int
dtrace_next_frame(register_t * pc,register_t * sp,register_t * args,int * valid_args)307 dtrace_next_frame(register_t *pc, register_t *sp,
308 register_t *args, int *valid_args)
309 {
310 InstFmt i;
311 /*
312 * Arrays for a0..a3 registers and flags if content
313 * of these registers is valid, e.g. obtained from the stack
314 */
315 uintptr_t va;
316 unsigned instr, mask;
317 unsigned int frames = 0;
318 int more, stksize;
319 register_t ra = 0;
320 int arg, r;
321 vm_offset_t addr;
322
323 /*
324 * Invalidate arguments values
325 */
326 if (valid_args) {
327 for (r = 0; r < 8; r++)
328 valid_args[r] = 0;
329 }
330
331 /* Jump here after a nonstandard (interrupt handler) frame */
332 stksize = 0;
333 if (frames++ > 100) {
334 /* return breaks stackframe-size heuristics with gcc -O2 */
335 goto error; /* XXX */
336 }
337
338 /* check for bad SP: could foul up next frame */
339 if (!MIPS_IS_VALID_KERNELADDR(*sp)) {
340 goto error;
341 }
342
343 /* check for bad PC */
344 if (!MIPS_IS_VALID_KERNELADDR(*pc)) {
345 goto error;
346 }
347
348 /*
349 * Find the beginning of the current subroutine by scanning
350 * backwards from the current PC for the end of the previous
351 * subroutine.
352 */
353 va = *pc - sizeof(int);
354 while (1) {
355 instr = KDBPEEK(va);
356
357 /* [d]addiu sp,sp,-X */
358 if (((instr & 0xffff8000) == 0x27bd8000)
359 || ((instr & 0xffff8000) == 0x67bd8000))
360 break;
361
362 /* jr ra */
363 if (instr == 0x03e00008) {
364 /* skip over branch-delay slot instruction */
365 va += 2 * sizeof(int);
366 break;
367 }
368
369 va -= sizeof(int);
370 }
371
372 /* skip over nulls which might separate .o files */
373 while ((instr = KDBPEEK(va)) == 0)
374 va += sizeof(int);
375
376 /* scan forwards to find stack size and any saved registers */
377 stksize = 0;
378 more = 3;
379 mask = 0;
380 for (; more; va += sizeof(int),
381 more = (more == 3) ? 3 : more - 1) {
382 /* stop if hit our current position */
383 if (va >= *pc)
384 break;
385 instr = KDBPEEK(va);
386 i.word = instr;
387 switch (i.JType.op) {
388 case OP_SPECIAL:
389 switch (i.RType.func) {
390 case OP_JR:
391 case OP_JALR:
392 more = 2; /* stop after next instruction */
393 break;
394
395 case OP_SYSCALL:
396 case OP_BREAK:
397 more = 1; /* stop now */
398 };
399 break;
400
401 case OP_BCOND:
402 case OP_J:
403 case OP_JAL:
404 case OP_BEQ:
405 case OP_BNE:
406 case OP_BLEZ:
407 case OP_BGTZ:
408 more = 2; /* stop after next instruction */
409 break;
410
411 case OP_COP0:
412 case OP_COP1:
413 case OP_COP2:
414 case OP_COP3:
415 switch (i.RType.rs) {
416 case OP_BCx:
417 case OP_BCy:
418 more = 2; /* stop after next instruction */
419 };
420 break;
421
422 case OP_SW:
423 /* look for saved registers on the stack */
424 if (i.IType.rs != 29)
425 break;
426 /* only restore the first one */
427 if (mask & (1 << i.IType.rt))
428 break;
429 mask |= (1 << i.IType.rt);
430 addr = (vm_offset_t)(*sp + (short)i.IType.imm);
431 switch (i.IType.rt) {
432 case 4:/* a0 */
433 case 5:/* a1 */
434 case 6:/* a2 */
435 case 7:/* a3 */
436 #if defined(__mips_n64) || defined(__mips_n32)
437 case 8:/* a4 */
438 case 9:/* a5 */
439 case 10:/* a6 */
440 case 11:/* a7 */
441 #endif
442 arg = i.IType.rt - 4;
443 if (args)
444 args[arg] = KDBPEEK(addr);
445 if (valid_args)
446 valid_args[arg] = 1;
447 break;
448 case 31: /* ra */
449 ra = KDBPEEK(addr);
450 }
451 break;
452
453 case OP_SD:
454 /* look for saved registers on the stack */
455 if (i.IType.rs != 29)
456 break;
457 /* only restore the first one */
458 if (mask & (1 << i.IType.rt))
459 break;
460 mask |= (1 << i.IType.rt);
461 addr = (vm_offset_t)(*sp + (short)i.IType.imm);
462 switch (i.IType.rt) {
463 case 4:/* a0 */
464 case 5:/* a1 */
465 case 6:/* a2 */
466 case 7:/* a3 */
467 #if defined(__mips_n64) || defined(__mips_n32)
468 case 8:/* a4 */
469 case 9:/* a5 */
470 case 10:/* a6 */
471 case 11:/* a7 */
472 #endif
473 arg = i.IType.rt - 4;
474 if (args)
475 args[arg] = KDBPEEKD(addr);
476 if (valid_args)
477 valid_args[arg] = 1;
478 break;
479
480 case 31: /* ra */
481 ra = KDBPEEKD(addr);
482 }
483 break;
484
485 case OP_ADDI:
486 case OP_ADDIU:
487 case OP_DADDI:
488 case OP_DADDIU:
489 /* look for stack pointer adjustment */
490 if (i.IType.rs != 29 || i.IType.rt != 29)
491 break;
492 stksize = -((short)i.IType.imm);
493 }
494 }
495
496 if (!MIPS_IS_VALID_KERNELADDR(ra))
497 return (-1);
498
499 *pc = ra;
500 *sp += stksize;
501
502 #if defined(__mips_o32)
503 /*
504 * For MIPS32 fill out arguments 5..8 from the stack
505 */
506 for (arg = 4; arg < 8; arg++) {
507 addr = (vm_offset_t)(*sp + arg*sizeof(register_t));
508 if (args)
509 args[arg] = KDBPEEKD(addr);
510 if (valid_args)
511 valid_args[arg] = 1;
512 }
513 #endif
514
515 return (0);
516 error:
517 return (-1);
518 }
519
520 static int
dtrace_next_uframe(register_t * pc,register_t * sp,register_t * ra)521 dtrace_next_uframe(register_t *pc, register_t *sp, register_t *ra)
522 {
523 int offset, registers_on_stack;
524 uint32_t opcode, mask;
525 register_t function_start;
526 int stksize;
527 InstFmt i;
528
529 volatile uint16_t *flags =
530 (volatile uint16_t *)&cpu_core[CURRENT_CPU].cpuc_dtrace_flags;
531
532 registers_on_stack = 0;
533 mask = 0;
534 function_start = 0;
535 offset = 0;
536 stksize = 0;
537
538 while (offset < MAX_FUNCTION_SIZE) {
539 opcode = dtrace_fuword32((void *)(vm_offset_t)(*pc - offset));
540
541 if (*flags & CPU_DTRACE_FAULT)
542 goto fault;
543
544 /* [d]addiu sp, sp, -X*/
545 if (((opcode & 0xffff8000) == 0x27bd8000)
546 || ((opcode & 0xffff8000) == 0x67bd8000)) {
547 function_start = *pc - offset;
548 registers_on_stack = 1;
549 break;
550 }
551
552 /* lui gp, X */
553 if ((opcode & 0xffff8000) == 0x3c1c0000) {
554 /*
555 * Function might start with this instruction
556 * Keep an eye on "jr ra" and sp correction
557 * with positive value further on
558 */
559 function_start = *pc - offset;
560 }
561
562 if (function_start) {
563 /*
564 * Stop looking further. Possible end of
565 * function instruction: it means there is no
566 * stack modifications, sp is unchanged
567 */
568
569 /* [d]addiu sp,sp,X */
570 if (((opcode & 0xffff8000) == 0x27bd0000)
571 || ((opcode & 0xffff8000) == 0x67bd0000))
572 break;
573
574 if (opcode == 0x03e00008)
575 break;
576 }
577
578 offset += sizeof(int);
579 }
580
581 if (!function_start)
582 return (-1);
583
584 if (registers_on_stack) {
585 offset = 0;
586 while ((offset < MAX_PROLOGUE_SIZE)
587 && ((function_start + offset) < *pc)) {
588 i.word =
589 dtrace_fuword32((void *)(vm_offset_t)(function_start + offset));
590 switch (i.JType.op) {
591 case OP_SW:
592 /* look for saved registers on the stack */
593 if (i.IType.rs != 29)
594 break;
595 /* only restore the first one */
596 if (mask & (1 << i.IType.rt))
597 break;
598 mask |= (1 << i.IType.rt);
599 if (i.IType.rt == 31)
600 *ra = dtrace_fuword32((void *)(vm_offset_t)(*sp + (short)i.IType.imm));
601 break;
602
603 case OP_SD:
604 /* look for saved registers on the stack */
605 if (i.IType.rs != 29)
606 break;
607 /* only restore the first one */
608 if (mask & (1 << i.IType.rt))
609 break;
610 mask |= (1 << i.IType.rt);
611 /* ra */
612 if (i.IType.rt == 31)
613 *ra = dtrace_fuword64((void *)(vm_offset_t)(*sp + (short)i.IType.imm));
614 break;
615
616 case OP_ADDI:
617 case OP_ADDIU:
618 case OP_DADDI:
619 case OP_DADDIU:
620 /* look for stack pointer adjustment */
621 if (i.IType.rs != 29 || i.IType.rt != 29)
622 break;
623 stksize = -((short)i.IType.imm);
624 }
625
626 offset += sizeof(int);
627
628 if (*flags & CPU_DTRACE_FAULT)
629 goto fault;
630 }
631 }
632
633 /*
634 * We reached the end of backtrace
635 */
636 if (*pc == *ra)
637 return (-1);
638
639 *pc = *ra;
640 *sp += stksize;
641
642 return (0);
643 fault:
644 /*
645 * We just got lost in backtrace, no big deal
646 */
647 *flags &= ~CPU_DTRACE_FAULT;
648 return (-1);
649 }
650
651 static int
dtrace_copycheck(uintptr_t uaddr,uintptr_t kaddr,size_t size)652 dtrace_copycheck(uintptr_t uaddr, uintptr_t kaddr, size_t size)
653 {
654
655 if (uaddr + size > VM_MAXUSER_ADDRESS || uaddr + size < uaddr) {
656 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
657 cpu_core[CURRENT_CPU].cpuc_dtrace_illval = uaddr;
658 return (0);
659 }
660
661 return (1);
662 }
663
664 void
dtrace_copyin(uintptr_t uaddr,uintptr_t kaddr,size_t size,volatile uint16_t * flags)665 dtrace_copyin(uintptr_t uaddr, uintptr_t kaddr, size_t size,
666 volatile uint16_t *flags)
667 {
668 if (dtrace_copycheck(uaddr, kaddr, size))
669 dtrace_copy(uaddr, kaddr, size);
670 }
671
672 void
dtrace_copyout(uintptr_t kaddr,uintptr_t uaddr,size_t size,volatile uint16_t * flags)673 dtrace_copyout(uintptr_t kaddr, uintptr_t uaddr, size_t size,
674 volatile uint16_t *flags)
675 {
676 if (dtrace_copycheck(uaddr, kaddr, size))
677 dtrace_copy(kaddr, uaddr, size);
678 }
679
680 void
dtrace_copyinstr(uintptr_t uaddr,uintptr_t kaddr,size_t size,volatile uint16_t * flags)681 dtrace_copyinstr(uintptr_t uaddr, uintptr_t kaddr, size_t size,
682 volatile uint16_t *flags)
683 {
684 if (dtrace_copycheck(uaddr, kaddr, size))
685 dtrace_copystr(uaddr, kaddr, size, flags);
686 }
687
688 void
dtrace_copyoutstr(uintptr_t kaddr,uintptr_t uaddr,size_t size,volatile uint16_t * flags)689 dtrace_copyoutstr(uintptr_t kaddr, uintptr_t uaddr, size_t size,
690 volatile uint16_t *flags)
691 {
692 if (dtrace_copycheck(uaddr, kaddr, size))
693 dtrace_copystr(kaddr, uaddr, size, flags);
694 }
695
696 uint8_t
dtrace_fuword8(void * uaddr)697 dtrace_fuword8(void *uaddr)
698 {
699 if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
700 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
701 cpu_core[CURRENT_CPU].cpuc_dtrace_illval = (uintptr_t)uaddr;
702 return (0);
703 }
704 return (dtrace_fuword8_nocheck(uaddr));
705 }
706
707 uint16_t
dtrace_fuword16(void * uaddr)708 dtrace_fuword16(void *uaddr)
709 {
710 if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
711 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
712 cpu_core[CURRENT_CPU].cpuc_dtrace_illval = (uintptr_t)uaddr;
713 return (0);
714 }
715 return (dtrace_fuword16_nocheck(uaddr));
716 }
717
718 uint32_t
dtrace_fuword32(void * uaddr)719 dtrace_fuword32(void *uaddr)
720 {
721 if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
722 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
723 cpu_core[CURRENT_CPU].cpuc_dtrace_illval = (uintptr_t)uaddr;
724 return (0);
725 }
726 return (dtrace_fuword32_nocheck(uaddr));
727 }
728
729 uint64_t
dtrace_fuword64(void * uaddr)730 dtrace_fuword64(void *uaddr)
731 {
732 if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
733 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
734 cpu_core[CURRENT_CPU].cpuc_dtrace_illval = (uintptr_t)uaddr;
735 return (0);
736 }
737 return (dtrace_fuword64_nocheck(uaddr));
738 }
739