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
84uint8_t dtrace_fuword8_nocheck(void *);
85uint16_t dtrace_fuword16_nocheck(void *);
86uint32_t dtrace_fuword32_nocheck(void *);
87uint64_t dtrace_fuword64_nocheck(void *);
88
89static int dtrace_next_frame(register_t *pc, register_t *sp, register_t *args, int *valid_args);
90static int dtrace_next_uframe(register_t *pc, register_t *sp, register_t *ra);
91
92void
93dtrace_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
140void
141dtrace_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
186zero:
187	while (pcstack_limit-- > 0)
188		*pcstack++ = 0;
189}
190
191int
192dtrace_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
224void
225dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit)
226{
227	printf("IMPLEMENT ME: %s\n", __func__);
228}
229
230/*ARGSUSED*/
231uint64_t
232dtrace_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
269int
270dtrace_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
299ulong_t
300dtrace_getreg(struct trapframe *rp, uint_t reg)
301{
302
303	return (0);
304}
305
306static int
307dtrace_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);
516error:
517	return (-1);
518}
519
520static int
521dtrace_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);
643fault:
644	/*
645	 * We just got lost in backtrace, no big deal
646	 */
647	*flags &= ~CPU_DTRACE_FAULT;
648	return (-1);
649}
650
651static int
652dtrace_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
664void
665dtrace_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
672void
673dtrace_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
680void
681dtrace_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
688void
689dtrace_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
696uint8_t
697dtrace_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
707uint16_t
708dtrace_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
718uint32_t
719dtrace_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
729uint64_t
730dtrace_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