[BACK]Return to db_run.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / ddb

Annotation of src/sys/ddb/db_run.c, Revision 1.20

1.20    ! augustss    1: /*     $NetBSD: db_run.c,v 1.19 1999/04/21 00:00:06 thorpej Exp $      */
1.5       cgd         2:
1.1       cgd         3: /*
                      4:  * Mach Operating System
1.11      thorpej     5:  * Copyright (c) 1993-1990 Carnegie Mellon University
1.1       cgd         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:  *
1.18      pk         14:  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
1.1       cgd        15:  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
                     16:  * 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.
1.2       cgd        27:  *
1.1       cgd        28:  *     Author: David B. Golub, Carnegie Mellon University
                     29:  *     Date:   7/90
                     30:  */
                     31:
                     32: /*
                     33:  * Commands to run process.
                     34:  */
1.15      jonathan   35:
                     36: #include "opt_ddb.h"
                     37:
1.7       mycroft    38: #include <sys/param.h>
                     39: #include <sys/proc.h>
                     40:
                     41: #include <machine/db_machdep.h>
                     42:
1.6       mycroft    43: #include <ddb/db_run.h>
1.14      pk         44: #include <ddb/db_access.h>
                     45: #include <ddb/db_break.h>
                     46:
                     47: #ifdef SOFTWARE_SSTEP
                     48: static void    db_set_temp_breakpoint __P((db_breakpoint_t, db_addr_t));
                     49: static void    db_delete_temp_breakpoint __P((db_breakpoint_t));
                     50: static struct  db_breakpoint   db_not_taken_bkpt;
                     51: static struct  db_breakpoint   db_taken_bkpt;
                     52: #endif
                     53:
                     54: #if defined(DDB)
1.1       cgd        55: #include <ddb/db_lex.h>
1.8       christos   56: #include <ddb/db_watch.h>
                     57: #include <ddb/db_output.h>
                     58: #include <ddb/db_sym.h>
                     59: #include <ddb/db_extern.h>
1.1       cgd        60:
                     61: int    db_run_mode;
                     62: #define        STEP_NONE       0
                     63: #define        STEP_ONCE       1
                     64: #define        STEP_RETURN     2
                     65: #define        STEP_CALLT      3
                     66: #define        STEP_CONTINUE   4
                     67: #define STEP_INVISIBLE 5
                     68: #define        STEP_COUNT      6
                     69:
                     70: boolean_t      db_sstep_print;
                     71: int            db_loop_count;
                     72: int            db_call_depth;
                     73:
                     74: boolean_t
1.6       mycroft    75: db_stop_at_pc(regs, is_breakpoint)
                     76:        db_regs_t *regs;
