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$"); 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 57273265Spfg#define STEP_INVISIBLE 5 584Srgrimes#define STEP_COUNT 6 594Srgrimes 6012720Sphkstatic boolean_t 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 684Srgrimes#ifndef db_set_single_step 69131952Smarcelvoid db_set_single_step(void); 704Srgrimes#endif 714Srgrimes#ifndef db_clear_single_step 72131952Smarcelvoid db_clear_single_step(void); 734Srgrimes#endif 744Srgrimes 75137974Scognet#ifdef SOFTWARE_SSTEP 76137974Scognetdb_breakpoint_t db_not_taken_bkpt = 0; 77137974Scognetdb_breakpoint_t db_taken_bkpt = 0; 78137974Scognet#endif 79137974Scognet 804Srgrimesboolean_t 81273265Spfgdb_stop_at_pc(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 182273265Spfgdb_restart_at_pc(boolean_t watchpt) 1834Srgrimes{ 184131952Smarcel register db_addr_t pc = PC_REGS(); 1854Srgrimes 1864Srgrimes if ((db_run_mode == STEP_COUNT) || 1874Srgrimes (db_run_mode == STEP_RETURN) || 1884Srgrimes (db_run_mode == STEP_CALLT)) { 1894Srgrimes db_expr_t ins; 1904Srgrimes 1914Srgrimes /* 1924Srgrimes * We are about to execute this instruction, 1934Srgrimes * so count it now. 1944Srgrimes */ 1954Srgrimes 1964Srgrimes ins = db_get_value(pc, sizeof(int), FALSE); 1974Srgrimes db_inst_count++; 1984Srgrimes db_load_count += inst_load(ins); 1994Srgrimes db_store_count += inst_store(ins); 2004Srgrimes#ifdef SOFTWARE_SSTEP 2014Srgrimes /* XXX works on mips, but... */ 2024Srgrimes if (inst_branch(ins) || inst_call(ins)) { 2034Srgrimes ins = db_get_value(next_instr_address(pc,1), 2044Srgrimes sizeof(int), FALSE); 2054Srgrimes db_inst_count++; 2064Srgrimes db_load_count += inst_load(ins); 2074Srgrimes db_store_count += inst_store(ins); 2084Srgrimes } 20981670Sobrien#endif /* SOFTWARE_SSTEP */ 2104Srgrimes } 2114Srgrimes 2124Srgrimes if (db_run_mode == STEP_CONTINUE) { 2134Srgrimes if (watchpt || db_find_breakpoint_here(pc)) { 2144Srgrimes /* 2154Srgrimes * Step over breakpoint/watchpoint. 2164Srgrimes */ 2174Srgrimes db_run_mode = STEP_INVISIBLE; 218131952Smarcel db_set_single_step(); 2194Srgrimes } else { 2204Srgrimes db_set_breakpoints(); 2214Srgrimes db_set_watchpoints(); 2224Srgrimes } 2234Srgrimes } else { 224131952Smarcel db_set_single_step(); 2254Srgrimes } 2264Srgrimes} 2274Srgrimes 2284Srgrimes#ifdef SOFTWARE_SSTEP 2294Srgrimes/* 2304Srgrimes * Software implementation of single-stepping. 2314Srgrimes * If your machine does not have a trace mode 2324Srgrimes * similar to the vax or sun ones you can use 2334Srgrimes * this implementation, done for the mips. 2344Srgrimes * Just define the above conditional and provide 2354Srgrimes * the functions/macros defined below. 2364Srgrimes * 2374Srgrimes * extern boolean_t 2384Srgrimes * inst_branch(), returns true if the instruction might branch 2394Srgrimes * extern unsigned 2404Srgrimes * branch_taken(), return the address the instruction might 2414Srgrimes * branch to 2424Srgrimes * db_getreg_val(); return the value of a user register, 2434Srgrimes * as indicated in the hardware instruction 2444Srgrimes * encoding, e.g. 8 for r8 2458876Srgrimes * 2464Srgrimes * next_instr_address(pc,bd) returns the address of the first 2474Srgrimes * instruction following the one at "pc", 2484Srgrimes * which is either in the taken path of 2494Srgrimes * the branch (bd==1) or not. This is 2504Srgrimes * for machines (mips) with branch delays. 2514Srgrimes * 2524Srgrimes * A single-step may involve at most 2 breakpoints - 2534Srgrimes * one for branch-not-taken and one for branch taken. 2544Srgrimes * If one of these addresses does not already have a breakpoint, 2554Srgrimes * we allocate a breakpoint and save it here. 2564Srgrimes * These breakpoints are deleted on return. 2578876Srgrimes */ 2584Srgrimes 2594Srgrimesvoid 260131952Smarceldb_set_single_step(void) 2614Srgrimes{ 262131952Smarcel db_addr_t pc = PC_REGS(), brpc; 263131952Smarcel unsigned inst; 2644Srgrimes 2654Srgrimes /* 2664Srgrimes * User was stopped at pc, e.g. the instruction 2674Srgrimes * at pc was not executed. 2684Srgrimes */ 2694Srgrimes inst = db_get_value(pc, sizeof(int), FALSE); 270181175Scognet if (inst_branch(inst) || inst_call(inst) || inst_return(inst)) { 271131952Smarcel brpc = branch_taken(inst, pc); 272131952Smarcel if (brpc != pc) { /* self-branches are hopeless */ 273131952Smarcel db_taken_bkpt = db_set_temp_breakpoint(brpc); 274131952Smarcel } 275131952Smarcel pc = next_instr_address(pc, 1); 2764Srgrimes } 277131952Smarcel pc = next_instr_address(pc, 0); 2784Srgrimes db_not_taken_bkpt = db_set_temp_breakpoint(pc); 2794Srgrimes} 2804Srgrimes 2814Srgrimesvoid 282131952Smarceldb_clear_single_step(void) 2834Srgrimes{ 2844Srgrimes 28537392Sdfr if (db_not_taken_bkpt != 0) { 286131952Smarcel db_delete_temp_breakpoint(db_not_taken_bkpt); 287131952Smarcel db_not_taken_bkpt = 0; 28837392Sdfr } 2894Srgrimes if (db_taken_bkpt != 0) { 290131952Smarcel db_delete_temp_breakpoint(db_taken_bkpt); 291131952Smarcel db_taken_bkpt = 0; 2924Srgrimes } 2934Srgrimes} 2944Srgrimes 29581670Sobrien#endif /* SOFTWARE_SSTEP */ 2964Srgrimes 2974Srgrimesextern int db_cmd_loop_done; 2984Srgrimes 2994Srgrimes/* single-step */ 3004Srgrimes/*ARGSUSED*/ 3014Srgrimesvoid 3024Srgrimesdb_single_step_cmd(addr, have_addr, count, modif) 3034Srgrimes db_expr_t addr; 30412473Sbde boolean_t have_addr; 3054Srgrimes db_expr_t count; 3064Srgrimes char * modif; 3074Srgrimes{ 3084Srgrimes boolean_t print = FALSE; 3094Srgrimes 3104Srgrimes if (count == -1) 3114Srgrimes count = 1; 3124Srgrimes 3134Srgrimes if (modif[0] == 'p') 3144Srgrimes print = TRUE; 3154Srgrimes 3164Srgrimes db_run_mode = STEP_ONCE; 3174Srgrimes db_loop_count = count; 3184Srgrimes db_sstep_print = print; 3194Srgrimes db_inst_count = 0; 3204Srgrimes db_load_count = 0; 3214Srgrimes db_store_count = 0; 3224Srgrimes 3234Srgrimes db_cmd_loop_done = 1; 3244Srgrimes} 3254Srgrimes 3264Srgrimes/* trace and print until call/return */ 3274Srgrimes/*ARGSUSED*/ 3284Srgrimesvoid 329273265Spfgdb_trace_until_call_cmd(db_expr_t addr, boolean_t have_addr, db_expr_t count, 330273265Spfg char *modif) 3314Srgrimes{ 3324Srgrimes boolean_t print = FALSE; 3334Srgrimes 3344Srgrimes if (modif[0] == 'p') 3354Srgrimes print = TRUE; 3364Srgrimes 3374Srgrimes db_run_mode = STEP_CALLT; 3384Srgrimes db_sstep_print = print; 3394Srgrimes db_inst_count = 0; 3404Srgrimes db_load_count = 0; 3414Srgrimes db_store_count = 0; 3424Srgrimes 3434Srgrimes db_cmd_loop_done = 1; 3444Srgrimes} 3454Srgrimes 3464Srgrimes/*ARGSUSED*/ 3474Srgrimesvoid 348273265Spfgdb_trace_until_matching_cmd(db_expr_t addr, boolean_t have_addr, 349273265Spfg db_expr_t count, char *modif) 3504Srgrimes{ 3514Srgrimes boolean_t print = FALSE; 3524Srgrimes 3534Srgrimes if (modif[0] == 'p') 3544Srgrimes print = TRUE; 3554Srgrimes 3564Srgrimes db_run_mode = STEP_RETURN; 3574Srgrimes db_call_depth = 1; 3584Srgrimes db_sstep_print = print; 3594Srgrimes db_inst_count = 0; 3604Srgrimes db_load_count = 0; 3614Srgrimes db_store_count = 0; 3624Srgrimes 3634Srgrimes db_cmd_loop_done = 1; 3644Srgrimes} 3654Srgrimes 3664Srgrimes/* continue */ 3674Srgrimes/*ARGSUSED*/ 3684Srgrimesvoid 369273265Spfgdb_continue_cmd(db_expr_t addr, boolean_t have_addr, db_expr_t count, 370273265Spfg char *modif) 3714Srgrimes{ 3724Srgrimes if (modif[0] == 'c') 3734Srgrimes db_run_mode = STEP_COUNT; 3744Srgrimes else 3754Srgrimes db_run_mode = STEP_CONTINUE; 3764Srgrimes db_inst_count = 0; 3774Srgrimes db_load_count = 0; 3784Srgrimes db_store_count = 0; 3794Srgrimes 3804Srgrimes db_cmd_loop_done = 1; 3814Srgrimes} 382