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