xref: /netbsd/sys/arch/m68k/m68k/db_trace.c (revision c4a72b64)
1 /*	$NetBSD: db_trace.c,v 1.37 2002/10/26 13:24:55 jdolecek Exp $	*/
2 
3 /*
4  * Mach Operating System
5  * Copyright (c) 1992 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 Mellon
26  * the rights to redistribute these changes.
27  */
28 
29 #include <sys/param.h>
30 #include <sys/proc.h>
31 #include <sys/user.h>
32 #include <sys/systm.h>
33 
34 #include <machine/db_machdep.h>
35 
36 #include <ddb/db_interface.h>
37 #include <ddb/db_output.h>
38 #include <ddb/db_access.h>
39 #include <ddb/db_sym.h>
40 #include <ddb/db_extern.h>
41 #include <ddb/db_variables.h>
42 
43 /*
44  * Register list
45  */
46 static int db_var_short __P((const struct db_variable *, db_expr_t *, int));
47 
48 const struct db_variable db_regs[] = {
49 	/* D0-D7 */
50 	{ "d0",	(long *)&ddb_regs.tf_regs[0],	FCN_NULL },
51 	{ "d1",	(long *)&ddb_regs.tf_regs[1],	FCN_NULL },
52 	{ "d2",	(long *)&ddb_regs.tf_regs[2],	FCN_NULL },
53 	{ "d3",	(long *)&ddb_regs.tf_regs[3],	FCN_NULL },
54 	{ "d4",	(long *)&ddb_regs.tf_regs[4],	FCN_NULL },
55 	{ "d5",	(long *)&ddb_regs.tf_regs[5],	FCN_NULL },
56 	{ "d6",	(long *)&ddb_regs.tf_regs[6],	FCN_NULL },
57 	{ "d7",	(long *)&ddb_regs.tf_regs[7],	FCN_NULL },
58 	/* A0-A7 */
59 	{ "a0",	(long *)&ddb_regs.tf_regs[8+0],	FCN_NULL },
60 	{ "a1",	(long *)&ddb_regs.tf_regs[8+1],	FCN_NULL },
61 	{ "a2",	(long *)&ddb_regs.tf_regs[8+2],	FCN_NULL },
62 	{ "a3",	(long *)&ddb_regs.tf_regs[8+3],	FCN_NULL },
63 	{ "a4",	(long *)&ddb_regs.tf_regs[8+4],	FCN_NULL },
64 	{ "a5",	(long *)&ddb_regs.tf_regs[8+5],	FCN_NULL },
65 	{ "a6",	(long *)&ddb_regs.tf_regs[8+6],	FCN_NULL },
66 	{ "sp",	(long *)&ddb_regs.tf_regs[8+7],	FCN_NULL },
67 	/* misc. */
68 	{ "pc",	(long *)&ddb_regs.tf_pc, 	FCN_NULL },
69 	{ "sr",	(long *)&ddb_regs.tf_sr,	db_var_short }
70 };
71 const struct db_variable * const db_eregs = db_regs + sizeof(db_regs)/sizeof(db_regs[0]);
72 
73 static int
74 db_var_short(varp, valp, op)
75     const struct db_variable *varp;
76     db_expr_t *valp;
77     int op;
78 {
79     if (op == DB_VAR_GET)
80 	*valp = (db_expr_t) *((short*)varp->valuep);
81     else
82 	*((short*)varp->valuep) = (short) *valp;
83     return(0);
84 }
85 
86 #define	MAXINT	0x7fffffff
87 
88 extern struct pcb *curpcb;
89 #define	INKERNEL(va,pcb)	(((u_int)(va) > (u_int)(pcb)) && \
90 				 ((u_int)(va) < ((u_int)(pcb) + USPACE)))
91 
92 #define	get(addr, space) \
93 		(db_get_value((db_addr_t)(addr), sizeof(int), FALSE))
94 #define	get16(addr, space) \
95 		(db_get_value((db_addr_t)(addr), sizeof(u_short), FALSE))
96 
97 #define	NREGISTERS	16
98 
99 struct stackpos {
100 	 int	k_pc;
101 	 int	k_fp;
102 	 int	k_nargs;
103 	 int	k_entry;
104 	 int	k_caller;
105 	 int	k_flags;
106 	 int	k_regloc[NREGISTERS];
107 };
108 
109 static void findentry __P((struct stackpos *, void (*)(const char *, ...)));
110 static void findregs __P((struct stackpos *, db_addr_t));
111 static int  nextframe __P((struct stackpos *, struct pcb *, int,
112     void (*)(const char *, ...)));
113 static void stacktop __P((db_regs_t *, struct stackpos *,
114     void (*)(const char *, ...)));
115 
116 
117 #define FR_SAVFP	0
118 #define FR_SAVPC	4
119 
120 static void
121 stacktop(regs, sp, pr)
122 	db_regs_t *regs;
123 	struct stackpos *sp;
124 	void (*pr) __P((const char *, ...));
125 {
126 	int i;
127 
128 	/* Note: leave out a6, a7 */
129 	for (i = 0; i < (8+6); i++) {
130 		sp->k_regloc[i] = (int) &regs->tf_regs[i];
131 	}
132 
133 	sp->k_fp = get(&regs->tf_regs[8+6], 0);
134 	/* skip sp (a7) */
135 	sp->k_pc = get(&regs->tf_pc, 0);
136 	sp->k_flags = 0;
137 
138 	findentry(sp, pr);
139 }
140 
141 
142 /*
143  * The VAX has a very nice calling convention, and it is quite easy to
144  * find saved registers, and the number of parameters. We are not nearly
145  * so lucky. We must grub around in code for much of this information
146  * (remember the PDP-11?), and the saved register list seems to be
147  * especially hard to find.
148  */
149 
150 #define HIWORD	0xffff0000
151 #define LOWORD	0x0000ffff
152 #define LINKLA6	0x480e0000	/* linkl a6,#x    */
153 #define LINKWA6	0x4e560000	/* linkw a6,#x    */
154 #define ADDLSP	0xdffc0000	/* addl #x,sp    */
155 #define ADDWSP	0xdefc0000	/* addw #x,sp    */
156 #define LEASP	0x4fef0000	/* lea	sp@(x),sp*/
157 #define TSTBSP	0x4a2f0000	/* tstb sp@(x)   */
158 #define INSMSK	0xfff80000
159 #define MOVLSP	0x2e800000	/* movl dx,sp@   */
160 #define MOVLD0	0x20000000	/* movl d0,dx	 */
161 #define MOVLA0	0x20400000	/* movl d0,ax	 */
162 #define MVLMSK	0xf1ff0000
163 #define MOVEML	0x48d70000	/* moveml #x,sp@ */
164 #define JSR	0x4eb80000	/* jsr x.[WL]    */
165 #define JSRPC	0x4eba0000	/* jsr PC@( )    */
166 #define LONGBIT 0x00010000
167 #define BSR	0x61000000	/* bsr x	 */
168 #define BSRL	0x61ff0000	/* bsrl x	 */
169 #define BYTE3	0x0000ff00
170 #define LOBYTE	0x000000ff
171 #define ADQMSK	0xf1ff0000
172 #define ADDQSP	0x508f0000	/* addql #x,sp   */
173 #define ADDQWSP	0x504f0000	/* addqw #x,sp   */
174 
175 struct nlist *	trampsym = 0;
176 struct nlist *	funcsym = 0;
177 
178 static int
179 nextframe(sp, pcb, kerneltrace, pr)
180 	struct stackpos *sp;
181 	struct pcb *pcb;
182 	int kerneltrace;
183 	void (*pr) __P((const char *, ...));
184 {
185 	int		i;
186 	db_addr_t	addr;
187 	db_addr_t	calladdr;
188 	db_addr_t	oldfp = sp->k_fp;
189 
190 	/*
191 	 * Find our entry point. Then find out
192 	 * which registers we saved, and map them.
193 	 * Our entry point is the address our caller called.
194 	 */
195 
196 	calladdr = sp->k_caller;
197 	addr     = sp->k_entry;
198 	if (addr == MAXINT) {
199 
200 		/*
201 		 * we don't know what registers are involved here,
202 		 * invalidate them all.
203 		 */
204 		for (i = 0; i < NREGISTERS; i++)
205 			sp->k_regloc[i] = -1;
206 	} else
207 		findregs(sp, addr);
208 
209 	/* find caller's pc and fp */
210 	sp->k_pc = calladdr;
211 	sp->k_fp = get(sp->k_fp + FR_SAVFP, DSP);
212 
213 	/*
214 	 * Now that we have assumed the identity of our caller, find
215 	 * how many longwords of argument WE were called with.
216 	 */
217 	sp->k_flags = 0;
218 
219 	/*
220 	 * Don't dig around in user stack to find no. of args and
221 	 * entry point if just tracing the kernel
222 	 */
223 	if (kerneltrace && !INKERNEL(sp->k_fp, pcb)) {
224 		sp->k_nargs = 0;
225 		sp->k_entry = MAXINT;
226 	} else
227 		findentry(sp, pr);
228 
229 	if (sp->k_fp == 0 || oldfp == sp->k_fp)
230 		return 0;
231 	return (sp->k_fp);
232 }
233 
234 static void
235 findentry(sp, pr)
236 	struct stackpos *sp;
237 	void (*pr) __P((const char *, ...));
238 {
239 	/*
240 	 * Set the k_nargs and k_entry fields in the stackpos structure.  This
241 	 * is called from stacktop() and from nextframe().  Our caller will do
242 	 * an addq or addl or addw to sp just after we return to pop off our
243 	 * arguments.  Find that instruction and extract the value.
244 	 */
245 	int		instruc;
246 	int		val;
247 	db_addr_t	addr, nextword;
248 	label_t		db_jmpbuf;
249 	label_t		*savejmp;
250 
251 	savejmp = db_recover;
252 	db_recover = &db_jmpbuf;
253 	if (setjmp(&db_jmpbuf)) {
254 		/* oops -- we touched something we ought not to have */
255 		/* cannot trace caller of "start" */
256 		sp->k_entry = MAXINT;
257 		sp->k_nargs = 0;
258 		db_recover = savejmp;
259 		return;
260 	}
261 
262 	addr = get(sp->k_fp + FR_SAVPC, DSP);
263 	if (addr == 0) {
264 		/* oops -- we touched something we ought not to have */
265 		/* cannot trace caller of "start" */
266 		sp->k_entry = MAXINT;
267 		sp->k_nargs = 0;
268 		db_recover = savejmp;
269 		return;
270 	}
271 	instruc  = get(addr - 6, ISP);
272 	nextword = get(addr - 4, ISP);
273 
274 	db_recover = savejmp;
275 
276 	if ((instruc & HIWORD) == (JSR | LONGBIT)) {
277 		/* longword offset here */
278 		sp->k_caller = addr - 6;
279 		sp->k_entry  = nextword;
280 	} else if ((instruc & HIWORD) == BSRL) {
281 		/* longword self-relative offset */
282 		sp->k_caller = addr - 6;
283 		sp->k_entry  = nextword + (addr - 4);
284 	} else {
285 		instruc = nextword;
286 		if ((instruc & HIWORD) == JSR) {
287 			/* short word offset */
288 			sp->k_caller = addr - 4;
289 			sp->k_entry  = instruc & LOWORD;
290 		} else if ((instruc & HIWORD) == BSR) {
291 			/* short word, self-relative offset */
292 			sp->k_caller = addr - 4;
293 			sp->k_entry  = (addr - 2) + (short)(instruc & LOWORD);
294 		} else if ((instruc & HIWORD) == JSRPC) {
295 			/* PC-relative, short word offset */
296 			sp->k_caller = addr - 4;
297 			sp->k_entry  = (addr - 2) + (instruc & LOWORD);
298 		} else {
299 			if ((instruc & BYTE3) == (BSR >> 16)) {
300 				/* byte, self-relative offset */
301 				sp->k_caller = addr - 2;
302 				sp->k_entry  = addr + (char)(instruc & LOBYTE);
303 			} else {
304 				/* was a call through a proc parameter */
305 				sp->k_caller = addr - 2;
306 				sp->k_entry  = MAXINT;
307 			}
308 		}
309 	}
310 	instruc = get(addr, ISP);
311 	/* on bad days, the compiler dumps a register move here */
312 	if ((instruc & MVLMSK) == MOVLA0 ||
313 	    (instruc & MVLMSK) == MOVLD0)
314 		instruc = get(addr += 2, ISP);
315 	if ((instruc & ADQMSK) == ADDQSP ||
316 	    (instruc & ADQMSK) == ADDQWSP) {
317 		val = 0;
318 		do {
319 			int n;
320 			n = (instruc >> (16+9)) & 07;
321 			if (n == 0)
322 				n = 8;
323 			val += n;
324 			instruc = get(addr += 2, ISP);
325 		} while ((instruc & ADQMSK) == ADDQSP ||
326 			 (instruc & ADQMSK) == ADDQWSP);
327 	} else if ((instruc & HIWORD) == ADDLSP)
328 		val = get(addr + 2, ISP);
329 	else if ((instruc & HIWORD) == ADDWSP ||
330 		 (instruc & HIWORD) == LEASP)
331 		val = instruc & LOWORD;
332 	else
333 		val = 20;
334 	sp->k_nargs = val / 4;
335 }
336 
337 /*
338  * Look at the procedure prolog of the current called procedure.
339  * Figure out which registers we saved, and where they are
340  */
341 static void
342 findregs(sp, addr)
343 	struct stackpos *sp;
344 	db_addr_t addr;
345 {
346 	long instruc, val, i;
347 	int  regp;
348 
349 	regp = 0;
350 	instruc = get(addr, ISP);
351 	if ((instruc & HIWORD) == LINKLA6) {
352 		instruc = get(addr + 2, ISP);
353 		addr += 6;
354 		regp = sp->k_fp + instruc;
355 	} else if ((instruc & HIWORD) == LINKWA6) {
356 		addr += 4;
357 		if ((instruc &= LOWORD) == 0) {
358 			/* look for addl */
359 			instruc = get(addr, ISP);
360 			if ((instruc & HIWORD) == ADDLSP) {
361 				instruc = get(addr + 2, ISP);
362 				addr += 6;
363 			}
364 			/* else frame is really size 0 */
365 		} else {
366 			/* link offset was non-zero -- sign extend it */
367 			instruc <<= 16;
368 			instruc >>= 16;
369 		}
370 		/* we now have the negative frame size */
371 		regp = sp->k_fp + instruc;
372 	}
373 
374 	/* find which registers were saved */
375 	/* (expecting probe instruction next) */
376 	instruc = get(addr, ISP);
377 	if ((instruc & HIWORD) == TSTBSP)
378 		addr += 4;
379 
380 	/* now we expect either a moveml or a movl */
381 	instruc = get(addr, ISP);
382 	if ((instruc & INSMSK) == MOVLSP) {
383 		/* only saving one register */
384 		i = (instruc >> 16) & 07;
385 		sp->k_regloc[i] = regp;
386 	} else if ((instruc & HIWORD) == MOVEML) {
387 		/* saving multiple registers or unoptimized code */
388 		val = instruc & LOWORD;
389 		i = 0;
390 		while (val) {
391 			if (val & 1) {
392 				sp->k_regloc[i] = regp;
393 				regp += sizeof(int);
394 			}
395 			val >>= 1;
396 			i++;
397 		}
398 	}
399 	/* else no registers saved */
400 }
401 
402 /*
403  *	Frame tracing.
404  */
405 void
406 db_stack_trace_print(addr, have_addr, count, modif, pr)
407 	db_expr_t	addr;
408 	int		have_addr;
409 	db_expr_t	count;
410 	char		*modif;
411 	void		(*pr) __P((const char *, ...));
412 {
413 	int i, nargs;
414 	long val;
415 	db_addr_t	regp;
416 	char *		name;
417 	struct stackpos pos;
418 	struct pcb	*pcb = curpcb;
419 	boolean_t	kernel_only = TRUE;
420 	boolean_t	trace_thread = FALSE;
421 	int		fault_pc = 0;
422 
423 	{
424 		char *cp = modif;
425 		char c;
426 
427 		while ((c = *cp++) != 0)
428 			if (c == 't')
429 				trace_thread = TRUE;
430 			else
431 			if (c == 'u')
432 				kernel_only = FALSE;
433 	}
434 
435 	if (!have_addr)
436 		stacktop(&ddb_regs, &pos, pr);
437 	else {
438 		if (trace_thread) {
439 			struct proc *p;
440 			struct user *u;
441 			(*pr)("trace: pid %d ", (int)addr);
442 			p = pfind(addr);
443 			if (p == NULL) {
444 				(*pr)("not found\n");
445 				return;
446 			}
447 			if (!(p->p_flag & P_INMEM)) {
448 				(*pr)("swapped out\n");
449 				return;
450 			}
451 			u = p->p_addr;
452 			pos.k_fp = u->u_pcb.pcb_regs[PCB_REGS_FP];
453 			/*
454 			 * Note: The following only works because cpu_switch()
455 			 * doesn't push anything on the stack before it saves
456 			 * the process' context in the pcb.
457 			 */
458 			pos.k_pc = get(u->u_pcb.pcb_regs[PCB_REGS_SP], DSP);
459 			(*pr)("at %p\n", (void *)pos.k_fp);
460 			pcb = &u->u_pcb;
461 		} else {
462 			pos.k_fp = addr;
463 			pos.k_pc = MAXINT;
464 		}
465 
466 		pos.k_flags = 0;
467 		pos.k_nargs = 0;
468 		pos.k_entry = MAXINT;
469 
470 		for (i = 0; i < NREGISTERS; i++)
471 			pos.k_regloc[i] = 0;
472 
473 		findentry(&pos, pr);
474 	}
475 
476 	while (count) {
477 		count--;
478 
479 		/* HACK */
480 		if (pos.k_pc == MAXINT) {
481 			name = "?";
482 			pos.k_pc = 0;
483 			val = MAXINT;
484 		} else {
485 			db_find_sym_and_offset(pos.k_pc, &name, &val);
486 			if (name == 0) {
487 				name = "?";
488 				val = MAXINT;
489 			}
490 		}
491 
492 		/*
493 		 * Since faultstkadj doesn't set up a valid stack frame,
494 		 * we would assume it was the source of the fault. To
495 		 * get around this we peek at the fourth argument of
496 		 * "trap()" (the stack frame at the time of the fault)
497 		 * to determine the _real_ value of PC when things wen
498 		 * wrong.
499 		 *
500 		 * NOTE: If the argument list for 'trap()' ever changes,
501 		 * we lose.
502 		 */
503 		if (strcmp(___STRING(_C_LABEL(trap)), name) == 0) {
504 			int tfp;
505 
506 			/* Point to 'trap()'s 4th argument (frame structure) */
507 			tfp = pos.k_fp + FR_SAVFP + 4 + (4 * 4);
508 
509 			/* Determine if fault was from kernel or user mode */
510 			regp = tfp + offsetof(struct frame, f_sr);
511 			if (!USERMODE(get16(regp, DSP))) {
512 
513 				/*
514 				 * Definitely a kernel mode fault,
515 				 * so get the PC at the time of the fault.
516 				 */
517 				regp = tfp + offsetof(struct frame, f_pc);
518 				fault_pc = get(regp, DSP);
519 			}
520 		} else if (fault_pc) {
521 			if (strcmp("faultstkadj", name) == 0) {
522 				db_find_sym_and_offset(fault_pc, &name, &val);
523 				if (name == 0) {
524 					name = "?";
525 					val = MAXINT;
526 				}
527 			}
528 			fault_pc = 0;
529 		}
530 
531 		(*pr)("%s", name);
532 		if (pos.k_entry != MAXINT && name) {
533 			char *	entry_name;
534 			long	e_val;
535 
536 			db_find_sym_and_offset(pos.k_entry, &entry_name,
537 			    &e_val);
538 			if (entry_name != 0 && entry_name != name &&
539 			    e_val != val) {
540 				(*pr)("(?)\n%s", entry_name);
541 			}
542 		}
543 		(*pr)("(");
544 		regp = pos.k_fp + FR_SAVFP + 4;
545 		if ((nargs = pos.k_nargs)) {
546 			while (nargs--) {
547 				(*pr)("%lx", get(regp += 4, DSP));
548 				if (nargs)
549 					(*pr)(",");
550 			}
551 		}
552 		if (val == MAXINT)
553 			(*pr)(") at %x\n", pos.k_pc);
554 		else
555 			(*pr)(") + %lx\n", val);
556 
557 		/*
558 		 * Stop tracing if frame ptr no longer points into kernel
559 		 * stack.
560 		 */
561 		if (kernel_only && !INKERNEL(pos.k_fp, pcb))
562 			break;
563 		if (nextframe(&pos, pcb, kernel_only, pr) == 0)
564 			break;
565 	}
566 }
567 
568