[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     ! 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