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