1.1       cgd        77:        boolean_t       *is_breakpoint;
                     78: {
1.20    ! augustss   79:        db_addr_t       pc;
        !            80:        db_breakpoint_t bkpt;
1.1       cgd        81:
1.13      pk         82:        pc = PC_REGS(regs);
                     83:
1.19      thorpej    84: #ifdef FIXUP_PC_AFTER_BREAK
                     85:        if (*is_breakpoint) {
                     86:                /*
                     87:                 * Breakpoint trap.  Regardless if we treat this as a
                     88:                 * real breakpoint (e.g. software single-step), fix up the PC.
                     89:                 */
                     90:                FIXUP_PC_AFTER_BREAK(regs);
                     91:                pc = PC_REGS(regs);
                     92:        }
                     93: #endif
                     94:
1.13      pk         95: #ifdef SOFTWARE_SSTEP
                     96:        /*
1.19      thorpej    97:         * If we stopped at one of the single-step breakpoints, say it's not
                     98:         * really a breakpoint so that we don't skip over the real instruction.
1.13      pk         99:         */
1.14      pk        100:        if (db_taken_bkpt.address == pc || db_not_taken_bkpt.address == pc)
1.13      pk        101:                *is_breakpoint = FALSE;
1.19      thorpej   102: #endif /* SOFTWARE_SSTEP */
1.13      pk        103:
1.6       mycroft   104:        db_clear_single_step(regs);
1.1       cgd       105:        db_clear_breakpoints();
                    106:        db_clear_watchpoints();
                    107:
                    108:        /*
                    109:         * Now check for a breakpoint at this address.
                    110:         */
                    111:        bkpt = db_find_breakpoint_here(pc);
                    112:        if (bkpt) {
                    113:            if (--bkpt->count == 0) {
                    114:                bkpt->count = bkpt->init_count;
                    115:                *is_breakpoint = TRUE;
                    116:                return (TRUE);  /* stop here */
                    117:            }
                    118:        } else if (*is_breakpoint) {
1.12      pk        119: #ifdef PC_ADVANCE
                    120:                PC_ADVANCE(regs);
                    121: #else
1.6       mycroft   122:                PC_REGS(regs) += BKPT_SIZE;
1.12      pk        123: #endif
1.1       cgd       124:        }
                    125:
                    126:        *is_breakpoint = FALSE;
                    127:
                    128:        if (db_run_mode == STEP_INVISIBLE) {
                    129:            db_run_mode = STEP_CONTINUE;
                    130:            return (FALSE);     /* continue */
                    131:        }
                    132:        if (db_run_mode == STEP_COUNT) {
                    133:            return (FALSE); /* continue */
                    134:        }
                    135:        if (db_run_mode == STEP_ONCE) {
                    136:            if (--db_loop_count > 0) {
                    137:                if (db_sstep_print) {
                    138:                    db_printf("\t\t");
                    139:                    db_print_loc_and_inst(pc);
                    140:                    db_printf("\n");
                    141:                }
                    142:                return (FALSE); /* continue */
                    143:            }
                    144:        }
                    145:        if (db_run_mode == STEP_RETURN) {
                    146:            db_expr_t ins = db_get_value(pc, sizeof(int), FALSE);
                    147:
                    148:            /* continue until matching return */
                    149:
                    150:            if (!inst_trap_return(ins) &&
                    151:                (!inst_return(ins) || --db_call_depth != 0)) {
                    152:                if (db_sstep_print) {
                    153:                    if (inst_call(ins) || inst_return(ins)) {
1.20    ! augustss  154:                        int i;
1.1       cgd       155:
                    156:                        db_printf("[after %6d]     ", db_inst_count);
                    157:                        for (i = db_call_depth; --i > 0; )
                    158:                            db_printf("  ");
                    159:                        db_print_loc_and_inst(pc);
                    160:                        db_printf("\n");
                    161:                    }
                    162:                }
                    163:                if (inst_call(ins))
                    164:                    db_call_depth++;
                    165:                return (FALSE); /* continue */
                    166:            }
                    167:        }
                    168:        if (db_run_mode == STEP_CALLT) {
                    169:            db_expr_t ins = db_get_value(pc, sizeof(int), FALSE);
                    170:
                    171:            /* continue until call or return */
                    172:
                    173:            if (!inst_call(ins) &&
                    174:                !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
1.6       mycroft   184: db_restart_at_pc(regs, watchpt)
                    185:        db_regs_t *regs;
1.1       cgd       186:        boolean_t watchpt;
                    187: {
1.20    ! augustss  188:        db_addr_t pc = PC_REGS(regs);
1.1       cgd       189:
                    190:        if ((db_run_mode == STEP_COUNT) ||
                    191:            (db_run_mode == STEP_RETURN) ||
                    192:            (db_run_mode == STEP_CALLT)) {
                    193:            db_expr_t           ins;
                    194:
                    195:            /*
                    196:             * We are about to execute this instruction,
                    197:             * so count it now.
                    198:             */
                    199:            ins = db_get_value(pc, sizeof(int), FALSE);
                    200:            db_inst_count++;
                    201:            db_load_count += inst_load(ins);
                    202:            db_store_count += inst_store(ins);
1.11      thorpej   203:
                    204: #ifdef SOFTWARE_SSTEP
                    205:            /*
                    206:             * Account for instructions in delay slots.
                    207:             */
                    208:            {
                    209:                db_addr_t brpc;
                    210:
                    211:                brpc = next_instr_address(pc, TRUE);
1.16      mycroft   212:                if ((brpc != pc) &&
                    213:                    (inst_branch(ins) || inst_call(ins) || inst_return(ins))) {
1.11      thorpej   214:                    ins = db_get_value(brpc, sizeof(int), FALSE);
                    215:                    db_inst_count++;
                    216:                    db_load_count += inst_load(ins);
                    217:                    db_store_count += inst_store(ins);
                    218:                }
1.1       cgd       219:            }
1.9       cgd       220: #endif
1.1       cgd       221:        }
                    222:
                    223:        if (db_run_mode == STEP_CONTINUE) {
                    224:            if (watchpt || db_find_breakpoint_here(pc)) {
                    225:                /*
                    226:                 * Step over breakpoint/watchpoint.
                    227:                 */
                    228:                db_run_mode = STEP_INVISIBLE;
1.6       mycroft   229:                db_set_single_step(regs);
1.1       cgd       230:            } else {
                    231:                db_set_breakpoints();
                    232:                db_set_watchpoints();
                    233:            }
                    234:        } else {
1.6       mycroft   235:            db_set_single_step(regs);
1.1       cgd       236:        }
                    237: }
                    238:
                    239: void
                    240: db_single_step(regs)
                    241:        db_regs_t *regs;
                    242: {
                    243:        if (db_run_mode == STEP_CONTINUE) {
                    244:            db_run_mode = STEP_INVISIBLE;
                    245:            db_set_single_step(regs);
                    246:        }
                    247: }
                    248:
1.14      pk        249:
                    250: extern int     db_cmd_loop_done;
                    251:
                    252: /* single-step */
                    253: /*ARGSUSED*/
                    254: void
                    255: db_single_step_cmd(addr, have_addr, count, modif)
                    256:        db_expr_t       addr;
                    257:        int             have_addr;
                    258:        db_expr_t       count;
                    259:        char *          modif;
                    260: {
                    261:        boolean_t       print = FALSE;
                    262:
                    263:        if (count == -1)
                    264:            count = 1;
                    265:
                    266:        if (modif[0] == 'p')
                    267:            print = TRUE;
                    268:
                    269:        db_run_mode = STEP_ONCE;
                    270:        db_loop_count = count;
                    271:        db_sstep_print = print;
                    272:        db_inst_count = 0;
                    273:        db_load_count = 0;
                    274:        db_store_count = 0;
                    275:
                    276:        db_cmd_loop_done = 1;
                    277: }
                    278:
                    279: /* trace and print until call/return */
                    280: /*ARGSUSED*/
                    281: void
                    282: db_trace_until_call_cmd(addr, have_addr, count, modif)
                    283:        db_expr_t       addr;
                    284:        int             have_addr;
                    285:        db_expr_t       count;
                    286:        char *          modif;
                    287: {
                    288:        boolean_t       print = FALSE;
                    289:
                    290:        if (modif[0] == 'p')
                    291:            print = TRUE;
                    292:
                    293:        db_run_mode = STEP_CALLT;
                    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: /*ARGSUSED*/
                    303: void
                    304: db_trace_until_matching_cmd(addr, have_addr, count, modif)
                    305:        db_expr_t       addr;
                    306:        int             have_addr;
                    307:        db_expr_t       count;
                    308:        char *          modif;
                    309: {
                    310:        boolean_t       print = FALSE;
                    311:
                    312:        if (modif[0] == 'p')
                    313:            print = TRUE;
                    314:
                    315:        db_run_mode = STEP_RETURN;
                    316:        db_call_depth = 1;
                    317:        db_sstep_print = print;
                    318:        db_inst_count = 0;
                    319:        db_load_count = 0;
                    320:        db_store_count = 0;
                    321:
                    322:        db_cmd_loop_done = 1;
                    323: }
                    324:
                    325: /* continue */
                    326: /*ARGSUSED*/
                    327: void
                    328: db_continue_cmd(addr, have_addr, count, modif)
                    329:        db_expr_t       addr;
                    330:        int             have_addr;
                    331:        db_expr_t       count;
                    332:        char *          modif;
                    333: {
                    334:        if (modif[0] == 'c')
                    335:            db_run_mode = STEP_COUNT;
                    336:        else
                    337:            db_run_mode = STEP_CONTINUE;
                    338:        db_inst_count = 0;
                    339:        db_load_count = 0;
                    340:        db_store_count = 0;
                    341:
                    342:        db_cmd_loop_done = 1;
                    343: }
                    344: #endif /* DDB */
                    345:
1.11      thorpej   346: #ifdef SOFTWARE_SSTEP
1.1       cgd       347: /*
                    348:  *     Software implementation of single-stepping.
                    349:  *     If your machine does not have a trace mode
                    350:  *     similar to the vax or sun ones you can use
                    351:  *     this implementation, done for the mips.
                    352:  *     Just define the above conditional and provide
                    353:  *     the functions/macros defined below.
                    354:  *
1.11      thorpej   355:  * boolean_t inst_branch(int inst)
                    356:  * boolean_t inst_call(int inst)
                    357:  *     returns TRUE if the instruction might branch
                    358:  *
                    359:  * boolean_t inst_unconditional_flow_transfer(int inst)
                    360:  *     returns TRUE if the instruction is an unconditional
                    361:  *     transter of flow (i.e. unconditional branch)
                    362:  *
                    363:  * db_addr_t branch_taken(int inst, db_addr_t pc, db_regs_t *regs)
                    364:  *     returns the target address of the branch
                    365:  *
                    366:  * db_addr_t next_instr_address(db_addr_t pc, boolean_t bd)
                    367:  *     returns the address of the first instruction following the
                    368:  *     one at "pc", which is either in the taken path of the branch
                    369:  *     (bd == TRUE) or not.  This is for machines (e.g. mips) with
                    370:  *     branch delays.
1.1       cgd       371:  *
                    372:  *     A single-step may involve at most 2 breakpoints -
                    373:  *     one for branch-not-taken and one for branch taken.
                    374:  *     If one of these addresses does not already have a breakpoint,
                    375:  *     we allocate a breakpoint and save it here.
                    376:  *     These breakpoints are deleted on return.
                    377:  */
                    378:
1.14      pk        379: #if !defined(DDB)
                    380: /* XXX - don't check for existing breakpoints in KGDB-only case */
                    381: #define db_find_breakpoint_here(pc)    (0)
                    382: #endif
                    383:
1.1       cgd       384: void
                    385: db_set_single_step(regs)
1.20    ! augustss  386:        db_regs_t *regs;
1.1       cgd       387: {
1.13      pk        388:        db_addr_t pc = PC_REGS(regs), brpc = pc;
1.11      thorpej   389:        boolean_t unconditional;
                    390:        unsigned int inst;
1.1       cgd       391:
                    392:        /*
                    393:         *      User was stopped at pc, e.g. the instruction
                    394:         *      at pc was not executed.
                    395:         */
                    396:        inst = db_get_value(pc, sizeof(int), FALSE);
1.16      mycroft   397:        if (inst_branch(inst) || inst_call(inst) || inst_return(inst)) {
1.11      thorpej   398:                brpc = branch_taken(inst, pc, regs);
                    399:                if (brpc != pc) {       /* self-branches are hopeless */
1.14      pk        400:                        db_set_temp_breakpoint(&db_taken_bkpt, brpc);
1.11      thorpej   401:                } else
1.14      pk        402:                        db_taken_bkpt.address = 0;
1.11      thorpej   403:                pc = next_instr_address(pc, TRUE);
                    404:        }
                    405:
                    406:        /*
                    407:         *      Check if this control flow instruction is an
                    408:         *      unconditional transfer.
                    409:         */
                    410:        unconditional = inst_unconditional_flow_transfer(inst);
                    411:
                    412:        pc = next_instr_address(pc, FALSE);
1.1       cgd       413:
1.11      thorpej   414:        /*
                    415:         *      We only set the sequential breakpoint if previous
                    416:         *      instruction was not an unconditional change of flow
                    417:         *      control.  If the previous instruction is an
                    418:         *      unconditional change of flow control, setting a
                    419:         *      breakpoint in the next sequential location may set
                    420:         *      a breakpoint in data or in another routine, which
                    421:         *      could screw up in either the program or the debugger.
                    422:         *      (Consider, for instance, that the next sequential
                    423:         *      instruction is the start of a routine needed by the
                    424:         *      debugger.)
1.13      pk        425:         *
                    426:         *      Also, don't set both the taken and not-taken breakpoints
                    427:         *      in the same place even if the MD code would otherwise
                    428:         *      have us do so.
1.11      thorpej   429:         */
1.13      pk        430:        if (unconditional == FALSE &&
                    431:            db_find_breakpoint_here(pc) == 0 &&
                    432:            pc != brpc)
1.14      pk        433:                db_set_temp_breakpoint(&db_not_taken_bkpt, pc);
1.11      thorpej   434:        else
1.14      pk        435:                db_not_taken_bkpt.address = 0;
1.1       cgd       436: }
                    437:
                    438: void
                    439: db_clear_single_step(regs)
                    440:        db_regs_t *regs;
                    441: {
                    442:
1.14      pk        443:        if (db_taken_bkpt.address != 0)
                    444:                db_delete_temp_breakpoint(&db_taken_bkpt);
1.1       cgd       445:
1.14      pk        446:        if (db_not_taken_bkpt.address != 0)
                    447:                db_delete_temp_breakpoint(&db_not_taken_bkpt);
1.1       cgd       448: }
                    449:
                    450: void
1.14      pk        451: db_set_temp_breakpoint(bkpt, addr)
                    452:        db_breakpoint_t bkpt;
                    453:        db_addr_t       addr;
1.1       cgd       454: {
                    455:
1.14      pk        456:        bkpt->map = NULL;
                    457:        bkpt->address = addr;
                    458:        /* bkpt->flags = BKPT_TEMP;     - this is not used */
                    459:        bkpt->init_count = 1;
                    460:        bkpt->count = 1;
1.1       cgd       461:
1.14      pk        462:        bkpt->bkpt_inst = db_get_value(bkpt->address, BKPT_SIZE, FALSE);
                    463:        db_put_value(bkpt->address, BKPT_SIZE, BKPT_SET(bkpt->bkpt_inst));
1.1       cgd       464: }
                    465:
                    466: void
1.14      pk        467: db_delete_temp_breakpoint(bkpt)
                    468:        db_breakpoint_t bkpt;
1.1       cgd       469: {
1.14      pk        470:        db_put_value(bkpt->address, BKPT_SIZE, bkpt->bkpt_inst);
                    471:        bkpt->address = 0;
1.1       cgd       472: }
                    473:
1.14      pk        474: #endif /* SOFTWARE_SSTEP */

CVSweb <webmaster@jp.NetBSD.org>