db_run.c revision 139747
1139747Simp/*- 24Srgrimes * Mach Operating System 34Srgrimes * Copyright (c) 1991,1990 Carnegie Mellon University 44Srgrimes * All Rights Reserved. 58876Srgrimes * 64Srgrimes * Permission to use, copy, modify and distribute this software and its 74Srgrimes * documentation is hereby granted, provided that both the copyright 84Srgrimes * notice and this permission notice appear in all copies of the 94Srgrimes * software, derivative works or modified versions, and any portions 104Srgrimes * thereof, and that both notices appear in supporting documentation. 118876Srgrimes * 128876Srgrimes * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS 134Srgrimes * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 144Srgrimes * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 158876Srgrimes * 164Srgrimes * Carnegie Mellon requests users of this software to return to 178876Srgrimes * 184Srgrimes * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 194Srgrimes * School of Computer Science 204Srgrimes * Carnegie Mellon University 214Srgrimes * Pittsburgh PA 15213-3890 228876Srgrimes * 234Srgrimes * any improvements or extensions that they make and grant Carnegie the 244Srgrimes * rights to redistribute these changes. 254Srgrimes */ 264Srgrimes/* 274Srgrimes * Author: David B. Golub, Carnegie Mellon University 284Srgrimes * Date: 7/90 294Srgrimes */ 304Srgrimes 314Srgrimes/* 324Srgrimes * Commands to run process. 334Srgrimes */ 34116176Sobrien 35116176Sobrien#include <sys/cdefs.h> 36116176Sobrien__FBSDID("$FreeBSD: head/sys/ddb/db_run.c 139747 2005-01-06 01:34:41Z imp $"); 37116176Sobrien 382056Swollman#include <sys/param.h> 39131952Smarcel#include <sys/kdb.h> 4012734Sbde 41131952Smarcel#include <machine/kdb.h> 42131952Smarcel#include <machine/pcb.h> 43131952Smarcel 4412662Sdg#include <vm/vm.h> 4512734Sbde 462056Swollman#include <ddb/ddb.h> 474Srgrimes#include <ddb/db_break.h> 484Srgrimes#include <ddb/db_access.h> 494Srgrimes 5012720Sphkstatic int db_run_mode; 514Srgrimes#define STEP_NONE 0 524Srgrimes#define STEP_ONCE 1 534Srgrimes#define STEP_RETURN 2 544Srgrimes#define STEP_CALLT 3 554Srgrimes#define STEP_CONTINUE 4 564Srgrimes#define STEP_INVISIBLE 5 574Srgrimes#define STEP_COUNT 6 584Srgrimes 5912720Sphkstatic boolean_t db_sstep_print; 6012720Sphkstatic int db_loop_count; 6112720Sphkstatic int db_call_depth; 624Srgrimes 634Srgrimesint db_inst_count; 644Srgrimesint db_load_count; 654Srgrimesint db_store_count; 664Srgrimes 674Srgrimes#ifndef db_set_single_step 68131952Smarcelvoid db_set_single_step(void); 694Srgrimes#endif 704Srgrimes#ifndef db_clear_single_step 71131952Smarcelvoid db_clear_single_step(void); 724Srgrimes#endif 734Srgrimes 74137974Scognet#ifdef SOFTWARE_SSTEP 75137974Scognetdb_breakpoint_t db_not_taken_bkpt = 0; 76137974Scognetdb_breakpoint_t db_taken_bkpt = 0; 77137974Scognet#endif 78137974Scognet 794Srgrimesboolean_t 804Srgrimesdb_stop_at_pc(is_breakpoint) 814Srgrimes boolean_t *is_breakpoint; 824Srgrimes{ 834Srgrimes register db_addr_t pc; 844Srgrimes register db_breakpoint_t bkpt; 854Srgrimes 86137974Scognet pc = PC_REGS(); 87137974Scognet#ifdef SOFTWARE_SSTEP 88137974Scognet if ((db_not_taken_bkpt != 0 && pc == db_not_taken_bkpt->address) 89137974Scognet || (db_taken_bkpt != 0 && pc == db_taken_bkpt->address)) 90137974Scognet *is_breakpoint = FALSE; 91137974Scognet#endif 92137974Scognet 93131952Smarcel db_clear_single_step(); 944Srgrimes db_clear_breakpoints(); 954Srgrimes db_clear_watchpoints(); 964Srgrimes 974Srgrimes#ifdef FIXUP_PC_AFTER_BREAK 984Srgrimes if (*is_breakpoint) { 994Srgrimes /* 1004Srgrimes * Breakpoint trap. Fix up the PC if the 1014Srgrimes * machine requires it. 1024Srgrimes */ 1034Srgrimes FIXUP_PC_AFTER_BREAK 104131952Smarcel pc = PC_REGS(); 1054Srgrimes } 1064Srgrimes#endif 1074Srgrimes 1084Srgrimes /* 1094Srgrimes * Now check for a breakpoint at this address. 1104Srgrimes */ 1114Srgrimes bkpt = db_find_breakpoint_here(pc); 1124Srgrimes if (bkpt) { 1134Srgrimes if (--bkpt->count == 0) { 1144Srgrimes bkpt->count = bkpt->init_count; 1154Srgrimes *is_breakpoint = TRUE; 1164Srgrimes return (TRUE); /* stop here */ 1174Srgrimes } 1184Srgrimes } else if (*is_breakpoint) { 11983506Sdfr#ifdef BKPT_SKIP 12083506Sdfr BKPT_SKIP; 12136735Sdfr#endif 1224Srgrimes } 1238876Srgrimes 1244Srgrimes *is_breakpoint = FALSE; 1254Srgrimes 1264Srgrimes if (db_run_mode == STEP_INVISIBLE) { 1274Srgrimes db_run_mode = STEP_CONTINUE; 1284Srgrimes return (FALSE); /* continue */ 1294Srgrimes } 1304Srgrimes if (db_run_mode == STEP_COUNT) { 1314Srgrimes return (FALSE); /* continue */ 1324Srgrimes } 1334Srgrimes if (db_run_mode == STEP_ONCE) { 1344Srgrimes if (--db_loop_count > 0) { 1354Srgrimes if (db_sstep_print) { 1364Srgrimes db_printf("\t\t"); 1374Srgrimes db_print_loc_and_inst(pc); 1384Srgrimes db_printf("\n"); 1394Srgrimes } 1404Srgrimes return (FALSE); /* continue */ 1414Srgrimes } 1424Srgrimes } 1434Srgrimes if (db_run_mode == STEP_RETURN) { 1444Srgrimes /* continue until matching return */ 14598694Smux db_expr_t ins; 1464Srgrimes 14798694Smux ins = db_get_value(pc, sizeof(int), FALSE); 1484Srgrimes if (!inst_trap_return(ins) && 1494Srgrimes (!inst_return(ins) || --db_call_depth != 0)) { 1504Srgrimes if (db_sstep_print) { 1514Srgrimes if (inst_call(ins) || inst_return(ins)) { 1524Srgrimes register int i; 1534Srgrimes 1544Srgrimes db_printf("[after %6d] ", db_inst_count); 1554Srgrimes for (i = db_call_depth; --i > 0; ) 1564Srgrimes db_printf(" "); 1574Srgrimes db_print_loc_and_inst(pc); 1584Srgrimes db_printf("\n"); 1594Srgrimes } 1604Srgrimes } 1614Srgrimes if (inst_call(ins)) 1624Srgrimes db_call_depth++; 1634Srgrimes return (FALSE); /* continue */ 1644Srgrimes } 1654Srgrimes } 1664Srgrimes if (db_run_mode == STEP_CALLT) { 1674Srgrimes /* continue until call or return */ 16898694Smux db_expr_t ins; 1694Srgrimes 17098694Smux ins = db_get_value(pc, sizeof(int), FALSE); 1714Srgrimes if (!inst_call(ins) && 1724Srgrimes !inst_return(ins) && 1734Srgrimes !inst_trap_return(ins)) { 1744Srgrimes return (FALSE); /* continue */ 1754Srgrimes } 1764Srgrimes } 1774Srgrimes db_run_mode = STEP_NONE; 1784Srgrimes return (TRUE); 1794Srgrimes} 1804Srgrimes 1814Srgrimesvoid 1824Srgrimesdb_restart_at_pc(watchpt) 1834Srgrimes boolean_t watchpt; 1844Srgrimes{ 185131952Smarcel register db_addr_t pc = PC_REGS(); 1864Srgrimes 1874Srgrimes if ((db_run_mode == STEP_COUNT) || 1884Srgrimes (db_run_mode == STEP_RETURN) || 1894Srgrimes (db_run_mode == STEP_CALLT)) { 1904Srgrimes db_expr_t ins; 1914Srgrimes 1924Srgrimes /* 1934Srgrimes * We are about to execute this instruction, 1944Srgrimes * so count it now. 1954Srgrimes */ 1964Srgrimes 1974Srgrimes ins = db_get_value(pc, sizeof(int), FALSE); 1984Srgrimes db_inst_count++; 1994Srgrimes db_load_count += inst_load(ins); 2004Srgrimes db_store_count += inst_store(ins); 2014Srgrimes#ifdef SOFTWARE_SSTEP 2024Srgrimes /* XXX works on mips, but... */ 2034Srgrimes if (inst_branch(ins) || inst_call(ins)) { 2044Srgrimes ins = db_get_value(next_instr_address(pc,1), 2054Srgrimes sizeof(int), FALSE); 2064Srgrimes db_inst_count++; 2074Srgrimes db_load_count += inst_load(ins); 2084Srgrimes db_store_count += inst_store(ins); 2094Srgrimes } 21081670Sobrien#endif /* SOFTWARE_SSTEP */ 2114Srgrimes } 2124Srgrimes 2134Srgrimes if (db_run_mode == STEP_CONTINUE) { 2144Srgrimes if (watchpt || db_find_breakpoint_here(pc)) { 2154Srgrimes /* 2164Srgrimes * Step over breakpoint/watchpoint. 2174Srgrimes */ 2184Srgrimes db_run_mode = STEP_INVISIBLE; 219131952Smarcel db_set_single_step(); 2204Srgrimes } else { 2214Srgrimes db_set_breakpoints(); 2224Srgrimes db_set_watchpoints(); 2234Srgrimes } 2244Srgrimes } else { 225131952Smarcel db_set_single_step(); 2264Srgrimes } 2274Srgrimes} 2284Srgrimes 2294Srgrimes#ifdef SOFTWARE_SSTEP 2304Srgrimes/* 2314Srgrimes * Software implementation of single-stepping. 2324Srgrimes * If your machine does not have a trace mode 2334Srgrimes * similar to the vax or sun ones you can use 2344Srgrimes * this implementation, done for the mips. 2354Srgrimes * Just define the above conditional and provide 2364Srgrimes * the functions/macros defined below. 2374Srgrimes * 2384Srgrimes * extern boolean_t 2394Srgrimes * inst_branch(), returns true if the instruction might branch 2404Srgrimes * extern unsigned 2414Srgrimes * branch_taken(), return the address the instruction might 2424Srgrimes * branch to 2434Srgrimes * db_getreg_val(); return the value of a user register, 2444Srgrimes * as indicated in the hardware instruction 2454Srgrimes * encoding, e.g. 8 for r8 2468876Srgrimes * 2474Srgrimes * next_instr_address(pc,bd) returns the address of the first 2484Srgrimes * instruction following the one at "pc", 2494Srgrimes * which is either in the taken path of 2504Srgrimes * the branch (bd==1) or not. This is 2514Srgrimes * for machines (mips) with branch delays. 2524Srgrimes * 2534Srgrimes * A single-step may involve at most 2 breakpoints - 2544Srgrimes * one for branch-not-taken and one for branch taken. 2554Srgrimes * If one of these addresses does not already have a breakpoint, 2564Srgrimes * we allocate a breakpoint and save it here. 2574Srgrimes * These breakpoints are deleted on return. 2588876Srgrimes */ 2594Srgrimes 2604Srgrimesvoid 261131952Smarceldb_set_single_step(void) 2624Srgrimes{ 263131952Smarcel db_addr_t pc = PC_REGS(), brpc; 264131952Smarcel unsigned inst; 2654Srgrimes 2664Srgrimes /* 2674Srgrimes * User was stopped at pc, e.g. the instruction 2684Srgrimes * at pc was not executed. 2694Srgrimes */ 2704Srgrimes inst = db_get_value(pc, sizeof(int), FALSE); 2714Srgrimes if (inst_branch(inst) || inst_call(inst)) { 272131952Smarcel brpc = branch_taken(inst, pc); 273131952Smarcel if (brpc != pc) { /* self-branches are hopeless */ 274131952Smarcel db_taken_bkpt = db_set_temp_breakpoint(brpc); 275131952Smarcel } 276131952Smarcel pc = next_instr_address(pc, 1); 2774Srgrimes } 278131952Smarcel pc = next_instr_address(pc, 0); 2794Srgrimes db_not_taken_bkpt = db_set_temp_breakpoint(pc); 2804Srgrimes} 2814Srgrimes 2824Srgrimesvoid 283131952Smarceldb_clear_single_step(void) 2844Srgrimes{ 2854Srgrimes 28637392Sdfr if (db_not_taken_bkpt != 0) { 287131952Smarcel db_delete_temp_breakpoint(db_not_taken_bkpt); 288131952Smarcel db_not_taken_bkpt = 0; 28937392Sdfr } 2904Srgrimes if (db_taken_bkpt != 0) { 291131952Smarcel db_delete_temp_breakpoint(db_taken_bkpt); 292131952Smarcel db_taken_bkpt = 0; 2934Srgrimes } 2944Srgrimes} 2954Srgrimes 29681670Sobrien#endif /* SOFTWARE_SSTEP */ 2974Srgrimes 2984Srgrimesextern int db_cmd_loop_done; 2994Srgrimes 3004Srgrimes/* single-step */ 3014Srgrimes/*ARGSUSED*/ 3024Srgrimesvoid 3034Srgrimesdb_single_step_cmd(addr, have_addr, count, modif) 3044Srgrimes db_expr_t addr; 30512473Sbde boolean_t have_addr; 3064Srgrimes db_expr_t count; 3074Srgrimes char * modif; 3084Srgrimes{ 3094Srgrimes boolean_t print = FALSE; 3104Srgrimes 3114Srgrimes if (count == -1) 3124Srgrimes count = 1; 3134Srgrimes 3144Srgrimes if (modif[0] == 'p') 3154Srgrimes print = TRUE; 3164Srgrimes 3174Srgrimes db_run_mode = STEP_ONCE; 3184Srgrimes db_loop_count = count; 3194Srgrimes db_sstep_print = print; 3204Srgrimes db_inst_count = 0; 3214Srgrimes db_load_count = 0; 3224Srgrimes db_store_count = 0; 3234Srgrimes 3244Srgrimes db_cmd_loop_done = 1; 3254Srgrimes} 3264Srgrimes 3274Srgrimes/* trace and print until call/return */ 3284Srgrimes/*ARGSUSED*/ 3294Srgrimesvoid 3304Srgrimesdb_trace_until_call_cmd(addr, have_addr, count, modif) 3314Srgrimes db_expr_t addr; 33212473Sbde boolean_t have_addr; 3334Srgrimes db_expr_t count; 3344Srgrimes char * modif; 3354Srgrimes{ 3364Srgrimes boolean_t print = FALSE; 3374Srgrimes 3384Srgrimes if (modif[0] == 'p') 3394Srgrimes print = TRUE; 3404Srgrimes 3414Srgrimes db_run_mode = STEP_CALLT; 3424Srgrimes db_sstep_print = print; 3434Srgrimes db_inst_count = 0; 3444Srgrimes db_load_count = 0; 3454Srgrimes db_store_count = 0; 3464Srgrimes 3474Srgrimes db_cmd_loop_done = 1; 3484Srgrimes} 3494Srgrimes 3504Srgrimes/*ARGSUSED*/ 3514Srgrimesvoid 3524Srgrimesdb_trace_until_matching_cmd(addr, have_addr, count, modif) 3534Srgrimes db_expr_t addr; 35412473Sbde boolean_t have_addr; 3554Srgrimes db_expr_t count; 3564Srgrimes char * modif; 3574Srgrimes{ 3584Srgrimes boolean_t print = FALSE; 3594Srgrimes 3604Srgrimes if (modif[0] == 'p') 3614Srgrimes print = TRUE; 3624Srgrimes 3634Srgrimes db_run_mode = STEP_RETURN; 3644Srgrimes db_call_depth = 1; 3654Srgrimes db_sstep_print = print; 3664Srgrimes db_inst_count = 0; 3674Srgrimes db_load_count = 0; 3684Srgrimes db_store_count = 0; 3694Srgrimes 3704Srgrimes db_cmd_loop_done = 1; 3714Srgrimes} 3724Srgrimes 3734Srgrimes/* continue */ 3744Srgrimes/*ARGSUSED*/ 3754Srgrimesvoid 3764Srgrimesdb_continue_cmd(addr, have_addr, count, modif) 3774Srgrimes db_expr_t addr; 37812473Sbde boolean_t have_addr; 3794Srgrimes db_expr_t count; 3804Srgrimes char * modif; 3814Srgrimes{ 3824Srgrimes if (modif[0] == 'c') 3834Srgrimes db_run_mode = STEP_COUNT; 3844Srgrimes else 3854Srgrimes db_run_mode = STEP_CONTINUE; 3864Srgrimes db_inst_count = 0; 3874Srgrimes db_load_count = 0; 3884Srgrimes db_store_count = 0; 3894Srgrimes 3904Srgrimes db_cmd_loop_done = 1; 3914Srgrimes} 392