[BACK]Return to db_run.c CVS log [TXT][DIR] Up to [local] / sys / ddb

Annotation of sys/ddb/db_run.c, Revision 1.1.1.1

1.1       nbrk        1: /*     $OpenBSD: db_run.c,v 1.19 2006/03/13 06:23:20 jsg Exp $ */
                      2: /*     $NetBSD: db_run.c,v 1.8 1996/02/05 01:57:12 christos Exp $      */
                      3:
                      4: /*
                      5:  * Mach Operating System
                      6:  * Copyright (c) 1993,1992,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:  *     Author: David B. Golub, Carnegie Mellon University
                     30:  *     Date:   7/90
                     31:  */
                     32:
                     33: /*
                     34:  * Commands to run process.
                     35:  */
                     36: #include <sys/param.h>
                     37: #include <sys/proc.h>
                     38:
                     39: #include <uvm/uvm_extern.h>
                     40:
                     41: #include <machine/db_machdep.h>
                     42:
                     43: #include <ddb/db_run.h>
                     44: #include <ddb/db_break.h>
                     45: #include <ddb/db_access.h>
                     46:
                     47: #ifdef SOFTWARE_SSTEP
                     48: db_breakpoint_t        db_not_taken_bkpt = 0;
                     49: db_breakpoint_t        db_taken_bkpt = 0;
                     50: #endif
                     51:
                     52: int            db_inst_count;
                     53: int            db_load_count;
                     54: int            db_store_count;
                     55:
                     56: #ifndef KGDB
                     57:
                     58: #include <ddb/db_lex.h>
                     59: #include <ddb/db_watch.h>
                     60: #include <ddb/db_output.h>
                     61: #include <ddb/db_sym.h>
                     62: #include <ddb/db_extern.h>
                     63:
                     64: int    db_run_mode;
                     65: #define        STEP_NONE       0
                     66: #define        STEP_ONCE       1
                     67: #define        STEP_RETURN     2
                     68: #define        STEP_CALLT      3
                     69: #define        STEP_CONTINUE   4
                     70: #define STEP_INVISIBLE 5
                     71: #define        STEP_COUNT      6
                     72:
                     73: boolean_t      db_sstep_print;
                     74: int            db_loop_count;
                     75: int            db_call_depth;
                     76:
                     77: boolean_t
                     78: db_stop_at_pc(db_regs_t *regs, boolean_t *is_breakpoint)
                     79: {
                     80:        db_addr_t       pc, old_pc;
                     81:        db_breakpoint_t bkpt;
                     82:
                     83:        db_clear_breakpoints();
                     84:        db_clear_watchpoints();
                     85:        old_pc = pc = PC_REGS(regs);
                     86:
                     87: #ifdef FIXUP_PC_AFTER_BREAK
                     88:        if (*is_breakpoint) {
                     89:                /*
                     90:                 * Breakpoint trap.  Fix up the PC if the
                     91:                 * machine requires it.
                     92:                 */
                     93:                FIXUP_PC_AFTER_BREAK(regs);
                     94:                pc = PC_REGS(regs);
                     95:        }
                     96: #endif
                     97:
                     98:        /*
                     99:         * Now check for a breakpoint at this address.
                    100:         */
                    101:        bkpt = db_find_breakpoint_here(pc);
                    102:        if (bkpt) {
                    103:                if (--bkpt->count == 0) {
                    104:                        db_clear_single_step(regs);
                    105:                        bkpt->count = bkpt->init_count;
                    106:                        *is_breakpoint = TRUE;
                    107:                        return (TRUE);  /* stop here */
                    108:                }
                    109:        } else if (*is_breakpoint
                    110: #ifdef SOFTWARE_SSTEP
                    111:            && !((db_taken_bkpt && db_taken_bkpt->address == pc) ||
                    112:            (db_not_taken_bkpt && db_not_taken_bkpt->address == pc))
                    113: #endif
                    114:            ) {
                    115: #ifdef PC_ADVANCE
                    116:                PC_ADVANCE(regs);
                    117: #else
                    118: # ifdef SET_PC_REGS
                    119:                SET_PC_REGS(regs, old_pc);
                    120: # else
                    121:                PC_REGS(regs) = old_pc;
                    122: # endif
                    123: #endif
                    124:        }
                    125:        db_clear_single_step(regs);
                    126:
                    127:        *is_breakpoint = FALSE;
                    128:
                    129:        if (db_run_mode == STEP_INVISIBLE) {
                    130:                db_run_mode = STEP_CONTINUE;
                    131:                return (FALSE); /* continue */
                    132:        }
                    133:        if (db_run_mode == STEP_COUNT) {
                    134:                return (FALSE); /* continue */
                    135:        }
                    136:        if (db_run_mode == STEP_ONCE) {
                    137:                if (--db_loop_count > 0) {
                    138:                        if (db_sstep_print) {
                    139:                                db_printf("\t\t");
                    140:                                db_print_loc_and_inst(pc);
                    141:                                db_printf("\n");
                    142:                        }
                    143:                        return (FALSE); /* continue */
                    144:                }
                    145:        }
                    146:        if (db_run_mode == STEP_RETURN) {
                    147:            db_expr_t ins = db_get_value(pc, sizeof(int), FALSE);
                    148:
                    149:            /* continue until matching return */
                    150:
                    151:            if (!inst_trap_return(ins) &&
                    152:                (!inst_return(ins) || --db_call_depth != 0)) {
                    153:                if (db_sstep_print) {
                    154:                    if (inst_call(ins) || inst_return(ins)) {
                    155:                        int i;
                    156:
                    157:                        db_printf("[after %6d]     ", db_inst_count);
                    158:                        for (i = db_call_depth; --i > 0; )
                    159:                            db_printf("  ");
                    160:                        db_print_loc_and_inst(pc);
                    161:                        db_printf("\n");
                    162:                    }
                    163:                }
                    164:                if (inst_call(ins))
                    165:                    db_call_depth++;
                    166:                return (FALSE); /* continue */
                    167:            }
                    168:        }
                    169:        if (db_run_mode == STEP_CALLT) {
                    170:            db_expr_t ins = db_get_value(pc, sizeof(int), FALSE);
                    171:
                    172:            /* continue until call or return */
                    173:
                    174:            if (!inst_call(ins) && !inst_return(ins) &&
                    175:                !inst_trap_return(ins)) {
                    176:                return (FALSE); /* continue */
                    177:            }
                    178:        }
                    179:        db_run_mode = STEP_NONE;
                    180:        return (TRUE);
                    181: }
                    182:
                    183: void
                    184: db_restart_at_pc(db_regs_t *regs, boolean_t watchpt)
                    185: {
                    186:        db_addr_t pc = PC_REGS(regs);
                    187:
                    188:        if ((db_run_mode == STEP_COUNT) || (db_run_mode == STEP_RETURN) ||
                    189:            (db_run_mode == STEP_CALLT)) {
                    190:                db_expr_t       ins;
                    191:
                    192:                /*
                    193:                 * We are about to execute this instruction,
                    194:                 * so count it now.
                    195:                 */
                    196:                ins = db_get_value(pc, sizeof(int), FALSE);
                    197:                db_inst_count++;
                    198:                db_load_count += inst_load(ins);
                    199:                db_store_count += inst_store(ins);
                    200: #ifdef SOFTWARE_SSTEP
                    201:                /* XXX works on mips, but... */
                    202:                if (inst_branch(ins) || inst_call(ins)) {
                    203:                        ins = db_get_value(next_instr_address(pc, 1),
                    204:                            sizeof(int), FALSE);
                    205:                        db_inst_count++;
                    206:                        db_load_count += inst_load(ins);
                    207:                        db_store_count += inst_store(ins);
                    208:                }
                    209: #endif /* SOFTWARE_SSTEP */
                    210:        }
                    211:
                    212:        if (db_run_mode == STEP_CONTINUE) {
                    213:                if (watchpt || db_find_breakpoint_here(pc)) {
                    214:                        /*
                    215:                         * Step over breakpoint/watchpoint.
                    216:                         */
                    217:                        db_run_mode = STEP_INVISIBLE;
                    218:                        db_set_single_step(regs);
                    219:                } else {
                    220:                        db_set_breakpoints();
                    221:                        db_set_watchpoints();
                    222:                }
                    223:        } else {
                    224:                db_set_single_step(regs);
                    225:        }
                    226: }
                    227:
                    228: void
                    229: db_single_step(db_regs_t *regs)
                    230: {
                    231:        if (db_run_mode == STEP_CONTINUE) {
                    232:            db_run_mode = STEP_INVISIBLE;
                    233:            db_set_single_step(regs);
                    234:        }
                    235: }
                    236:
                    237: extern int     db_cmd_loop_done;
                    238:
                    239: /* single-step */
                    240: /*ARGSUSED*/
                    241: void
                    242: db_single_step_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
                    243: {
                    244:        boolean_t       print = FALSE;
                    245:
                    246:        if (count == -1)
                    247:            count = 1;
                    248:
                    249:        if (modif[0] == 'p')
                    250:            print = TRUE;
                    251:
                    252:        db_run_mode = STEP_ONCE;
                    253:        db_loop_count = count;
                    254:        db_sstep_print = print;
                    255:        db_inst_count = 0;
                    256:        db_load_count = 0;
                    257:        db_store_count = 0;
                    258:
                    259:        db_cmd_loop_done = 1;
                    260: }
                    261:
                    262: /* trace and print until call/return */
                    263: /*ARGSUSED*/
                    264: void
                    265: db_trace_until_call_cmd(db_expr_t addr, int have_addr, db_expr_t count,
                    266:     char *modif)
                    267: {
                    268:        boolean_t       print = FALSE;
                    269:
                    270:        if (modif[0] == 'p')
                    271:            print = TRUE;
                    272:
                    273:        db_run_mode = STEP_CALLT;
                    274:        db_sstep_print = print;
                    275:        db_inst_count = 0;
                    276:        db_load_count = 0;
                    277:        db_store_count = 0;
                    278:
                    279:        db_cmd_loop_done = 1;
                    280: }
                    281:
                    282: /*ARGSUSED*/
                    283: void
                    284: db_trace_until_matching_cmd(db_expr_t addr, int have_addr, db_expr_t count,
                    285:     char *modif)
                    286: {
                    287:        boolean_t       print = FALSE;
                    288:
                    289:        if (modif[0] == 'p')
                    290:            print = TRUE;
                    291:
                    292:        db_run_mode = STEP_RETURN;
                    293:        db_call_depth = 1;
                    294:        db_sstep_print = print;
                    295:        db_inst_count = 0;
                    296:        db_load_count = 0;
                    297:        db_store_count = 0;
                    298:
                    299:        db_cmd_loop_done = 1;
                    300: }
                    301:
                    302: /* continue */
                    303: /*ARGSUSED*/
                    304: void
                    305: db_continue_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
                    306: {
                    307:        if (modif[0] == 'c')
                    308:            db_run_mode = STEP_COUNT;
                    309:        else
                    310:            db_run_mode = STEP_CONTINUE;
                    311:        db_inst_count = 0;
                    312:        db_load_count = 0;
                    313:        db_store_count = 0;
                    314:
                    315:        db_cmd_loop_done = 1;
                    316: }
                    317: #endif /* NO KGDB */
                    318:
                    319: #ifdef SOFTWARE_SSTEP
                    320: /*
                    321:  *     Software implementation of single-stepping.
                    322:  *     If your machine does not have a trace mode
                    323:  *     similar to the vax or sun ones you can use
                    324:  *     this implementation, done for the mips.
                    325:  *     Just define the above conditional and provide
                    326:  *     the functions/macros defined below.
                    327:  *
                    328:  * extern boolean_t
                    329:  *     inst_branch(ins),       returns true if the instruction might branch
                    330:  * extern unsigned
                    331:  *     branch_taken(ins, pc, getreg_val, regs),
                    332:  *                             return the address the instruction might
                    333:  *                             branch to
                    334:  *     getreg_val(regs, reg),  return the value of a user register,
                    335:  *                             as indicated in the hardware instruction
                    336:  *                             encoding, e.g. 8 for r8
                    337:  *
                    338:  * next_instr_address(pc, bd)  returns the address of the first
                    339:  *                             instruction following the one at "pc",
                    340:  *                             which is either in the taken path of
                    341:  *                             the branch (bd==1) or not.  This is
                    342:  *                             for machines (mips) with branch delays.
                    343:  *
                    344:  *     A single-step may involve at most 2 breakpoints -
                    345:  *     one for branch-not-taken and one for branch taken.
                    346:  *     If one of these addresses does not already have a breakpoint,
                    347:  *     we allocate a breakpoint and save it here.
                    348:  *     These breakpoints are deleted on return.
                    349:  */
                    350:
                    351: void
                    352: db_set_single_step(db_regs_t *regs)
                    353: {
                    354:        db_addr_t pc = PC_REGS(regs);
                    355: #ifndef SOFTWARE_SSTEP_EMUL
                    356:        db_addr_t brpc;
                    357:        u_int inst;
                    358:
                    359:        /*
                    360:         * User was stopped at pc, e.g. the instruction
                    361:         * at pc was not executed.
                    362:         */
                    363:        inst = db_get_value(pc, sizeof(int), FALSE);
                    364:        if (inst_branch(inst) || inst_call(inst) || inst_return(inst)) {
                    365:            brpc = branch_taken(inst, pc, getreg_val, regs);
                    366:            if (brpc != pc) {   /* self-branches are hopeless */
                    367:                db_taken_bkpt = db_set_temp_breakpoint(brpc);
                    368:            }
                    369: #if 0
                    370:            /* XXX this seems like a true bug, no?  */
                    371:            pc = next_instr_address(pc, 1);
                    372: #endif
                    373:        }
                    374: #endif /*SOFTWARE_SSTEP_EMUL*/
                    375:        pc = next_instr_address(pc, 0);
                    376:        db_not_taken_bkpt = db_set_temp_breakpoint(pc);
                    377: }
                    378:
                    379: void
                    380: db_clear_single_step(db_regs_t *regs)
                    381: {
                    382:        if (db_taken_bkpt != 0) {
                    383:            db_delete_temp_breakpoint(db_taken_bkpt);
                    384:            db_taken_bkpt = 0;
                    385:        }
                    386:        if (db_not_taken_bkpt != 0) {
                    387:            db_delete_temp_breakpoint(db_not_taken_bkpt);
                    388:            db_not_taken_bkpt = 0;
                    389:        }
                    390: }
                    391:
                    392: #endif /* SOFTWARE_SSTEP */

CVSweb