|
|
1.1 ! root 1: /* ! 2: * Mach Operating System ! 3: * Copyright (c) 1991,1990 Carnegie Mellon University ! 4: * All Rights Reserved. ! 5: * ! 6: * Permission to use, copy, modify and distribute this software and its ! 7: * documentation is hereby granted, provided that both the copyright ! 8: * notice and this permission notice appear in all copies of the ! 9: * software, derivative works or modified versions, and any portions ! 10: * thereof, and that both notices appear in supporting documentation. ! 11: * ! 12: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS ! 13: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR ! 14: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. ! 15: * ! 16: * Carnegie Mellon requests users of this software to return to ! 17: * ! 18: * Software Distribution Coordinator or [email protected] ! 19: * School of Computer Science ! 20: * Carnegie Mellon University ! 21: * Pittsburgh PA 15213-3890 ! 22: * ! 23: * any improvements or extensions that they make and grant Carnegie the ! 24: * rights to redistribute these changes. ! 25: */ ! 26: /* ! 27: * HISTORY ! 28: * $Log: db_run.c,v $ ! 29: * Revision 1.1 1992/03/25 21:45:24 pace ! 30: * Initial revision ! 31: * ! 32: * Revision 2.5 91/02/05 17:06:58 mrt ! 33: * Changed to new Mach copyright ! 34: * [91/01/31 16:19:05 mrt] ! 35: * ! 36: * Revision 2.4 91/01/08 15:09:10 rpd ! 37: * Fixed bug in db_restart_at_pc. ! 38: * [90/12/07 rpd] ! 39: * Added STEP_COUNT and count option to db_continue_cmd. ! 40: * Changed db_stop_at_pc to return (modified) is_breakpoint. ! 41: * Fixed db_stop_at_pc to print newlines in the right places. ! 42: * [90/11/27 rpd] ! 43: * ! 44: * Revision 2.3 90/10/25 14:43:59 rwd ! 45: * Changed db_find_breakpoint to db_find_breakpoint_here. ! 46: * [90/10/18 rpd] ! 47: * ! 48: * Fixed db_set_single_step to pass regs to branch_taken. ! 49: * Added watchpoint argument to db_restart_at_pc. ! 50: * [90/10/17 rpd] ! 51: * Generalized the watchpoint support. ! 52: * [90/10/16 rwd] ! 53: * Added watchpoint support. ! 54: * [90/10/16 rpd] ! 55: * ! 56: * Revision 2.2 90/08/27 21:51:59 dbg ! 57: * Fixed names for single-step functions. ! 58: * [90/08/20 af] ! 59: * Reduce lint. ! 60: * [90/08/07 dbg] ! 61: * Created. ! 62: * [90/07/25 dbg] ! 63: * ! 64: */ ! 65: /* ! 66: * Author: David B. Golub, Carnegie Mellon University ! 67: * Date: 7/90 ! 68: */ ! 69: ! 70: /* ! 71: * Commands to run process. ! 72: */ ! 73: #include "param.h" ! 74: #include "proc.h" ! 75: #include <machine/db_machdep.h> ! 76: ! 77: #include <ddb/db_lex.h> ! 78: #include <ddb/db_break.h> ! 79: #include <ddb/db_access.h> ! 80: ! 81: int db_run_mode; ! 82: #define STEP_NONE 0 ! 83: #define STEP_ONCE 1 ! 84: #define STEP_RETURN 2 ! 85: #define STEP_CALLT 3 ! 86: #define STEP_CONTINUE 4 ! 87: #define STEP_INVISIBLE 5 ! 88: #define STEP_COUNT 6 ! 89: ! 90: boolean_t db_sstep_print; ! 91: int db_loop_count; ! 92: int db_call_depth; ! 93: ! 94: int db_inst_count; ! 95: int db_load_count; ! 96: int db_store_count; ! 97: ! 98: #ifndef db_set_single_step ! 99: void db_set_single_step(/* db_regs_t *regs */); /* forward */ ! 100: #endif ! 101: #ifndef db_clear_single_step ! 102: void db_clear_single_step(/* db_regs_t *regs */); ! 103: #endif ! 104: ! 105: boolean_t ! 106: db_stop_at_pc(is_breakpoint) ! 107: boolean_t *is_breakpoint; ! 108: { ! 109: register db_addr_t pc; ! 110: register db_breakpoint_t bkpt; ! 111: ! 112: db_clear_single_step(DDB_REGS); ! 113: db_clear_breakpoints(); ! 114: db_clear_watchpoints(); ! 115: pc = PC_REGS(DDB_REGS); ! 116: ! 117: #ifdef FIXUP_PC_AFTER_BREAK ! 118: if (*is_breakpoint) { ! 119: /* ! 120: * Breakpoint trap. Fix up the PC if the ! 121: * machine requires it. ! 122: */ ! 123: FIXUP_PC_AFTER_BREAK ! 124: pc = PC_REGS(DDB_REGS); ! 125: } ! 126: #endif ! 127: ! 128: /* ! 129: * Now check for a breakpoint at this address. ! 130: */ ! 131: bkpt = db_find_breakpoint_here(pc); ! 132: if (bkpt) { ! 133: if (--bkpt->count == 0) { ! 134: bkpt->count = bkpt->init_count; ! 135: *is_breakpoint = TRUE; ! 136: return (TRUE); /* stop here */ ! 137: } ! 138: } else if (*is_breakpoint) { ! 139: ddb_regs.tf_eip += 1; ! 140: } ! 141: ! 142: *is_breakpoint = FALSE; ! 143: ! 144: if (db_run_mode == STEP_INVISIBLE) { ! 145: db_run_mode = STEP_CONTINUE; ! 146: return (FALSE); /* continue */ ! 147: } ! 148: if (db_run_mode == STEP_COUNT) { ! 149: return (FALSE); /* continue */ ! 150: } ! 151: if (db_run_mode == STEP_ONCE) { ! 152: if (--db_loop_count > 0) { ! 153: if (db_sstep_print) { ! 154: db_printf("\t\t"); ! 155: db_print_loc_and_inst(pc); ! 156: db_printf("\n"); ! 157: } ! 158: return (FALSE); /* continue */ ! 159: } ! 160: } ! 161: if (db_run_mode == STEP_RETURN) { ! 162: db_expr_t ins = db_get_value(pc, sizeof(int), FALSE); ! 163: ! 164: /* continue until matching return */ ! 165: ! 166: if (!inst_trap_return(ins) && ! 167: (!inst_return(ins) || --db_call_depth != 0)) { ! 168: if (db_sstep_print) { ! 169: if (inst_call(ins) || inst_return(ins)) { ! 170: register int i; ! 171: ! 172: db_printf("[after %6d] ", db_inst_count); ! 173: for (i = db_call_depth; --i > 0; ) ! 174: db_printf(" "); ! 175: db_print_loc_and_inst(pc); ! 176: db_printf("\n"); ! 177: } ! 178: } ! 179: if (inst_call(ins)) ! 180: db_call_depth++; ! 181: return (FALSE); /* continue */ ! 182: } ! 183: } ! 184: if (db_run_mode == STEP_CALLT) { ! 185: db_expr_t ins = db_get_value(pc, sizeof(int), FALSE); ! 186: ! 187: /* continue until call or return */ ! 188: ! 189: if (!inst_call(ins) && ! 190: !inst_return(ins) && ! 191: !inst_trap_return(ins)) { ! 192: return (FALSE); /* continue */ ! 193: } ! 194: } ! 195: db_run_mode = STEP_NONE; ! 196: return (TRUE); ! 197: } ! 198: ! 199: void ! 200: db_restart_at_pc(watchpt) ! 201: boolean_t watchpt; ! 202: { ! 203: register db_addr_t pc = PC_REGS(DDB_REGS); ! 204: ! 205: if ((db_run_mode == STEP_COUNT) || ! 206: (db_run_mode == STEP_RETURN) || ! 207: (db_run_mode == STEP_CALLT)) { ! 208: db_expr_t ins; ! 209: ! 210: /* ! 211: * We are about to execute this instruction, ! 212: * so count it now. ! 213: */ ! 214: ! 215: ins = db_get_value(pc, sizeof(int), FALSE); ! 216: db_inst_count++; ! 217: db_load_count += inst_load(ins); ! 218: db_store_count += inst_store(ins); ! 219: #ifdef SOFTWARE_SSTEP ! 220: /* XXX works on mips, but... */ ! 221: if (inst_branch(ins) || inst_call(ins)) { ! 222: ins = db_get_value(next_instr_address(pc,1), ! 223: sizeof(int), FALSE); ! 224: db_inst_count++; ! 225: db_load_count += inst_load(ins); ! 226: db_store_count += inst_store(ins); ! 227: } ! 228: #endif SOFTWARE_SSTEP ! 229: } ! 230: ! 231: if (db_run_mode == STEP_CONTINUE) { ! 232: if (watchpt || db_find_breakpoint_here(pc)) { ! 233: /* ! 234: * Step over breakpoint/watchpoint. ! 235: */ ! 236: db_run_mode = STEP_INVISIBLE; ! 237: db_set_single_step(DDB_REGS); ! 238: } else { ! 239: db_set_breakpoints(); ! 240: db_set_watchpoints(); ! 241: } ! 242: } else { ! 243: db_set_single_step(DDB_REGS); ! 244: } ! 245: } ! 246: ! 247: void ! 248: db_single_step(regs) ! 249: db_regs_t *regs; ! 250: { ! 251: if (db_run_mode == STEP_CONTINUE) { ! 252: db_run_mode = STEP_INVISIBLE; ! 253: db_set_single_step(regs); ! 254: } ! 255: } ! 256: ! 257: #ifdef SOFTWARE_SSTEP ! 258: /* ! 259: * Software implementation of single-stepping. ! 260: * If your machine does not have a trace mode ! 261: * similar to the vax or sun ones you can use ! 262: * this implementation, done for the mips. ! 263: * Just define the above conditional and provide ! 264: * the functions/macros defined below. ! 265: * ! 266: * extern boolean_t ! 267: * inst_branch(), returns true if the instruction might branch ! 268: * extern unsigned ! 269: * branch_taken(), return the address the instruction might ! 270: * branch to ! 271: * db_getreg_val(); return the value of a user register, ! 272: * as indicated in the hardware instruction ! 273: * encoding, e.g. 8 for r8 ! 274: * ! 275: * next_instr_address(pc,bd) returns the address of the first ! 276: * instruction following the one at "pc", ! 277: * which is either in the taken path of ! 278: * the branch (bd==1) or not. This is ! 279: * for machines (mips) with branch delays. ! 280: * ! 281: * A single-step may involve at most 2 breakpoints - ! 282: * one for branch-not-taken and one for branch taken. ! 283: * If one of these addresses does not already have a breakpoint, ! 284: * we allocate a breakpoint and save it here. ! 285: * These breakpoints are deleted on return. ! 286: */ ! 287: db_breakpoint_t db_not_taken_bkpt = 0; ! 288: db_breakpoint_t db_taken_bkpt = 0; ! 289: ! 290: void ! 291: db_set_single_step(regs) ! 292: register db_regs_t *regs; ! 293: { ! 294: db_addr_t pc = PC_REGS(regs); ! 295: register unsigned inst, brpc; ! 296: ! 297: /* ! 298: * User was stopped at pc, e.g. the instruction ! 299: * at pc was not executed. ! 300: */ ! 301: inst = db_get_value(pc, sizeof(int), FALSE); ! 302: if (inst_branch(inst) || inst_call(inst)) { ! 303: extern unsigned getreg_val(); ! 304: ! 305: brpc = branch_taken(inst, pc, getreg_val, regs); ! 306: if (brpc != pc) { /* self-branches are hopeless */ ! 307: db_taken_bkpt = db_set_temp_breakpoint(brpc); ! 308: } ! 309: pc = next_instr_address(pc,1); ! 310: } ! 311: pc = next_instr_address(pc,0); ! 312: db_not_taken_bkpt = db_set_temp_breakpoint(pc); ! 313: } ! 314: ! 315: void ! 316: db_clear_single_step(regs) ! 317: db_regs_t *regs; ! 318: { ! 319: register db_breakpoint_t bkpt; ! 320: ! 321: if (db_taken_bkpt != 0) { ! 322: db_delete_temp_breakpoint(db_taken_bkpt); ! 323: db_taken_bkpt = 0; ! 324: } ! 325: if (db_not_taken_bkpt != 0) { ! 326: db_delete_temp_breakpoint(db_not_taken_bkpt); ! 327: db_not_taken_bkpt = 0; ! 328: } ! 329: } ! 330: ! 331: #endif SOFTWARE_SSTEP ! 332: ! 333: extern int db_cmd_loop_done; ! 334: ! 335: /* single-step */ ! 336: /*ARGSUSED*/ ! 337: void ! 338: db_single_step_cmd(addr, have_addr, count, modif) ! 339: db_expr_t addr; ! 340: int have_addr; ! 341: db_expr_t count; ! 342: char * modif; ! 343: { ! 344: boolean_t print = FALSE; ! 345: ! 346: if (count == -1) ! 347: count = 1; ! 348: ! 349: if (modif[0] == 'p') ! 350: print = TRUE; ! 351: ! 352: db_run_mode = STEP_ONCE; ! 353: db_loop_count = count; ! 354: db_sstep_print = print; ! 355: db_inst_count = 0; ! 356: db_load_count = 0; ! 357: db_store_count = 0; ! 358: ! 359: db_cmd_loop_done = 1; ! 360: } ! 361: ! 362: /* trace and print until call/return */ ! 363: /*ARGSUSED*/ ! 364: void ! 365: db_trace_until_call_cmd(addr, have_addr, count, modif) ! 366: db_expr_t addr; ! 367: int have_addr; ! 368: db_expr_t count; ! 369: char * modif; ! 370: { ! 371: boolean_t print = FALSE; ! 372: ! 373: if (modif[0] == 'p') ! 374: print = TRUE; ! 375: ! 376: db_run_mode = STEP_CALLT; ! 377: db_sstep_print = print; ! 378: db_inst_count = 0; ! 379: db_load_count = 0; ! 380: db_store_count = 0; ! 381: ! 382: db_cmd_loop_done = 1; ! 383: } ! 384: ! 385: /*ARGSUSED*/ ! 386: void ! 387: db_trace_until_matching_cmd(addr, have_addr, count, modif) ! 388: db_expr_t addr; ! 389: int have_addr; ! 390: db_expr_t count; ! 391: char * modif; ! 392: { ! 393: boolean_t print = FALSE; ! 394: ! 395: if (modif[0] == 'p') ! 396: print = TRUE; ! 397: ! 398: db_run_mode = STEP_RETURN; ! 399: db_call_depth = 1; ! 400: db_sstep_print = print; ! 401: db_inst_count = 0; ! 402: db_load_count = 0; ! 403: db_store_count = 0; ! 404: ! 405: db_cmd_loop_done = 1; ! 406: } ! 407: ! 408: /* continue */ ! 409: /*ARGSUSED*/ ! 410: void ! 411: db_continue_cmd(addr, have_addr, count, modif) ! 412: db_expr_t addr; ! 413: int have_addr; ! 414: db_expr_t count; ! 415: char * modif; ! 416: { ! 417: if (modif[0] == 'c') ! 418: db_run_mode = STEP_COUNT; ! 419: else ! 420: db_run_mode = STEP_CONTINUE; ! 421: db_inst_count = 0; ! 422: db_load_count = 0; ! 423: db_store_count = 0; ! 424: ! 425: db_cmd_loop_done = 1; ! 426: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.