db_run.c revision 139747
1132718Skan/*- 2132718Skan * Mach Operating System 3169689Skan * Copyright (c) 1991,1990 Carnegie Mellon University 4132718Skan * All Rights Reserved. 5132718Skan * 6132718Skan * Permission to use, copy, modify and distribute this software and its 7132718Skan * documentation is hereby granted, provided that both the copyright 8132718Skan * notice and this permission notice appear in all copies of the 9132718Skan * software, derivative works or modified versions, and any portions 10132718Skan * thereof, and that both notices appear in supporting documentation. 11132718Skan * 12132718Skan * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS 13132718Skan * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 14132718Skan * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 15132718Skan * 16132718Skan * Carnegie Mellon requests users of this software to return to 17132718Skan * 18132718Skan * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 19169689Skan * School of Computer Science 20169689Skan * Carnegie Mellon University 21132718Skan * Pittsburgh PA 15213-3890 22132718Skan * 23132718Skan * any improvements or extensions that they make and grant Carnegie the 24132718Skan * rights to redistribute these changes. 25132718Skan */ 26132718Skan/* 27132718Skan * Author: David B. Golub, Carnegie Mellon University 28132718Skan * Date: 7/90 29132718Skan */ 30132718Skan 31132718Skan/* 32132718Skan * Commands to run process. 33132718Skan */ 34132718Skan 35132718Skan#include <sys/cdefs.h> 36146895Skan__FBSDID("$FreeBSD: head/sys/ddb/db_run.c 139747 2005-01-06 01:34:41Z imp $"); 37132718Skan 38146895Skan#include <sys/param.h> 39132718Skan#include <sys/kdb.h> 40132718Skan 41132718Skan#include <machine/kdb.h> 42132718Skan#include <machine/pcb.h> 43132718Skan 44132718Skan#include <vm/vm.h> 45132718Skan 46132718Skan#include <ddb/ddb.h> 47132718Skan#include <ddb/db_break.h> 48132718Skan#include <ddb/db_access.h> 49132718Skan 50132718Skanstatic int db_run_mode; 51132718Skan#define STEP_NONE 0 52132718Skan#define STEP_ONCE 1 53146895Skan#define STEP_RETURN 2 54146895Skan#define STEP_CALLT 3 55146895Skan#define STEP_CONTINUE 4 56169689Skan#define STEP_INVISIBLE 5 57169689Skan#define STEP_COUNT 6 58146895Skan 59146895Skanstatic boolean_t db_sstep_print; 60146895Skanstatic int db_loop_count; 61146895Skanstatic int db_call_depth; 62146895Skan 63132718Skanint db_inst_count; 64132718Skanint db_load_count; 65132718Skanint db_store_count; 66132718Skan 67132718Skan#ifndef db_set_single_step 68132718Skanvoid db_set_single_step(void); 69132718Skan#endif 70132718Skan#ifndef db_clear_single_step 71132718Skanvoid db_clear_single_step(void); 72132718Skan#endif 73132718Skan 74132718Skan#ifdef SOFTWARE_SSTEP 75169689Skandb_breakpoint_t db_not_taken_bkpt = 0; 76146895Skandb_breakpoint_t db_taken_bkpt = 0; 77132718Skan#endif 78132718Skan 79132718Skanboolean_t 80132718Skandb_stop_at_pc(is_breakpoint) 81132718Skan boolean_t *is_breakpoint; 82132718Skan{ 83132718Skan register db_addr_t pc; 84132718Skan register db_breakpoint_t bkpt; 85132718Skan 86132718Skan pc = PC_REGS(); 87132718Skan#ifdef SOFTWARE_SSTEP 88132718Skan if ((db_not_taken_bkpt != 0 && pc == db_not_taken_bkpt->address) 89132718Skan || (db_taken_bkpt != 0 && pc == db_taken_bkpt->address)) 90132718Skan *is_breakpoint = FALSE; 91132718Skan#endif 92132718Skan 93132718Skan db_clear_single_step(); 94132718Skan db_clear_breakpoints(); 95132718Skan db_clear_watchpoints(); 96132718Skan 97132718Skan#ifdef FIXUP_PC_AFTER_BREAK 98132718Skan if (*is_breakpoint) { 99132718Skan /* 100132718Skan * Breakpoint trap. Fix up the PC if the 101132718Skan * machine requires it. 102132718Skan */ 103132718Skan FIXUP_PC_AFTER_BREAK 104132718Skan pc = PC_REGS(); 105132718Skan } 106132718Skan#endif 107132718Skan 108132718Skan /* 109132718Skan * Now check for a breakpoint at this address. 110132718Skan */ 111132718Skan bkpt = db_find_breakpoint_here(pc); 112146895Skan if (bkpt) { 113146895Skan if (--bkpt->count == 0) { 114146895Skan bkpt->count = bkpt->init_count; 115146895Skan *is_breakpoint = TRUE; 116146895Skan return (TRUE); /* stop here */ 117146895Skan } 118169689Skan } else if (*is_breakpoint) { 119146895Skan#ifdef BKPT_SKIP 120146895Skan BKPT_SKIP; 121146895Skan#endif 122146895Skan } 123146895Skan 124146895Skan *is_breakpoint = FALSE; 125146895Skan 126146895Skan if (db_run_mode == STEP_INVISIBLE) { 127146895Skan db_run_mode = STEP_CONTINUE; 128146895Skan return (FALSE); /* continue */ 129146895Skan } 130146895Skan if (db_run_mode == STEP_COUNT) { 131146895Skan return (FALSE); /* continue */ 132146895Skan } 133146895Skan if (db_run_mode == STEP_ONCE) { 134146895Skan if (--db_loop_count > 0) { 135146895Skan if (db_sstep_print) { 136146895Skan db_printf("\t\t"); 137146895Skan db_print_loc_and_inst(pc); 138146895Skan db_printf("\n"); 139146895Skan } 140146895Skan return (FALSE); /* continue */ 141146895Skan } 142146895Skan } 143146895Skan if (db_run_mode == STEP_RETURN) { 144146895Skan /* continue until matching return */ 145146895Skan db_expr_t ins; 146146895Skan 147146895Skan ins = db_get_value(pc, sizeof(int), FALSE); 148146895Skan if (!inst_trap_return(ins) && 149146895Skan (!inst_return(ins) || --db_call_depth != 0)) { 150146895Skan if (db_sstep_print) { 151132718Skan if (inst_call(ins) || inst_return(ins)) { 152132718Skan register int i; 153132718Skan 154132718Skan db_printf("[after %6d] ", db_inst_count); 155132718Skan for (i = db_call_depth; --i > 0; ) 156132718Skan db_printf(" "); 157132718Skan db_print_loc_and_inst(pc); 158169689Skan db_printf("\n"); 159132718Skan } 160132718Skan } 161132718Skan if (inst_call(ins)) 162132718Skan db_call_depth++; 163132718Skan return (FALSE); /* continue */ 164132718Skan } 165132718Skan } 166132718Skan if (db_run_mode == STEP_CALLT) { 167132718Skan /* continue until call or return */ 168169689Skan db_expr_t ins; 169132718Skan 170132718Skan ins = db_get_value(pc, sizeof(int), FALSE); 171132718Skan if (!inst_call(ins) && 172132718Skan !inst_return(ins) && 173132718Skan !inst_trap_return(ins)) { 174132718Skan return (FALSE); /* continue */ 175132718Skan } 176132718Skan } 177132718Skan db_run_mode = STEP_NONE; 178132718Skan return (TRUE); 179132718Skan} 180132718Skan 181132718Skanvoid 182132718Skandb_restart_at_pc(watchpt) 183132718Skan boolean_t watchpt; 184132718Skan{ 185132718Skan register db_addr_t pc = PC_REGS(); 186132718Skan 187132718Skan if ((db_run_mode == STEP_COUNT) || 188132718Skan (db_run_mode == STEP_RETURN) || 189132718Skan (db_run_mode == STEP_CALLT)) { 190132718Skan db_expr_t ins; 191132718Skan 192132718Skan /* 193132718Skan * We are about to execute this instruction, 194132718Skan * so count it now. 195132718Skan */ 196132718Skan 197132718Skan ins = db_get_value(pc, sizeof(int), FALSE); 198132718Skan db_inst_count++; 199132718Skan db_load_count += inst_load(ins); 200132718Skan db_store_count += inst_store(ins); 201132718Skan#ifdef SOFTWARE_SSTEP 202132718Skan /* XXX works on mips, but... */ 203132718Skan if (inst_branch(ins) || inst_call(ins)) { 204132718Skan ins = db_get_value(next_instr_address(pc,1), 205132718Skan sizeof(int), FALSE); 206132718Skan db_inst_count++; 207132718Skan db_load_count += inst_load(ins); 208132718Skan db_store_count += inst_store(ins); 209132718Skan } 210132718Skan#endif /* SOFTWARE_SSTEP */ 211132718Skan } 212146895Skan 213146895Skan if (db_run_mode == STEP_CONTINUE) { 214146895Skan if (watchpt || db_find_breakpoint_here(pc)) { 215146895Skan /* 216146895Skan * Step over breakpoint/watchpoint. 217146895Skan */ 218146895Skan db_run_mode = STEP_INVISIBLE; 219146895Skan db_set_single_step(); 220146895Skan } else { 221146895Skan db_set_breakpoints(); 222146895Skan db_set_watchpoints(); 223146895Skan } 224146895Skan } else { 225146895Skan db_set_single_step(); 226146895Skan } 227146895Skan} 228146895Skan 229146895Skan#ifdef SOFTWARE_SSTEP 230146895Skan/* 231146895Skan * Software implementation of single-stepping. 232146895Skan * If your machine does not have a trace mode 233146895Skan * similar to the vax or sun ones you can use 234146895Skan * this implementation, done for the mips. 235146895Skan * Just define the above conditional and provide 236146895Skan * the functions/macros defined below. 237146895Skan * 238146895Skan * extern boolean_t 239146895Skan * inst_branch(), returns true if the instruction might branch 240146895Skan * extern unsigned 241146895Skan * branch_taken(), return the address the instruction might 242146895Skan * branch to 243146895Skan * db_getreg_val(); return the value of a user register, 244146895Skan * as indicated in the hardware instruction 245146895Skan * encoding, e.g. 8 for r8 246146895Skan * 247146895Skan * next_instr_address(pc,bd) returns the address of the first 248146895Skan * instruction following the one at "pc", 249146895Skan * which is either in the taken path of 250146895Skan * the branch (bd==1) or not. This is 251146895Skan * for machines (mips) with branch delays. 252146895Skan * 253146895Skan * A single-step may involve at most 2 breakpoints - 254146895Skan * one for branch-not-taken and one for branch taken. 255146895Skan * If one of these addresses does not already have a breakpoint, 256169689Skan * we allocate a breakpoint and save it here. 257169689Skan * These breakpoints are deleted on return. 258146895Skan */ 259146895Skan 260146895Skanvoid 261146895Skandb_set_single_step(void) 262146895Skan{ 263146895Skan db_addr_t pc = PC_REGS(), brpc; 264132718Skan unsigned inst; 265132718Skan 266132718Skan /* 267132718Skan * User was stopped at pc, e.g. the instruction 268132718Skan * at pc was not executed. 269132718Skan */ 270132718Skan inst = db_get_value(pc, sizeof(int), FALSE); 271132718Skan if (inst_branch(inst) || inst_call(inst)) { 272132718Skan brpc = branch_taken(inst, pc); 273132718Skan if (brpc != pc) { /* self-branches are hopeless */ 274132718Skan db_taken_bkpt = db_set_temp_breakpoint(brpc); 275132718Skan } 276169689Skan pc = next_instr_address(pc, 1); 277132718Skan } 278132718Skan pc = next_instr_address(pc, 0); 279132718Skan db_not_taken_bkpt = db_set_temp_breakpoint(pc); 280132718Skan} 281169689Skan 282132718Skanvoid 283132718Skandb_clear_single_step(void) 284132718Skan{ 285132718Skan 286132718Skan if (db_not_taken_bkpt != 0) { 287132718Skan db_delete_temp_breakpoint(db_not_taken_bkpt); 288132718Skan db_not_taken_bkpt = 0; 289132718Skan } 290169689Skan if (db_taken_bkpt != 0) { 291169689Skan db_delete_temp_breakpoint(db_taken_bkpt); 292169689Skan db_taken_bkpt = 0; 293169689Skan } 294169689Skan} 295169689Skan 296169689Skan#endif /* SOFTWARE_SSTEP */ 297169689Skan 298169689Skanextern int db_cmd_loop_done; 299169689Skan 300169689Skan/* single-step */ 301169689Skan/*ARGSUSED*/ 302169689Skanvoid 303169689Skandb_single_step_cmd(addr, have_addr, count, modif) 304169689Skan db_expr_t addr; 305169689Skan boolean_t have_addr; 306169689Skan db_expr_t count; 307169689Skan char * modif; 308169689Skan{ 309169689Skan boolean_t print = FALSE; 310132718Skan 311132718Skan if (count == -1) 312132718Skan count = 1; 313169689Skan 314169689Skan if (modif[0] == 'p') 315132718Skan print = TRUE; 316132718Skan 317132718Skan db_run_mode = STEP_ONCE; 318132718Skan db_loop_count = count; 319132718Skan db_sstep_print = print; 320132718Skan db_inst_count = 0; 321132718Skan db_load_count = 0; 322132718Skan db_store_count = 0; 323132718Skan 324132718Skan db_cmd_loop_done = 1; 325132718Skan} 326132718Skan 327132718Skan/* trace and print until call/return */ 328132718Skan/*ARGSUSED*/ 329132718Skanvoid 330132718Skandb_trace_until_call_cmd(addr, have_addr, count, modif) 331169689Skan db_expr_t addr; 332132718Skan boolean_t have_addr; 333169689Skan db_expr_t count; 334132718Skan char * modif; 335132718Skan{ 336132718Skan boolean_t print = FALSE; 337132718Skan 338169689Skan if (modif[0] == 'p') 339132718Skan print = TRUE; 340169689Skan 341132718Skan db_run_mode = STEP_CALLT; 342132718Skan db_sstep_print = print; 343132718Skan db_inst_count = 0; 344132718Skan db_load_count = 0; 345132718Skan db_store_count = 0; 346132718Skan 347132718Skan db_cmd_loop_done = 1; 348132718Skan} 349132718Skan 350169689Skan/*ARGSUSED*/ 351169689Skanvoid 352169689Skandb_trace_until_matching_cmd(addr, have_addr, count, modif) 353169689Skan db_expr_t addr; 354169689Skan boolean_t have_addr; 355169689Skan db_expr_t count; 356132718Skan char * modif; 357132718Skan{ 358132718Skan boolean_t print = FALSE; 359132718Skan 360132718Skan if (modif[0] == 'p') 361132718Skan print = TRUE; 362132718Skan 363132718Skan db_run_mode = STEP_RETURN; 364132718Skan db_call_depth = 1; 365169689Skan db_sstep_print = print; 366169689Skan db_inst_count = 0; 367169689Skan db_load_count = 0; 368169689Skan db_store_count = 0; 369169689Skan 370169689Skan db_cmd_loop_done = 1; 371132718Skan} 372132718Skan 373132718Skan/* continue */ 374132718Skan/*ARGSUSED*/ 375169689Skanvoid 376169689Skandb_continue_cmd(addr, have_addr, count, modif) 377169689Skan db_expr_t addr; 378169689Skan boolean_t have_addr; 379169689Skan db_expr_t count; 380169689Skan char * modif; 381132718Skan{ 382132718Skan if (modif[0] == 'c') 383132718Skan db_run_mode = STEP_COUNT; 384132718Skan else 385132718Skan db_run_mode = STEP_CONTINUE; 386132718Skan db_inst_count = 0; 387132718Skan db_load_count = 0; 388132718Skan db_store_count = 0; 389132718Skan 390132718Skan db_cmd_loop_done = 1; 391132718Skan} 392132718Skan