1 /* $NetBSD: db_run.c,v 1.20 2000/03/30 11:31:27 augustss Exp $ */ 2 3 /* 4 * Mach Operating System 5 * Copyright (c) 1993-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 "AS IS" 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 * Author: David B. Golub, Carnegie Mellon University 29 * Date: 7/90 30 */ 31 32 /* 33 * Commands to run process. 34 */ 35 36 #include "opt_ddb.h" 37 38 #include <sys/param.h> 39 #include <sys/proc.h> 40 41 #include <machine/db_machdep.h> 42 43 #include <ddb/db_run.h> 44 #include <ddb/db_access.h> 45 #include <ddb/db_break.h> 46 47 #ifdef SOFTWARE_SSTEP 48 static void db_set_temp_breakpoint __P((db_breakpoint_t, db_addr_t)); 49 static void db_delete_temp_breakpoint __P((db_breakpoint_t)); 50 static struct db_breakpoint db_not_taken_bkpt; 51 static struct db_breakpoint db_taken_bkpt; 52 #endif 53 54 #if defined(DDB) 55 #include <ddb/db_lex.h> 56 #include <ddb/db_watch.h> 57 #include <ddb/db_output.h> 58 #include <ddb/db_sym.h> 59 #include <ddb/db_extern.h> 60 61 int db_run_mode; 62 #define STEP_NONE 0 63 #define STEP_ONCE 1 64 #define STEP_RETURN 2 65 #define STEP_CALLT 3 66 #define STEP_CONTINUE 4 67 #define STEP_INVISIBLE 5 68 #define STEP_COUNT 6 69 70 boolean_t db_sstep_print; 71 int db_loop_count; 72 int db_call_depth; 73 74 boolean_t 75 db_stop_at_pc(regs, is_breakpoint) 76 db_regs_t *regs; 77 boolean_t *is_breakpoint; 78 { 79 db_addr_t pc; 80 db_breakpoint_t bkpt; 81 82 pc = PC_REGS(regs); 83 84 #ifdef FIXUP_PC_AFTER_BREAK 85 if (*is_breakpoint) { 86 /* 87 * Breakpoint trap. Regardless if we treat this as a 88 * real breakpoint (e.g. software single-step), fix up the PC. 89 */ 90 FIXUP_PC_AFTER_BREAK(regs); 91 pc = PC_REGS(regs); 92 } 93 #endif 94 95 #ifdef SOFTWARE_SSTEP 96 /* 97 * If we stopped at one of the single-step breakpoints, say it's not 98 * really a breakpoint so that we don't skip over the real instruction. 99 */ 100 if (db_taken_bkpt.address == pc || db_not_taken_bkpt.address == pc) 101 *is_breakpoint = FALSE; 102 #endif /* SOFTWARE_SSTEP */ 103 104 db_clear_single_step(regs); 105 db_clear_breakpoints(); 106 db_clear_watchpoints(); 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 */ 117 } 118 } else if (*is_breakpoint) { 119 #ifdef PC_ADVANCE 120 PC_ADVANCE(regs); 121 #else 122 PC_REGS(regs) += BKPT_SIZE; 123 #endif 124 } 125 126 *is_breakpoint = FALSE; 127 128 if (db_run_mode == STEP_INVISIBLE) { 129 db_run_mode = STEP_CONTINUE; 130 return (FALSE); /* continue */ 131 } 132 if (db_run_mode == STEP_COUNT) { 133 return (FALSE); /* continue */ 134 } 135 if (db_run_mode == STEP_ONCE) { 136 if (--db_loop_count > 0) { 137 if (db_sstep_print) { 138 db_printf("\t\t"); 139 db_print_loc_and_inst(pc); 140 db_printf("\n"); 141 } 142 return (FALSE); /* continue */ 143 } 144 } 145 if (db_run_mode == STEP_RETURN) { 146 db_expr_t ins = db_get_value(pc, sizeof(int), FALSE); 147 148 /* continue until matching return */ 149 150 if (!inst_trap_return(ins) && 151 (!inst_return(ins) || --db_call_depth != 0)) { 152 if (db_sstep_print) { 153 if (inst_call(ins) || inst_return(ins)) { 154 int i; 155 156 db_printf("[after %6d] ", db_inst_count); 157 for (i = db_call_depth; --i > 0; ) 158 db_printf(" "); 159 db_print_loc_and_inst(pc); 160 db_printf("\n"); 161 } 162 } 163 if (inst_call(ins)) 164 db_call_depth++; 165 return (FALSE); /* continue */ 166 } 167 } 168 if (db_run_mode == STEP_CALLT) { 169 db_expr_t ins = db_get_value(pc, sizeof(int), FALSE); 170 171 /* continue until call or return */ 172 173 if (!inst_call(ins) && 174 !inst_return(ins) && 175 !inst_trap_return(ins)) { 176 return (FALSE); /* continue */ 177 } 178 } 179 db_run_mode = STEP_NONE; 180 return (TRUE); 181 } 182 183 void 184 db_restart_at_pc(regs, watchpt) 185 db_regs_t *regs; 186 boolean_t watchpt; 187 { 188 db_addr_t pc = PC_REGS(regs); 189 190 if ((db_run_mode == STEP_COUNT) || 191 (db_run_mode == STEP_RETURN) || 192 (db_run_mode == STEP_CALLT)) { 193 db_expr_t ins; 194 195 /* 196 * We are about to execute this instruction, 197 * so count it now. 198 */ 199 ins = db_get_value(pc, sizeof(int), FALSE); 200 db_inst_count++; 201 db_load_count += inst_load(ins); 202 db_store_count += inst_store(ins); 203 204 #ifdef SOFTWARE_SSTEP 205 /* 206 * Account for instructions in delay slots. 207 */ 208 { 209 db_addr_t brpc; 210 211 brpc = next_instr_address(pc, TRUE); 212 if ((brpc != pc) && 213 (inst_branch(ins) || inst_call(ins) || inst_return(ins))) { 214 ins = db_get_value(brpc, sizeof(int), FALSE); 215 db_inst_count++; 216 db_load_count += inst_load(ins); 217 db_store_count += inst_store(ins); 218 } 219 } 220 #endif 221 } 222 223 if (db_run_mode == STEP_CONTINUE) { 224 if (watchpt || db_find_breakpoint_here(pc)) { 225 /* 226 * Step over breakpoint/watchpoint. 227 */ 228 db_run_mode = STEP_INVISIBLE; 229 db_set_single_step(regs); 230 } else { 231 db_set_breakpoints(); 232 db_set_watchpoints(); 233 } 234 } else { 235 db_set_single_step(regs); 236 } 237 } 238 239 void 240 db_single_step(regs) 241 db_regs_t *regs; 242 { 243 if (db_run_mode == STEP_CONTINUE) { 244 db_run_mode = STEP_INVISIBLE; 245 db_set_single_step(regs); 246 } 247 } 248 249 250 extern int db_cmd_loop_done; 251 252 /* single-step */ 253 /*ARGSUSED*/ 254 void 255 db_single_step_cmd(addr, have_addr, count, modif) 256 db_expr_t addr; 257 int have_addr; 258 db_expr_t count; 259 char * modif; 260 { 261 boolean_t print = FALSE; 262 263 if (count == -1) 264 count = 1; 265 266 if (modif[0] == 'p') 267 print = TRUE; 268 269 db_run_mode = STEP_ONCE; 270 db_loop_count = count; 271 db_sstep_print = print; 272 db_inst_count = 0; 273 db_load_count = 0; 274 db_store_count = 0; 275 276 db_cmd_loop_done = 1; 277 } 278 279 /* trace and print until call/return */ 280 /*ARGSUSED*/ 281 void 282 db_trace_until_call_cmd(addr, have_addr, count, modif) 283 db_expr_t addr; 284 int have_addr; 285 db_expr_t count; 286 char * modif; 287 { 288 boolean_t print = FALSE; 289 290 if (modif[0] == 'p') 291 print = TRUE; 292 293 db_run_mode = STEP_CALLT; 294 db_sstep_print = print; 295 db_inst_count = 0; 296 db_load_count = 0; 297 db_store_count = 0; 298 299 db_cmd_loop_done = 1; 300 } 301 302 /*ARGSUSED*/ 303 void 304 db_trace_until_matching_cmd(addr, have_addr, count, modif) 305 db_expr_t addr; 306 int have_addr; 307 db_expr_t count; 308 char * modif; 309 { 310 boolean_t print = FALSE; 311 312 if (modif[0] == 'p') 313 print = TRUE; 314 315 db_run_mode = STEP_RETURN; 316 db_call_depth = 1; 317 db_sstep_print = print; 318 db_inst_count = 0; 319 db_load_count = 0; 320 db_store_count = 0; 321 322 db_cmd_loop_done = 1; 323 } 324 325 /* continue */ 326 /*ARGSUSED*/ 327 void 328 db_continue_cmd(addr, have_addr, count, modif) 329 db_expr_t addr; 330 int have_addr; 331 db_expr_t count; 332 char * modif; 333 { 334 if (modif[0] == 'c') 335 db_run_mode = STEP_COUNT; 336 else 337 db_run_mode = STEP_CONTINUE; 338 db_inst_count = 0; 339 db_load_count = 0; 340 db_store_count = 0; 341 342 db_cmd_loop_done = 1; 343 } 344 #endif /* DDB */ 345 346 #ifdef SOFTWARE_SSTEP 347 /* 348 * Software implementation of single-stepping. 349 * If your machine does not have a trace mode 350 * similar to the vax or sun ones you can use 351 * this implementation, done for the mips. 352 * Just define the above conditional and provide 353 * the functions/macros defined below. 354 * 355 * boolean_t inst_branch(int inst) 356 * boolean_t inst_call(int inst) 357 * returns TRUE if the instruction might branch 358 * 359 * boolean_t inst_unconditional_flow_transfer(int inst) 360 * returns TRUE if the instruction is an unconditional 361 * transter of flow (i.e. unconditional branch) 362 * 363 * db_addr_t branch_taken(int inst, db_addr_t pc, db_regs_t *regs) 364 * returns the target address of the branch 365 * 366 * db_addr_t next_instr_address(db_addr_t pc, boolean_t bd) 367 * returns the address of the first instruction following the 368 * one at "pc", which is either in the taken path of the branch 369 * (bd == TRUE) or not. This is for machines (e.g. mips) with 370 * branch delays. 371 * 372 * A single-step may involve at most 2 breakpoints - 373 * one for branch-not-taken and one for branch taken. 374 * If one of these addresses does not already have a breakpoint, 375 * we allocate a breakpoint and save it here. 376 * These breakpoints are deleted on return. 377 */ 378 379 #if !defined(DDB) 380 /* XXX - don't check for existing breakpoints in KGDB-only case */ 381 #define db_find_breakpoint_here(pc) (0) 382 #endif 383 384 void 385 db_set_single_step(regs) 386 db_regs_t *regs; 387 { 388 db_addr_t pc = PC_REGS(regs), brpc = pc; 389 boolean_t unconditional; 390 unsigned int inst; 391 392 /* 393 * User was stopped at pc, e.g. the instruction 394 * at pc was not executed. 395 */ 396 inst = db_get_value(pc, sizeof(int), FALSE); 397 if (inst_branch(inst) || inst_call(inst) || inst_return(inst)) { 398 brpc = branch_taken(inst, pc, regs); 399 if (brpc != pc) { /* self-branches are hopeless */ 400 db_set_temp_breakpoint(&db_taken_bkpt, brpc); 401 } else 402 db_taken_bkpt.address = 0; 403 pc = next_instr_address(pc, TRUE); 404 } 405 406 /* 407 * Check if this control flow instruction is an 408 * unconditional transfer. 409 */ 410 unconditional = inst_unconditional_flow_transfer(inst); 411 412 pc = next_instr_address(pc, FALSE); 413 414 /* 415 * We only set the sequential breakpoint if previous 416 * instruction was not an unconditional change of flow 417 * control. If the previous instruction is an 418 * unconditional change of flow control, setting a 419 * breakpoint in the next sequential location may set 420 * a breakpoint in data or in another routine, which 421 * could screw up in either the program or the debugger. 422 * (Consider, for instance, that the next sequential 423 * instruction is the start of a routine needed by the 424 * debugger.) 425 * 426 * Also, don't set both the taken and not-taken breakpoints 427 * in the same place even if the MD code would otherwise 428 * have us do so. 429 */ 430 if (unconditional == FALSE && 431 db_find_breakpoint_here(pc) == 0 && 432 pc != brpc) 433 db_set_temp_breakpoint(&db_not_taken_bkpt, pc); 434 else 435 db_not_taken_bkpt.address = 0; 436 } 437 438 void 439 db_clear_single_step(regs) 440 db_regs_t *regs; 441 { 442 443 if (db_taken_bkpt.address != 0) 444 db_delete_temp_breakpoint(&db_taken_bkpt); 445 446 if (db_not_taken_bkpt.address != 0) 447 db_delete_temp_breakpoint(&db_not_taken_bkpt); 448 } 449 450 void 451 db_set_temp_breakpoint(bkpt, addr) 452 db_breakpoint_t bkpt; 453 db_addr_t addr; 454 { 455 456 bkpt->map = NULL; 457 bkpt->address = addr; 458 /* bkpt->flags = BKPT_TEMP; - this is not used */ 459 bkpt->init_count = 1; 460 bkpt->count = 1; 461 462 bkpt->bkpt_inst = db_get_value(bkpt->address, BKPT_SIZE, FALSE); 463 db_put_value(bkpt->address, BKPT_SIZE, BKPT_SET(bkpt->bkpt_inst)); 464 } 465 466 void 467 db_delete_temp_breakpoint(bkpt) 468 db_breakpoint_t bkpt; 469 { 470 db_put_value(bkpt->address, BKPT_SIZE, bkpt->bkpt_inst); 471 bkpt->address = 0; 472 } 473 474 #endif /* SOFTWARE_SSTEP */ 475