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