|
|
1.1 ! root 1: /* ! 2: * Mach Operating System ! 3: * Copyright (c) 1993-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 "AS IS" ! 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 Mellon ! 24: * the rights to redistribute these changes. ! 25: */ ! 26: /* ! 27: * Author: David B. Golub, Carnegie Mellon University ! 28: * Date: 7/90 ! 29: */ ! 30: ! 31: #include "mach_kdb.h" ! 32: #if MACH_KDB ! 33: ! 34: /* ! 35: * Commands to run process. ! 36: */ ! 37: #include <mach/boolean.h> ! 38: #include <machine/db_machdep.h> ! 39: ! 40: #include <ddb/db_lex.h> ! 41: #include <ddb/db_break.h> ! 42: #include <ddb/db_access.h> ! 43: #include <ddb/db_run.h> ! 44: #include <ddb/db_task_thread.h> ! 45: ! 46: int db_run_mode; ! 47: ! 48: boolean_t db_sstep_print; ! 49: int db_loop_count; ! 50: int db_call_depth; ! 51: ! 52: int db_inst_count; ! 53: int db_last_inst_count; ! 54: int db_load_count; ! 55: int db_store_count; ! 56: ! 57: #ifndef db_set_single_step ! 58: void db_set_task_single_step(/* db_regs_t *, task_t */);/* forward */ ! 59: #else ! 60: #define db_set_task_single_step(regs,task) db_set_single_step(regs) ! 61: #endif ! 62: #ifndef db_clear_single_step ! 63: void db_clear_task_single_step(/* db_regs_t *, task_t */); ! 64: #else ! 65: #define db_clear_task_single_step(regs,task) db_clear_single_step(regs) ! 66: #endif ! 67: ! 68: boolean_t ! 69: db_stop_at_pc(is_breakpoint, task) ! 70: boolean_t *is_breakpoint; ! 71: task_t task; ! 72: { ! 73: register db_addr_t pc; ! 74: register db_thread_breakpoint_t bkpt; ! 75: boolean_t db_cond_check(); ! 76: ! 77: db_clear_task_single_step(DDB_REGS, task); ! 78: db_clear_breakpoints(); ! 79: db_clear_watchpoints(); ! 80: pc = PC_REGS(DDB_REGS); ! 81: ! 82: #ifdef FIXUP_PC_AFTER_BREAK ! 83: if (*is_breakpoint) { ! 84: /* ! 85: * Breakpoint trap. Fix up the PC if the ! 86: * machine requires it. ! 87: */ ! 88: FIXUP_PC_AFTER_BREAK ! 89: pc = PC_REGS(DDB_REGS); ! 90: } ! 91: #endif ! 92: ! 93: /* ! 94: * Now check for a breakpoint at this address. ! 95: */ ! 96: bkpt = db_find_thread_breakpoint_here(task, pc); ! 97: if (bkpt) { ! 98: if (db_cond_check(bkpt)) { ! 99: *is_breakpoint = TRUE; ! 100: return (TRUE); /* stop here */ ! 101: } ! 102: } ! 103: *is_breakpoint = FALSE; ! 104: ! 105: if (db_run_mode == STEP_INVISIBLE) { ! 106: db_run_mode = STEP_CONTINUE; ! 107: return (FALSE); /* continue */ ! 108: } ! 109: if (db_run_mode == STEP_COUNT) { ! 110: return (FALSE); /* continue */ ! 111: } ! 112: if (db_run_mode == STEP_ONCE) { ! 113: if (--db_loop_count > 0) { ! 114: if (db_sstep_print) { ! 115: db_print_loc_and_inst(pc, task); ! 116: } ! 117: return (FALSE); /* continue */ ! 118: } ! 119: } ! 120: if (db_run_mode == STEP_RETURN) { ! 121: /* WARNING: the following assumes an instruction fits an int */ ! 122: db_expr_t ins = db_get_task_value(pc, sizeof(int), FALSE, task); ! 123: ! 124: /* continue until matching return */ ! 125: ! 126: if (!inst_trap_return(ins) && ! 127: (!inst_return(ins) || --db_call_depth != 0)) { ! 128: if (db_sstep_print) { ! 129: if (inst_call(ins) || inst_return(ins)) { ! 130: register int i; ! 131: ! 132: db_printf("[after %6d /%4d] ", ! 133: db_inst_count, ! 134: db_inst_count - db_last_inst_count); ! 135: db_last_inst_count = db_inst_count; ! 136: for (i = db_call_depth; --i > 0; ) ! 137: db_printf(" "); ! 138: db_print_loc_and_inst(pc, task); ! 139: db_printf("\n"); ! 140: } ! 141: } ! 142: if (inst_call(ins)) ! 143: db_call_depth++; ! 144: return (FALSE); /* continue */ ! 145: } ! 146: } ! 147: if (db_run_mode == STEP_CALLT) { ! 148: /* WARNING: the following assumes an instruction fits an int */ ! 149: db_expr_t ins = db_get_task_value(pc, sizeof(int), FALSE, task); ! 150: ! 151: /* continue until call or return */ ! 152: ! 153: if (!inst_call(ins) && ! 154: !inst_return(ins) && ! 155: !inst_trap_return(ins)) { ! 156: return (FALSE); /* continue */ ! 157: } ! 158: } ! 159: if (db_find_breakpoint_here(task, pc)) ! 160: return(FALSE); ! 161: db_run_mode = STEP_NONE; ! 162: return (TRUE); ! 163: } ! 164: ! 165: void ! 166: db_restart_at_pc(watchpt, task) ! 167: boolean_t watchpt; ! 168: task_t task; ! 169: { ! 170: register db_addr_t pc = PC_REGS(DDB_REGS), brpc; ! 171: ! 172: if ((db_run_mode == STEP_COUNT) || ! 173: (db_run_mode == STEP_RETURN) || ! 174: (db_run_mode == STEP_CALLT)) { ! 175: db_expr_t ins; ! 176: ! 177: /* ! 178: * We are about to execute this instruction, ! 179: * so count it now. ! 180: */ ! 181: ! 182: ins = db_get_task_value(pc, sizeof(int), FALSE, task); ! 183: db_inst_count++; ! 184: db_load_count += inst_load(ins); ! 185: db_store_count += inst_store(ins); ! 186: #ifdef SOFTWARE_SSTEP ! 187: /* Account for instructions in delay slots */ ! 188: brpc = next_instr_address(pc,1,task); ! 189: if ((brpc != pc) && (inst_branch(ins) || inst_call(ins))) { ! 190: /* Note: this ~assumes an instruction <= sizeof(int) */ ! 191: ins = db_get_task_value(brpc, sizeof(int), FALSE, task); ! 192: db_inst_count++; ! 193: db_load_count += inst_load(ins); ! 194: db_store_count += inst_store(ins); ! 195: } ! 196: #endif /* SOFTWARE_SSTEP */ ! 197: } ! 198: ! 199: if (db_run_mode == STEP_CONTINUE) { ! 200: if (watchpt || db_find_breakpoint_here(task, pc)) { ! 201: /* ! 202: * Step over breakpoint/watchpoint. ! 203: */ ! 204: db_run_mode = STEP_INVISIBLE; ! 205: db_set_task_single_step(DDB_REGS, task); ! 206: } else { ! 207: db_set_breakpoints(); ! 208: db_set_watchpoints(); ! 209: } ! 210: } else { ! 211: db_set_task_single_step(DDB_REGS, task); ! 212: } ! 213: } ! 214: ! 215: void ! 216: db_single_step(regs, task) ! 217: db_regs_t *regs; ! 218: task_t task; ! 219: { ! 220: if (db_run_mode == STEP_CONTINUE) { ! 221: db_run_mode = STEP_INVISIBLE; ! 222: db_set_task_single_step(regs, task); ! 223: } ! 224: } ! 225: ! 226: #ifdef SOFTWARE_SSTEP ! 227: /* ! 228: * Software implementation of single-stepping. ! 229: * If your machine does not have a trace mode ! 230: * similar to the vax or sun ones you can use ! 231: * this implementation, done for the mips. ! 232: * Just define the above conditional and provide ! 233: * the functions/macros defined below. ! 234: * ! 235: * extern boolean_t ! 236: * inst_branch(), returns true if the instruction might branch ! 237: * extern unsigned ! 238: * branch_taken(), return the address the instruction might ! 239: * branch to ! 240: * db_getreg_val(); return the value of a user register, ! 241: * as indicated in the hardware instruction ! 242: * encoding, e.g. 8 for r8 ! 243: * ! 244: * next_instr_address(pc,bd,task) returns the address of the first ! 245: * instruction following the one at "pc", ! 246: * which is either in the taken path of ! 247: * the branch (bd==1) or not. This is ! 248: * for machines (mips) with branch delays. ! 249: * ! 250: * A single-step may involve at most 2 breakpoints - ! 251: * one for branch-not-taken and one for branch taken. ! 252: * If one of these addresses does not already have a breakpoint, ! 253: * we allocate a breakpoint and save it here. ! 254: * These breakpoints are deleted on return. ! 255: */ ! 256: db_breakpoint_t db_not_taken_bkpt = 0; ! 257: db_breakpoint_t db_taken_bkpt = 0; ! 258: ! 259: db_breakpoint_t ! 260: db_find_temp_breakpoint(task, addr) ! 261: task_t task; ! 262: db_addr_t addr; ! 263: { ! 264: if (db_taken_bkpt && (db_taken_bkpt->address == addr) && ! 265: db_taken_bkpt->task == task) ! 266: return db_taken_bkpt; ! 267: if (db_not_taken_bkpt && (db_not_taken_bkpt->address == addr) && ! 268: db_not_taken_bkpt->task == task) ! 269: return db_not_taken_bkpt; ! 270: return 0; ! 271: } ! 272: ! 273: void ! 274: db_set_task_single_step(regs, task) ! 275: register db_regs_t *regs; ! 276: task_t task; ! 277: { ! 278: db_addr_t pc = PC_REGS(regs), brpc; ! 279: register unsigned int inst; ! 280: register boolean_t unconditional; ! 281: ! 282: /* ! 283: * User was stopped at pc, e.g. the instruction ! 284: * at pc was not executed. ! 285: */ ! 286: inst = db_get_task_value(pc, sizeof(int), FALSE, task); ! 287: if (inst_branch(inst) || inst_call(inst)) { ! 288: extern db_expr_t getreg_val(); ! 289: ! 290: brpc = branch_taken(inst, pc, getreg_val, regs); ! 291: if (brpc != pc) { /* self-branches are hopeless */ ! 292: db_taken_bkpt = db_set_temp_breakpoint(task, brpc); ! 293: } else ! 294: db_taken_bkpt = 0; ! 295: pc = next_instr_address(pc,1,task); ! 296: } ! 297: ! 298: /* check if this control flow instruction is an unconditional transfer */ ! 299: unconditional = inst_unconditional_flow_transfer(inst); ! 300: ! 301: pc = next_instr_address(pc,0,task); ! 302: /* ! 303: We only set the sequential breakpoint if previous instruction was not ! 304: an unconditional change of flow of control. If the previous instruction ! 305: is an unconditional change of flow of control, setting a breakpoint in the ! 306: next sequential location may set a breakpoint in data or in another routine, ! 307: which could screw up either the program or the debugger. ! 308: (Consider, for instance, that the next sequential instruction is the ! 309: start of a routine needed by the debugger.) ! 310: */ ! 311: if (!unconditional && db_find_breakpoint_here(task, pc) == 0) { ! 312: db_not_taken_bkpt = db_set_temp_breakpoint(task, pc); ! 313: } ! 314: else ! 315: db_not_taken_bkpt = 0; ! 316: } ! 317: ! 318: void ! 319: db_clear_task_single_step(regs, task) ! 320: db_regs_t *regs; ! 321: task_t task; ! 322: { ! 323: if (db_taken_bkpt != 0) { ! 324: db_delete_temp_breakpoint(task, db_taken_bkpt); ! 325: db_taken_bkpt = 0; ! 326: } ! 327: if (db_not_taken_bkpt != 0) { ! 328: db_delete_temp_breakpoint(task, db_not_taken_bkpt); ! 329: db_not_taken_bkpt = 0; ! 330: } ! 331: } ! 332: ! 333: #endif /* SOFTWARE_SSTEP */ ! 334: ! 335: ! 336: extern int db_cmd_loop_done; ! 337: ! 338: /* single-step */ ! 339: /*ARGSUSED*/ ! 340: void ! 341: db_single_step_cmd(addr, have_addr, count, modif) ! 342: db_expr_t addr; ! 343: int have_addr; ! 344: db_expr_t count; ! 345: char * modif; ! 346: { ! 347: boolean_t print = FALSE; ! 348: ! 349: if (count == -1) ! 350: count = 1; ! 351: ! 352: if (modif[0] == 'p') ! 353: print = TRUE; ! 354: ! 355: db_run_mode = STEP_ONCE; ! 356: db_loop_count = count; ! 357: db_sstep_print = print; ! 358: db_inst_count = 0; ! 359: db_last_inst_count = 0; ! 360: db_load_count = 0; ! 361: db_store_count = 0; ! 362: ! 363: db_cmd_loop_done = 1; ! 364: } ! 365: ! 366: /* trace and print until call/return */ ! 367: /*ARGSUSED*/ ! 368: void ! 369: db_trace_until_call_cmd(addr, have_addr, count, modif) ! 370: db_expr_t addr; ! 371: int have_addr; ! 372: db_expr_t count; ! 373: char * modif; ! 374: { ! 375: boolean_t print = FALSE; ! 376: ! 377: if (modif[0] == 'p') ! 378: print = TRUE; ! 379: ! 380: db_run_mode = STEP_CALLT; ! 381: db_sstep_print = print; ! 382: db_inst_count = 0; ! 383: db_last_inst_count = 0; ! 384: db_load_count = 0; ! 385: db_store_count = 0; ! 386: ! 387: db_cmd_loop_done = 1; ! 388: } ! 389: ! 390: /*ARGSUSED*/ ! 391: void ! 392: db_trace_until_matching_cmd(addr, have_addr, count, modif) ! 393: db_expr_t addr; ! 394: int have_addr; ! 395: db_expr_t count; ! 396: char * modif; ! 397: { ! 398: boolean_t print = FALSE; ! 399: ! 400: if (modif[0] == 'p') ! 401: print = TRUE; ! 402: ! 403: db_run_mode = STEP_RETURN; ! 404: db_call_depth = 1; ! 405: db_sstep_print = print; ! 406: db_inst_count = 0; ! 407: db_last_inst_count = 0; ! 408: db_load_count = 0; ! 409: db_store_count = 0; ! 410: ! 411: db_cmd_loop_done = 1; ! 412: } ! 413: ! 414: /* continue */ ! 415: /*ARGSUSED*/ ! 416: void ! 417: db_continue_cmd(addr, have_addr, count, modif) ! 418: db_expr_t addr; ! 419: int have_addr; ! 420: db_expr_t count; ! 421: char * modif; ! 422: { ! 423: if (modif[0] == 'c') ! 424: db_run_mode = STEP_COUNT; ! 425: else ! 426: db_run_mode = STEP_CONTINUE; ! 427: db_inst_count = 0; ! 428: db_last_inst_count = 0; ! 429: db_load_count = 0; ! 430: db_store_count = 0; ! 431: ! 432: db_cmd_loop_done = 1; ! 433: } ! 434: ! 435: boolean_t ! 436: db_in_single_step() ! 437: { ! 438: return(db_run_mode != STEP_NONE && db_run_mode != STEP_CONTINUE); ! 439: } ! 440: ! 441: #endif MACH_KDB
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.