Annotation of sys/arch/m88k/m88k/db_trace.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: db_trace.c,v 1.9 2006/05/08 14:36:09 miod Exp $ */
! 2: /*
! 3: * Mach Operating System
! 4: * Copyright (c) 1993-1991 Carnegie Mellon University
! 5: * Copyright (c) 1991 OMRON Corporation
! 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 AND OMRON ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS"
! 15: * CONDITION. CARNEGIE MELLON AND OMRON DISCLAIM ANY LIABILITY OF ANY KIND
! 16: * FOR 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 the
! 26: * rights to redistribute these changes.
! 27: */
! 28:
! 29: #include <sys/param.h>
! 30: #include <sys/systm.h>
! 31:
! 32: #include <machine/cpu.h>
! 33: #include <machine/db_machdep.h>
! 34:
! 35: #include <ddb/db_variables.h> /* db_variable, DB_VAR_GET, etc. */
! 36: #include <ddb/db_output.h> /* db_printf */
! 37: #include <ddb/db_sym.h> /* DB_STGY_PROC, etc. */
! 38: #include <ddb/db_command.h> /* db_recover */
! 39: #include <ddb/db_access.h>
! 40: #include <ddb/db_interface.h>
! 41:
! 42: static inline
! 43: unsigned br_dest(unsigned addr, u_int inst)
! 44: {
! 45: inst = (inst & 0x03ffffff) << 2;
! 46: /* check if sign extension is needed */
! 47: if (inst & 0x08000000)
! 48: inst |= 0xf0000000;
! 49: return (addr + inst);
! 50: }
! 51:
! 52: int frame_is_sane(db_regs_t *regs, int);
! 53: const char *m88k_exception_name(unsigned vector);
! 54: unsigned db_trace_get_val(vaddr_t addr, unsigned *ptr);
! 55:
! 56: /*
! 57: * Some macros to tell if the given text is the instruction.
! 58: */
! 59: #define JMPN_R1(I) ( (I) == 0xf400c401) /* jmp.n r1 */
! 60: #define JMP_R1(I) ( (I) == 0xf400c001) /* jmp r1 */
! 61:
! 62: /* gets the IMM16 value from an instruction */
! 63: #define IMM16VAL(I) ((I) & 0x0000ffff)
! 64:
! 65: /* subu r31, r31, IMM */
! 66: #define SUBU_R31_R31_IMM(I) (((I) & 0xffff0000) == 0x67ff0000U)
! 67:
! 68: /* st r1, r31, IMM */
! 69: #define ST_R1_R31_IMM(I) (((I) & 0xffff0000) == 0x243f0000U)
! 70:
! 71: extern label_t *db_recover;
! 72:
! 73: /*
! 74: * m88k trace/register state interface for ddb.
! 75: */
! 76:
! 77: /* lifted from mips */
! 78: static int
! 79: db_setf_regs(struct db_variable *vp,
! 80: db_expr_t *valuep,
! 81: int op) /* read/write */
! 82: {
! 83: int *regp = (int *) ((char *) DDB_REGS + (int) (vp->valuep));
! 84:
! 85: if (op == DB_VAR_GET)
! 86: *valuep = *regp;
! 87: else if (op == DB_VAR_SET)
! 88: *regp = *valuep;
! 89:
! 90: return (0); /* silence warning */
! 91: }
! 92:
! 93: #define N(s, x) {s, (long *)&(((db_regs_t *) 0)->x), db_setf_regs}
! 94:
! 95: struct db_variable db_regs[] = {
! 96: N("r1", r[1]), N("r2", r[2]), N("r3", r[3]), N("r4", r[4]),
! 97: N("r5", r[5]), N("r6", r[6]), N("r7", r[7]), N("r8", r[8]),
! 98: N("r9", r[9]), N("r10", r[10]), N("r11", r[11]), N("r12", r[12]),
! 99: N("r13", r[13]), N("r14", r[14]), N("r15", r[15]), N("r16", r[16]),
! 100: N("r17", r[17]), N("r18", r[18]), N("r19", r[19]), N("r20", r[20]),
! 101: N("r21", r[21]), N("r22", r[22]), N("r23", r[23]), N("r24", r[24]),
! 102: N("r25", r[25]), N("r26", r[26]), N("r27", r[27]), N("r28", r[28]),
! 103: N("r29", r[29]), N("r30", r[30]), N("r31", r[31]), N("epsr", epsr),
! 104: N("sxip", sxip), N("snip", snip), N("sfip", sfip), N("ssbr", ssbr),
! 105: N("dmt0", dmt0), N("dmd0", dmd0), N("dma0", dma0), N("dmt1", dmt1),
! 106: N("dmd1", dmd1), N("dma1", dma1), N("dmt2", dmt2), N("dmd2", dmd2),
! 107: N("dma2", dma2), N("fpecr", fpecr),N("fphs1", fphs1),N("fpls1", fpls1),
! 108: N("fphs2", fphs2), N("fpls2", fpls2),N("fppt", fppt), N("fprh", fprh),
! 109: N("fprl", fprl), N("fpit", fpit), N("fpsr", fpsr), N("fpcr", fpcr),
! 110: };
! 111: #undef N
! 112:
! 113: struct db_variable *db_eregs = db_regs + sizeof(db_regs)/sizeof(db_regs[0]);
! 114:
! 115: #define TRASHES 0x001 /* clobbers instruction field D */
! 116: #define STORE 0x002 /* does a store to S1+IMM16 */
! 117: #define LOAD 0x004 /* does a load from S1+IMM16 */
! 118: #define DOUBLE 0x008 /* double-register */
! 119: #define FLOW_CTRL 0x010 /* flow-control instruction */
! 120: #define DELAYED 0x020 /* delayed flow control */
! 121: #define JSR 0x040 /* flow-control is a jsr[.n] */
! 122: #define BSR 0x080 /* flow-control is a bsr[.n] */
! 123:
! 124: /*
! 125: * Given a word of instruction text, return some flags about that
! 126: * instruction (flags defined above).
! 127: */
! 128: static unsigned
! 129: m88k_instruction_info(unsigned instruction)
! 130: {
! 131: static const struct {
! 132: unsigned mask, value, flags;
! 133: } *ptr, control[] = {
! 134: /* runs in the same order as 2nd Ed 88100 manual Table 3-14 */
! 135: { 0xf0000000U, 0x00000000U, /* xmem */ TRASHES | STORE | LOAD},
! 136: { 0xec000000U, 0x00000000U, /* ld.d */ TRASHES | LOAD | DOUBLE},
! 137: { 0xe0000000U, 0x00000000U, /* load */ TRASHES | LOAD},
! 138: { 0xfc000000U, 0x20000000U, /* st.d */ STORE | DOUBLE},
! 139: { 0xf0000000U, 0x20000000U, /* store */ STORE},
! 140: { 0xc0000000U, 0x40000000U, /* arith */ TRASHES},
! 141: { 0xfc004000U, 0x80004000U, /* ld cr */ TRASHES},
! 142: { 0xfc004000U, 0x80000000U, /* st cr */ 0},
! 143: { 0xfc008060U, 0x84000000U, /* f */ TRASHES},
! 144: { 0xfc008060U, 0x84000020U, /* f.d */ TRASHES | DOUBLE},
! 145: { 0xfc000000U, 0xcc000000U, /* bsr.n */ FLOW_CTRL | DELAYED | BSR},
! 146: { 0xfc000000U, 0xc8000000U, /* bsr */ FLOW_CTRL | BSR},
! 147: { 0xe4000000U, 0xc4000000U, /* br/bb.n */ FLOW_CTRL | DELAYED},
! 148: { 0xe4000000U, 0xc0000000U, /* br/bb */ FLOW_CTRL},
! 149: { 0xfc000000U, 0xec000000U, /* bcnd.n */ FLOW_CTRL | DELAYED},
! 150: { 0xfc000000U, 0xe8000000U, /* bcnd */ FLOW_CTRL},
! 151: { 0xfc00c000U, 0xf0008000U, /* bits */ TRASHES},
! 152: { 0xfc00c000U, 0xf000c000U, /* trap */ 0},
! 153: { 0xfc00f0e0U, 0xf4002000U, /* st */ 0},
! 154: { 0xfc00cce0U, 0xf4000000U, /* ld.d */ TRASHES | DOUBLE},
! 155: { 0xfc00c0e0U, 0xf4000000U, /* ld */ TRASHES},
! 156: { 0xfc00c0e0U, 0xf4004000U, /* arith */ TRASHES},
! 157: { 0xfc00c3e0U, 0xf4008000U, /* bits */ TRASHES},
! 158: { 0xfc00ffe0U, 0xf400cc00U, /* jsr.n */ FLOW_CTRL | DELAYED | JSR},
! 159: { 0xfc00ffe0U, 0xf400c800U, /* jsr */ FLOW_CTRL | JSR},
! 160: { 0xfc00ffe0U, 0xf400c400U, /* jmp.n */ FLOW_CTRL | DELAYED},
! 161: { 0xfc00ffe0U, 0xf400c000U, /* jmp */ FLOW_CTRL},
! 162: { 0xfc00fbe0U, 0xf400e800U, /* ff */ TRASHES},
! 163: { 0xfc00ffe0U, 0xf400f800U, /* tbnd */ 0},
! 164: { 0xfc00ffe0U, 0xf400fc00U, /* rte */ FLOW_CTRL},
! 165: { 0xfc000000U, 0xf8000000U, /* tbnd */ 0},
! 166: };
! 167: #define ctrl_count (sizeof(control)/sizeof(control[0]))
! 168: for (ptr = &control[0]; ptr < &control[ctrl_count]; ptr++)
! 169: if ((instruction & ptr->mask) == ptr->value)
! 170: return ptr->flags;
! 171: return 0;
! 172: }
! 173:
! 174: static int
! 175: hex_value_needs_0x(unsigned value)
! 176: {
! 177: int c;
! 178: int have_a_hex_digit = 0;
! 179:
! 180: if (value <= 9)
! 181: return (0);
! 182:
! 183: while (value != 0) {
! 184: c = value & 0xf;
! 185: value >>= 4;
! 186: if (c > 9)
! 187: have_a_hex_digit = 1;
! 188: }
! 189: if (have_a_hex_digit == 0) /* has no letter, thus needs 0x */
! 190: return (1);
! 191: if (c > 9) /* starts with a letter, thus needs 0x */
! 192: return (1);
! 193: return (0);
! 194: }
! 195:
! 196: /*
! 197: * returns
! 198: * 1 if regs seems to be a reasonable kernel exception frame.
! 199: * 2 if regs seems to be a reasonable user exception frame
! 200: * (in the current task).
! 201: * 0 if this looks like neither.
! 202: */
! 203: int
! 204: frame_is_sane(db_regs_t *regs, int quiet)
! 205: {
! 206: /* no good if we can't read the whole frame */
! 207: if (badaddr((vaddr_t)regs, 4) || badaddr((vaddr_t)®s->fpit, 4)) {
! 208: if (quiet == 0)
! 209: db_printf("[WARNING: frame at %p : unreadable]\n", regs);
! 210: return 0;
! 211: }
! 212:
! 213: /* r0 must be 0 (obviously) */
! 214: if (regs->r[0] != 0) {
! 215: if (quiet == 0)
! 216: db_printf("[WARNING: frame at %p : r[0] != 0]\n", regs);
! 217: return 0;
! 218: }
! 219:
! 220: /* stack sanity ... r31 must be nonzero, and must be word aligned */
! 221: if (regs->r[31] == 0 || (regs->r[31] & 3) != 0) {
! 222: if (quiet == 0)
! 223: db_printf("[WARNING: frame at %p : r[31] == 0 or not word aligned]\n", regs);
! 224: return 0;
! 225: }
! 226:
! 227: #ifdef M88100
! 228: if (CPU_IS88100) {
! 229: /* sxip is reasonable */
! 230: #if 0
! 231: if ((regs->sxip & XIP_E) != 0)
! 232: goto out;
! 233: #endif
! 234: /* snip is reasonable */
! 235: if ((regs->snip & ~NIP_ADDR) != NIP_V)
! 236: goto out;
! 237: /* sfip is reasonable */
! 238: if ((regs->sfip & ~FIP_ADDR) != FIP_V)
! 239: goto out;
! 240: }
! 241: #endif
! 242:
! 243: /* epsr sanity */
! 244: if (regs->epsr & PSR_BO)
! 245: goto out;
! 246:
! 247: return ((regs->epsr & PSR_MODE) ? 1 : 2);
! 248:
! 249: out:
! 250: if (quiet == 0)
! 251: db_printf("[WARNING: not an exception frame?]\n");
! 252: return (0);
! 253: }
! 254:
! 255: const char *
! 256: m88k_exception_name(unsigned vector)
! 257: {
! 258: switch (vector) {
! 259: default:
! 260: case 0: return "Reset";
! 261: case 1: return "Interrupt";
! 262: case 2: return "Instruction Access Exception";
! 263: case 3: return "Data Access Exception";
! 264: case 4: return "Misaligned Access Exception";
! 265: case 5: return "Unimplemented Opcode Exception";
! 266: case 6: return "Privilege Violation";
! 267: case 7: return "Bounds Check";
! 268: case 8: return "Integer Divide Exception";
! 269: case 9: return "Integer Overflow Exception";
! 270: case 10: return "Error Exception";
! 271: case 11: return "Non Maskable Interrupt";
! 272: case 114: return "FPU precise";
! 273: case 115: return "FPU imprecise";
! 274: case DDB_ENTRY_BKPT_NO:
! 275: return "ddb break";
! 276: case DDB_ENTRY_TRACE_NO:
! 277: return "ddb trace";
! 278: case DDB_ENTRY_TRAP_NO:
! 279: return "ddb trap";
! 280: case 451: return "Syscall";
! 281: }
! 282: }
! 283:
! 284: /*
! 285: * Read a word at address addr.
! 286: * Return 1 if was able to read, 0 otherwise.
! 287: */
! 288: unsigned
! 289: db_trace_get_val(vaddr_t addr, unsigned *ptr)
! 290: {
! 291: label_t db_jmpbuf;
! 292: label_t *prev = db_recover;
! 293:
! 294: if (setjmp((db_recover = &db_jmpbuf)) != 0) {
! 295: db_recover = prev;
! 296: return 0;
! 297: } else {
! 298: db_read_bytes(addr, 4, (char *)ptr);
! 299: db_recover = prev;
! 300: return 1;
! 301: }
! 302: }
! 303:
! 304: #define FIRST_CALLPRESERVED_REG 14
! 305: #define LAST_CALLPRESERVED_REG 29
! 306: #define FIRST_ARG_REG 2
! 307: #define LAST_ARG_REG 9
! 308: #define RETURN_VAL_REG 1
! 309:
! 310: static unsigned global_saved_list = 0x0; /* one bit per register */
! 311: static unsigned local_saved_list = 0x0; /* one bit per register */
! 312: static unsigned trashed_list = 0x0; /* one bit per register */
! 313: static unsigned saved_reg[32]; /* one value per register */
! 314:
! 315: #define reg_bit(reg) 1 << (reg)
! 316:
! 317: static void
! 318: save_reg(int reg, unsigned value)
! 319: {
! 320: reg &= 0x1f;
! 321: if (trashed_list & reg_bit(reg))
! 322: return; /* don't save trashed registers */
! 323:
! 324: saved_reg[reg] = value;
! 325: global_saved_list |= reg_bit(reg);
! 326: local_saved_list |= reg_bit(reg);
! 327: }
! 328:
! 329: #define mark_reg_trashed(reg) trashed_list |= reg_bit((reg) & 0x1f)
! 330:
! 331: #define have_global_reg(reg) (global_saved_list & reg_bit(reg))
! 332: #define have_local_reg(reg) (local_saved_list & reg_bit(reg))
! 333:
! 334: #define clear_local_saved_regs() local_saved_list = trashed_list = 0
! 335: #define clear_global_saved_regs() local_saved_list = global_saved_list = 0
! 336:
! 337: #define saved_reg_value(reg) saved_reg[(reg)]
! 338:
! 339: /*
! 340: * Show any arguments that we might have been able to determine.
! 341: */
! 342: static void
! 343: print_args(void)
! 344: {
! 345: int reg, last_arg;
! 346:
! 347: /* find the highest argument register saved */
! 348: for (last_arg = LAST_ARG_REG; last_arg >= FIRST_ARG_REG; last_arg--)
! 349: if (have_local_reg(last_arg))
! 350: break;
! 351: if (last_arg < FIRST_ARG_REG)
! 352: return; /* none were saved */
! 353:
! 354: db_printf("(");
! 355:
! 356: /* print each one, up to the highest */
! 357: for (reg = FIRST_ARG_REG; /*nothing */; reg++) {
! 358: if (!have_local_reg(reg))
! 359: db_printf("?");
! 360: else {
! 361: unsigned value = saved_reg_value(reg);
! 362: db_printf("%s%x", hex_value_needs_0x(value) ?
! 363: "0x" : "", value);
! 364: }
! 365: if (reg == last_arg)
! 366: break;
! 367: else
! 368: db_printf(", ");
! 369: }
! 370: db_printf(")");
! 371: }
! 372:
! 373: #define JUMP_SOURCE_IS_BAD 0
! 374: #define JUMP_SOURCE_IS_OK 1
! 375: #define JUMP_SOURCE_IS_UNLIKELY 2
! 376:
! 377: /*
! 378: * Give an address to where we return, and an address to where we'd jumped,
! 379: * Decided if it all makes sense.
! 380: *
! 381: * Gcc sometimes optimized something like
! 382: * if (condition)
! 383: * func1();
! 384: * else
! 385: * OtherStuff...
! 386: * to
! 387: * bcnd !condition, mark
! 388: * bsr.n func1
! 389: * or r1, r0, mark2
! 390: * mark:
! 391: * OtherStuff...
! 392: * mark2:
! 393: *
! 394: * So RETURN_TO will be mark2, even though we really did branch via
! 395: * 'bsr.n func1', so this makes it difficult to be certain about being
! 396: * wrong.
! 397: */
! 398: static int
! 399: is_jump_source_ok(unsigned return_to, unsigned jump_to)
! 400: {
! 401: unsigned flags;
! 402: u_int instruction;
! 403:
! 404: /*
! 405: * Delayed branches are the most common... look two instructions before
! 406: * where we were going to return to to see if it's a delayed branch.
! 407: */
! 408: if (!db_trace_get_val(return_to - 8, &instruction))
! 409: return JUMP_SOURCE_IS_BAD;
! 410:
! 411: flags = m88k_instruction_info(instruction);
! 412: if ((flags & (FLOW_CTRL | DELAYED)) == (FLOW_CTRL | DELAYED) &&
! 413: (flags & (JSR | BSR)) != 0) {
! 414: if ((flags & JSR) != 0)
! 415: return JUMP_SOURCE_IS_OK; /* have to assume it's correct */
! 416: /* calculate the offset */
! 417: if (br_dest(return_to - 8, instruction) == jump_to)
! 418: return JUMP_SOURCE_IS_OK; /* exactamundo! */
! 419: else
! 420: return JUMP_SOURCE_IS_UNLIKELY; /* seems wrong */
! 421: }
! 422:
! 423: /*
! 424: * Try again, looking for a non-delayed jump one instruction back.
! 425: */
! 426: if (!db_trace_get_val(return_to - 4, &instruction))
! 427: return JUMP_SOURCE_IS_BAD;
! 428:
! 429: flags = m88k_instruction_info(instruction);
! 430: if ((flags & (FLOW_CTRL | DELAYED)) == FLOW_CTRL &&
! 431: (flags & (JSR | BSR)) != 0) {
! 432: if ((flags & JSR) != 0)
! 433: return JUMP_SOURCE_IS_OK; /* have to assume it's correct */
! 434: /* calculate the offset */
! 435: if (br_dest(return_to - 4, instruction) == jump_to)
! 436: return JUMP_SOURCE_IS_OK; /* exactamundo! */
! 437: else
! 438: return JUMP_SOURCE_IS_UNLIKELY; /* seems wrong */
! 439: }
! 440:
! 441: return JUMP_SOURCE_IS_UNLIKELY;
! 442: }
! 443:
! 444: static const char *note;
! 445: static int next_address_likely_wrong = 0;
! 446:
! 447: /* How much slop we expect in the stack trace */
! 448: #define FRAME_PLAY 8
! 449:
! 450: /*
! 451: * Stack decode -
! 452: * unsigned addr; program counter
! 453: * unsigned *stack; IN/OUT stack pointer
! 454: *
! 455: * given an address within a function and a stack pointer,
! 456: * try to find the function from which this one was called
! 457: * and the stack pointer for that function.
! 458: *
! 459: * The return value is zero if we get confused or
! 460: * we determine that the return address has not yet
! 461: * been saved (early in the function prologue). Otherwise
! 462: * the return value is the address from which this function
! 463: * was called.
! 464: *
! 465: * Note that even is zero is returned (the second case) the
! 466: * stack pointer can be adjusted.
! 467: */
! 468: static int
! 469: stack_decode(db_addr_t addr, unsigned *stack, int (*pr)(const char *, ...))
! 470: {
! 471: db_sym_t proc;
! 472: db_expr_t offset_from_proc;
! 473: unsigned instructions_to_search;
! 474: db_addr_t check_addr;
! 475: db_addr_t function_addr; /* start of function */
! 476: unsigned r31 = *stack; /* the r31 of the function */
! 477: unsigned inst; /* text of an instruction */
! 478: unsigned ret_addr; /* address to which we return */
! 479: unsigned tried_to_save_r1 = 0;
! 480:
! 481: /* get what we hope will be the db_sym_t for the function name */
! 482: proc = db_search_symbol(addr, DB_STGY_PROC, &offset_from_proc);
! 483: if (offset_from_proc == addr) /* i.e. no symbol found */
! 484: proc = DB_SYM_NULL;
! 485:
! 486: /*
! 487: * Somehow, find the start of this function.
! 488: * If we found a symbol above, it'll have the address.
! 489: * Otherwise, we've got to search for it....
! 490: */
! 491: if (proc != DB_SYM_NULL) {
! 492: char *names;
! 493: db_symbol_values(proc, &names, &function_addr);
! 494: if (names == 0)
! 495: return 0;
! 496: } else {
! 497: int instructions_to_check = 400;
! 498: /*
! 499: * hmm - unable to find symbol. Search back
! 500: * looking for a function prolog.
! 501: */
! 502: for (check_addr = addr; instructions_to_check-- > 0; check_addr -= 4) {
! 503: if (!db_trace_get_val(check_addr, &inst))
! 504: break;
! 505:
! 506: if (SUBU_R31_R31_IMM(inst)) {
! 507: #if 0
! 508: /*
! 509: * If the next instruction is "st r1, r31, ####"
! 510: * then we can feel safe we have the start of
! 511: * a function.
! 512: */
! 513: if (!db_trace_get_val(check_addr + 4, &inst))
! 514: continue;
! 515: if (ST_R1_R31_IMM(instr))
! 516: break; /* success */
! 517: #else
! 518: /*
! 519: * Latest GCC optimizer is just too good... the store
! 520: * of r1 might come much later... so we'll have to
! 521: * settle for just the "subr r31, r31, ###" to mark
! 522: * the start....
! 523: */
! 524: break;
! 525: #endif
! 526: }
! 527: /*
! 528: * if we come across a [jmp r1] or [jmp.n r1] assume we have hit
! 529: * the previous functions epilogue and stop our search.
! 530: * Since we know we would have hit the "subr r31, r31" if it was
! 531: * right in front of us, we know this doesn't have one so
! 532: * we just return failure....
! 533: */
! 534: if (JMP_R1(inst) || JMPN_R1(inst))
! 535: return 0;
! 536: }
! 537: if (instructions_to_check < 0)
! 538: return 0; /* bummer, couldn't find it */
! 539: function_addr = check_addr;
! 540: }
! 541:
! 542: /*
! 543: * We now know the start of the function (function_addr).
! 544: * If we're stopped right there, or if it's not a
! 545: * subu r31, r31, ####
! 546: * then we're done.
! 547: */
! 548: if (addr == function_addr)
! 549: return 0;
! 550: if (!db_trace_get_val(function_addr, &inst))
! 551: return 0;
! 552: if (!SUBU_R31_R31_IMM(inst))
! 553: return 0;
! 554:
! 555: /* add the size of this frame to the stack (for the next frame) */
! 556: *stack += IMM16VAL(inst);
! 557:
! 558: /*
! 559: * Search from the beginning of the function (funstart) to where we are
! 560: * in the function (addr) looking to see what kind of registers have
! 561: * been saved on the stack.
! 562: *
! 563: * We'll stop looking before we get to ADDR if we hit a branch.
! 564: */
! 565: clear_local_saved_regs();
! 566: check_addr = function_addr + 4; /* we know the first inst isn't a store */
! 567:
! 568: for (instructions_to_search = (addr - check_addr)/sizeof(long);
! 569: instructions_to_search-- > 0;
! 570: check_addr += 4) {
! 571: u_int instruction, s1, d;
! 572: unsigned flags;
! 573:
! 574: /* read the instruction */
! 575: if (!db_trace_get_val(check_addr, &instruction))
! 576: break;
! 577:
! 578: /* find out the particulars about this instruction */
! 579: flags = m88k_instruction_info(instruction);
! 580:
! 581: /* split the instruction in its diatic components anyway */
! 582: s1 = (instruction >> 16) & 0x1f;
! 583: d = (instruction >> 21) & 0x1f;
! 584:
! 585: /* if a store to something off the stack pointer, note the value */
! 586: if ((flags & STORE) && s1 == 31 /*stack pointer*/) {
! 587: unsigned value;
! 588: if (!have_local_reg(d)) {
! 589: if (d == 1)
! 590: tried_to_save_r1 = r31 +
! 591: IMM16VAL(instruction);
! 592: if (db_trace_get_val(r31 +
! 593: IMM16VAL(instruction), &value))
! 594: save_reg(d, value);
! 595: }
! 596: if ((flags & DOUBLE) && !have_local_reg(d + 1)) {
! 597: if (d == 0)
! 598: tried_to_save_r1 = r31 +
! 599: IMM16VAL(instruction) + 4;
! 600: if (db_trace_get_val(r31 +
! 601: IMM16VAL(instruction) + 4, &value))
! 602: save_reg(d + 1, value);
! 603: }
! 604: }
! 605:
! 606: /* if an inst that kills D (and maybe D+1), note that */
! 607: if (flags & TRASHES) {
! 608: mark_reg_trashed(d);
! 609: if (flags & DOUBLE)
! 610: mark_reg_trashed(d + 1);
! 611: }
! 612:
! 613: /* if a flow control instruction, stop now (or next if delayed) */
! 614: if ((flags & FLOW_CTRL) && instructions_to_search != 0)
! 615: instructions_to_search = (flags & DELAYED) ? 1 : 0;
! 616: }
! 617:
! 618: /*
! 619: * If we didn't save r1 at some point, we're hosed.
! 620: */
! 621: if (!have_local_reg(1)) {
! 622: if (tried_to_save_r1) {
! 623: (*pr)(" <return value of next fcn unreadable in %08x>\n",
! 624: tried_to_save_r1);
! 625: }
! 626: return 0;
! 627: }
! 628:
! 629: ret_addr = saved_reg_value(1);
! 630:
! 631: if (ret_addr != 0) {
! 632: switch (is_jump_source_ok(ret_addr, function_addr)) {
! 633: case JUMP_SOURCE_IS_OK:
! 634: break; /* excellent */
! 635:
! 636: case JUMP_SOURCE_IS_BAD:
! 637: return 0; /* bummer */
! 638:
! 639: case JUMP_SOURCE_IS_UNLIKELY:
! 640: next_address_likely_wrong = 1;
! 641: break;
! 642: }
! 643: }
! 644:
! 645: return ret_addr;
! 646: }
! 647:
! 648: static void
! 649: db_stack_trace_cmd2(db_regs_t *regs, int (*pr)(const char *, ...))
! 650: {
! 651: unsigned stack;
! 652: unsigned depth=1;
! 653: unsigned where;
! 654: unsigned ft;
! 655: unsigned pair[2];
! 656: int i;
! 657:
! 658: /*
! 659: * Frame_is_sane returns:
! 660: * 1 if regs seems to be a reasonable kernel exception frame.
! 661: * 2 if regs seems to be a reasonable user exception frame
! 662: * (in the current task).
! 663: * 0 if this looks like neither.
! 664: */
! 665: if ((ft = frame_is_sane(regs, 1)) == 0) {
! 666: (*pr)("Register frame 0x%x is suspicious; skipping trace\n", regs);
! 667: return;
! 668: }
! 669:
! 670: /* if user space and no user space trace specified, puke */
! 671: if (ft == 2)
! 672: return;
! 673:
! 674: /* fetch address */
! 675: where = PC_REGS(regs);
! 676: stack = regs->r[31];
! 677: (*pr)("stack base = 0x%x\n", stack);
! 678: (*pr)("(0) "); /* depth of trace */
! 679: db_printsym(where, DB_STGY_PROC, pr);
! 680: clear_global_saved_regs();
! 681:
! 682: /* see if this routine had a stack frame */
! 683: if ((where = stack_decode(where, &stack, pr)) == 0) {
! 684: where = regs->r[1];
! 685: (*pr)("(stackless)");
! 686: } else
! 687: print_args();
! 688: (*pr)("\n");
! 689: if (note) {
! 690: (*pr)(" %s\n", note);
! 691: note = NULL;
! 692: }
! 693:
! 694: do {
! 695: /*
! 696: * If requested, show preserved registers at the time
! 697: * the next-shown call was made. Only registers known to have
! 698: * changed from the last exception frame are shown, as others
! 699: * can be gotten at by looking at the exception frame.
! 700: */
! 701: (*pr)("(%d)%c", depth++, next_address_likely_wrong ? '?' : ' ');
! 702: next_address_likely_wrong = 0;
! 703:
! 704: db_printsym(where, DB_STGY_PROC, pr);
! 705: where = stack_decode(where, &stack, pr);
! 706: print_args();
! 707: (*pr)("\n");
! 708: if (note) {
! 709: (*pr)(" %s\n", note);
! 710: note = NULL;
! 711: }
! 712: } while (where);
! 713:
! 714: /* try to trace back over trap/exception */
! 715:
! 716: stack &= ~7; /* double word aligned */
! 717: /* take last top of stack, and try to find an exception frame near it */
! 718:
! 719: i = FRAME_PLAY;
! 720: while (i) {
! 721: /*
! 722: * On the stack, a pointer to the exception frame is written
! 723: * in two adjacent words. In the case of a fault from the kernel,
! 724: * this should point to the frame right above them:
! 725: *
! 726: * Exception Frame Top
! 727: * ..
! 728: * Exception Frame Bottom <-- frame addr
! 729: * frame addr
! 730: * frame addr <-- stack pointer
! 731: *
! 732: * In the case of a fault from user mode, the top of stack
! 733: * will just have the address of the frame
! 734: * replicated twice.
! 735: *
! 736: * frame addr <-- top of stack
! 737: * frame addr
! 738: *
! 739: * Here we are just looking for kernel exception frames.
! 740: */
! 741:
! 742: if (badaddr((vaddr_t)stack, 4) ||
! 743: badaddr((vaddr_t)(stack + 4), 4))
! 744: break;
! 745:
! 746: db_read_bytes((vaddr_t)stack, 2 * sizeof(int), (char *)pair);
! 747:
! 748: /* the pairs should match and equal stack+8 */
! 749: if (pair[0] == pair[1]) {
! 750: if (pair[0] != stack+8) {
! 751: #if 0
! 752: if (!badaddr((vaddr_t)pair[0], 4) &&
! 753: pair[0] != 0)
! 754: (*pr)("stack_trace:found pair 0x%x but != to stack+8\n",
! 755: pair[0]);
! 756: #endif
! 757: } else if (frame_is_sane((db_regs_t*)pair[0], 1) != 0) {
! 758: struct trapframe *frame =
! 759: (struct trapframe *)pair[0];
! 760:
! 761: (*pr)("-------------- %s [EF: 0x%x] -------------\n",
! 762: m88k_exception_name(frame->tf_vector),
! 763: frame);
! 764: db_stack_trace_cmd2(&frame->tf_regs, pr);
! 765: return;
! 766: }
! 767: }
! 768: stack += 8;
! 769: i--;
! 770: }
! 771: }
! 772:
! 773: /*
! 774: * stack trace - needs a pointer to a m88k saved state.
! 775: *
! 776: * If argument f is given, the stack pointer of each call frame is
! 777: * printed.
! 778: */
! 779: void
! 780: db_stack_trace_print(db_expr_t addr,
! 781: int have_addr,
! 782: db_expr_t count,
! 783: char *modif,
! 784: int (*pr)(const char *, ...))
! 785: {
! 786: enum {
! 787: Default, Stack, Frame
! 788: } style = Default;
! 789: db_regs_t frame;
! 790: db_regs_t *regs;
! 791: union {
! 792: db_regs_t *frame;
! 793: db_expr_t num;
! 794: } arg;
! 795:
! 796: arg.num = addr;
! 797:
! 798: while (modif && *modif) {
! 799: switch (*modif++) {
! 800: case 's': style = Stack ; break;
! 801: case 'f': style = Frame ; break;
! 802: default:
! 803: (*pr)("unknown trace modifier [%c]\n", modif[-1]);
! 804: /*FALLTHROUGH*/
! 805: case 'h':
! 806: (*pr)("usage: trace/[MODIFIER] [ARG]\n");
! 807: (*pr)(" s = ARG is a stack pointer\n");
! 808: (*pr)(" f = ARG is a frame pointer\n");
! 809: return;
! 810: }
! 811: }
! 812:
! 813: if (!have_addr && style != Default) {
! 814: (*pr)("expecting argument with /s or /f\n");
! 815: return;
! 816: }
! 817: if (have_addr && style == Default)
! 818: style = Frame;
! 819:
! 820: switch (style) {
! 821: case Default:
! 822: regs = DDB_REGS;
! 823: break;
! 824: case Frame:
! 825: regs = arg.frame;
! 826: break;
! 827: case Stack:
! 828: {
! 829: unsigned val1, val2, sxip;
! 830: unsigned ptr;
! 831: bzero((void *)&frame, sizeof(frame));
! 832: #define REASONABLE_FRAME_DISTANCE 2048
! 833:
! 834: /*
! 835: * We've got to find the top of a stack frame so we can get both
! 836: * a PC and and real SP.
! 837: */
! 838: for (ptr = arg.num;/**/; ptr += 4) {
! 839: /* Read a word from the named stack */
! 840: if (db_trace_get_val(ptr, &val1) == 0) {
! 841: (*pr)("can't read from %x, aborting.\n", ptr);
! 842: return;
! 843: }
! 844:
! 845: /*
! 846: * See if it's a frame pointer.... if so it will be larger than
! 847: * the address it was taken from (i.e. point back up the stack)
! 848: * and we'll be able to read where it points.
! 849: */
! 850: if (val1 <= ptr ||
! 851: (val1 & 3) ||
! 852: val1 > (ptr + REASONABLE_FRAME_DISTANCE))
! 853: continue;
! 854:
! 855: /* peek at the next word to see if it could be a return address */
! 856: if (db_trace_get_val(ptr, &sxip) == 0) {
! 857: (*pr)("can't read from %x, aborting.\n", ptr);
! 858: return;
! 859: }
! 860: if (sxip == 0 || !db_trace_get_val(sxip, &val2))
! 861: continue;
! 862:
! 863: if (db_trace_get_val(val1, &val2) == 0) {
! 864: (*pr)("can't read from %x, aborting.\n", val1);
! 865: continue;
! 866: }
! 867:
! 868: /*
! 869: * The value we've just read will be either
! 870: * another frame pointer, or the start of
! 871: * another exception frame.
! 872: */
! 873: if (val2 == 0x12345678 &&
! 874: db_trace_get_val(val1 - 4, &val2) &&
! 875: val2 == val1 &&
! 876: db_trace_get_val(val1 - 8, &val2) &&
! 877: val2 == val1) {
! 878: /* we've found a frame, so the stack
! 879: must have been good */
! 880: (*pr)("%x looks like a frame, accepting %x\n",val1,ptr);
! 881: break;
! 882: }
! 883:
! 884: if (val2 > val1 && (val2 & 3) == 0) {
! 885: /* well, looks close enough to be another frame pointer */
! 886: (*pr)("*%x = %x looks like a stack frame pointer, accepting %x\n", val1, val2, ptr);
! 887: break;
! 888: }
! 889: }
! 890: frame.r[31] = ptr;
! 891: frame.epsr = 0x800003f0U;
! 892: #ifdef M88100
! 893: if (CPU_IS88100) {
! 894: frame.sxip = sxip | XIP_V;
! 895: frame.snip = frame.sxip + 4;
! 896: frame.sfip = frame.snip + 4;
! 897: }
! 898: #endif
! 899: (*pr)("[r31=%x, %sxip=%x]\n", frame.r[31],
! 900: CPU_IS88110 ? "e" : "s", frame.sxip);
! 901: regs = &frame;
! 902: }
! 903: break;
! 904: }
! 905: db_stack_trace_cmd2(regs, pr);
! 906: }
CVSweb