[BACK]Return to db_trace.c CVS log [TXT][DIR] Up to [local] / sys / arch / m88k / m88k

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)&regs->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