|
|
1.1.1.2 ! root 1: /* 1.1 root 2: * Mach Operating System 3: * Copyright (c) 1993-1990 Carnegie Mellon University 4: * All Rights Reserved. 1.1.1.2 ! root 5: * 1.1 root 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. 1.1.1.2 ! root 11: * 1.1 root 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. 1.1.1.2 ! root 15: * 1.1 root 16: * Carnegie Mellon requests users of this software to return to 1.1.1.2 ! root 17: * 1.1 root 18: * Software Distribution Coordinator or [email protected] 19: * School of Computer Science 20: * Carnegie Mellon University 21: * Pittsburgh PA 15213-3890 1.1.1.2 ! root 22: * 1.1 root 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 1.1.1.2 ! root 243: * 1.1 root 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. 1.1.1.2 ! root 255: */ 1.1 root 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: } 1.1.1.2 ! root 297: 1.1 root 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); 1.1.1.2 ! root 302: /* 1.1 root 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, 1.1.1.2 ! root 307: which could screw up either the program or the debugger. ! 308: (Consider, for instance, that the next sequential instruction is the 1.1 root 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: 1.1.1.2 ! root 441: #endif /* MACH_KDB */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.