Annotation of sys/arch/m68k/m68k/db_trace.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: db_trace.c,v 1.17 2002/05/18 09:49:17 art Exp $ */
2: /* $NetBSD: db_trace.c,v 1.20 1997/02/05 05:10:25 scottr Exp $ */
3:
4: /*
5: * Mach Operating System
6: * Copyright (c) 1992 Carnegie Mellon University
7: * All Rights Reserved.
8: *
9: * Permission to use, copy, modify and distribute this software and its
10: * documentation is hereby granted, provided that both the copyright
11: * notice and this permission notice appear in all copies of the
12: * software, derivative works or modified versions, and any portions
13: * thereof, and that both notices appear in supporting documentation.
14: *
15: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
16: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
17: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
18: *
19: * Carnegie Mellon requests users of this software to return to
20: *
21: * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
22: * School of Computer Science
23: * Carnegie Mellon University
24: * Pittsburgh PA 15213-3890
25: *
26: * any improvements or extensions that they make and grant Carnegie Mellon
27: * the rights to redistribute these changes.
28: */
29:
30: #include <sys/param.h>
31: #include <sys/proc.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_variables.h>
41:
42: extern label_t *db_recover;
43:
44: /*
45: * Register list
46: */
47: static int db_var_short(struct db_variable *, db_expr_t *, int);
48:
49: struct db_variable db_regs[] = {
50: /* D0-D7 */
51: { "d0", (long *)&ddb_regs.tf_regs[0], FCN_NULL },
52: { "d1", (long *)&ddb_regs.tf_regs[1], FCN_NULL },
53: { "d2", (long *)&ddb_regs.tf_regs[2], FCN_NULL },
54: { "d3", (long *)&ddb_regs.tf_regs[3], FCN_NULL },
55: { "d4", (long *)&ddb_regs.tf_regs[4], FCN_NULL },
56: { "d5", (long *)&ddb_regs.tf_regs[5], FCN_NULL },
57: { "d6", (long *)&ddb_regs.tf_regs[6], FCN_NULL },
58: { "d7", (long *)&ddb_regs.tf_regs[7], FCN_NULL },
59: /* A0-A7 */
60: { "a0", (long *)&ddb_regs.tf_regs[8+0], FCN_NULL },
61: { "a1", (long *)&ddb_regs.tf_regs[8+1], FCN_NULL },
62: { "a2", (long *)&ddb_regs.tf_regs[8+2], FCN_NULL },
63: { "a3", (long *)&ddb_regs.tf_regs[8+3], FCN_NULL },
64: { "a4", (long *)&ddb_regs.tf_regs[8+4], FCN_NULL },
65: { "a5", (long *)&ddb_regs.tf_regs[8+5], FCN_NULL },
66: { "a6", (long *)&ddb_regs.tf_regs[8+6], FCN_NULL },
67: { "sp", (long *)&ddb_regs.tf_regs[8+7], FCN_NULL },
68: /* misc. */
69: { "pc", (long *)&ddb_regs.tf_pc, FCN_NULL },
70: { "sr", (long *)&ddb_regs.tf_sr, db_var_short }
71: };
72: struct db_variable *db_eregs = db_regs + sizeof(db_regs)/sizeof(db_regs[0]);
73:
74: static int
75: db_var_short(varp, valp, op)
76: struct db_variable *varp;
77: db_expr_t *valp;
78: int op;
79: {
80: if (op == DB_VAR_GET)
81: *valp = (db_expr_t) *((short *)varp->valuep);
82: else
83: *((short *)varp->valuep) = (short) *valp;
84: return(0);
85: }
86:
87: #define MAXINT 0x7fffffff
88:
89: #if 0
90: #define INKERNEL(va) (((vaddr_t)(va)) >= VM_MIN_KERNEL_ADDRESS && \
91: (((vaddr_t)(va)) < (USRSTACK - MAXSSIZ) || \
92: ((vaddr_t)(va)) >= USRSTACK))
93: #else
94: /* XXX - Slight hack... */
95: extern int curpcb;
96: #define INKERNEL(va) (((int)(va) > curpcb) && \
97: ((int)(va) < (curpcb + USPACE)))
98: #endif
99:
100: #define get(addr, space) \
101: (db_get_value((db_addr_t)(addr), sizeof(int), FALSE))
102: #define get16(addr, space) \
103: (db_get_value((db_addr_t)(addr), sizeof(u_short), FALSE))
104:
105: #define NREGISTERS 16
106:
107: struct stackpos {
108: int k_pc;
109: int k_fp;
110: int k_nargs;
111: int k_entry;
112: int k_caller;
113: int k_flags;
114: int k_regloc[NREGISTERS];
115: };
116:
117: static void findentry(struct stackpos *);
118: static void findregs(struct stackpos *, db_addr_t);
119: static int nextframe(struct stackpos *, int);
120: static void stacktop(db_regs_t *, struct stackpos *);
121:
122:
123: #define FR_SAVFP 0
124: #define FR_SAVPC 4
125: #define K_CALLTRAMP 1 /* for k_flags: caller is __sigtramp */
126: #define K_SIGTRAMP 2 /* for k_flags: this is __sigtramp */
127:
128: static void
129: stacktop(regs, sp)
130: db_regs_t *regs;
131: struct stackpos *sp;
132: {
133: int i;
134:
135: /* Note: leave out a6, a7 */
136: for (i = 0; i < (8+6); i++) {
137: sp->k_regloc[i] = (int) ®s->tf_regs[i];
138: }
139:
140: sp->k_fp = get(®s->tf_regs[8+6], 0);
141: /* skip sp (a7) */
142: sp->k_pc = get(®s->tf_pc, 0);
143: sp->k_flags = 0;
144:
145: findentry(sp);
146: }
147:
148:
149: /*
150: * The VAX has a very nice calling convention, and it is quite easy to
151: * find saved registers, and the number of parameters. We are not nearly
152: * so lucky. We must grub around in code for much of this information
153: * (remember the PDP-11?), and the saved register list seems to be
154: * especially hard to find.
155: */
156:
157: #define HIWORD 0xffff0000
158: #define LOWORD 0x0000ffff
159: #define LINKLA6 0x480e0000 /* linkl a6,#x */
160: #define LINKWA6 0x4e560000 /* linkw a6,#x */
161: #define ADDLSP 0xdffc0000 /* addl #x,sp */
162: #define ADDWSP 0xdefc0000 /* addw #x,sp */
163: #define LEASP 0x4fef0000 /* lea sp@(x),sp*/
164: #define TSTBSP 0x4a2f0000 /* tstb sp@(x) */
165: #define INSMSK 0xfff80000
166: #define MOVLSP 0x2e800000 /* movl dx,sp@ */
167: #define MOVLD0 0x20000000 /* movl d0,dx */
168: #define MOVLA0 0x20400000 /* movl d0,ax */
169: #define MVLMSK 0xf1ff0000
170: #define MOVEML 0x48d70000 /* moveml #x,sp@ */
171: #define JSR 0x4eb80000 /* jsr x.[WL] */
172: #define JSRPC 0x4eba0000 /* jsr PC@( ) */
173: #define LONGBIT 0x00010000
174: #define BSR 0x61000000 /* bsr x */
175: #define BSRL 0x61ff0000 /* bsrl x */
176: #define BYTE3 0x0000ff00
177: #define LOBYTE 0x000000ff
178: #define ADQMSK 0xf1ff0000
179: #define ADDQSP 0x508f0000 /* addql #x,sp */
180: #define ADDQWSP 0x504f0000 /* addqw #x,sp */
181:
182: struct nlist * trampsym = 0;
183: struct nlist * funcsym = 0;
184:
185: static int
186: nextframe(sp, kerneltrace)
187: struct stackpos *sp;
188: int kerneltrace;
189: {
190: int i;
191: db_addr_t addr;
192: db_addr_t calladdr;
193: db_addr_t oldfp = sp->k_fp;
194:
195: /*
196: * Find our entry point. Then find out
197: * which registers we saved, and map them.
198: * Our entry point is the address our caller called.
199: */
200:
201: calladdr = sp->k_caller;
202: addr = sp->k_entry;
203: if (sp->k_flags & K_CALLTRAMP) {
204: #if 0
205: /* we never set CALLTRAMP */
206: /*
207: * Caller was sigtramp. Therefore:
208: * - no registers were saved;
209: * - no new frame-pointer
210: * - caller found in sigcontext structure.
211: * - WE become sigtramp
212: * - we have no parameters
213: * MUCH MAGIC USED IN FINDING CALLER'S PC.
214: */
215: sp->k_pc = sp->k_caller;
216: sp->k_entry = trampsym->n_value;
217: sp->k_flags = 0;
218: addr = get(sp->k_fp + sizeof(int) * 11, DSP);
219: sp->k_nargs = 0;
220: #if DEBUG
221: db_printf("nextframe: sigcontext at 0x%x, signaled at 0x%x\n",
222: addr, sp->k_caller);
223: #endif
224: errflg = 0;
225: #endif /* 0 */
226: } else {
227: if (addr == MAXINT) {
228: /* we don't know what registers are involved here--
229: invalidate all */
230: for (i = 0; i < NREGISTERS; i++)
231: sp->k_regloc[i] = -1;
232: } else
233: findregs(sp, addr);
234:
235: /* find caller's pc and fp */
236: sp->k_pc = calladdr;
237: sp->k_fp = get(sp->k_fp + FR_SAVFP, DSP);
238:
239: /*
240: * Now that we have assumed the identity of our caller, find
241: * how many longwords of argument WE were called with.
242: */
243: sp->k_flags = 0;
244:
245: /*
246: * Don't dig around in user stack to find no. of args and
247: * entry point if just tracing the kernel
248: */
249: if (kerneltrace && !INKERNEL(sp->k_fp)) {
250: sp->k_nargs = 0;
251: sp->k_entry = MAXINT;
252: } else
253: findentry(sp);
254: }
255:
256: if (sp->k_fp == 0 || oldfp == sp->k_fp)
257: return 0;
258: return (sp->k_fp);
259: }
260:
261: static void
262: findentry(sp)
263: struct stackpos *sp;
264: {
265: /*
266: * Set the k_nargs and k_entry fields in the stackpos structure. This
267: * is called from stacktop() and from nextframe(). Our caller will do
268: * an addq or addl or addw to sp just after we return to pop off our
269: * arguments. Find that instruction and extract the value.
270: */
271: int instruc;
272: int val;
273: db_addr_t addr, nextword;
274: label_t db_jmpbuf;
275: label_t *savejmp;
276:
277: savejmp = db_recover;
278: db_recover = &db_jmpbuf;
279: if (setjmp(&db_jmpbuf)) {
280: /* oops -- we touched something we ought not to have */
281: /* cannot trace caller of "start" */
282: sp->k_entry = MAXINT;
283: sp->k_nargs = 0;
284: db_recover = savejmp;
285: return;
286: }
287:
288: addr = get(sp->k_fp + FR_SAVPC, DSP);
289: if (addr == 0) {
290: /* oops -- we touched something we ought not to have */
291: /* cannot trace caller of "start" */
292: sp->k_entry = MAXINT;
293: sp->k_nargs = 0;
294: db_recover = savejmp;
295: return;
296: }
297: instruc = get(addr - 6, ISP);
298: nextword = get(addr - 4, ISP);
299:
300: db_recover = savejmp;
301:
302: if ((instruc & HIWORD) == (JSR | LONGBIT)) {
303: /* longword offset here */
304: sp->k_caller = addr - 6;
305: sp->k_entry = nextword;
306: } else if ((instruc & HIWORD) == BSRL) {
307: /* longword self-relative offset */
308: sp->k_caller = addr - 6;
309: sp->k_entry = nextword + (addr - 4);
310: } else {
311: instruc = nextword;
312: if ((instruc & HIWORD) == JSR) {
313: /* short word offset */
314: sp->k_caller = addr - 4;
315: sp->k_entry = instruc & LOWORD;
316: } else if ((instruc & HIWORD) == BSR) {
317: /* short word, self-relative offset */
318: sp->k_caller = addr - 4;
319: sp->k_entry = (addr - 2) + (short)(instruc & LOWORD);
320: } else if ((instruc & HIWORD) == JSRPC) {
321: /* PC-relative, short word offset */
322: sp->k_caller = addr - 4;
323: sp->k_entry = (addr - 2) + (instruc & LOWORD);
324: } else {
325: if ((instruc & BYTE3) == (BSR >> 16)) {
326: /* byte, self-relative offset */
327: sp->k_caller = addr - 2;
328: sp->k_entry = addr + (char)(instruc & LOBYTE);
329: } else {
330: /* was a call through a proc parameter */
331: sp->k_caller = addr - 2;
332: sp->k_entry = MAXINT;
333: /*
334: * We know that sigtramp calls your signal
335: * catcher this way -- see if this is the
336: * tramp: if so then:
337: * - set the K_CALLTRAMP flag, for use by
338: * nextframe();
339: * - take k_entry from __sigfunc array.
340: */
341: #if 0
342: /* not in kernel */
343: /*
344: * The number (9) in the below expression is
345: * magic: it is the number of stack items below
346: * callee`s fp and sigtramp`s copy of the
347: * signal number.
348: */
349: if (trampsym &&
350: (findsym(sp->k_caller, ISYM), cursym == trampsym)) {
351: int signl;
352: sp->k_flags |= K_CALLTRAMP;
353: if (funcsym) {
354: signl = get(sp->k_fp + sizeof(int) * 9, DSP);
355: sp->k_entry = get(funcsym->n_value+(sizeof(int(*)()))*signl, DSP);
356: } else
357: sp->k_entry = -1;
358:
359: errflg = 0;
360: #ifdef DEBUG
361: db_printf("Caller is sigtramp: signal is %d: entry is %x\n",
362: signl, sp->k_entry);
363: #endif
364: }
365: #ifdef DEBUG
366: else
367: db_printf("Non-tramp jsr a0@\n");
368: #endif
369: #endif /* 0 */
370: }
371: }
372: }
373: instruc = get(addr, ISP);
374: /* on bad days, the compiler dumps a register move here */
375: if ((instruc & MVLMSK) == MOVLA0 ||
376: (instruc & MVLMSK) == MOVLD0)
377: instruc = get(addr += 2, ISP);
378: if ((instruc & ADQMSK) == ADDQSP ||
379: (instruc & ADQMSK) == ADDQWSP) {
380: val = 0;
381: do {
382: int n;
383: n = (instruc >> (16+9)) & 07;
384: if (n == 0)
385: n = 8;
386: val += n;
387: instruc = get(addr += 2, ISP);
388: } while ((instruc & ADQMSK) == ADDQSP ||
389: (instruc & ADQMSK) == ADDQWSP);
390: } else if ((instruc & HIWORD) == ADDLSP)
391: val = get(addr + 2, ISP);
392: else if ((instruc & HIWORD) == ADDWSP ||
393: (instruc & HIWORD) == LEASP)
394: val = instruc & LOWORD;
395: else
396: val = 20;
397: sp->k_nargs = val / 4;
398: }
399:
400: /*
401: * Look at the procedure prolog of the current called procedure.
402: * Figure out which registers we saved, and where they are
403: */
404: static void
405: findregs(sp, addr)
406: struct stackpos *sp;
407: db_addr_t addr;
408: {
409: long instruc, val, i;
410: int regp;
411:
412: regp = 0;
413: instruc = get(addr, ISP);
414: if ((instruc & HIWORD) == LINKLA6) {
415: instruc = get(addr + 2, ISP);
416: addr += 6;
417: regp = sp->k_fp + instruc;
418: } else if ((instruc & HIWORD) == LINKWA6) {
419: addr += 4;
420: if ((instruc &= LOWORD) == 0) {
421: /* look for addl */
422: instruc = get(addr, ISP);
423: if ((instruc & HIWORD) == ADDLSP) {
424: instruc = get(addr + 2, ISP);
425: addr += 6;
426: }
427: /* else frame is really size 0 */
428: } else {
429: /* link offset was non-zero -- sign extend it */
430: instruc <<= 16;
431: instruc >>= 16;
432: }
433: /* we now have the negative frame size */
434: regp = sp->k_fp + instruc;
435: }
436:
437: /* find which registers were saved */
438: /* (expecting probe instruction next) */
439: instruc = get(addr, ISP);
440: if ((instruc & HIWORD) == TSTBSP)
441: addr += 4;
442:
443: /* now we expect either a moveml or a movl */
444: instruc = get(addr, ISP);
445: if ((instruc & INSMSK) == MOVLSP) {
446: /* only saving one register */
447: i = (instruc >> 16) & 07;
448: sp->k_regloc[i] = regp;
449: } else if ((instruc & HIWORD) == MOVEML) {
450: /* saving multiple registers or unoptimized code */
451: val = instruc & LOWORD;
452: i = 0;
453: while (val) {
454: if (val & 1) {
455: sp->k_regloc[i] = regp;
456: regp += sizeof(int);
457: }
458: val >>= 1;
459: i++;
460: }
461: }
462: /* else no registers saved */
463: }
464:
465: /*
466: * Frame tracing.
467: */
468: void
469: db_stack_trace_print(addr, have_addr, count, modif, pr)
470: db_expr_t addr;
471: int have_addr;
472: db_expr_t count;
473: char *modif;
474: int (*pr)(const char *, ...);
475: {
476: int i, nargs;
477: long val;
478: db_addr_t regp;
479: char * name;
480: struct stackpos pos;
481: boolean_t kernel_only = TRUE;
482: int fault_pc = 0;
483:
484: {
485: char *cp = modif;
486: char c;
487:
488: while ((c = *cp++) != 0)
489: if (c == 'u')
490: kernel_only = FALSE;
491: }
492:
493: if (count == -1)
494: count = 65535;
495:
496: if (!have_addr)
497: stacktop(&ddb_regs, &pos);
498: #if 0
499: else {
500:
501: /*
502: * Only have user register state.
503: */
504: pcb_t t_pcb;
505: db_regs_t *user_regs;
506:
507: t_pcb = (pcb_t) get(&th->pcb, 0);
508: user_regs = (db_regs_t *)
509: get(&t_pcb->user_regs, 0);
510:
511: stacktop(user_regs, &pos);
512:
513: /* foo*/
514: }
515: #endif
516: else {
517: pos.k_flags = 0;
518: pos.k_fp = addr;
519:
520: pos.k_nargs = 0;
521: pos.k_pc = MAXINT;
522: pos.k_entry = MAXINT;
523: /* sorry, we cannot find our registers without knowing our pc */
524: for (i = 0; i < NREGISTERS; i++)
525: pos.k_regloc[i] = 0;
526: findentry(&pos);
527: }
528:
529: while (count) {
530: count--;
531:
532: /* HACK */
533: if (pos.k_pc == MAXINT) {
534: name = "?";
535: pos.k_pc = 0;
536: } else {
537: db_find_sym_and_offset(pos.k_pc, &name, &val);
538: if (name == 0) {
539: val = MAXINT;
540: name = "?";
541: }
542: }
543:
544: /*
545: * Since faultstkadj doesn't set up a valid stack frame,
546: * we would assume it was the source of the fault. To
547: * get around this we peek at the fourth argument of
548: * "trap()" (the stack frame at the time of the fault)
549: * to determine the _real_ value of PC when things wen
550: * wrong.
551: *
552: * NOTE: If the argument list for 'trap()' ever changes,
553: * we lose.
554: */
555: if (strcmp("_trap", name) == 0) {
556: int tfp;
557:
558: /* Point to 'trap()'s 4th argument (frame structure) */
559: tfp = pos.k_fp + FR_SAVFP + 4 + (4 * 4);
560:
561: /* Determine if fault was from kernel or user mode */
562: regp = tfp + offsetof(struct frame, f_sr);
563: if (!USERMODE(get16(regp, DSP))) {
564: /*
565: * Definitely a kernel mode fault,
566: * so get the PC at the time of the fault.
567: */
568: regp = tfp + offsetof(struct frame, f_pc);
569: fault_pc = get(regp, DSP);
570: }
571: } else
572: if (fault_pc) {
573: if (strcmp("faultstkadj", name) == 0) {
574: db_find_sym_and_offset(fault_pc, &name, &val);
575: if (name == 0) {
576: val = MAXINT;
577: name = "?";
578: }
579: }
580: fault_pc = 0;
581: }
582:
583: (*pr)("%s", name);
584: if (pos.k_entry != MAXINT && name) {
585: char * entry_name;
586: long e_val;
587:
588: db_find_sym_and_offset(pos.k_entry, &entry_name,
589: &e_val);
590: if (entry_name != 0 && entry_name != name &&
591: e_val != val) {
592: (*pr)("(?)\n%s", entry_name);
593: }
594: }
595: (*pr)("(");
596: regp = pos.k_fp + FR_SAVFP + 4;
597: if ((nargs = pos.k_nargs)) {
598: while (nargs--) {
599: (*pr)("%lx", get(regp += 4, DSP));
600: if (nargs)
601: (*pr)(",");
602: }
603: }
604: if (val == MAXINT)
605: (*pr)(") at %x\n", pos.k_pc);
606: else
607: (*pr)(") + %lx\n", val);
608:
609: /*
610: * Stop tracing if frame ptr no longer points into kernel
611: * stack.
612: */
613: if (kernel_only && !INKERNEL(pos.k_fp))
614: break;
615: if (nextframe(&pos, kernel_only) == 0)
616: break;
617: }
618: }
619:
CVSweb