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 Software.Distribution@CS.CMU.EDU 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 * Author: David B. Golub, Carnegie Mellon University 27 * Date: 7/90 28 * $Id: db_run.c,v 1.4 1993/12/18 04:46:37 mycroft Exp $ 29 */ 30 31 /* 32 * Commands to run process. 33 */ 34 #include <sys/param.h> 35 #include <sys/proc.h> 36 37 #include <machine/db_machdep.h> 38 39 #include <ddb/db_lex.h> 40 #include <ddb/db_break.h> 41 #include <ddb/db_access.h> 42 43 int db_run_mode; 44 #define STEP_NONE 0 45 #define STEP_ONCE 1 46 #define STEP_RETURN 2 47 #define STEP_CALLT 3 48 #define STEP_CONTINUE 4 49 #define STEP_INVISIBLE 5 50 #define STEP_COUNT 6 51 52 boolean_t db_sstep_print; 53 int db_loop_count; 54 int db_call_depth; 55 56 int db_inst_count; 57 int db_load_count; 58 int db_store_count; 59 60 #ifndef db_set_single_step 61 void db_set_single_step(/* db_regs_t *regs */); /* forward */ 62 #endif 63 #ifndef db_clear_single_step 64 void db_clear_single_step(/* db_regs_t *regs */); 65 #endif 66 67 boolean_t 68 db_stop_at_pc(is_breakpoint) 69 boolean_t *is_breakpoint; 70 { 71 register db_addr_t pc; 72 register db_breakpoint_t bkpt; 73 74 db_clear_single_step(DDB_REGS); 75 db_clear_breakpoints(); 76 db_clear_watchpoints(); 77 pc = PC_REGS(DDB_REGS); 78 79 #ifdef FIXUP_PC_AFTER_BREAK 80 if (*is_breakpoint) { 81 /* 82 * Breakpoint trap. Fix up the PC if the 83 * machine requires it. 84 */ 85 FIXUP_PC_AFTER_BREAK 86 pc = PC_REGS(DDB_REGS); 87 } 88 #endif 89 90 /* 91 * Now check for a breakpoint at this address. 92 */ 93 bkpt = db_find_breakpoint_here(pc); 94 if (bkpt) { 95 if (--bkpt->count == 0) { 96 bkpt->count = bkpt->init_count; 97 *is_breakpoint = TRUE; 98 return (TRUE); /* stop here */ 99 } 100 } else if (*is_breakpoint) { 101 PC_REGS(&ddb_regs) += BKPT_SIZE; 102 } 103 104 *is_breakpoint = FALSE; 105 106 if (db_run_mode == STEP_INVISIBLE) { 107 db_run_mode = STEP_CONTINUE; 108 return (FALSE); /* continue */ 109 } 110 if (db_run_mode == STEP_COUNT) { 111 return (FALSE); /* continue */ 112 } 113 if (db_run_mode == STEP_ONCE) { 114 if (--db_loop_count > 0) { 115 if (db_sstep_print) { 116 db_printf("\t\t"); 117 db_print_loc_and_inst(pc); 118 db_printf("\n"); 119 } 120 return (FALSE); /* continue */ 121 } 122 } 123 if (db_run_mode == STEP_RETURN) { 124 db_expr_t ins = db_get_value(pc, sizeof(int), FALSE); 125 126 /* continue until matching return */ 127 128 if (!inst_trap_return(ins) && 129 (!inst_return(ins) || --db_call_depth != 0)) { 130 if (db_sstep_print) { 131 if (inst_call(ins) || inst_return(ins)) { 132 register int i; 133 134 db_printf("[after %6d] ", db_inst_count); 135 for (i = db_call_depth; --i > 0; ) 136 db_printf(" "); 137 db_print_loc_and_inst(pc); 138 db_printf("\n"); 139 } 140 } 141 if (inst_call(ins)) 142 db_call_depth++; 143 return (FALSE); /* continue */ 144 } 145 } 146 if (db_run_mode == STEP_CALLT) { 147 db_expr_t ins = db_get_value(pc, sizeof(int), FALSE); 148 149 /* continue until call or return */ 150 151 if (!inst_call(ins) && 152 !inst_return(ins) && 153 !inst_trap_return(ins)) { 154 return (FALSE); /* continue */ 155 } 156 } 157 db_run_mode = STEP_NONE; 158 return (TRUE); 159 } 160 161 void 162 db_restart_at_pc(watchpt) 163 boolean_t watchpt; 164 { 165 register db_addr_t pc = PC_REGS(DDB_REGS); 166 167 if ((db_run_mode == STEP_COUNT) || 168 (db_run_mode == STEP_RETURN) || 169 (db_run_mode == STEP_CALLT)) { 170 db_expr_t ins; 171 172 /* 173 * We are about to execute this instruction, 174 * so count it now. 175 */ 176 177 ins = db_get_value(pc, sizeof(int), FALSE); 178 db_inst_count++; 179 db_load_count += inst_load(ins); 180 db_store_count += inst_store(ins); 181 #ifdef SOFTWARE_SSTEP 182 /* XXX works on mips, but... */ 183 if (inst_branch(ins) || inst_call(ins)) { 184 ins = db_get_value(next_instr_address(pc,1), 185 sizeof(int), FALSE); 186 db_inst_count++; 187 db_load_count += inst_load(ins); 188 db_store_count += inst_store(ins); 189 } 190 #endif SOFTWARE_SSTEP 191 } 192 193 if (db_run_mode == STEP_CONTINUE) { 194 if (watchpt || db_find_breakpoint_here(pc)) { 195 /* 196 * Step over breakpoint/watchpoint. 197 */ 198 db_run_mode = STEP_INVISIBLE; 199 db_set_single_step(DDB_REGS); 200 } else { 201 db_set_breakpoints(); 202 db_set_watchpoints(); 203 } 204 } else { 205 db_set_single_step(DDB_REGS); 206 } 207 } 208 209 void 210 db_single_step(regs) 211 db_regs_t *regs; 212 { 213 if (db_run_mode == STEP_CONTINUE) { 214 db_run_mode = STEP_INVISIBLE; 215 db_set_single_step(regs); 216 } 217 } 218 219 #ifdef SOFTWARE_SSTEP 220 /* 221 * Software implementation of single-stepping. 222 * If your machine does not have a trace mode 223 * similar to the vax or sun ones you can use 224 * this implementation, done for the mips. 225 * Just define the above conditional and provide 226 * the functions/macros defined below. 227 * 228 * extern boolean_t 229 * inst_branch(), returns true if the instruction might branch 230 * extern unsigned 231 * branch_taken(), return the address the instruction might 232 * branch to 233 * db_getreg_val(); return the value of a user register, 234 * as indicated in the hardware instruction 235 * encoding, e.g. 8 for r8 236 * 237 * next_instr_address(pc,bd) returns the address of the first 238 * instruction following the one at "pc", 239 * which is either in the taken path of 240 * the branch (bd==1) or not. This is 241 * for machines (mips) with branch delays. 242 * 243 * A single-step may involve at most 2 breakpoints - 244 * one for branch-not-taken and one for branch taken. 245 * If one of these addresses does not already have a breakpoint, 246 * we allocate a breakpoint and save it here. 247 * These breakpoints are deleted on return. 248 */ 249 db_breakpoint_t db_not_taken_bkpt = 0; 250 db_breakpoint_t db_taken_bkpt = 0; 251 252 void 253 db_set_single_step(regs) 254 register db_regs_t *regs; 255 { 256 db_addr_t pc = PC_REGS(regs); 257 register unsigned inst, brpc; 258 259 /* 260 * User was stopped at pc, e.g. the instruction 261 * at pc was not executed. 262 */ 263 inst = db_get_value(pc, sizeof(int), FALSE); 264 if (inst_branch(inst) || inst_call(inst)) { 265 extern unsigned getreg_val(); 266 267 brpc = branch_taken(inst, pc, getreg_val, regs); 268 if (brpc != pc) { /* self-branches are hopeless */ 269 db_taken_bkpt = db_set_temp_breakpoint(brpc); 270 } 271 pc = next_instr_address(pc,1); 272 } 273 pc = next_instr_address(pc,0); 274 db_not_taken_bkpt = db_set_temp_breakpoint(pc); 275 } 276 277 void 278 db_clear_single_step(regs) 279 db_regs_t *regs; 280 { 281 register db_breakpoint_t bkpt; 282 283 if (db_taken_bkpt != 0) { 284 db_delete_temp_breakpoint(db_taken_bkpt); 285 db_taken_bkpt = 0; 286 } 287 if (db_not_taken_bkpt != 0) { 288 db_delete_temp_breakpoint(db_not_taken_bkpt); 289 db_not_taken_bkpt = 0; 290 } 291 } 292 293 #endif SOFTWARE_SSTEP 294 295 extern int db_cmd_loop_done; 296 297 /* single-step */ 298 /*ARGSUSED*/ 299 void 300 db_single_step_cmd(addr, have_addr, count, modif) 301 db_expr_t addr; 302 int have_addr; 303 db_expr_t count; 304 char * modif; 305 { 306 boolean_t print = FALSE; 307 308 if (count == -1) 309 count = 1; 310 311 if (modif[0] == 'p') 312 print = TRUE; 313 314 db_run_mode = STEP_ONCE; 315 db_loop_count = count; 316 db_sstep_print = print; 317 db_inst_count = 0; 318 db_load_count = 0; 319 db_store_count = 0; 320 321 db_cmd_loop_done = 1; 322 } 323 324 /* trace and print until call/return */ 325 /*ARGSUSED*/ 326 void 327 db_trace_until_call_cmd(addr, have_addr, count, modif) 328 db_expr_t addr; 329 int have_addr; 330 db_expr_t count; 331 char * modif; 332 { 333 boolean_t print = FALSE; 334 335 if (modif[0] == 'p') 336 print = TRUE; 337 338 db_run_mode = STEP_CALLT; 339 db_sstep_print = print; 340 db_inst_count = 0; 341 db_load_count = 0; 342 db_store_count = 0; 343 344 db_cmd_loop_done = 1; 345 } 346 347 /*ARGSUSED*/ 348 void 349 db_trace_until_matching_cmd(addr, have_addr, count, modif) 350 db_expr_t addr; 351 int have_addr; 352 db_expr_t count; 353 char * modif; 354 { 355 boolean_t print = FALSE; 356 357 if (modif[0] == 'p') 358 print = TRUE; 359 360 db_run_mode = STEP_RETURN; 361 db_call_depth = 1; 362 db_sstep_print = print; 363 db_inst_count = 0; 364 db_load_count = 0; 365 db_store_count = 0; 366 367 db_cmd_loop_done = 1; 368 } 369 370 /* continue */ 371 /*ARGSUSED*/ 372 void 373 db_continue_cmd(addr, have_addr, count, modif) 374 db_expr_t addr; 375 int have_addr; 376 db_expr_t count; 377 char * modif; 378 { 379 if (modif[0] == 'c') 380 db_run_mode = STEP_COUNT; 381 else 382 db_run_mode = STEP_CONTINUE; 383 db_inst_count = 0; 384 db_load_count = 0; 385 db_store_count = 0; 386 387 db_cmd_loop_done = 1; 388 } 389