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