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/param.h> 38 #include <sys/kdb.h> 39 #include <sys/proc.h> 40 #include <sys/reg.h> 41 #include <sys/systm.h> 42 43 #include <machine/kdb.h> 44 #include <machine/pcb.h> 45 46 #include <vm/vm.h> 47 48 #include <ddb/ddb.h> 49 #include <ddb/db_access.h> 50 #include <ddb/db_break.h> 51 #include <ddb/db_command.h> 52 53 #define STEP_ONCE 1 54 #define STEP_RETURN 2 55 #define STEP_CALLT 3 56 #define STEP_CONTINUE 4 57 #define STEP_INVISIBLE 5 58 #define STEP_COUNT 6 59 static int db_run_mode = STEP_CONTINUE; 60 61 static bool db_sstep_multiple; 62 static bool db_sstep_print; 63 static int db_loop_count; 64 static int db_call_depth; 65 66 int db_inst_count; 67 int db_load_count; 68 int db_store_count; 69 70 bool 71 db_stop_at_pc(int type, int code, bool *is_breakpoint, bool *is_watchpoint) 72 { 73 db_addr_t pc; 74 db_breakpoint_t bkpt; 75 76 *is_breakpoint = IS_BREAKPOINT_TRAP(type, code); 77 *is_watchpoint = IS_WATCHPOINT_TRAP(type, code); 78 pc = PC_REGS(); 79 80 db_clear_single_step(); 81 db_clear_breakpoints(); 82 db_clear_watchpoints(); 83 84 #ifdef FIXUP_PC_AFTER_BREAK 85 if (*is_breakpoint) { 86 /* 87 * Breakpoint trap. Fix up the PC if the 88 * machine requires it. 89 */ 90 FIXUP_PC_AFTER_BREAK 91 pc = PC_REGS(); 92 } 93 #endif 94 95 /* 96 * Now check for a breakpoint at this address. 97 */ 98 bkpt = db_find_breakpoint_here(pc); 99 if (bkpt) { 100 if (--bkpt->count == 0) { 101 bkpt->count = bkpt->init_count; 102 *is_breakpoint = true; 103 return (true); /* stop here */ 104 } 105 return (false); /* continue the countdown */ 106 } else if (*is_breakpoint) { 107 #ifdef BKPT_SKIP 108 BKPT_SKIP; 109 #endif 110 } 111 112 *is_breakpoint = false; /* might be a breakpoint, but not ours */ 113 114 /* 115 * If not stepping, then silently ignore single-step traps 116 * (except for clearing the single-step-flag above). 117 * 118 * If stepping, then abort if the trap type is unexpected. 119 * Breakpoints owned by us are expected and were handled above. 120 * Single-steps are expected and are handled below. All others 121 * are unexpected. 122 * 123 * Only do either of these if the MD layer claims to classify 124 * single-step traps unambiguously (by defining IS_SSTEP_TRAP). 125 * Otherwise, fall through to the bad historical behaviour 126 * given by turning unexpected traps into expected traps: if not 127 * stepping, then expect only breakpoints and stop, and if 128 * stepping, then expect only single-steps and step. 129 */ 130 #ifdef IS_SSTEP_TRAP 131 if (db_run_mode == STEP_CONTINUE && IS_SSTEP_TRAP(type, code)) 132 return (false); 133 if (db_run_mode != STEP_CONTINUE && !IS_SSTEP_TRAP(type, code)) { 134 printf("Stepping aborted\n"); 135 return (true); 136 } 137 #endif 138 139 if (db_run_mode == STEP_INVISIBLE) { 140 db_run_mode = STEP_CONTINUE; 141 return (false); /* continue */ 142 } 143 if (db_run_mode == STEP_COUNT) { 144 return (false); /* continue */ 145 } 146 if (db_run_mode == STEP_ONCE) { 147 if (--db_loop_count > 0) { 148 if (db_sstep_print) { 149 db_printf("\t\t"); 150 db_print_loc_and_inst(pc); 151 } 152 return (false); /* continue */ 153 } 154 } 155 if (db_run_mode == STEP_RETURN) { 156 /* continue until matching return */ 157 db_expr_t ins; 158 159 ins = db_get_value(pc, sizeof(int), false); 160 if (!inst_trap_return(ins) && 161 (!inst_return(ins) || --db_call_depth != 0)) { 162 if (db_sstep_print) { 163 if (inst_call(ins) || inst_return(ins)) { 164 int i; 165 166 db_printf("[after %6d] ", db_inst_count); 167 for (i = db_call_depth; --i > 0; ) 168 db_printf(" "); 169 db_print_loc_and_inst(pc); 170 } 171 } 172 if (inst_call(ins)) 173 db_call_depth++; 174 return (false); /* continue */ 175 } 176 } 177 if (db_run_mode == STEP_CALLT) { 178 /* continue until call or return */ 179 db_expr_t ins; 180 181 ins = db_get_value(pc, sizeof(int), false); 182 if (!inst_call(ins) && 183 !inst_return(ins) && 184 !inst_trap_return(ins)) { 185 return (false); /* continue */ 186 } 187 } 188 return (true); 189 } 190 191 void 192 db_restart_at_pc(bool watchpt) 193 { 194 db_addr_t pc = PC_REGS(); 195 196 if ((db_run_mode == STEP_COUNT) || 197 ((db_run_mode == STEP_ONCE) && db_sstep_multiple) || 198 (db_run_mode == STEP_RETURN) || 199 (db_run_mode == STEP_CALLT)) { 200 /* 201 * We are about to execute this instruction, 202 * so count it now. 203 */ 204 db_get_value(pc, sizeof(int), false); 205 db_inst_count++; 206 db_load_count += inst_load(ins); 207 db_store_count += inst_store(ins); 208 } 209 210 if (db_run_mode == STEP_CONTINUE) { 211 if (watchpt || db_find_breakpoint_here(pc)) { 212 /* 213 * Step over breakpoint/watchpoint. 214 */ 215 db_run_mode = STEP_INVISIBLE; 216 db_set_single_step(); 217 } else { 218 db_set_breakpoints(); 219 db_set_watchpoints(); 220 } 221 } else { 222 db_set_single_step(); 223 } 224 } 225 226 /* single-step */ 227 /*ARGSUSED*/ 228 void 229 db_single_step_cmd(db_expr_t addr, bool have_addr, db_expr_t count, char *modif) 230 { 231 bool print = false; 232 233 if (count == -1) 234 count = 1; 235 236 if (modif[0] == 'p') 237 print = true; 238 239 db_run_mode = STEP_ONCE; 240 db_loop_count = count; 241 db_sstep_multiple = (count != 1); 242 db_sstep_print = print; 243 db_inst_count = 0; 244 db_load_count = 0; 245 db_store_count = 0; 246 247 db_cmd_loop_done = 1; 248 } 249 250 /* trace and print until call/return */ 251 /*ARGSUSED*/ 252 void 253 db_trace_until_call_cmd(db_expr_t addr, bool have_addr, db_expr_t count, 254 char *modif) 255 { 256 bool print = false; 257 258 if (modif[0] == 'p') 259 print = true; 260 261 db_run_mode = STEP_CALLT; 262 db_sstep_print = print; 263 db_inst_count = 0; 264 db_load_count = 0; 265 db_store_count = 0; 266 267 db_cmd_loop_done = 1; 268 } 269 270 /*ARGSUSED*/ 271 void 272 db_trace_until_matching_cmd(db_expr_t addr, bool have_addr, db_expr_t count, 273 char *modif) 274 { 275 bool print = false; 276 277 if (modif[0] == 'p') 278 print = true; 279 280 db_run_mode = STEP_RETURN; 281 db_call_depth = 1; 282 db_sstep_print = print; 283 db_inst_count = 0; 284 db_load_count = 0; 285 db_store_count = 0; 286 287 db_cmd_loop_done = 1; 288 } 289 290 /* continue */ 291 /*ARGSUSED*/ 292 void 293 db_continue_cmd(db_expr_t addr, bool have_addr, db_expr_t count, char *modif) 294 { 295 if (modif[0] == 'c') 296 db_run_mode = STEP_COUNT; 297 else 298 db_run_mode = STEP_CONTINUE; 299 db_inst_count = 0; 300 db_load_count = 0; 301 db_store_count = 0; 302 303 db_cmd_loop_done = 1; 304 } 305