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