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