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

Annotation of sys/arch/i386/i386/db_trace.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: db_trace.c,v 1.13 2006/11/28 18:56:17 uwe Exp $       */
        !             2: /*     $NetBSD: db_trace.c,v 1.18 1996/05/03 19:42:01 christos Exp $   */
        !             3:
        !             4: /*
        !             5:  * Mach Operating System
        !             6:  * Copyright (c) 1991,1990 Carnegie Mellon University
        !             7:  * All Rights Reserved.
        !             8:  *
        !             9:  * Permission to use, copy, modify and distribute this software and its
        !            10:  * documentation is hereby granted, provided that both the copyright
        !            11:  * notice and this permission notice appear in all copies of the
        !            12:  * software, derivative works or modified versions, and any portions
        !            13:  * thereof, and that both notices appear in supporting documentation.
        !            14:  *
        !            15:  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
        !            16:  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
        !            17:  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
        !            18:  *
        !            19:  * Carnegie Mellon requests users of this software to return to
        !            20:  *
        !            21:  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
        !            22:  *  School of Computer Science
        !            23:  *  Carnegie Mellon University
        !            24:  *  Pittsburgh PA 15213-3890
        !            25:  *
        !            26:  * any improvements or extensions that they make and grant Carnegie Mellon
        !            27:  * the rights to redistribute these changes.
        !            28:  */
        !            29:
        !            30: #include <sys/param.h>
        !            31: #include <sys/systm.h>
        !            32: #include <sys/proc.h>
        !            33: #include <sys/user.h>
        !            34:
        !            35: #include <machine/db_machdep.h>
        !            36:
        !            37: #include <ddb/db_sym.h>
        !            38: #include <ddb/db_access.h>
        !            39: #include <ddb/db_variables.h>
        !            40: #include <ddb/db_output.h>
        !            41: #include <ddb/db_interface.h>
        !            42:
        !            43: /*
        !            44:  * Machine register set.
        !            45:  */
        !            46: struct db_variable db_regs[] = {
        !            47:        { "ds",         (long *)&ddb_regs.tf_ds,     FCN_NULL },
        !            48:        { "es",         (long *)&ddb_regs.tf_es,     FCN_NULL },
        !            49:        { "fs",         (long *)&ddb_regs.tf_fs,     FCN_NULL },
        !            50:        { "gs",         (long *)&ddb_regs.tf_gs,     FCN_NULL },
        !            51:        { "edi",        (long *)&ddb_regs.tf_edi,    FCN_NULL },
        !            52:        { "esi",        (long *)&ddb_regs.tf_esi,    FCN_NULL },
        !            53:        { "ebp",        (long *)&ddb_regs.tf_ebp,    FCN_NULL },
        !            54:        { "ebx",        (long *)&ddb_regs.tf_ebx,    FCN_NULL },
        !            55:        { "edx",        (long *)&ddb_regs.tf_edx,    FCN_NULL },
        !            56:        { "ecx",        (long *)&ddb_regs.tf_ecx,    FCN_NULL },
        !            57:        { "eax",        (long *)&ddb_regs.tf_eax,    FCN_NULL },
        !            58:        { "eip",        (long *)&ddb_regs.tf_eip,    FCN_NULL },
        !            59:        { "cs",         (long *)&ddb_regs.tf_cs,     FCN_NULL },
        !            60:        { "eflags",     (long *)&ddb_regs.tf_eflags, FCN_NULL },
        !            61:        { "esp",        (long *)&ddb_regs.tf_esp,    FCN_NULL },
        !            62:        { "ss",         (long *)&ddb_regs.tf_ss,     FCN_NULL },
        !            63: };
        !            64: struct db_variable *db_eregs = db_regs + sizeof(db_regs)/sizeof(db_regs[0]);
        !            65:
        !            66: /*
        !            67:  * Stack trace.
        !            68:  */
        !            69: #define        INKERNEL(va)    (((vaddr_t)(va)) >= VM_MIN_KERNEL_ADDRESS)
        !            70:
        !            71: struct i386_frame {
        !            72:        struct i386_frame       *f_frame;
        !            73:        int                     f_retaddr;
        !            74:        int                     f_arg0;
        !            75: };
        !            76:
        !            77: #define        NONE            0
        !            78: #define        TRAP            1
        !            79: #define        SYSCALL         2
        !            80: #define        INTERRUPT       3
        !            81:
        !            82: db_addr_t      db_trap_symbol_value = 0;
        !            83: db_addr_t      db_syscall_symbol_value = 0;
        !            84: db_addr_t      db_kdintr_symbol_value = 0;
        !            85: boolean_t      db_trace_symbols_found = FALSE;
        !            86:
        !            87: void db_find_trace_symbols(void);
        !            88: int db_numargs(struct i386_frame *);
        !            89: void db_nextframe(struct i386_frame **, db_addr_t *, int *, int,
        !            90:     int (*pr)(const char *, ...));
        !            91:
        !            92: void
        !            93: db_find_trace_symbols(void)
        !            94: {
        !            95:        db_expr_t       value;
        !            96:
        !            97:        if (db_value_of_name("trap", &value))
        !            98:                db_trap_symbol_value = (db_addr_t) value;
        !            99:        if (db_value_of_name("kdintr", &value))
        !           100:                db_kdintr_symbol_value = (db_addr_t) value;
        !           101:        if (db_value_of_name("syscall", &value))
        !           102:                db_syscall_symbol_value = (db_addr_t) value;
        !           103:        db_trace_symbols_found = TRUE;
        !           104: }
        !           105:
        !           106: /*
        !           107:  * Figure out how many arguments were passed into the frame at "fp".
        !           108:  */
        !           109: int
        !           110: db_numargs(struct i386_frame *fp)
        !           111: {
        !           112:        int     *argp;
        !           113:        int     inst;
        !           114:        int     args;
        !           115:        extern char     etext[];
        !           116:
        !           117:        argp = (int *)db_get_value((int)&fp->f_retaddr, 4, FALSE);
        !           118:        if (argp < (int *)VM_MIN_KERNEL_ADDRESS || argp > (int *)etext) {
        !           119:                args = 5;
        !           120:        } else {
        !           121:                inst = db_get_value((int)argp, 4, FALSE);
        !           122:                if ((inst & 0xff) == 0x59)      /* popl %ecx */
        !           123:                        args = 1;
        !           124:                else if ((inst & 0xffff) == 0xc483)     /* addl %n, %esp */
        !           125:                        args = ((inst >> 16) & 0xff) / 4;
        !           126:                else
        !           127:                        args = 5;
        !           128:        }
        !           129:        return (args);
        !           130: }
        !           131:
        !           132: /*
        !           133:  * Figure out the next frame up in the call stack.
        !           134:  * For trap(), we print the address of the faulting instruction and
        !           135:  *   proceed with the calling frame.  We return the ip that faulted.
        !           136:  *   If the trap was caused by jumping through a bogus pointer, then
        !           137:  *   the next line in the backtrace will list some random function as
        !           138:  *   being called.  It should get the argument list correct, though.
        !           139:  *   It might be possible to dig out from the next frame up the name
        !           140:  *   of the function that faulted, but that could get hairy.
        !           141:  */
        !           142: void
        !           143: db_nextframe(struct i386_frame **fp, db_addr_t *ip, int *argp, int is_trap,
        !           144:     int (*pr)(const char *, ...))
        !           145: {
        !           146:
        !           147:        switch (is_trap) {
        !           148:            case NONE:
        !           149:                *ip = (db_addr_t)
        !           150:                        db_get_value((int) &(*fp)->f_retaddr, 4, FALSE);
        !           151:                *fp = (struct i386_frame *)
        !           152:                        db_get_value((int) &(*fp)->f_frame, 4, FALSE);
        !           153:                break;
        !           154:
        !           155:            default: {
        !           156:                struct trapframe *tf;
        !           157:
        !           158:                /* The only argument to trap() or syscall() is the trapframe. */
        !           159:                tf = (struct trapframe *)argp;
        !           160:                switch (is_trap) {
        !           161:                case TRAP:
        !           162:                        (*pr)("--- trap (number %d) ---\n", tf->tf_trapno);
        !           163:                        break;
        !           164:                case SYSCALL:
        !           165:                        (*pr)("--- syscall (number %d) ---\n", tf->tf_eax);
        !           166:                        break;
        !           167:                case INTERRUPT:
        !           168:                        (*pr)("--- interrupt ---\n");
        !           169:                        break;
        !           170:                }
        !           171:                *fp = (struct i386_frame *)tf->tf_ebp;
        !           172:                *ip = (db_addr_t)tf->tf_eip;
        !           173:                break;
        !           174:            }
        !           175:        }
        !           176: }
        !           177:
        !           178: void
        !           179: db_stack_trace_print(db_expr_t addr, boolean_t have_addr, db_expr_t count,
        !           180:     char *modif, int (*pr)(const char *, ...))
        !           181: {
        !           182:        struct i386_frame *frame, *lastframe;
        !           183:        int             *argp;
        !           184:        db_addr_t       callpc;
        !           185:        int             is_trap = 0;
        !           186:        boolean_t       kernel_only = TRUE;
        !           187:        boolean_t       trace_thread = FALSE;
        !           188:        boolean_t       trace_proc = FALSE;
        !           189:
        !           190: #if 0
        !           191:        if (!db_trace_symbols_found)
        !           192:                db_find_trace_symbols();
        !           193: #endif
        !           194:
        !           195:        {
        !           196:                char *cp = modif;
        !           197:                char c;
        !           198:
        !           199:                while ((c = *cp++) != 0) {
        !           200:                        if (c == 't')
        !           201:                                trace_thread = TRUE;
        !           202:                        if (c == 'p')
        !           203:                                trace_proc = TRUE;
        !           204:                        if (c == 'u')
        !           205:                                kernel_only = FALSE;
        !           206:                }
        !           207:        }
        !           208:
        !           209:        if (count == -1)
        !           210:                count = 65535;
        !           211:
        !           212:        if (!have_addr) {
        !           213:                frame = (struct i386_frame *)ddb_regs.tf_ebp;
        !           214:                callpc = (db_addr_t)ddb_regs.tf_eip;
        !           215:        } else if (trace_thread) {
        !           216:                (*pr) ("db_trace.c: can't trace thread\n");
        !           217:        } else if (trace_proc) {
        !           218:                struct proc *p = pfind((pid_t)addr);
        !           219:                if (p == NULL) {
        !           220:                        (*pr) ("db_trace.c: process not found\n");
        !           221:                        return;
        !           222:                }
        !           223:                frame = (struct i386_frame *)p->p_addr->u_pcb.pcb_ebp;
        !           224:                callpc = (db_addr_t)
        !           225:                    db_get_value((int)&frame->f_retaddr, 4, FALSE);
        !           226:        } else {
        !           227:                frame = (struct i386_frame *)addr;
        !           228:                callpc = (db_addr_t)
        !           229:                         db_get_value((int)&frame->f_retaddr, 4, FALSE);
        !           230:        }
        !           231:
        !           232:        lastframe = 0;
        !           233:        while (count && frame != 0) {
        !           234:                int             narg;
        !           235:                char *  name;
        !           236:                db_expr_t       offset;
        !           237:                db_sym_t        sym;
        !           238: #define MAXNARG        16
        !           239:                char    *argnames[MAXNARG], **argnp = NULL;
        !           240:
        !           241:                sym = db_search_symbol(callpc, DB_STGY_ANY, &offset);
        !           242:                db_symbol_values(sym, &name, NULL);
        !           243:
        !           244:                if (lastframe == 0 && sym == NULL) {
        !           245:                        /* Symbol not found, peek at code */
        !           246:                        int     instr = db_get_value(callpc, 4, FALSE);
        !           247:
        !           248:                        offset = 1;
        !           249:                        if ((instr & 0x00ffffff) == 0x00e58955 ||
        !           250:                                        /* enter: pushl %ebp, movl %esp, %ebp */
        !           251:                            (instr & 0x0000ffff) == 0x0000e589
        !           252:                                        /* enter+1: movl %esp, %ebp */) {
        !           253:                                offset = 0;
        !           254:                        }
        !           255:                }
        !           256:                if (INKERNEL((int)frame) && name) {
        !           257:                        if (!strcmp(name, "trap")) {
        !           258:                                is_trap = TRAP;
        !           259:                        } else if (!strcmp(name, "syscall")) {
        !           260:                                is_trap = SYSCALL;
        !           261:                        } else if (!strncmp(name, "Xintr", 5) ||
        !           262:                            !strncmp(name, "Xresume", 7) ||
        !           263:                            !strncmp(name, "Xstray", 6) ||
        !           264:                            !strncmp(name, "Xhold", 5) ||
        !           265:                            !strncmp(name, "Xrecurse", 8) ||
        !           266:                            !strcmp(name, "Xdoreti") ||
        !           267:                            !strncmp(name, "Xsoft", 5)) {
        !           268:                                is_trap = INTERRUPT;
        !           269:                        } else
        !           270:                                goto normal;
        !           271:                        narg = 0;
        !           272:                } else {
        !           273:                normal:
        !           274:                        is_trap = NONE;
        !           275:                        narg = MAXNARG;
        !           276:                        if (db_sym_numargs(sym, &narg, argnames))
        !           277:                                argnp = argnames;
        !           278:                        else
        !           279:                                narg = db_numargs(frame);
        !           280:                }
        !           281:
        !           282:                (*pr)("%s(", name);
        !           283:
        !           284:                if (lastframe == 0 && offset == 0 && !have_addr) {
        !           285:                        /*
        !           286:                         * We have a breakpoint before the frame is set up
        !           287:                         * Use %esp instead
        !           288:                         */
        !           289:                        argp = &((struct i386_frame *)(ddb_regs.tf_esp-4))->f_arg0;
        !           290:                } else {
        !           291:                        argp = &frame->f_arg0;
        !           292:                }
        !           293:
        !           294:                while (narg) {
        !           295:                        if (argnp)
        !           296:                                (*pr)("%s=", *argnp++);
        !           297:                        (*pr)("%x", db_get_value((int)argp, 4, FALSE));
        !           298:                        argp++;
        !           299:                        if (--narg != 0)
        !           300:                                (*pr)(",");
        !           301:                }
        !           302:                (*pr)(") at ");
        !           303:                db_printsym(callpc, DB_STGY_PROC, pr);
        !           304:                (*pr)("\n");
        !           305:
        !           306:                if (lastframe == 0 && offset == 0 && !have_addr) {
        !           307:                        /* Frame really belongs to next callpc */
        !           308:                        lastframe = (struct i386_frame *)(ddb_regs.tf_esp-4);
        !           309:                        callpc = (db_addr_t)
        !           310:                                 db_get_value((int)&lastframe->f_retaddr, 4, FALSE);
        !           311:                        continue;
        !           312:                }
        !           313:
        !           314:                lastframe = frame;
        !           315:                db_nextframe(&frame, &callpc, &frame->f_arg0, is_trap, pr);
        !           316:
        !           317:                if (frame == 0) {
        !           318:                        /* end of chain */
        !           319:                        break;
        !           320:                }
        !           321:                if (INKERNEL((int)frame)) {
        !           322:                        /* staying in kernel */
        !           323:                        if (frame <= lastframe) {
        !           324:                                (*pr)("Bad frame pointer: %p\n", frame);
        !           325:                                break;
        !           326:                        }
        !           327:                } else if (INKERNEL((int)lastframe)) {
        !           328:                        /* switch from user to kernel */
        !           329:                        if (kernel_only)
        !           330:                                break;  /* kernel stack only */
        !           331:                } else {
        !           332:                        /* in user */
        !           333:                        if (frame <= lastframe) {
        !           334:                                (*pr)("Bad user frame pointer: %p\n",
        !           335:                                          frame);
        !           336:                                break;
        !           337:                        }
        !           338:                }
        !           339:                --count;
        !           340:        }
        !           341:
        !           342:        if (count && is_trap != NONE) {
        !           343:                db_printsym(callpc, DB_STGY_XTRN, pr);
        !           344:                (*pr)(":\n");
        !           345:        }
        !           346: }

CVSweb