[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

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