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: stable/11/sys/ddb/db_run.c 308418 2016-11-07 12:10:17Z kib $"); 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 514Srgrimes#define STEP_ONCE 1 524Srgrimes#define STEP_RETURN 2 534Srgrimes#define STEP_CALLT 3 544Srgrimes#define STEP_CONTINUE 4 55272958Spfg#define STEP_INVISIBLE 5 564Srgrimes#define STEP_COUNT 6 57308418Skibstatic int db_run_mode = STEP_CONTINUE; 584Srgrimes 59308418Skibstatic bool db_sstep_multiple; 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 93308418Skibdb_stop_at_pc(int type, int code, bool *is_breakpoint, bool *is_watchpoint) 944Srgrimes{ 95283315Spfg db_addr_t pc; 96283315Spfg db_breakpoint_t bkpt; 974Srgrimes 98308418Skib *is_breakpoint = IS_BREAKPOINT_TRAP(type, code); 99308418Skib *is_watchpoint = IS_WATCHPOINT_TRAP(type, code); 100137974Scognet pc = PC_REGS(); 101291407Szbb if (db_pc_is_singlestep(pc)) 102283088Spfg *is_breakpoint = false; 103137974Scognet 104131952Smarcel db_clear_single_step(); 1054Srgrimes db_clear_breakpoints(); 1064Srgrimes db_clear_watchpoints(); 1074Srgrimes 1084Srgrimes#ifdef FIXUP_PC_AFTER_BREAK 1094Srgrimes if (*is_breakpoint) { 1104Srgrimes /* 1114Srgrimes * Breakpoint trap. Fix up the PC if the 1124Srgrimes * machine requires it. 1134Srgrimes */ 1144Srgrimes FIXUP_PC_AFTER_BREAK 115131952Smarcel pc = PC_REGS(); 1164Srgrimes } 1174Srgrimes#endif 1184Srgrimes 1194Srgrimes /* 1204Srgrimes * Now check for a breakpoint at this address. 1214Srgrimes */ 1224Srgrimes bkpt = db_find_breakpoint_here(pc); 1234Srgrimes if (bkpt) { 1244Srgrimes if (--bkpt->count == 0) { 1254Srgrimes bkpt->count = bkpt->init_count; 126283088Spfg *is_breakpoint = true; 127283088Spfg return (true); /* stop here */ 1284Srgrimes } 129308418Skib return (false); /* continue the countdown */ 1304Srgrimes } else if (*is_breakpoint) { 13183506Sdfr#ifdef BKPT_SKIP 13283506Sdfr BKPT_SKIP; 13336735Sdfr#endif 1344Srgrimes } 1358876Srgrimes 136308418Skib *is_breakpoint = false; /* might be a breakpoint, but not ours */ 1374Srgrimes 138308418Skib /* 139308418Skib * If not stepping, then silently ignore single-step traps 140308418Skib * (except for clearing the single-step-flag above). 141308418Skib * 142308418Skib * If stepping, then abort if the trap type is unexpected. 143308418Skib * Breakpoints owned by us are expected and were handled above. 144308418Skib * Single-steps are expected and are handled below. All others 145308418Skib * are unexpected. 146308418Skib * 147308418Skib * Only do either of these if the MD layer claims to classify 148308418Skib * single-step traps unambiguously (by defining IS_SSTEP_TRAP). 149308418Skib * Otherwise, fall through to the bad historical behaviour 150308418Skib * given by turning unexpected traps into expected traps: if not 151308418Skib * stepping, then expect only breakpoints and stop, and if 152308418Skib * stepping, then expect only single-steps and step. 153308418Skib */ 154308418Skib#ifdef IS_SSTEP_TRAP 155308418Skib if (db_run_mode == STEP_CONTINUE && IS_SSTEP_TRAP(type, code)) 156308418Skib return (false); 157308418Skib if (db_run_mode != STEP_CONTINUE && !IS_SSTEP_TRAP(type, code)) { 158308418Skib printf("Stepping aborted\n"); 159308418Skib return (true); 160308418Skib } 161308418Skib#endif 162308418Skib 1634Srgrimes if (db_run_mode == STEP_INVISIBLE) { 1644Srgrimes db_run_mode = STEP_CONTINUE; 165283088Spfg return (false); /* continue */ 1664Srgrimes } 1674Srgrimes if (db_run_mode == STEP_COUNT) { 168283088Spfg return (false); /* continue */ 1694Srgrimes } 1704Srgrimes if (db_run_mode == STEP_ONCE) { 1714Srgrimes if (--db_loop_count > 0) { 1724Srgrimes if (db_sstep_print) { 1734Srgrimes db_printf("\t\t"); 1744Srgrimes db_print_loc_and_inst(pc); 1754Srgrimes db_printf("\n"); 1764Srgrimes } 177283088Spfg return (false); /* continue */ 1784Srgrimes } 1794Srgrimes } 1804Srgrimes if (db_run_mode == STEP_RETURN) { 1814Srgrimes /* continue until matching return */ 18298694Smux db_expr_t ins; 1834Srgrimes 184283088Spfg ins = db_get_value(pc, sizeof(int), false); 1854Srgrimes if (!inst_trap_return(ins) && 1864Srgrimes (!inst_return(ins) || --db_call_depth != 0)) { 1874Srgrimes if (db_sstep_print) { 1884Srgrimes if (inst_call(ins) || inst_return(ins)) { 189283315Spfg int i; 1904Srgrimes 1914Srgrimes db_printf("[after %6d] ", db_inst_count); 1924Srgrimes for (i = db_call_depth; --i > 0; ) 1934Srgrimes db_printf(" "); 1944Srgrimes db_print_loc_and_inst(pc); 1954Srgrimes db_printf("\n"); 1964Srgrimes } 1974Srgrimes } 1984Srgrimes if (inst_call(ins)) 1994Srgrimes db_call_depth++; 200283088Spfg return (false); /* continue */ 2014Srgrimes } 2024Srgrimes } 2034Srgrimes if (db_run_mode == STEP_CALLT) { 2044Srgrimes /* continue until call or return */ 20598694Smux db_expr_t ins; 2064Srgrimes 207283088Spfg ins = db_get_value(pc, sizeof(int), false); 2084Srgrimes if (!inst_call(ins) && 2094Srgrimes !inst_return(ins) && 2104Srgrimes !inst_trap_return(ins)) { 211283088Spfg return (false); /* continue */ 2124Srgrimes } 2134Srgrimes } 214283088Spfg return (true); 2154Srgrimes} 2164Srgrimes 2174Srgrimesvoid 218283248Spfgdb_restart_at_pc(bool watchpt) 2194Srgrimes{ 220283315Spfg db_addr_t pc = PC_REGS(); 2214Srgrimes 2224Srgrimes if ((db_run_mode == STEP_COUNT) || 223308418Skib ((db_run_mode == STEP_ONCE) && db_sstep_multiple) || 2244Srgrimes (db_run_mode == STEP_RETURN) || 2254Srgrimes (db_run_mode == STEP_CALLT)) { 2264Srgrimes /* 2274Srgrimes * We are about to execute this instruction, 2284Srgrimes * so count it now. 2294Srgrimes */ 230269982Simp#ifdef SOFTWARE_SSTEP 231269982Simp db_expr_t ins = 232269982Simp#endif 233283088Spfg db_get_value(pc, sizeof(int), false); 2344Srgrimes db_inst_count++; 2354Srgrimes db_load_count += inst_load(ins); 2364Srgrimes db_store_count += inst_store(ins); 2374Srgrimes#ifdef SOFTWARE_SSTEP 2384Srgrimes /* XXX works on mips, but... */ 2394Srgrimes if (inst_branch(ins) || inst_call(ins)) { 2404Srgrimes ins = db_get_value(next_instr_address(pc,1), 241283088Spfg sizeof(int), false); 2424Srgrimes db_inst_count++; 2434Srgrimes db_load_count += inst_load(ins); 2444Srgrimes db_store_count += inst_store(ins); 2454Srgrimes } 24681670Sobrien#endif /* SOFTWARE_SSTEP */ 2474Srgrimes } 2484Srgrimes 2494Srgrimes if (db_run_mode == STEP_CONTINUE) { 2504Srgrimes if (watchpt || db_find_breakpoint_here(pc)) { 2514Srgrimes /* 2524Srgrimes * Step over breakpoint/watchpoint. 2534Srgrimes */ 2544Srgrimes db_run_mode = STEP_INVISIBLE; 255131952Smarcel db_set_single_step(); 2564Srgrimes } else { 2574Srgrimes db_set_breakpoints(); 2584Srgrimes db_set_watchpoints(); 2594Srgrimes } 2604Srgrimes } else { 261131952Smarcel db_set_single_step(); 2624Srgrimes } 2634Srgrimes} 2644Srgrimes 2654Srgrimes#ifdef SOFTWARE_SSTEP 2664Srgrimes/* 2674Srgrimes * Software implementation of single-stepping. 2684Srgrimes * If your machine does not have a trace mode 2694Srgrimes * similar to the vax or sun ones you can use 2704Srgrimes * this implementation, done for the mips. 2714Srgrimes * Just define the above conditional and provide 2724Srgrimes * the functions/macros defined below. 2734Srgrimes * 274283248Spfg * extern bool 2754Srgrimes * inst_branch(), returns true if the instruction might branch 2764Srgrimes * extern unsigned 2774Srgrimes * branch_taken(), return the address the instruction might 2784Srgrimes * branch to 2794Srgrimes * db_getreg_val(); return the value of a user register, 2804Srgrimes * as indicated in the hardware instruction 2814Srgrimes * encoding, e.g. 8 for r8 2828876Srgrimes * 2834Srgrimes * next_instr_address(pc,bd) returns the address of the first 2844Srgrimes * instruction following the one at "pc", 2854Srgrimes * which is either in the taken path of 2864Srgrimes * the branch (bd==1) or not. This is 2874Srgrimes * for machines (mips) with branch delays. 2884Srgrimes * 2894Srgrimes * A single-step may involve at most 2 breakpoints - 2904Srgrimes * one for branch-not-taken and one for branch taken. 2914Srgrimes * If one of these addresses does not already have a breakpoint, 2924Srgrimes * we allocate a breakpoint and save it here. 2934Srgrimes * These breakpoints are deleted on return. 2948876Srgrimes */ 2954Srgrimes 2964Srgrimesvoid 297131952Smarceldb_set_single_step(void) 2984Srgrimes{ 299131952Smarcel db_addr_t pc = PC_REGS(), brpc; 300131952Smarcel unsigned inst; 3014Srgrimes 3024Srgrimes /* 3034Srgrimes * User was stopped at pc, e.g. the instruction 3044Srgrimes * at pc was not executed. 3054Srgrimes */ 306283088Spfg inst = db_get_value(pc, sizeof(int), false); 307181175Scognet if (inst_branch(inst) || inst_call(inst) || inst_return(inst)) { 308131952Smarcel brpc = branch_taken(inst, pc); 309131952Smarcel if (brpc != pc) { /* self-branches are hopeless */ 310131952Smarcel db_taken_bkpt = db_set_temp_breakpoint(brpc); 311131952Smarcel } 312131952Smarcel pc = next_instr_address(pc, 1); 3134Srgrimes } 314131952Smarcel pc = next_instr_address(pc, 0); 3154Srgrimes db_not_taken_bkpt = db_set_temp_breakpoint(pc); 3164Srgrimes} 3174Srgrimes 3184Srgrimesvoid 319131952Smarceldb_clear_single_step(void) 3204Srgrimes{ 3214Srgrimes 32237392Sdfr if (db_not_taken_bkpt != 0) { 323131952Smarcel db_delete_temp_breakpoint(db_not_taken_bkpt); 324131952Smarcel db_not_taken_bkpt = 0; 32537392Sdfr } 3264Srgrimes if (db_taken_bkpt != 0) { 327131952Smarcel db_delete_temp_breakpoint(db_taken_bkpt); 328131952Smarcel db_taken_bkpt = 0; 3294Srgrimes } 3304Srgrimes} 3314Srgrimes 33281670Sobrien#endif /* SOFTWARE_SSTEP */ 3334Srgrimes 3344Srgrimesextern int db_cmd_loop_done; 3354Srgrimes 3364Srgrimes/* single-step */ 3374Srgrimes/*ARGSUSED*/ 3384Srgrimesvoid 339283248Spfgdb_single_step_cmd(db_expr_t addr, bool have_addr, db_expr_t count, char *modif) 3404Srgrimes{ 341283248Spfg bool print = false; 3424Srgrimes 3434Srgrimes if (count == -1) 3444Srgrimes count = 1; 3454Srgrimes 3464Srgrimes if (modif[0] == 'p') 347283088Spfg print = true; 3484Srgrimes 3494Srgrimes db_run_mode = STEP_ONCE; 3504Srgrimes db_loop_count = count; 351308418Skib db_sstep_multiple = (count != 1); 3524Srgrimes db_sstep_print = print; 3534Srgrimes db_inst_count = 0; 3544Srgrimes db_load_count = 0; 3554Srgrimes db_store_count = 0; 3564Srgrimes 3574Srgrimes db_cmd_loop_done = 1; 3584Srgrimes} 3594Srgrimes 3604Srgrimes/* trace and print until call/return */ 3614Srgrimes/*ARGSUSED*/ 3624Srgrimesvoid 363283248Spfgdb_trace_until_call_cmd(db_expr_t addr, bool have_addr, db_expr_t count, 364273006Spfg char *modif) 3654Srgrimes{ 366283248Spfg bool print = false; 3674Srgrimes 3684Srgrimes if (modif[0] == 'p') 369283088Spfg print = true; 3704Srgrimes 3714Srgrimes db_run_mode = STEP_CALLT; 3724Srgrimes db_sstep_print = print; 3734Srgrimes db_inst_count = 0; 3744Srgrimes db_load_count = 0; 3754Srgrimes db_store_count = 0; 3764Srgrimes 3774Srgrimes db_cmd_loop_done = 1; 3784Srgrimes} 3794Srgrimes 3804Srgrimes/*ARGSUSED*/ 3814Srgrimesvoid 382283248Spfgdb_trace_until_matching_cmd(db_expr_t addr, bool have_addr, db_expr_t count, 383283248Spfg char *modif) 3844Srgrimes{ 385283248Spfg bool print = false; 3864Srgrimes 3874Srgrimes if (modif[0] == 'p') 388283088Spfg print = true; 3894Srgrimes 3904Srgrimes db_run_mode = STEP_RETURN; 3914Srgrimes db_call_depth = 1; 3924Srgrimes db_sstep_print = print; 3934Srgrimes db_inst_count = 0; 3944Srgrimes db_load_count = 0; 3954Srgrimes db_store_count = 0; 3964Srgrimes 3974Srgrimes db_cmd_loop_done = 1; 3984Srgrimes} 3994Srgrimes 4004Srgrimes/* continue */ 4014Srgrimes/*ARGSUSED*/ 4024Srgrimesvoid 403283248Spfgdb_continue_cmd(db_expr_t addr, bool have_addr, db_expr_t count, char *modif) 4044Srgrimes{ 4054Srgrimes if (modif[0] == 'c') 4064Srgrimes db_run_mode = STEP_COUNT; 4074Srgrimes else 4084Srgrimes db_run_mode = STEP_CONTINUE; 4094Srgrimes db_inst_count = 0; 4104Srgrimes db_load_count = 0; 4114Srgrimes db_store_count = 0; 4124Srgrimes 4134Srgrimes db_cmd_loop_done = 1; 4144Srgrimes} 415