db_run.c revision 291407
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 291407 2015-11-27 19:03:59Z zbb $"); 37116176Sobrien 382056Swollman#include <sys/param.h> 39131952Smarcel#include <sys/kdb.h> 40145053Speter#include <sys/proc.h> 4112734Sbde 42131952Smarcel#include <machine/kdb.h> 43131952Smarcel#include <machine/pcb.h> 44131952Smarcel 4512662Sdg#include <vm/vm.h> 4612734Sbde 472056Swollman#include <ddb/ddb.h> 484Srgrimes#include <ddb/db_break.h> 494Srgrimes#include <ddb/db_access.h> 504Srgrimes 5112720Sphkstatic int db_run_mode; 524Srgrimes#define STEP_NONE 0 534Srgrimes#define STEP_ONCE 1 544Srgrimes#define STEP_RETURN 2 554Srgrimes#define STEP_CALLT 3 564Srgrimes#define STEP_CONTINUE 4 57272958Spfg#define STEP_INVISIBLE 5 584Srgrimes#define STEP_COUNT 6 594Srgrimes 60283248Spfgstatic bool db_sstep_print; 6112720Sphkstatic int db_loop_count; 6212720Sphkstatic int db_call_depth; 634Srgrimes 644Srgrimesint db_inst_count; 654Srgrimesint db_load_count; 664Srgrimesint db_store_count; 674Srgrimes 68291407Szbb#ifdef SOFTWARE_SSTEP 69291407Szbbdb_breakpoint_t db_not_taken_bkpt = 0; 70291407Szbbdb_breakpoint_t db_taken_bkpt = 0; 71291407Szbb#endif 72291407Szbb 734Srgrimes#ifndef db_set_single_step 74131952Smarcelvoid db_set_single_step(void); 754Srgrimes#endif 764Srgrimes#ifndef db_clear_single_step 77131952Smarcelvoid db_clear_single_step(void); 784Srgrimes#endif 79291407Szbb#ifndef db_pc_is_singlestep 80291407Szbbstatic bool 81291407Szbbdb_pc_is_singlestep(db_addr_t pc) 82291407Szbb{ 83137974Scognet#ifdef SOFTWARE_SSTEP 84291407Szbb if ((db_not_taken_bkpt != 0 && pc == db_not_taken_bkpt->address) 85291407Szbb || (db_taken_bkpt != 0 && pc == db_taken_bkpt->address)) 86291407Szbb return (true); 87137974Scognet#endif 88291407Szbb return (false); 89291407Szbb} 90291407Szbb#endif 91137974Scognet 92283248Spfgbool 93283248Spfgdb_stop_at_pc(bool *is_breakpoint) 944Srgrimes{ 95283315Spfg db_addr_t pc; 96283315Spfg db_breakpoint_t bkpt; 974Srgrimes 98137974Scognet pc = PC_REGS(); 99291407Szbb 100291407Szbb if (db_pc_is_singlestep(pc)) 101283088Spfg *is_breakpoint = false; 102137974Scognet 103131952Smarcel db_clear_single_step(); 1044Srgrimes db_clear_breakpoints(); 1054Srgrimes db_clear_watchpoints(); 1064Srgrimes 1074Srgrimes#ifdef FIXUP_PC_AFTER_BREAK 1084Srgrimes if (*is_breakpoint) { 1094Srgrimes /* 1104Srgrimes * Breakpoint trap. Fix up the PC if the 1114Srgrimes * machine requires it. 1124Srgrimes */ 1134Srgrimes FIXUP_PC_AFTER_BREAK 114131952Smarcel pc = PC_REGS(); 1154Srgrimes } 1164Srgrimes#endif 1174Srgrimes 1184Srgrimes /* 1194Srgrimes * Now check for a breakpoint at this address. 1204Srgrimes */ 1214Srgrimes bkpt = db_find_breakpoint_here(pc); 1224Srgrimes if (bkpt) { 1234Srgrimes if (--bkpt->count == 0) { 1244Srgrimes bkpt->count = bkpt->init_count; 125283088Spfg *is_breakpoint = true; 126283088Spfg return (true); /* stop here */ 1274Srgrimes } 1284Srgrimes } else if (*is_breakpoint) { 12983506Sdfr#ifdef BKPT_SKIP 13083506Sdfr BKPT_SKIP; 13136735Sdfr#endif 1324Srgrimes } 1338876Srgrimes 134283088Spfg *is_breakpoint = false; 1354Srgrimes 1364Srgrimes if (db_run_mode == STEP_INVISIBLE) { 1374Srgrimes db_run_mode = STEP_CONTINUE; 138283088Spfg return (false); /* continue */ 1394Srgrimes } 1404Srgrimes if (db_run_mode == STEP_COUNT) { 141283088Spfg return (false); /* continue */ 1424Srgrimes } 1434Srgrimes if (db_run_mode == STEP_ONCE) { 1444Srgrimes if (--db_loop_count > 0) { 1454Srgrimes if (db_sstep_print) { 1464Srgrimes db_printf("\t\t"); 1474Srgrimes db_print_loc_and_inst(pc); 1484Srgrimes db_printf("\n"); 1494Srgrimes } 150283088Spfg return (false); /* continue */ 1514Srgrimes } 1524Srgrimes } 1534Srgrimes if (db_run_mode == STEP_RETURN) { 1544Srgrimes /* continue until matching return */ 15598694Smux db_expr_t ins; 1564Srgrimes 157283088Spfg ins = db_get_value(pc, sizeof(int), false); 1584Srgrimes if (!inst_trap_return(ins) && 1594Srgrimes (!inst_return(ins) || --db_call_depth != 0)) { 1604Srgrimes if (db_sstep_print) { 1614Srgrimes if (inst_call(ins) || inst_return(ins)) { 162283315Spfg int i; 1634Srgrimes 1644Srgrimes db_printf("[after %6d] ", db_inst_count); 1654Srgrimes for (i = db_call_depth; --i > 0; ) 1664Srgrimes db_printf(" "); 1674Srgrimes db_print_loc_and_inst(pc); 1684Srgrimes db_printf("\n"); 1694Srgrimes } 1704Srgrimes } 1714Srgrimes if (inst_call(ins)) 1724Srgrimes db_call_depth++; 173283088Spfg return (false); /* continue */ 1744Srgrimes } 1754Srgrimes } 1764Srgrimes if (db_run_mode == STEP_CALLT) { 1774Srgrimes /* continue until call or return */ 17898694Smux db_expr_t ins; 1794Srgrimes 180283088Spfg ins = db_get_value(pc, sizeof(int), false); 1814Srgrimes if (!inst_call(ins) && 1824Srgrimes !inst_return(ins) && 1834Srgrimes !inst_trap_return(ins)) { 184283088Spfg return (false); /* continue */ 1854Srgrimes } 1864Srgrimes } 1874Srgrimes db_run_mode = STEP_NONE; 188283088Spfg return (true); 1894Srgrimes} 1904Srgrimes 1914Srgrimesvoid 192283248Spfgdb_restart_at_pc(bool watchpt) 1934Srgrimes{ 194283315Spfg db_addr_t pc = PC_REGS(); 1954Srgrimes 1964Srgrimes if ((db_run_mode == STEP_COUNT) || 1974Srgrimes (db_run_mode == STEP_RETURN) || 1984Srgrimes (db_run_mode == STEP_CALLT)) { 1994Srgrimes /* 2004Srgrimes * We are about to execute this instruction, 2014Srgrimes * so count it now. 2024Srgrimes */ 203269982Simp#ifdef SOFTWARE_SSTEP 204269982Simp db_expr_t ins = 205269982Simp#endif 206283088Spfg db_get_value(pc, sizeof(int), false); 2074Srgrimes db_inst_count++; 2084Srgrimes db_load_count += inst_load(ins); 2094Srgrimes db_store_count += inst_store(ins); 2104Srgrimes#ifdef SOFTWARE_SSTEP 2114Srgrimes /* XXX works on mips, but... */ 2124Srgrimes if (inst_branch(ins) || inst_call(ins)) { 2134Srgrimes ins = db_get_value(next_instr_address(pc,1), 214283088Spfg sizeof(int), false); 2154Srgrimes db_inst_count++; 2164Srgrimes db_load_count += inst_load(ins); 2174Srgrimes db_store_count += inst_store(ins); 2184Srgrimes } 21981670Sobrien#endif /* SOFTWARE_SSTEP */ 2204Srgrimes } 2214Srgrimes 2224Srgrimes if (db_run_mode == STEP_CONTINUE) { 2234Srgrimes if (watchpt || db_find_breakpoint_here(pc)) { 2244Srgrimes /* 2254Srgrimes * Step over breakpoint/watchpoint. 2264Srgrimes */ 2274Srgrimes db_run_mode = STEP_INVISIBLE; 228131952Smarcel db_set_single_step(); 2294Srgrimes } else { 2304Srgrimes db_set_breakpoints(); 2314Srgrimes db_set_watchpoints(); 2324Srgrimes } 2334Srgrimes } else { 234131952Smarcel db_set_single_step(); 2354Srgrimes } 2364Srgrimes} 2374Srgrimes 2384Srgrimes#ifdef SOFTWARE_SSTEP 2394Srgrimes/* 2404Srgrimes * Software implementation of single-stepping. 2414Srgrimes * If your machine does not have a trace mode 2424Srgrimes * similar to the vax or sun ones you can use 2434Srgrimes * this implementation, done for the mips. 2444Srgrimes * Just define the above conditional and provide 2454Srgrimes * the functions/macros defined below. 2464Srgrimes * 247283248Spfg * extern bool 2484Srgrimes * inst_branch(), returns true if the instruction might branch 2494Srgrimes * extern unsigned 2504Srgrimes * branch_taken(), return the address the instruction might 2514Srgrimes * branch to 2524Srgrimes * db_getreg_val(); return the value of a user register, 2534Srgrimes * as indicated in the hardware instruction 2544Srgrimes * encoding, e.g. 8 for r8 2558876Srgrimes * 2564Srgrimes * next_instr_address(pc,bd) returns the address of the first 2574Srgrimes * instruction following the one at "pc", 2584Srgrimes * which is either in the taken path of 2594Srgrimes * the branch (bd==1) or not. This is 2604Srgrimes * for machines (mips) with branch delays. 2614Srgrimes * 2624Srgrimes * A single-step may involve at most 2 breakpoints - 2634Srgrimes * one for branch-not-taken and one for branch taken. 2644Srgrimes * If one of these addresses does not already have a breakpoint, 2654Srgrimes * we allocate a breakpoint and save it here. 2664Srgrimes * These breakpoints are deleted on return. 2678876Srgrimes */ 2684Srgrimes 2694Srgrimesvoid 270131952Smarceldb_set_single_step(void) 2714Srgrimes{ 272131952Smarcel db_addr_t pc = PC_REGS(), brpc; 273131952Smarcel unsigned inst; 2744Srgrimes 2754Srgrimes /* 2764Srgrimes * User was stopped at pc, e.g. the instruction 2774Srgrimes * at pc was not executed. 2784Srgrimes */ 279283088Spfg inst = db_get_value(pc, sizeof(int), false); 280181175Scognet if (inst_branch(inst) || inst_call(inst) || inst_return(inst)) { 281131952Smarcel brpc = branch_taken(inst, pc); 282131952Smarcel if (brpc != pc) { /* self-branches are hopeless */ 283131952Smarcel db_taken_bkpt = db_set_temp_breakpoint(brpc); 284131952Smarcel } 285131952Smarcel pc = next_instr_address(pc, 1); 2864Srgrimes } 287131952Smarcel pc = next_instr_address(pc, 0); 2884Srgrimes db_not_taken_bkpt = db_set_temp_breakpoint(pc); 2894Srgrimes} 2904Srgrimes 2914Srgrimesvoid 292131952Smarceldb_clear_single_step(void) 2934Srgrimes{ 2944Srgrimes 29537392Sdfr if (db_not_taken_bkpt != 0) { 296131952Smarcel db_delete_temp_breakpoint(db_not_taken_bkpt); 297131952Smarcel db_not_taken_bkpt = 0; 29837392Sdfr } 2994Srgrimes if (db_taken_bkpt != 0) { 300131952Smarcel db_delete_temp_breakpoint(db_taken_bkpt); 301131952Smarcel db_taken_bkpt = 0; 3024Srgrimes } 3034Srgrimes} 3044Srgrimes 30581670Sobrien#endif /* SOFTWARE_SSTEP */ 3064Srgrimes 3074Srgrimesextern int db_cmd_loop_done; 3084Srgrimes 3094Srgrimes/* single-step */ 3104Srgrimes/*ARGSUSED*/ 3114Srgrimesvoid 312283248Spfgdb_single_step_cmd(db_expr_t addr, bool have_addr, db_expr_t count, char *modif) 3134Srgrimes{ 314283248Spfg bool print = false; 3154Srgrimes 3164Srgrimes if (count == -1) 3174Srgrimes count = 1; 3184Srgrimes 3194Srgrimes if (modif[0] == 'p') 320283088Spfg print = true; 3214Srgrimes 3224Srgrimes db_run_mode = STEP_ONCE; 3234Srgrimes db_loop_count = count; 3244Srgrimes db_sstep_print = print; 3254Srgrimes db_inst_count = 0; 3264Srgrimes db_load_count = 0; 3274Srgrimes db_store_count = 0; 3284Srgrimes 3294Srgrimes db_cmd_loop_done = 1; 3304Srgrimes} 3314Srgrimes 3324Srgrimes/* trace and print until call/return */ 3334Srgrimes/*ARGSUSED*/ 3344Srgrimesvoid 335283248Spfgdb_trace_until_call_cmd(db_expr_t addr, bool have_addr, db_expr_t count, 336273006Spfg char *modif) 3374Srgrimes{ 338283248Spfg bool print = false; 3394Srgrimes 3404Srgrimes if (modif[0] == 'p') 341283088Spfg print = true; 3424Srgrimes 3434Srgrimes db_run_mode = STEP_CALLT; 3444Srgrimes db_sstep_print = print; 3454Srgrimes db_inst_count = 0; 3464Srgrimes db_load_count = 0; 3474Srgrimes db_store_count = 0; 3484Srgrimes 3494Srgrimes db_cmd_loop_done = 1; 3504Srgrimes} 3514Srgrimes 3524Srgrimes/*ARGSUSED*/ 3534Srgrimesvoid 354283248Spfgdb_trace_until_matching_cmd(db_expr_t addr, bool have_addr, db_expr_t count, 355283248Spfg char *modif) 3564Srgrimes{ 357283248Spfg bool print = false; 3584Srgrimes 3594Srgrimes if (modif[0] == 'p') 360283088Spfg print = true; 3614Srgrimes 3624Srgrimes db_run_mode = STEP_RETURN; 3634Srgrimes db_call_depth = 1; 3644Srgrimes db_sstep_print = print; 3654Srgrimes db_inst_count = 0; 3664Srgrimes db_load_count = 0; 3674Srgrimes db_store_count = 0; 3684Srgrimes 3694Srgrimes db_cmd_loop_done = 1; 3704Srgrimes} 3714Srgrimes 3724Srgrimes/* continue */ 3734Srgrimes/*ARGSUSED*/ 3744Srgrimesvoid 375283248Spfgdb_continue_cmd(db_expr_t addr, bool have_addr, db_expr_t count, char *modif) 3764Srgrimes{ 3774Srgrimes if (modif[0] == 'c') 3784Srgrimes db_run_mode = STEP_COUNT; 3794Srgrimes else 3804Srgrimes db_run_mode = STEP_CONTINUE; 3814Srgrimes db_inst_count = 0; 3824Srgrimes db_load_count = 0; 3834Srgrimes db_store_count = 0; 3844Srgrimes 3854Srgrimes db_cmd_loop_done = 1; 3864Srgrimes} 387