xref: /openbsd-src/sys/arch/alpha/alpha/db_trace.c (revision 949c1c4ec8cc03255798b09f6078e1d0aed70a6a)
1 /*	$OpenBSD: db_trace.c,v 1.24 2024/11/07 16:02:29 miod Exp $	*/
2 
3 /*
4  * Copyright (c) 1997 Niklas Hallqvist.  All rights reserved.
5  * Copyright (c) 1997 Theo de Raadt.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include <sys/param.h>
29 #include <sys/systm.h>
30 
31 #include <uvm/uvm_extern.h>
32 
33 #include <machine/db_machdep.h>
34 #include <machine/frame.h>
35 
36 #include <ddb/db_access.h>
37 #include <ddb/db_command.h>
38 #include <ddb/db_output.h>
39 #include <ddb/db_sym.h>
40 #include <ddb/db_variables.h>
41 #include <ddb/db_extern.h>
42 #include <ddb/db_interface.h>
43 
44 extern int	etext;
45 
46 struct opcode opcode[] = {
47 	{ OPC_PAL, "call_pal", 0 },	/* 00 */
48 	{ OPC_RES, "opc01", 0 },	/* 01 */
49 	{ OPC_RES, "opc02", 0 },	/* 02 */
50 	{ OPC_RES, "opc03", 0 },	/* 03 */
51 	{ OPC_RES, "opc04", 0 },	/* 04 */
52 	{ OPC_RES, "opc05", 0 },	/* 05 */
53 	{ OPC_RES, "opc06", 0 },	/* 06 */
54 	{ OPC_RES, "opc07", 0 },	/* 07 */
55 	{ OPC_MEM, "lda", 1 },		/* 08 */
56 	{ OPC_MEM, "ldah", 1 },		/* 09 */
57 	{ OPC_RES, "opc0a", 0 },	/* 0A */
58 	{ OPC_MEM, "ldq_u", 1 },	/* 0B */
59 	{ OPC_RES, "opc0c", 0 },	/* 0C */
60 	{ OPC_RES, "opc0d", 0 },	/* 0D */
61 	{ OPC_RES, "opc0e", 0 },	/* 0E */
62 	{ OPC_MEM, "stq_u", 1 },	/* 0F */
63 	{ OPC_OP, "inta", 0 },		/* 10 */
64 	{ OPC_OP, "intl", 0 },		/* 11 */
65 	{ OPC_OP, "ints", 0 },		/* 12 */
66 	{ OPC_OP, "intm", 0 },		/* 13 */
67 	{ OPC_RES, "opc14", 0 },	/* 14 */
68 	{ OPC_OP, "fltv", 1 },		/* 15 */
69 	{ OPC_OP, "flti", 1 },		/* 16 */
70 	{ OPC_OP, "fltl", 1 },		/* 17 */
71 	{ OPC_MEM, "misc", 0 },		/* 18 */
72 	{ OPC_PAL, "pal19", 0 },	/* 19 */
73 	{ OPC_MEM, "jsr", 0 },		/* 1A */
74 	{ OPC_PAL, "pal1b", 0 },	/* 1B */
75 	{ OPC_RES, "opc1c", 0 },	/* 1C */
76 	{ OPC_PAL, "pal1d", 0 },	/* 1D */
77 	{ OPC_PAL, "pal1e", 0 },	/* 1E */
78 	{ OPC_PAL, "pal1f", 0 },	/* 1F */
79 	{ OPC_MEM, "ldf", 1 },		/* 20 */
80 	{ OPC_MEM, "ldg", 1 },		/* 21 */
81 	{ OPC_MEM, "lds", 1 },		/* 22 */
82 	{ OPC_MEM, "ldt", 1 },		/* 23 */
83 	{ OPC_MEM, "stf", 1 },		/* 24 */
84 	{ OPC_MEM, "stg", 1 },		/* 25 */
85 	{ OPC_MEM, "sts", 1 },		/* 26 */
86 	{ OPC_MEM, "stt", 1 },		/* 27 */
87 	{ OPC_MEM, "ldl", 1 },		/* 28 */
88 	{ OPC_MEM, "ldq", 1 },		/* 29 */
89 	{ OPC_MEM, "ldl_l", 1 },	/* 2A */
90 	{ OPC_MEM, "ldq_l", 1 },	/* 2B */
91 	{ OPC_MEM, "stl", 1 },		/* 2C */
92 	{ OPC_MEM, "stq", 1 },		/* 2D */
93 	{ OPC_MEM, "stl_c", 1 },	/* 2E */
94 	{ OPC_MEM, "stq_c", 1 },	/* 2F */
95 	{ OPC_BR, "br", 1 },		/* 30 */
96 	{ OPC_BR, "fbeq", 1 },		/* 31 */
97 	{ OPC_BR, "fblt", 1 },		/* 32 */
98 	{ OPC_BR, "fble", 1 },		/* 33 */
99 	{ OPC_BR, "bsr", 1 },		/* 34 */
100 	{ OPC_BR, "fbne", 1 },		/* 35 */
101 	{ OPC_BR, "fbge", 1 },		/* 36 */
102 	{ OPC_BR, "fbgt", 1 },		/* 37 */
103 	{ OPC_BR, "blbc", 1 },		/* 38 */
104 	{ OPC_BR, "beq", 1 },		/* 39 */
105 	{ OPC_BR, "blt", 1 },		/* 3A */
106 	{ OPC_BR, "ble", 1 },		/* 3B */
107 	{ OPC_BR, "blbs", 1 },		/* 3C */
108 	{ OPC_BR, "bne", 1 },		/* 3D */
109 	{ OPC_BR, "bge", 1 },		/* 3E */
110 	{ OPC_BR, "bgt", 1 },		/* 3F */
111 };
112 
113 static __inline int sext(u_int);
114 static __inline int rega(u_int);
115 static __inline int regb(u_int);
116 static __inline int regc(u_int);
117 static __inline int disp(u_int);
118 
119 static __inline int
120 sext(u_int x)
121 {
122 	return ((x & 0x8000) ? -(-x & 0xffff) : (x & 0xffff));
123 }
124 
125 static __inline int
126 rega(u_int x)
127 {
128 	return ((x >> 21) & 0x1f);
129 }
130 
131 static __inline int
132 regb(u_int x)
133 {
134 	return ((x >> 16) & 0x1f);
135 }
136 
137 static __inline int
138 regc(u_int x)
139 {
140 	return (x & 0x1f);
141 }
142 
143 static __inline int
144 disp(u_int x)
145 {
146 	return (sext(x & 0xffff));
147 }
148 
149 /*
150  * XXX There are a couple of problems with this code:
151  *
152  *	The argument list printout code is likely to get confused.
153  *
154  *	It relies on the conventions of gcc code generation.
155  *
156  *	It uses heuristics to calculate the framesize, and might get it wrong.
157  *
158  *	It doesn't yet use the framepointer if available.
159  *
160  *	The address argument can only be used for pointing at trapframes
161  *	since a frame pointer of its own serves no good on the alpha,
162  *	you need a pc value too.
163  *
164  *	The heuristics used for tracing through a trap relies on having
165  *	symbols available.
166  */
167 void
168 db_stack_trace_print(db_expr_t addr, int have_addr, db_expr_t count,
169     char *modif, int (*pr)(const char *, ...))
170 {
171 	u_long		*frame;
172 	int		i, framesize;
173 	vaddr_t		pc, ra;
174 	u_int		inst;
175 	const char	*name;
176 	db_expr_t	offset;
177 	db_regs_t	*regs;
178 	u_long		*slot[32];
179 
180 	bzero(slot, sizeof(slot));
181 	if (count == -1)
182 		count = 65535;
183 
184 	if (have_addr) {
185 		(*pr)("alpha trace requires a trap frame... giving up.\n");
186 		return;
187 	}
188 	regs = &ddb_regs;
189 trapframe:
190 	/* remember where various registers are stored */
191 	for (i = 0; i < 31; i++)
192 		slot[i] = &regs->tf_regs[0] +
193 		    ((u_long *)db_regs[i].valuep - &ddb_regs.tf_regs[0]);
194 	frame = (u_long *)regs->tf_regs[FRAME_SP];
195 	pc = (vaddr_t)regs->tf_regs[FRAME_PC];
196 	ra = (vaddr_t)regs->tf_regs[FRAME_RA];
197 
198 	while (count-- && pc >= (vaddr_t)KERNBASE && pc < (vaddr_t)&etext) {
199 		db_find_sym_and_offset(pc, &name, &offset);
200 
201 		if (name == NULL) {
202 			(*pr)("%lx(", pc);
203 			/* Limit the search for procedure start */
204 			offset = 65536;
205 		} else {
206 			(*pr)("%s(", name);
207 		}
208 
209 		framesize = 0;
210 		for (i = sizeof (int); i <= offset; i += sizeof (int)) {
211 			inst = *(u_int *)(pc - i);
212 
213 			/*
214 			 * If by chance we don't have any symbols we have to
215 			 * get out somehow anyway.  Check for the preceding
216 			 * procedure return in that case.
217 			 */
218 			if (name[0] == '?' && inst_return(inst))
219 				break;
220 
221 			/*
222 			 * Disassemble to get the needed info for the frame.
223 			 */
224 			if ((inst & 0xffff0000) == 0x23de0000)
225 				/* lda sp,n(sp) */
226 				framesize -= disp(inst) / sizeof (u_long);
227 			else if ((inst & 0xfc1f0000) == 0xb41e0000)
228 				/* stq X,n(sp) */
229 				slot[rega(inst)] =
230 				    frame + disp(inst) / sizeof (u_long);
231 			else if ((inst & 0xfc000fe0) == 0x44000400 &&
232 			    rega(inst) == regb(inst)) {
233 				/* bis X,X,Y (aka mov X,Y) */
234 				/* zero is hardwired */
235 				if (rega(inst) != 31)
236 					slot[rega(inst)] = slot[regc(inst)];
237 				slot[regc(inst)] = 0;
238 				/*
239 				 * XXX In here we might special case a frame
240 				 * pointer setup, i.e. mov sp, fp.
241 				 */
242 			} else if (db_inst_load(inst))
243 				/* clobbers a register */
244 				slot[rega(inst)] = 0;
245 			else if (opcode[inst >> 26].opc_fmt == OPC_OP)
246 				/* clobbers a register */
247 				slot[regc(inst)] = 0;
248 			/*
249 			 * XXX Recognize more reg clobbering instructions and
250 			 * set slot[reg] = 0 then too.
251 			 */
252 		}
253 
254 		/*
255 		 * Try to print the 6 quads that might hold the args.
256 		 * We print 6 of them even if there are fewer, cause we don't
257 		 * know the number.  Maybe we could skip the last ones
258 		 * that never got used.  If we cannot know the value, print
259 		 * a question mark.
260 		 */
261 		for (i = 0; i < 6; i++) {
262 			if (i > 0)
263 				(*pr)(", ");
264 			if (slot[16 + i])
265 				(*pr)("%lx", *slot[16 + i]);
266 			else
267 				(*pr)("?");
268 		}
269 
270 #if 0
271 		/*
272 		 * XXX This will go eventually when I trust the argument
273 		 * printout heuristics.
274 		 *
275 		 * Print the stack frame contents.
276 		 */
277 		(*pr)(") [%p: ", frame);
278 		if (framesize > 1) {
279 			for (i = 0; i < framesize - 1; i++)
280 				(*pr)("%lx, ", frame[i]);
281 			(*pr)("%lx", frame[i]);
282 		}
283 		(*pr)("] at ");
284 #else
285 		(*pr)(") at ");
286 #endif
287 		db_printsym(pc, DB_STGY_PROC, pr);
288 		(*pr)("\n");
289 
290 		/*
291 		 * If we are looking at a Xent* routine we are in a trap
292 		 * context.
293 		 */
294 		if (strncmp(name, "Xent", sizeof("Xent") - 1) == 0) {
295 			regs = (db_regs_t *)frame;
296 			goto trapframe;
297 		}
298 
299 		/* Look for the return address if recorded.  */
300 		if (slot[26])
301 			ra = *(vaddr_t *)slot[26];
302 		else
303 			break;
304 
305 		/* Advance to the next frame, if any.  */
306 		frame += framesize;
307 		if (ra == pc)
308 			break;
309 		pc = ra;
310 	}
311 }
312