180709Sjake/*-
280709Sjake * Copyright (c) 2001 Jake Burkholder.
380709Sjake * All rights reserved.
480709Sjake *
580709Sjake * Redistribution and use in source and binary forms, with or without
680709Sjake * modification, are permitted provided that the following conditions
780709Sjake * are met:
880709Sjake * 1. Redistributions of source code must retain the above copyright
980709Sjake *    notice, this list of conditions and the following disclaimer.
1080709Sjake * 2. Redistributions in binary form must reproduce the above copyright
1180709Sjake *    notice, this list of conditions and the following disclaimer in the
1280709Sjake *    documentation and/or other materials provided with the distribution.
1380709Sjake *
1481337Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1580709Sjake * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1680709Sjake * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1781337Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1880709Sjake * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1980709Sjake * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2080709Sjake * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2180709Sjake * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2280709Sjake * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2380709Sjake * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2480709Sjake * SUCH DAMAGE.
2580709Sjake */
2680709Sjake
27155839Smarius#include <sys/cdefs.h>
28155839Smarius__FBSDID("$FreeBSD$");
29155839Smarius
3080709Sjake#include <sys/param.h>
3180709Sjake#include <sys/systm.h>
32131952Smarcel#include <sys/kdb.h>
3380709Sjake#include <sys/proc.h>
34148666Sjeff#include <sys/stack.h>
3586525Sjake#include <sys/sysent.h>
3680709Sjake
3780709Sjake#include <vm/vm.h>
3880709Sjake#include <vm/vm_page.h>
3980709Sjake#include <vm/vm_map.h>
4080709Sjake
4180709Sjake#include <machine/cpu.h>
42138129Sdas#include <machine/pcb.h>
43174195Srwatson#include <machine/stack.h>
4480709Sjake#include <machine/trap.h>
4580709Sjake#include <machine/vmparam.h>
4680709Sjake
4780709Sjake#include <ddb/ddb.h>
4880709Sjake#include <ddb/db_access.h>
4980709Sjake#include <ddb/db_sym.h>
5080709Sjake#include <ddb/db_variables.h>
5180709Sjake#include <ddb/db_watch.h>
5280709Sjake
53131952Smarcelstatic db_varfcn_t db_frame;
54131952Smarcel
55131952Smarcel#define	DB_OFFSET(x)	(db_expr_t *)offsetof(struct trapframe, x)
5680709Sjakestruct	db_variable db_regs[] = {
57131952Smarcel	{ "g0",		DB_OFFSET(tf_global[0]),	db_frame },
58131952Smarcel	{ "g1",		DB_OFFSET(tf_global[1]),	db_frame },
59131952Smarcel	{ "g2",		DB_OFFSET(tf_global[2]),	db_frame },
60131952Smarcel	{ "g3",		DB_OFFSET(tf_global[3]),	db_frame },
61131952Smarcel	{ "g4",		DB_OFFSET(tf_global[4]),	db_frame },
62131952Smarcel	{ "g5",		DB_OFFSET(tf_global[5]),	db_frame },
63131952Smarcel	{ "g6",		DB_OFFSET(tf_global[6]),	db_frame },
64131952Smarcel	{ "g7",		DB_OFFSET(tf_global[7]),	db_frame },
65131952Smarcel	{ "i0",		DB_OFFSET(tf_out[0]),		db_frame },
66131952Smarcel	{ "i1",		DB_OFFSET(tf_out[1]),		db_frame },
67131952Smarcel	{ "i2",		DB_OFFSET(tf_out[2]),		db_frame },
68131952Smarcel	{ "i3",		DB_OFFSET(tf_out[3]),		db_frame },
69131952Smarcel	{ "i4",		DB_OFFSET(tf_out[4]),		db_frame },
70131952Smarcel	{ "i5",		DB_OFFSET(tf_out[5]),		db_frame },
71131952Smarcel	{ "i6",		DB_OFFSET(tf_out[6]),		db_frame },
72131952Smarcel	{ "i7",		DB_OFFSET(tf_out[7]),		db_frame },
73131952Smarcel	{ "tnpc",	DB_OFFSET(tf_tnpc),		db_frame },
74131952Smarcel	{ "tpc",	DB_OFFSET(tf_tpc),		db_frame },
75131952Smarcel	{ "tstate",	DB_OFFSET(tf_tstate),		db_frame },
7680709Sjake};
77298352Spfgstruct db_variable *db_eregs = db_regs + nitems(db_regs);
7880709Sjake
79131952Smarcelstatic int
80131952Smarceldb_frame(struct db_variable *vp, db_expr_t *valuep, int op)
8180709Sjake{
82131952Smarcel	uint64_t *reg;
8380709Sjake
84131952Smarcel	if (kdb_frame == NULL)
85131952Smarcel		return (0);
86131952Smarcel	reg = (uint64_t*)((uintptr_t)kdb_frame + (uintptr_t)vp->valuep);
87131952Smarcel	if (op == DB_VAR_GET)
88131952Smarcel		*valuep = *reg;
89131952Smarcel	else
90131952Smarcel		*reg = *valuep;
91131952Smarcel	return (1);
92131952Smarcel}
93131952Smarcel
94131952Smarcel/*
95131952Smarcel * User stack trace (debugging aid).
96131952Smarcel */
97131952Smarcelstatic void
98160312Sjhbdb_utrace(struct thread *td, struct trapframe *tf, int count)
99131952Smarcel{
100131952Smarcel	struct pcb *pcb;
101131952Smarcel	db_addr_t sp, rsp, o7, pc;
102131952Smarcel	int i, found;
103131952Smarcel
104131952Smarcel	pcb = td->td_pcb;
105131952Smarcel	sp = db_get_value((db_addr_t)&tf->tf_sp, sizeof(tf->tf_sp), FALSE);
106131952Smarcel	o7 = db_get_value((db_addr_t)&tf->tf_out[7], sizeof(tf->tf_out[7]),
107131952Smarcel	    FALSE);
108131952Smarcel	pc = db_get_value((db_addr_t)&tf->tf_tpc, sizeof(tf->tf_tpc), FALSE);
109131952Smarcel	db_printf("user trace: trap %%o7=%#lx\n", o7);
110160312Sjhb	while (count-- && sp != 0 && !db_pager_quit) {
111131952Smarcel		db_printf("pc %#lx, sp %#lx\n", pc, sp);
112131952Smarcel		/* First, check whether the frame is in the pcb. */
113131952Smarcel		found = 0;
114131952Smarcel		for (i = 0; i < pcb->pcb_nsaved; i++) {
115131952Smarcel			if (pcb->pcb_rwsp[i] == sp) {
116131952Smarcel				found = 1;
117131952Smarcel				sp = pcb->pcb_rw[i].rw_in[6];
118131952Smarcel				pc = pcb->pcb_rw[i].rw_in[7];
119131952Smarcel				break;
12088635Sjake			}
12186525Sjake		}
122131952Smarcel		if (!found) {
123131952Smarcel			rsp = sp + SPOFF;
124131952Smarcel			sp = 0;
125131952Smarcel			if (copyin((void *)(rsp + offsetof(struct frame, fr_fp)),
126131952Smarcel			    &sp, sizeof(sp)) != 0 ||
127131952Smarcel			    copyin((void *)(rsp + offsetof(struct frame, fr_pc)),
128131952Smarcel			    &pc, sizeof(pc)) != 0)
129131952Smarcel				break;
13080709Sjake		}
13180709Sjake	}
132131952Smarcel	db_printf("done\n");
13380709Sjake}
13480709Sjake
13581379Sjakestatic int
136160312Sjhbdb_print_trap(struct thread *td, struct trapframe *tf, int count)
13780709Sjake{
13893028Sjake	struct proc *p;
13986525Sjake	const char *symname;
14086525Sjake	c_db_sym_t sym;
14186525Sjake	db_expr_t diff;
14286525Sjake	db_addr_t func;
14386525Sjake	db_addr_t tpc;
14480709Sjake	u_long type;
14588635Sjake	u_long sfar;
14688635Sjake	u_long sfsr;
14788635Sjake	u_long tar;
14888635Sjake	u_long level;
14988635Sjake	u_long pil;
15086525Sjake	u_long code;
15193028Sjake	u_long o7;
15288635Sjake	int user;
15380709Sjake
15493028Sjake	p = td->td_proc;
15588635Sjake	type = db_get_value((db_addr_t)&tf->tf_type,
15688635Sjake	    sizeof(tf->tf_type), FALSE);
15786525Sjake	db_printf("-- %s", trap_msg[type & ~T_KERNEL]);
15880709Sjake	switch (type & ~T_KERNEL) {
15988635Sjake	case T_DATA_PROTECTION:
16088635Sjake		tar = (u_long)db_get_value((db_addr_t)&tf->tf_tar,
16188635Sjake		    sizeof(tf->tf_tar), FALSE);
16288635Sjake		db_printf(" tar=%#lx", tar);
16388635Sjake		/* fall through */
16488635Sjake	case T_DATA_EXCEPTION:
16588635Sjake	case T_INSTRUCTION_EXCEPTION:
16688635Sjake	case T_MEM_ADDRESS_NOT_ALIGNED:
16788635Sjake		sfar = (u_long)db_get_value((db_addr_t)&tf->tf_sfar,
16888635Sjake		    sizeof(tf->tf_sfar), FALSE);
16988635Sjake		sfsr = (u_long)db_get_value((db_addr_t)&tf->tf_sfsr,
17088635Sjake		    sizeof(tf->tf_sfsr), FALSE);
17188635Sjake		db_printf(" sfar=%#lx sfsr=%#lx", sfar, sfsr);
17280709Sjake		break;
17388635Sjake	case T_DATA_MISS:
17488635Sjake	case T_INSTRUCTION_MISS:
17588635Sjake		tar = (u_long)db_get_value((db_addr_t)&tf->tf_tar,
17688635Sjake		    sizeof(tf->tf_tar), FALSE);
17788635Sjake		db_printf(" tar=%#lx", tar);
17888635Sjake		break;
17986525Sjake	case T_SYSCALL:
18086525Sjake		code = db_get_value((db_addr_t)&tf->tf_global[1],
18188635Sjake		    sizeof(tf->tf_global[1]), FALSE);
18286525Sjake		db_printf(" (%ld", code);
18386525Sjake		if (code >= 0 && code < p->p_sysent->sv_size) {
18486525Sjake			func = (db_addr_t)p->p_sysent->sv_table[code].sy_call;
18586525Sjake			sym = db_search_symbol(func, DB_STGY_ANY, &diff);
18686525Sjake			if (sym != DB_SYM_NULL && diff == 0) {
18786525Sjake				db_symbol_values(sym, &symname, NULL);
18886525Sjake				db_printf(", %s, %s", p->p_sysent->sv_name,
18986525Sjake				    symname);
19086525Sjake			}
19186525Sjake			db_printf(")");
19286525Sjake		}
19386525Sjake		break;
19488635Sjake	case T_INTERRUPT:
19588635Sjake		level = (u_long)db_get_value((db_addr_t)&tf->tf_level,
19688635Sjake		    sizeof(tf->tf_level), FALSE);
19788635Sjake		pil = (u_long)db_get_value((db_addr_t)&tf->tf_pil,
19888635Sjake		    sizeof(tf->tf_pil), FALSE);
19988635Sjake		db_printf(" level=%#lx pil=%#lx", level, pil);
20088635Sjake		break;
20180709Sjake	default:
20280709Sjake		break;
20380709Sjake	}
20493028Sjake	o7 = (u_long)db_get_value((db_addr_t)&tf->tf_out[7],
20593028Sjake	    sizeof(tf->tf_out[7]), FALSE);
20693028Sjake	db_printf(" %%o7=%#lx --\n", o7);
20788635Sjake	user = (type & T_KERNEL) == 0;
20888635Sjake	if (user) {
20988635Sjake		tpc = db_get_value((db_addr_t)&tf->tf_tpc,
21088635Sjake		    sizeof(tf->tf_tpc), FALSE);
21188635Sjake		db_printf("userland() at ");
21288635Sjake		db_printsym(tpc, DB_STGY_PROC);
21388635Sjake		db_printf("\n");
214160312Sjhb		db_utrace(td, tf, count);
21580709Sjake	}
21688635Sjake	return (user);
21780709Sjake}
21893028Sjake
219131952Smarcelstatic int
220131952Smarceldb_backtrace(struct thread *td, struct frame *fp, int count)
22193028Sjake{
222131952Smarcel	struct trapframe *tf;
223131952Smarcel	const char *name;
224131952Smarcel	c_db_sym_t sym;
225131952Smarcel	db_expr_t offset;
226131952Smarcel	db_expr_t value;
227131952Smarcel	db_addr_t npc;
228131952Smarcel	db_addr_t pc;
229131952Smarcel	int trap;
230131952Smarcel	int user;
23193028Sjake
232131952Smarcel	if (count == -1)
233131952Smarcel		count = 1024;
234131952Smarcel
235131952Smarcel	trap = 0;
236131952Smarcel	user = 0;
237131952Smarcel	npc = 0;
238160312Sjhb	while (count-- && !user && !db_pager_quit) {
239131952Smarcel		pc = (db_addr_t)db_get_value((db_addr_t)&fp->fr_pc,
240131952Smarcel		    sizeof(fp->fr_pc), FALSE);
241131952Smarcel		if (trap) {
242131952Smarcel			pc = npc;
243131952Smarcel			trap = 0;
24493028Sjake		}
245131952Smarcel		if (!INKERNEL((vm_offset_t)pc))
246131952Smarcel			break;
247131952Smarcel		sym = db_search_symbol(pc, DB_STGY_ANY, &offset);
248131952Smarcel		if (sym == C_DB_SYM_NULL) {
249131952Smarcel			value = 0;
250131952Smarcel			name = NULL;
251131952Smarcel		} else
252131952Smarcel			db_symbol_values(sym, &name, &value);
253131952Smarcel		if (name == NULL)
254131952Smarcel			name = "(null)";
255131952Smarcel		fp = (struct frame *)(db_get_value((db_addr_t)&fp->fr_fp,
256131952Smarcel		   sizeof(fp->fr_fp), FALSE) + SPOFF);
257155839Smarius		if ((value > (u_long)tl_trap_begin &&
258155839Smarius		    value < (u_long)tl_trap_end) ||
259155839Smarius		    (value > (u_long)tl_text_begin &&
260155839Smarius		    value < (u_long)tl_text_end)) {
261131952Smarcel			tf = (struct trapframe *)(fp + 1);
262131952Smarcel			npc = db_get_value((db_addr_t)&tf->tf_tpc,
263131952Smarcel			    sizeof(tf->tf_tpc), FALSE);
264160312Sjhb			user = db_print_trap(td, tf, count);
265131952Smarcel			trap = 1;
266131952Smarcel		} else {
267131952Smarcel			db_printf("%s() at ", name);
268131952Smarcel			db_printsym(pc, DB_STGY_PROC);
269131952Smarcel			db_printf("\n");
27093028Sjake		}
27193028Sjake	}
272131952Smarcel	return (0);
27393028Sjake}
274103646Sjhb
275103646Sjhbvoid
276131952Smarceldb_trace_self(void)
277131952Smarcel{
278131952Smarcel
279184376Smarius	db_backtrace(curthread,
280184376Smarius	    (struct frame *)__builtin_frame_address(1), -1);
281131952Smarcel}
282131952Smarcel
283131952Smarcelint
284131952Smarceldb_trace_thread(struct thread *td, int count)
285131952Smarcel{
286131952Smarcel	struct pcb *ctx;
287131952Smarcel
288131952Smarcel	ctx = kdb_thr_ctx(td);
289184376Smarius	return (db_backtrace(td,
290184376Smarius	    (struct frame *)(ctx->pcb_sp + SPOFF), count));
291131952Smarcel}
292