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 574Srgrimes#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 814Srgrimesdb_stop_at_pc(is_breakpoint) 824Srgrimes boolean_t *is_breakpoint; 834Srgrimes{ 844Srgrimes register db_addr_t pc; 854Srgrimes register db_breakpoint_t bkpt; 864Srgrimes 87137974Scognet pc = PC_REGS(); 88137974Scognet#ifdef SOFTWARE_SSTEP 89137974Scognet if ((db_not_taken_bkpt != 0 && pc == db_not_taken_bkpt->address) 90137974Scognet || (db_taken_bkpt != 0 && pc == db_taken_bkpt->address)) 91137974Scognet *is_breakpoint = FALSE; 92137974Scognet#endif 93137974Scognet 94131952Smarcel db_clear_single_step(); 954Srgrimes db_clear_breakpoints(); 964Srgrimes db_clear_watchpoints(); 974Srgrimes 984Srgrimes#ifdef FIXUP_PC_AFTER_BREAK 994Srgrimes if (*is_breakpoint) { 1004Srgrimes /* 1014Srgrimes * Breakpoint trap. Fix up the PC if the 1024Srgrimes * machine requires it. 1034Srgrimes */ 1044Srgrimes FIXUP_PC_AFTER_BREAK 105131952Smarcel pc = PC_REGS(); 1064Srgrimes } 1074Srgrimes#endif 1084Srgrimes 1094Srgrimes /* 1104Srgrimes * Now check for a breakpoint at this address. 1114Srgrimes */ 1124Srgrimes bkpt = db_find_breakpoint_here(pc); 1134Srgrimes if (bkpt) { 1144Srgrimes if (--bkpt->count == 0) { 1154Srgrimes bkpt->count = bkpt->init_count; 1164Srgrimes *is_breakpoint = TRUE; 1174Srgrimes return (TRUE); /* stop here */ 1184Srgrimes } 1194Srgrimes } else if (*is_breakpoint) { 12083506Sdfr#ifdef BKPT_SKIP 12183506Sdfr BKPT_SKIP; 12236735Sdfr#endif 1234Srgrimes } 1248876Srgrimes 1254Srgrimes *is_breakpoint = FALSE; 1264Srgrimes 1274Srgrimes if (db_run_mode == STEP_INVISIBLE) { 1284Srgrimes db_run_mode = STEP_CONTINUE; 1294Srgrimes return (FALSE); /* continue */ 1304Srgrimes } 1314Srgrimes if (db_run_mode == STEP_COUNT) { 1324Srgrimes return (FALSE); /* continue */ 1334Srgrimes } 1344Srgrimes if (db_run_mode == STEP_ONCE) { 1354Srgrimes if (--db_loop_count > 0) { 1364Srgrimes if (db_sstep_print) { 1374Srgrimes db_printf("\t\t"); 1384Srgrimes db_print_loc_and_inst(pc); 1394Srgrimes db_printf("\n"); 1404Srgrimes } 1414Srgrimes return (FALSE); /* continue */ 1424Srgrimes } 1434Srgrimes } 1444Srgrimes if (db_run_mode == STEP_RETURN) { 1454Srgrimes /* continue until matching return */ 14698694Smux db_expr_t ins; 1474Srgrimes 14898694Smux ins = db_get_value(pc, sizeof(int), FALSE); 1494Srgrimes if (!inst_trap_return(ins) && 1504Srgrimes (!inst_return(ins) || --db_call_depth != 0)) { 1514Srgrimes if (db_sstep_print) { 1524Srgrimes if (inst_call(ins) || inst_return(ins)) { 1534Srgrimes register int i; 1544Srgrimes 1554Srgrimes db_printf("[after %6d] ", db_inst_count); 1564Srgrimes for (i = db_call_depth; --i > 0; ) 1574Srgrimes db_printf(" "); 1584Srgrimes db_print_loc_and_inst(pc); 1594Srgrimes db_printf("\n"); 1604Srgrimes } 1614Srgrimes } 1624Srgrimes if (inst_call(ins)) 1634Srgrimes db_call_depth++; 1644Srgrimes return (FALSE); /* continue */ 1654Srgrimes } 1664Srgrimes } 1674Srgrimes if (db_run_mode == STEP_CALLT) { 1684Srgrimes /* continue until call or return */ 16998694Smux db_expr_t ins; 1704Srgrimes 17198694Smux ins = db_get_value(pc, sizeof(int), FALSE); 1724Srgrimes if (!inst_call(ins) && 1734Srgrimes !inst_return(ins) && 1744Srgrimes !inst_trap_return(ins)) { 1754Srgrimes return (FALSE); /* continue */ 1764Srgrimes } 1774Srgrimes } 1784Srgrimes db_run_mode = STEP_NONE; 1794Srgrimes return (TRUE); 1804Srgrimes} 1814Srgrimes 1824Srgrimesvoid 1834Srgrimesdb_restart_at_pc(watchpt) 1844Srgrimes boolean_t watchpt; 1854Srgrimes{ 186131952Smarcel register db_addr_t pc = PC_REGS(); 1874Srgrimes 1884Srgrimes if ((db_run_mode == STEP_COUNT) || 1894Srgrimes (db_run_mode == STEP_RETURN) || 1904Srgrimes (db_run_mode == STEP_CALLT)) { 1914Srgrimes db_expr_t ins; 1924Srgrimes 1934Srgrimes /* 1944Srgrimes * We are about to execute this instruction, 1954Srgrimes * so count it now. 1964Srgrimes */ 1974Srgrimes 1984Srgrimes ins = db_get_value(pc, sizeof(int), FALSE); 1994Srgrimes db_inst_count++; 2004Srgrimes db_load_count += inst_load(ins); 2014Srgrimes db_store_count += inst_store(ins); 2024Srgrimes#ifdef SOFTWARE_SSTEP 2034Srgrimes /* XXX works on mips, but... */ 2044Srgrimes if (inst_branch(ins) || inst_call(ins)) { 2054Srgrimes ins = db_get_value(next_instr_address(pc,1), 2064Srgrimes sizeof(int), FALSE); 2074Srgrimes db_inst_count++; 2084Srgrimes db_load_count += inst_load(ins); 2094Srgrimes db_store_count += inst_store(ins); 2104Srgrimes } 21181670Sobrien#endif /* SOFTWARE_SSTEP */ 2124Srgrimes } 2134Srgrimes 2144Srgrimes if (db_run_mode == STEP_CONTINUE) { 2154Srgrimes if (watchpt || db_find_breakpoint_here(pc)) { 2164Srgrimes /* 2174Srgrimes * Step over breakpoint/watchpoint. 2184Srgrimes */ 2194Srgrimes db_run_mode = STEP_INVISIBLE; 220131952Smarcel db_set_single_step(); 2214Srgrimes } else { 2224Srgrimes db_set_breakpoints(); 2234Srgrimes db_set_watchpoints(); 2244Srgrimes } 2254Srgrimes } else { 226131952Smarcel db_set_single_step(); 2274Srgrimes } 2284Srgrimes} 2294Srgrimes 2304Srgrimes#ifdef SOFTWARE_SSTEP 2314Srgrimes/* 2324Srgrimes * Software implementation of single-stepping. 2334Srgrimes * If your machine does not have a trace mode 2344Srgrimes * similar to the vax or sun ones you can use 2354Srgrimes * this implementation, done for the mips. 2364Srgrimes * Just define the above conditional and provide 2374Srgrimes * the functions/macros defined below. 2384Srgrimes * 2394Srgrimes * extern boolean_t 2404Srgrimes * inst_branch(), returns true if the instruction might branch 2414Srgrimes * extern unsigned 2424Srgrimes * branch_taken(), return the address the instruction might 2434Srgrimes * branch to 2444Srgrimes * db_getreg_val(); return the value of a user register, 2454Srgrimes * as indicated in the hardware instruction 2464Srgrimes * encoding, e.g. 8 for r8 2478876Srgrimes * 2484Srgrimes * next_instr_address(pc,bd) returns the address of the first 2494Srgrimes * instruction following the one at "pc", 2504Srgrimes * which is either in the taken path of 2514Srgrimes * the branch (bd==1) or not. This is 2524Srgrimes * for machines (mips) with branch delays. 2534Srgrimes * 2544Srgrimes * A single-step may involve at most 2 breakpoints - 2554Srgrimes * one for branch-not-taken and one for branch taken. 2564Srgrimes * If one of these addresses does not already have a breakpoint, 2574Srgrimes * we allocate a breakpoint and save it here. 2584Srgrimes * These breakpoints are deleted on return. 2598876Srgrimes */ 2604Srgrimes 2614Srgrimesvoid 262131952Smarceldb_set_single_step(void) 2634Srgrimes{ 264131952Smarcel db_addr_t pc = PC_REGS(), brpc; 265131952Smarcel unsigned inst; 2664Srgrimes 2674Srgrimes /* 2684Srgrimes * User was stopped at pc, e.g. the instruction 2694Srgrimes * at pc was not executed. 2704Srgrimes */ 2714Srgrimes inst = db_get_value(pc, sizeof(int), FALSE); 272181175Scognet if (inst_branch(inst) || inst_call(inst) || inst_return(inst)) { 273131952Smarcel brpc = branch_taken(inst, pc); 274131952Smarcel if (brpc != pc) { /* self-branches are hopeless */ 275131952Smarcel db_taken_bkpt = db_set_temp_breakpoint(brpc); 276131952Smarcel } 277131952Smarcel pc = next_instr_address(pc, 1); 2784Srgrimes } 279131952Smarcel pc = next_instr_address(pc, 0); 2804Srgrimes db_not_taken_bkpt = db_set_temp_breakpoint(pc); 2814Srgrimes} 2824Srgrimes 2834Srgrimesvoid 284131952Smarceldb_clear_single_step(void) 2854Srgrimes{ 2864Srgrimes 28737392Sdfr if (db_not_taken_bkpt != 0) { 288131952Smarcel db_delete_temp_breakpoint(db_not_taken_bkpt); 289131952Smarcel db_not_taken_bkpt = 0; 29037392Sdfr } 2914Srgrimes if (db_taken_bkpt != 0) { 292131952Smarcel db_delete_temp_breakpoint(db_taken_bkpt); 293131952Smarcel db_taken_bkpt = 0; 2944Srgrimes } 2954Srgrimes} 2964Srgrimes 29781670Sobrien#endif /* SOFTWARE_SSTEP */ 2984Srgrimes 2994Srgrimesextern int db_cmd_loop_done; 3004Srgrimes 3014Srgrimes/* single-step */ 3024Srgrimes/*ARGSUSED*/ 3034Srgrimesvoid 3044Srgrimesdb_single_step_cmd(addr, have_addr, count, modif) 3054Srgrimes db_expr_t addr; 30612473Sbde boolean_t have_addr; 3074Srgrimes db_expr_t count; 3084Srgrimes char * modif; 3094Srgrimes{ 3104Srgrimes boolean_t print = FALSE; 3114Srgrimes 3124Srgrimes if (count == -1) 3134Srgrimes count = 1; 3144Srgrimes 3154Srgrimes if (modif[0] == 'p') 3164Srgrimes print = TRUE; 3174Srgrimes 3184Srgrimes db_run_mode = STEP_ONCE; 3194Srgrimes db_loop_count = count; 3204Srgrimes db_sstep_print = print; 3214Srgrimes db_inst_count = 0; 3224Srgrimes db_load_count = 0; 3234Srgrimes db_store_count = 0; 3244Srgrimes 3254Srgrimes db_cmd_loop_done = 1; 3264Srgrimes} 3274Srgrimes 3284Srgrimes/* trace and print until call/return */ 3294Srgrimes/*ARGSUSED*/ 3304Srgrimesvoid 3314Srgrimesdb_trace_until_call_cmd(addr, have_addr, count, modif) 3324Srgrimes db_expr_t addr; 33312473Sbde boolean_t have_addr; 3344Srgrimes db_expr_t count; 3354Srgrimes char * modif; 3364Srgrimes{ 3374Srgrimes boolean_t print = FALSE; 3384Srgrimes 3394Srgrimes if (modif[0] == 'p') 3404Srgrimes print = TRUE; 3414Srgrimes 3424Srgrimes db_run_mode = STEP_CALLT; 3434Srgrimes db_sstep_print = print; 3444Srgrimes db_inst_count = 0; 3454Srgrimes db_load_count = 0; 3464Srgrimes db_store_count = 0; 3474Srgrimes 3484Srgrimes db_cmd_loop_done = 1; 3494Srgrimes} 3504Srgrimes 3514Srgrimes/*ARGSUSED*/ 3524Srgrimesvoid 3534Srgrimesdb_trace_until_matching_cmd(addr, have_addr, count, modif) 3544Srgrimes db_expr_t addr; 35512473Sbde boolean_t have_addr; 3564Srgrimes db_expr_t count; 3574Srgrimes char * modif; 3584Srgrimes{ 3594Srgrimes boolean_t print = FALSE; 3604Srgrimes 3614Srgrimes if (modif[0] == 'p') 3624Srgrimes print = TRUE; 3634Srgrimes 3644Srgrimes db_run_mode = STEP_RETURN; 3654Srgrimes db_call_depth = 1; 3664Srgrimes db_sstep_print = print; 3674Srgrimes db_inst_count = 0; 3684Srgrimes db_load_count = 0; 3694Srgrimes db_store_count = 0; 3704Srgrimes 3714Srgrimes db_cmd_loop_done = 1; 3724Srgrimes} 3734Srgrimes 3744Srgrimes/* continue */ 3754Srgrimes/*ARGSUSED*/ 3764Srgrimesvoid 3774Srgrimesdb_continue_cmd(addr, have_addr, count, modif) 3784Srgrimes db_expr_t addr; 37912473Sbde boolean_t have_addr; 3804Srgrimes db_expr_t count; 3814Srgrimes char * modif; 3824Srgrimes{ 3834Srgrimes if (modif[0] == 'c') 3844Srgrimes db_run_mode = STEP_COUNT; 3854Srgrimes else 3864Srgrimes db_run_mode = STEP_CONTINUE; 3874Srgrimes db_inst_count = 0; 3884Srgrimes db_load_count = 0; 3894Srgrimes db_store_count = 0; 3904Srgrimes 3914Srgrimes db_cmd_loop_done = 1; 3924Srgrimes} 393