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