Annotation of sys/arch/mips64/mips64/db_machdep.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: db_machdep.c,v 1.11 2007/05/03 19:34:00 miod Exp $ */
2:
3: /*
4: * Copyright (c) 1998-2003 Opsycon AB (www.opsycon.se)
5: *
6: * Redistribution and use in source and binary forms, with or without
7: * modification, are permitted provided that the following conditions
8: * are met:
9: * 1. Redistributions of source code must retain the above copyright
10: * notice, this list of conditions and the following disclaimer.
11: * 2. Redistributions in binary form must reproduce the above copyright
12: * notice, this list of conditions and the following disclaimer in the
13: * documentation and/or other materials provided with the distribution.
14: *
15: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
16: * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
19: * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25: * SUCH DAMAGE.
26: *
27: */
28:
29: #include <sys/param.h>
30: #include <sys/systm.h>
31: #include <sys/proc.h>
32: #include <dev/cons.h>
33:
34: #include <machine/autoconf.h>
35: #include <machine/db_machdep.h>
36: #include <machine/cpu.h>
37: #include <machine/mips_opcode.h>
38: #include <machine/pte.h>
39: #include <machine/frame.h>
40: #include <machine/regnum.h>
41:
42: #include <ddb/db_sym.h>
43: #include <ddb/db_extern.h>
44: #include <ddb/db_access.h>
45: #include <ddb/db_command.h>
46: #include <ddb/db_output.h>
47: #include <ddb/db_variables.h>
48: #include <ddb/db_interface.h>
49:
50: #define MIPS_JR_RA 0x03e00008 /* instruction code for jr ra */
51:
52: extern void trapDump(char *);
53: u_long MipsEmulateBranch(db_regs_t *, int, int, u_int);
54: void stacktrace_subr(db_regs_t *, int (*)(const char*, ...));
55:
56: int kdbpeek(void *);
57: int64_t kdbpeekd(void *);
58: short kdbpeekw(void *);
59: char kdbpeekb(void *);
60: void kdbpoke(vaddr_t, int);
61: void kdbpoked(vaddr_t, int64_t);
62: void kdbpokew(vaddr_t, short);
63: void kdbpokeb(vaddr_t, char);
64: int kdb_trap(int, struct trap_frame *);
65:
66: void db_trap_trace_cmd(db_expr_t, int, db_expr_t, char *);
67: void db_dump_tlb_cmd(db_expr_t, int, db_expr_t, char *);
68:
69: int db_active = 0;
70: db_regs_t ddb_regs;
71:
72: struct db_variable db_regs[] = {
73: { "at", (long *)&ddb_regs.ast, FCN_NULL },
74: { "v0", (long *)&ddb_regs.v0, FCN_NULL },
75: { "v1", (long *)&ddb_regs.v1, FCN_NULL },
76: { "a0", (long *)&ddb_regs.a0, FCN_NULL },
77: { "a1", (long *)&ddb_regs.a1, FCN_NULL },
78: { "a2", (long *)&ddb_regs.a2, FCN_NULL },
79: { "a3", (long *)&ddb_regs.a3, FCN_NULL },
80: { "a4", (long *)&ddb_regs.t0, FCN_NULL },
81: { "a5", (long *)&ddb_regs.t1, FCN_NULL },
82: { "a6", (long *)&ddb_regs.t2, FCN_NULL },
83: { "a7", (long *)&ddb_regs.t3, FCN_NULL },
84: { "t0", (long *)&ddb_regs.t4, FCN_NULL },
85: { "t1", (long *)&ddb_regs.t5, FCN_NULL },
86: { "t2", (long *)&ddb_regs.t6, FCN_NULL },
87: { "t3", (long *)&ddb_regs.t7, FCN_NULL },
88: { "s0", (long *)&ddb_regs.s0, FCN_NULL },
89: { "s1", (long *)&ddb_regs.s1, FCN_NULL },
90: { "s2", (long *)&ddb_regs.s2, FCN_NULL },
91: { "s3", (long *)&ddb_regs.s3, FCN_NULL },
92: { "s4", (long *)&ddb_regs.s4, FCN_NULL },
93: { "s5", (long *)&ddb_regs.s5, FCN_NULL },
94: { "s6", (long *)&ddb_regs.s6, FCN_NULL },
95: { "s7", (long *)&ddb_regs.s7, FCN_NULL },
96: { "t8", (long *)&ddb_regs.t8, FCN_NULL },
97: { "t9", (long *)&ddb_regs.t9, FCN_NULL },
98: { "k0", (long *)&ddb_regs.k0, FCN_NULL },
99: { "k1", (long *)&ddb_regs.k1, FCN_NULL },
100: { "gp", (long *)&ddb_regs.gp, FCN_NULL },
101: { "sp", (long *)&ddb_regs.sp, FCN_NULL },
102: { "s8", (long *)&ddb_regs.s8, FCN_NULL },
103: { "ra", (long *)&ddb_regs.ra, FCN_NULL },
104: { "sr", (long *)&ddb_regs.sr, FCN_NULL },
105: { "lo", (long *)&ddb_regs.mullo, FCN_NULL },
106: { "hi", (long *)&ddb_regs.mulhi, FCN_NULL },
107: { "bad", (long *)&ddb_regs.badvaddr,FCN_NULL },
108: { "cs", (long *)&ddb_regs.cause, FCN_NULL },
109: { "pc", (long *)&ddb_regs.pc, FCN_NULL },
110: };
111: struct db_variable *db_eregs = db_regs + sizeof(db_regs)/sizeof(db_regs[0]);
112:
113: extern label_t *db_recover;
114:
115: int
116: kdb_trap(type, fp)
117: int type;
118: struct trap_frame *fp;
119: {
120: switch(type) {
121: case T_BREAK: /* breakpoint */
122: if (db_get_value((fp)->pc, sizeof(int), FALSE) == BREAK_SOVER) {
123: (fp)->pc += BKPT_SIZE;
124: }
125: break;
126: case -1:
127: break;
128: default:
129: #if 0
130: if (!db_panic)
131: return (0);
132: #endif
133: if (db_recover != 0) {
134: db_error("Caught exception in ddb.\n");
135: /*NOTREACHED*/
136: }
137: printf("stoped on non ddb fault\n");
138: }
139:
140: bcopy((void *)fp, (void *)&ddb_regs, NUMSAVEREGS * sizeof(register_t));
141:
142: db_active++;
143: cnpollc(TRUE);
144: db_trap(type, 0);
145: cnpollc(FALSE);
146: db_active--;
147:
148: bcopy((void *)&ddb_regs, (void *)fp, NUMSAVEREGS * sizeof(register_t));
149: return(TRUE);
150: }
151: void
152: db_read_bytes(addr, size, data)
153: vaddr_t addr;
154: size_t size;
155: char *data;
156: {
157: while(size >= sizeof(int)) {
158: *((int *)data)++ = kdbpeek((void *)addr);
159: addr += sizeof(int);
160: size -= sizeof(int);
161: }
162:
163: if (size > sizeof(short)) {
164: *((short *)data)++ = kdbpeekw((void *)addr);
165: addr += sizeof(short);
166: size -= sizeof(short);
167: }
168:
169: if (size) {
170: *data++ = kdbpeekb((void *)addr);
171: }
172: }
173:
174: void
175: db_write_bytes(addr, size, data)
176: vaddr_t addr;
177: size_t size;
178: char *data;
179: {
180: vaddr_t ptr = addr;
181: size_t len = size;
182:
183: while (len >= sizeof(int)) {
184: kdbpoke(ptr, *((int *)data)++);
185: ptr += sizeof(int);
186: len -= sizeof(int);
187: }
188:
189: if (len >= sizeof(short)) {
190: kdbpokew(ptr, *((short *)data)++);
191: ptr += sizeof(int);
192: len -= sizeof(int);
193: }
194:
195: if (len) {
196: kdbpokeb(ptr, *data++);
197: }
198: if (addr < VM_MIN_KERNEL_ADDRESS) {
199: Mips_HitSyncDCache(addr, size);
200: Mips_InvalidateICache(PHYS_TO_KSEG0(addr & 0xffff), size);
201: }
202: }
203:
204: void
205: db_stack_trace_print(addr, have_addr, count, modif, pr)
206: db_expr_t addr;
207: boolean_t have_addr;
208: db_expr_t count;
209: char *modif;
210: int (*pr)(const char *, ...);
211: {
212: db_sym_t sym;
213: db_expr_t diff;
214: db_addr_t subr;
215: char *symname;
216: register_t pc, sp, ra, va;
217: register_t a0, a1, a2, a3;
218: unsigned instr, mask;
219: InstFmt i;
220: int more, stksize;
221: extern char edata[];
222: extern char k_intr[];
223: extern char k_general[];
224: extern char idle[];
225: struct trap_frame *regs = &ddb_regs;
226:
227: /* get initial values from the exception frame */
228: sp = regs->sp;
229: pc = regs->pc;
230: ra = regs->ra; /* May be a 'leaf' function */
231: a0 = regs->a0;
232: a1 = regs->a1;
233: a2 = regs->a2;
234: a3 = regs->a3;
235:
236: /* Jump here when done with a frame, to start a new one */
237: loop:
238:
239: /* Jump here after a nonstandard (interrupt handler) frame */
240: stksize = 0;
241:
242: /* check for bad SP: could foul up next frame */
243: if (sp & 3 || (!IS_XKPHYS((vaddr_t)sp) && sp < KSEG0_BASE)) {
244: (*pr)("SP %p: not in kernel\n", sp);
245: ra = 0;
246: subr = 0;
247: goto done;
248: }
249:
250: #if 0
251: /* Backtraces should contine through interrupts from kernel mode */
252: if (pc >= (unsigned)MipsKernIntr && pc < (unsigned)MipsUserIntr) {
253: (*pr)("MipsKernIntr+%x: (%x, %x ,%x) -------\n",
254: pc-(unsigned)MipsKernIntr, a0, a1, a2);
255: regs = (struct trap_frame *)(sp + STAND_ARG_SIZE);
256: a0 = kdbpeek(®s->a0);
257: a1 = kdbpeek(®s->a1);
258: a2 = kdbpeek(®s->a2);
259: a3 = kdbpeek(®s->a3);
260:
261: pc = kdbpeek(®s->pc); /* exc_pc - pc at time of exception */
262: ra = kdbpeek(®s->ra); /* ra at time of exception */
263: sp = kdbpeek(®s->sp);
264: goto specialframe;
265: }
266: #endif
267:
268:
269: /* check for bad PC */
270: if (pc & 3 || pc < KSEG0_BASE || pc >= (unsigned)edata) {
271: (*pr)("PC %p: not in kernel\n", pc);
272: ra = 0;
273: goto done;
274: }
275:
276: /*
277: * Dig out the function from the symbol table.
278: * Watch out for function tail optimizations.
279: */
280: sym = db_search_symbol(pc, DB_STGY_ANY, &diff);
281: if (sym != DB_SYM_NULL && diff == 0)
282: sym = db_search_symbol(pc - 4, DB_STGY_ANY, &diff);
283: db_symbol_values(sym, &symname, 0);
284: if (sym != DB_SYM_NULL) {
285: subr = pc - diff;
286: } else {
287: subr = 0;
288: }
289:
290: /*
291: * Find the beginning of the current subroutine by scanning backwards
292: * from the current PC for the end of the previous subroutine.
293: */
294: if (!subr) {
295: va = pc - sizeof(int);
296: while ((instr = kdbpeek((int *)va)) != MIPS_JR_RA)
297: va -= sizeof(int);
298: va += 2 * sizeof(int); /* skip back over branch & delay slot */
299: /* skip over nulls which might separate .o files */
300: while ((instr = kdbpeek((int *)va)) == 0)
301: va += sizeof(int);
302: subr = va;
303: }
304:
305: /*
306: * Jump here for locore entry points for which the preceding
307: * function doesn't end in "j ra"
308: */
309: /* scan forwards to find stack size and any saved registers */
310: stksize = 0;
311: more = 3;
312: mask = 0;
313: for (va = subr; more; va += sizeof(int),
314: more = (more == 3) ? 3 : more - 1) {
315: /* stop if hit our current position */
316: if (va >= pc)
317: break;
318: instr = kdbpeek((int *)va);
319: i.word = instr;
320: switch (i.JType.op) {
321: case OP_SPECIAL:
322: switch (i.RType.func) {
323: case OP_JR:
324: case OP_JALR:
325: more = 2; /* stop after next instruction */
326: break;
327:
328: case OP_SYSCALL:
329: case OP_BREAK:
330: more = 1; /* stop now */
331: };
332: break;
333:
334: case OP_BCOND:
335: case OP_J:
336: case OP_JAL:
337: case OP_BEQ:
338: case OP_BNE:
339: case OP_BLEZ:
340: case OP_BGTZ:
341: more = 2; /* stop after next instruction */
342: break;
343:
344: case OP_COP0:
345: case OP_COP1:
346: case OP_COP2:
347: case OP_COP3:
348: switch (i.RType.rs) {
349: case OP_BCx:
350: case OP_BCy:
351: more = 2; /* stop after next instruction */
352: };
353: break;
354:
355: case OP_SW:
356: case OP_SD:
357: /* look for saved registers on the stack */
358: if (i.IType.rs != 29)
359: break;
360: /* only restore the first one */
361: if (mask & (1 << i.IType.rt))
362: break;
363: mask |= (1 << i.IType.rt);
364: switch (i.IType.rt) {
365: case 4: /* a0 */
366: a0 = kdbpeekd((long *)(sp + (short)i.IType.imm));
367: break;
368:
369: case 5: /* a1 */
370: a1 = kdbpeekd((long *)(sp + (short)i.IType.imm));
371: break;
372:
373: case 6: /* a2 */
374: a2 = kdbpeekd((long *)(sp + (short)i.IType.imm));
375: break;
376:
377: case 7: /* a3 */
378: a3 = kdbpeekd((long *)(sp + (short)i.IType.imm));
379: break;
380:
381: case 31: /* ra */
382: ra = kdbpeekd((long *)(sp + (short)i.IType.imm));
383: break;
384: }
385: break;
386:
387: case OP_ADDI:
388: case OP_ADDIU:
389: case OP_DADDI:
390: case OP_DADDIU:
391: /* look for stack pointer adjustment */
392: if (i.IType.rs != 29 || i.IType.rt != 29)
393: break;
394: stksize = - ((short)i.IType.imm);
395: }
396: }
397:
398: done:
399: if (symname == NULL) {
400: if (subr == (long)idle)
401: (*pr)("idle ");
402: else
403: (*pr)("%p ", subr);
404: } else {
405: (*pr)("%s+%p ", symname, diff);
406: }
407: (*pr)("(%llx,%llx,%llx,%llx) sp %llx ra %llx, sz %d\n", a0, a1, a2, a3, sp, ra, stksize);
408:
409: if (subr == (long)k_intr || subr == (long)k_general) {
410: if (subr == (long)k_intr)
411: (*pr)("(KERNEL INTERRUPT)\n");
412: else
413: (*pr)("(KERNEL TRAP)\n");
414: sp = *(register_t *)sp;
415: pc = ((struct trap_frame *)sp)->pc;
416: ra = ((struct trap_frame *)sp)->ra;
417: sp = ((struct trap_frame *)sp)->sp; /* last */
418: goto loop;
419: }
420:
421: if (ra) {
422: if (pc == ra && stksize == 0)
423: (*pr)("stacktrace: loop!\n");
424: else {
425: pc = ra;
426: sp += stksize;
427: ra = 0;
428: goto loop;
429: }
430: } else {
431: if (curproc)
432: (*pr)("User-level: pid %d\n", curproc->p_pid);
433: else
434: (*pr)("User-level: curproc NULL\n");
435: }
436: }
437:
438: /*
439: * To do a single step ddb needs to know the next address
440: * that we will get to. It means that we need to find out
441: * both the address for a branch taken and for not taken, NOT! :-)
442: * MipsEmulateBranch will do the job to find out _exactly_ which
443: * address we will end up at so the 'dual bp' method is not
444: * requiered.
445: */
446: db_addr_t
447: next_instr_address(db_addr_t pc, boolean_t bd)
448: {
449: db_addr_t next;
450:
451: next = MipsEmulateBranch(&ddb_regs, pc, 0, 0);
452: return(next);
453: }
454:
455:
456: /*
457: * Decode instruction and figure out type.
458: */
459: int
460: db_inst_type(ins)
461: int ins;
462: {
463: InstFmt inst;
464: int ityp = 0;
465:
466: inst.word = ins;
467: switch ((int)inst.JType.op) {
468: case OP_SPECIAL:
469: switch ((int)inst.RType.func) {
470: case OP_JR:
471: ityp = IT_BRANCH;
472: break;
473: case OP_JALR:
474: case OP_SYSCALL:
475: ityp = IT_CALL;
476: break;
477: }
478: break;
479:
480: case OP_BCOND:
481: switch ((int)inst.IType.rt) {
482: case OP_BLTZ:
483: case OP_BLTZL:
484: case OP_BGEZ:
485: case OP_BGEZL:
486: ityp = IT_BRANCH;
487: break;
488:
489: case OP_BLTZAL:
490: case OP_BLTZALL:
491: case OP_BGEZAL:
492: case OP_BGEZALL:
493: ityp = IT_CALL;
494: break;
495: }
496: break;
497:
498: case OP_JAL:
499: ityp = IT_CALL;
500: break;
501:
502: case OP_J:
503: case OP_BEQ:
504: case OP_BEQL:
505: case OP_BNE:
506: case OP_BNEL:
507: case OP_BLEZ:
508: case OP_BLEZL:
509: case OP_BGTZ:
510: case OP_BGTZL:
511: ityp = IT_BRANCH;
512: break;
513:
514: case OP_COP1:
515: switch (inst.RType.rs) {
516: case OP_BCx:
517: case OP_BCy:
518: ityp = IT_BRANCH;
519: break;
520: }
521: break;
522:
523: case OP_LB:
524: case OP_LH:
525: case OP_LW:
526: case OP_LD:
527: case OP_LBU:
528: case OP_LHU:
529: case OP_LWU:
530: case OP_LWC1:
531: ityp = IT_LOAD;
532: break;
533:
534: case OP_SB:
535: case OP_SH:
536: case OP_SW:
537: case OP_SD:
538: case OP_SWC1:
539: ityp = IT_STORE;
540: break;
541: }
542: return (ityp);
543: }
544:
545: /*
546: * MIPS machine dependent DDB commands.
547: */
548:
549: /*
550: * Do a trap traceback.
551: */
552: void
553: db_trap_trace_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *m)
554: {
555: trapDump("ddb trap trace");
556: }
557:
558: /*
559: * Dump TLB contents.
560: */
561: void
562: db_dump_tlb_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *m)
563: {
564: int tlbno, last, check, pid;
565: struct tlb_entry tlb, tlbp;
566: char *attr[] = {
567: "WTNA", "WTA ", "UCBL", "CWB ", "RES ", "RES ", "UCNB", "BPAS"
568: };
569:
570: pid = -1;
571:
572: if (m[0] == 'p') {
573: if (have_addr && addr < 256) {
574: pid = addr;
575: tlbno = 0;
576: count = sys_config.cpu[0].tlbsize;
577: }
578: } else if (m[0] == 'c') {
579: last = sys_config.cpu[0].tlbsize;
580: for (tlbno = 0; tlbno < last; tlbno++) {
581: tlb_read(tlbno, &tlb);
582: for (check = tlbno + 1; check < last; check++) {
583: tlb_read(check, &tlbp);
584: if ((tlbp.tlb_hi == tlb.tlb_hi && (tlb.tlb_lo0 & PG_V || tlb.tlb_lo1 & PG_V)) ||
585: (pfn_to_pad(tlb.tlb_lo0) == pfn_to_pad(tlbp.tlb_lo0) && tlb.tlb_lo0 & PG_V) ||
586: (pfn_to_pad(tlb.tlb_lo1) == pfn_to_pad(tlbp.tlb_lo1) && tlb.tlb_lo1 & PG_V)) {
587: printf("MATCH:\n");
588: db_dump_tlb_cmd(tlbno, 1, 1, "");
589: db_dump_tlb_cmd(check, 1, 1, "");
590: }
591: }
592: }
593: return;
594: } else {
595: if (have_addr && addr < sys_config.cpu[0].tlbsize) {
596: tlbno = addr;
597: }
598: else {
599: tlbno = 0;
600: count = sys_config.cpu[0].tlbsize;
601: }
602: }
603: last = tlbno + count;
604:
605: for (; tlbno < sys_config.cpu[0].tlbsize && tlbno < last; tlbno++) {
606: tlb_read(tlbno, &tlb);
607:
608: if (pid >= 0 && (tlb.tlb_hi & 0xff) != pid)
609: continue;
610:
611: if (tlb.tlb_lo0 & PG_V || tlb.tlb_lo1 & PG_V) {
612: printf("%2d v=%16llx", tlbno, tlb.tlb_hi & (long)~0xff);
613: printf("/%02x ", tlb.tlb_hi & 0xff);
614:
615: if (tlb.tlb_lo0 & PG_V) {
616: printf("%16llx ", pfn_to_pad(tlb.tlb_lo0));
617: printf("%c", tlb.tlb_lo0 & PG_M ? 'M' : ' ');
618: printf("%c", tlb.tlb_lo0 & PG_G ? 'G' : ' ');
619: printf("%s ", attr[(tlb.tlb_lo0 >> 3) & 7]);
620: } else {
621: printf("invalid ");
622: }
623:
624: if (tlb.tlb_lo1 & PG_V) {
625: printf("%16llx ", pfn_to_pad(tlb.tlb_lo1));
626: printf("%c", tlb.tlb_lo1 & PG_M ? 'M' : ' ');
627: printf("%c", tlb.tlb_lo1 & PG_G ? 'G' : ' ');
628: printf("%s ", attr[(tlb.tlb_lo1 >> 3) & 7]);
629: } else {
630: printf("invalid ");
631: }
632: printf(" sz=%x", tlb.tlb_mask);
633: }
634: else if (pid < 0) {
635: printf("%2d v=invalid ", tlbno);
636: }
637: printf("\n");
638: }
639: }
640:
641:
642: struct db_command mips_db_command_table[] = {
643: { "tlb", db_dump_tlb_cmd, 0, NULL },
644: { "trap", db_trap_trace_cmd, 0, NULL },
645: { NULL, NULL, 0, NULL }
646: };
647:
648: void
649: db_machine_init()
650: {
651: extern char *ssym;
652: db_machine_commands_install(mips_db_command_table);
653: if (ssym != NULL) {
654: ddb_init(); /* Init symbols */
655: }
656: }
CVSweb