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