xref: /netbsd-src/sys/arch/sparc/sparc/db_trace.c (revision 2dd13abc5d2a544ea0570fc5ba6860215aebcb9b)
1 /*	$NetBSD: db_trace.c,v 1.37 2019/04/06 16:22:01 thorpej Exp $ */
2 
3 /*
4  * Mach Operating System
5  * Copyright (c) 1991,1990 Carnegie Mellon University
6  * All Rights Reserved.
7  *
8  * Permission to use, copy, modify and distribute this software and its
9  * documentation is hereby granted, provided that both the copyright
10  * notice and this permission notice appear in all copies of the
11  * software, derivative works or modified versions, and any portions
12  * thereof, and that both notices appear in supporting documentation.
13  *
14  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
15  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
16  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
17  *
18  * Carnegie Mellon requests users of this software to return to
19  *
20  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
21  *  School of Computer Science
22  *  Carnegie Mellon University
23  *  Pittsburgh PA 15213-3890
24  *
25  * any improvements or extensions that they make and grant Carnegie the
26  * rights to redistribute these changes.
27  */
28 
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: db_trace.c,v 1.37 2019/04/06 16:22:01 thorpej Exp $");
31 
32 #include <sys/param.h>
33 #include <sys/proc.h>
34 #include <sys/cpu.h>
35 #include <sys/systm.h>
36 
37 #include <machine/db_machdep.h>
38 
39 #include <ddb/db_access.h>
40 #include <ddb/db_user.h>
41 #include <ddb/db_sym.h>
42 #include <ddb/db_interface.h>
43 #include <ddb/db_output.h>
44 
45 #define INKERNEL(va)	(((vaddr_t)(va)) >= USRSTACK)
46 #ifdef _KERNEL
47 #define ONINTSTACK(fr)	(						\
48 	(u_int)(fr) <  (u_int)ddb_cpuinfo->eintstack &&		 	\
49 	(u_int)(fr) >= (u_int)ddb_cpuinfo->eintstack - INT_STACK_SIZE	\
50 )
51 #else
52 #define ONINTSTACK(fr)	(0)
53 #endif
54 
55 #ifdef _KERNEL
56 static db_addr_t
db_fetch_word(const void * uaddr)57 db_fetch_word(const void *uaddr)
58 {
59 	u_int val;
60 
61 	if (ufetch_int(uaddr, &val) != 0)
62 		val = (u_int)-1;
63 	return val;
64 }
65 #endif /* _KERNEL */
66 
67 void
db_stack_trace_print(db_expr_t addr,bool have_addr,db_expr_t count,const char * modif,void (* pr)(const char *,...))68 db_stack_trace_print(db_expr_t addr, bool have_addr,
69 		     db_expr_t count, const char *modif,
70 		     void (*pr)(const char *, ...))
71 {
72 	struct frame	*frame, *prevframe;
73 	db_addr_t	pc;
74 	bool		kernel_only = true;
75 	bool		trace_thread = false;
76 	bool		lwpaddr = false;
77 	const char	*cp = modif;
78 	char		c;
79 
80 #ifdef _KERNEL
81 	if (ddb_cpuinfo == NULL)
82 		ddb_cpuinfo = curcpu();
83 #endif
84 
85 	while ((c = *cp++) != 0) {
86 		if (c == 'a') {
87 			lwpaddr = true;
88 			trace_thread = true;
89 		}
90 		if (c == 't')
91 			trace_thread = true;
92 		if (c == 'u')
93 			kernel_only = false;
94 	}
95 
96 	if (!have_addr) {
97 		frame = (struct frame *)DDB_TF->tf_out[6];
98 		pc = DDB_TF->tf_pc;
99 	} else {
100 		if (trace_thread) {
101 			struct proc *p;
102 			struct pcb *pcb;
103 			struct lwp *l;
104 			if (lwpaddr) {
105 				l = (struct lwp *)addr;
106 				p = l->l_proc;
107 				(*pr)("trace: pid %d ", p->p_pid);
108 			} else {
109 				(*pr)("trace: pid %d ", (int)addr);
110 #ifdef _KERNEL
111 				p = proc_find_raw(addr);
112 				if (p == NULL) {
113 					(*pr)("not found\n");
114 					return;
115 				}
116 				l = LIST_FIRST(&p->p_lwps);
117 				KASSERT(l != NULL);
118 #else
119 				(*pr)("no proc_find_raw() in crash\n");
120 				return;
121 #endif
122 			}
123 			(*pr)("lid %d ", l->l_lid);
124 			pcb = lwp_getpcb(l);
125 			frame = (struct frame *)pcb->pcb_sp;
126 			pc = pcb->pcb_pc;
127 			(*pr)("at %p\n", frame);
128 		} else {
129 			frame = (struct frame *)addr;
130 			pc = 0;
131 		}
132 	}
133 
134 	while (count--) {
135 		int		i;
136 		db_expr_t	offset;
137 		const char	*name;
138 		db_addr_t	prevpc;
139 
140 #ifdef _KERNEL
141 #define FR(framep,field) (INKERNEL(framep)			\
142 				? (u_int)(framep)->field	\
143 				: db_fetch_word(&(framep)->field))
144 #else
145 /* XXX fix me, this is probably wrong */
146 #define FR(framep,field) ((u_int)(framep)->field)
147 #endif
148 
149 		/* Fetch return address and arguments frame */
150 		prevpc = (db_addr_t)FR(frame, fr_pc);
151 		prevframe = (struct frame *)FR(frame, fr_fp);
152 
153 		/*
154 		 * Switch to frame that contains arguments
155 		 */
156 		if (prevframe == NULL || (!INKERNEL(prevframe) && kernel_only))
157 			return;
158 
159 		if ((ONINTSTACK(frame) && !ONINTSTACK(prevframe)) ||
160 		    (INKERNEL(frame) && !INKERNEL(prevframe))) {
161 			/* We're crossing a trap frame; pc = %l1 */
162 			prevpc = (db_addr_t)FR(frame, fr_local[1]);
163 		}
164 
165 		name = NULL;
166 		if (INKERNEL(pc))
167 			db_find_sym_and_offset(pc, &name, &offset);
168 		if (name == NULL)
169 			(*pr)("0x%lx(", pc);
170 		else
171 			(*pr)("%s(", name);
172 
173 		/*
174 		 * Print %i0..%i5, hope these still reflect the
175 		 * actual arguments somewhat...
176 		 */
177 		for (i = 0; i < 6; i++)
178 			(*pr)("0x%x%s", FR(frame, fr_arg[i]),
179 				(i < 5) ? ", " : ") at ");
180 		if (INKERNEL(prevpc))
181 			db_printsym(prevpc, DB_STGY_PROC, pr);
182 		else
183 			(*pr)("0x%lx", prevpc);
184 		(*pr)("\n");
185 
186 		pc = prevpc;
187 		frame = prevframe;
188 	}
189 }
190