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