db_run.c revision 131952
18876Srgrimes/* 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 131952 2004-07-10 23:47:20Z marcel $"); 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 744Srgrimesboolean_t 754Srgrimesdb_stop_at_pc(is_breakpoint) 764Srgrimes boolean_t *is_breakpoint; 774Srgrimes{ 784Srgrimes register db_addr_t pc; 794Srgrimes register db_breakpoint_t bkpt; 804Srgrimes 81131952Smarcel db_clear_single_step(); 824Srgrimes db_clear_breakpoints(); 834Srgrimes db_clear_watchpoints(); 84131952Smarcel pc = PC_REGS(); 854Srgrimes 864Srgrimes#ifdef FIXUP_PC_AFTER_BREAK 874Srgrimes if (*is_breakpoint) { 884Srgrimes /* 894Srgrimes * Breakpoint trap. Fix up the PC if the 904Srgrimes * machine requires it. 914Srgrimes */ 924Srgrimes FIXUP_PC_AFTER_BREAK 93131952Smarcel pc = PC_REGS(); 944Srgrimes } 954Srgrimes#endif 964Srgrimes 974Srgrimes /* 984Srgrimes * Now check for a breakpoint at this address. 994Srgrimes */ 1004Srgrimes bkpt = db_find_breakpoint_here(pc); 1014Srgrimes if (bkpt) { 1024Srgrimes if (--bkpt->count == 0) { 1034Srgrimes bkpt->count = bkpt->init_count; 1044Srgrimes *is_breakpoint = TRUE; 1054Srgrimes return (TRUE); /* stop here */ 1064Srgrimes } 1074Srgrimes } else if (*is_breakpoint) { 10883506Sdfr#ifdef BKPT_SKIP 10983506Sdfr BKPT_SKIP; 11036735Sdfr#endif 1114Srgrimes } 1128876Srgrimes 1134Srgrimes *is_breakpoint = FALSE; 1144Srgrimes 1154Srgrimes if (db_run_mode == STEP_INVISIBLE) { 1164Srgrimes db_run_mode = STEP_CONTINUE; 1174Srgrimes return (FALSE); /* continue */ 1184Srgrimes } 1194Srgrimes if (db_run_mode == STEP_COUNT) { 1204Srgrimes return (FALSE); /* continue */ 1214Srgrimes } 1224Srgrimes if (db_run_mode == STEP_ONCE) { 1234Srgrimes if (--db_loop_count > 0) { 1244Srgrimes if (db_sstep_print) { 1254Srgrimes db_printf("\t\t"); 1264Srgrimes db_print_loc_and_inst(pc); 1274Srgrimes db_printf("\n"); 1284Srgrimes } 1294Srgrimes return (FALSE); /* continue */ 1304Srgrimes } 1314Srgrimes } 1324Srgrimes if (db_run_mode == STEP_RETURN) { 1334Srgrimes /* continue until matching return */ 13498694Smux db_expr_t ins; 1354Srgrimes 13698694Smux ins = db_get_value(pc, sizeof(int), FALSE); 1374Srgrimes if (!inst_trap_return(ins) && 1384Srgrimes (!inst_return(ins) || --db_call_depth != 0)) { 1394Srgrimes if (db_sstep_print) { 1404Srgrimes if (inst_call(ins) || inst_return(ins)) { 1414Srgrimes register int i; 1424Srgrimes 1434Srgrimes db_printf("[after %6d] ", db_inst_count); 1444Srgrimes for (i = db_call_depth; --i > 0; ) 1454Srgrimes db_printf(" "); 1464Srgrimes db_print_loc_and_inst(pc); 1474Srgrimes db_printf("\n"); 1484Srgrimes } 1494Srgrimes } 1504Srgrimes if (inst_call(ins)) 1514Srgrimes db_call_depth++; 1524Srgrimes return (FALSE); /* continue */ 1534Srgrimes } 1544Srgrimes } 1554Srgrimes if (db_run_mode == STEP_CALLT) { 1564Srgrimes /* continue until call or return */ 15798694Smux db_expr_t ins; 1584Srgrimes 15998694Smux ins = db_get_value(pc, sizeof(int), FALSE); 1604Srgrimes if (!inst_call(ins) && 1614Srgrimes !inst_return(ins) && 1624Srgrimes !inst_trap_return(ins)) { 1634Srgrimes return (FALSE); /* continue */ 1644Srgrimes } 1654Srgrimes } 1664Srgrimes db_run_mode = STEP_NONE; 1674Srgrimes return (TRUE); 1684Srgrimes} 1694Srgrimes 1704Srgrimesvoid 1714Srgrimesdb_restart_at_pc(watchpt) 1724Srgrimes boolean_t watchpt; 1734Srgrimes{ 174131952Smarcel register db_addr_t pc = PC_REGS(); 1754Srgrimes 1764Srgrimes if ((db_run_mode == STEP_COUNT) || 1774Srgrimes (db_run_mode == STEP_RETURN) || 1784Srgrimes (db_run_mode == STEP_CALLT)) { 1794Srgrimes db_expr_t ins; 1804Srgrimes 1814Srgrimes /* 1824Srgrimes * We are about to execute this instruction, 1834Srgrimes * so count it now. 1844Srgrimes */ 1854Srgrimes 1864Srgrimes ins = db_get_value(pc, sizeof(int), FALSE); 1874Srgrimes db_inst_count++; 1884Srgrimes db_load_count += inst_load(ins); 1894Srgrimes db_store_count += inst_store(ins); 1904Srgrimes#ifdef SOFTWARE_SSTEP 1914Srgrimes /* XXX works on mips, but... */ 1924Srgrimes if (inst_branch(ins) || inst_call(ins)) { 1934Srgrimes ins = db_get_value(next_instr_address(pc,1), 1944Srgrimes sizeof(int), FALSE); 1954Srgrimes db_inst_count++; 1964Srgrimes db_load_count += inst_load(ins); 1974Srgrimes db_store_count += inst_store(ins); 1984Srgrimes } 19981670Sobrien#endif /* SOFTWARE_SSTEP */ 2004Srgrimes } 2014Srgrimes 2024Srgrimes if (db_run_mode == STEP_CONTINUE) { 2034Srgrimes if (watchpt || db_find_breakpoint_here(pc)) { 2044Srgrimes /* 2054Srgrimes * Step over breakpoint/watchpoint. 2064Srgrimes */ 2074Srgrimes db_run_mode = STEP_INVISIBLE; 208131952Smarcel db_set_single_step(); 2094Srgrimes } else { 2104Srgrimes db_set_breakpoints(); 2114Srgrimes db_set_watchpoints(); 2124Srgrimes } 2134Srgrimes } else { 214131952Smarcel db_set_single_step(); 2154Srgrimes } 2164Srgrimes} 2174Srgrimes 2184Srgrimes#ifdef SOFTWARE_SSTEP 2194Srgrimes/* 2204Srgrimes * Software implementation of single-stepping. 2214Srgrimes * If your machine does not have a trace mode 2224Srgrimes * similar to the vax or sun ones you can use 2234Srgrimes * this implementation, done for the mips. 2244Srgrimes * Just define the above conditional and provide 2254Srgrimes * the functions/macros defined below. 2264Srgrimes * 2274Srgrimes * extern boolean_t 2284Srgrimes * inst_branch(), returns true if the instruction might branch 2294Srgrimes * extern unsigned 2304Srgrimes * branch_taken(), return the address the instruction might 2314Srgrimes * branch to 2324Srgrimes * db_getreg_val(); return the value of a user register, 2334Srgrimes * as indicated in the hardware instruction 2344Srgrimes * encoding, e.g. 8 for r8 2358876Srgrimes * 2364Srgrimes * next_instr_address(pc,bd) returns the address of the first 2374Srgrimes * instruction following the one at "pc", 2384Srgrimes * which is either in the taken path of 2394Srgrimes * the branch (bd==1) or not. This is 2404Srgrimes * for machines (mips) with branch delays. 2414Srgrimes * 2424Srgrimes * A single-step may involve at most 2 breakpoints - 2434Srgrimes * one for branch-not-taken and one for branch taken. 2444Srgrimes * If one of these addresses does not already have a breakpoint, 2454Srgrimes * we allocate a breakpoint and save it here. 2464Srgrimes * These breakpoints are deleted on return. 2478876Srgrimes */ 2484Srgrimesdb_breakpoint_t db_not_taken_bkpt = 0; 2494Srgrimesdb_breakpoint_t db_taken_bkpt = 0; 2504Srgrimes 2514Srgrimesvoid 252131952Smarceldb_set_single_step(void) 2534Srgrimes{ 254131952Smarcel db_addr_t pc = PC_REGS(), brpc; 255131952Smarcel unsigned inst; 2564Srgrimes 2574Srgrimes /* 2584Srgrimes * User was stopped at pc, e.g. the instruction 2594Srgrimes * at pc was not executed. 2604Srgrimes */ 2614Srgrimes inst = db_get_value(pc, sizeof(int), FALSE); 2624Srgrimes if (inst_branch(inst) || inst_call(inst)) { 263131952Smarcel brpc = branch_taken(inst, pc); 264131952Smarcel if (brpc != pc) { /* self-branches are hopeless */ 265131952Smarcel db_taken_bkpt = db_set_temp_breakpoint(brpc); 266131952Smarcel } 267131952Smarcel pc = next_instr_address(pc, 1); 2684Srgrimes } 269131952Smarcel pc = next_instr_address(pc, 0); 2704Srgrimes db_not_taken_bkpt = db_set_temp_breakpoint(pc); 2714Srgrimes} 2724Srgrimes 2734Srgrimesvoid 274131952Smarceldb_clear_single_step(void) 2754Srgrimes{ 2764Srgrimes 27737392Sdfr if (db_not_taken_bkpt != 0) { 278131952Smarcel db_delete_temp_breakpoint(db_not_taken_bkpt); 279131952Smarcel db_not_taken_bkpt = 0; 28037392Sdfr } 2814Srgrimes if (db_taken_bkpt != 0) { 282131952Smarcel db_delete_temp_breakpoint(db_taken_bkpt); 283131952Smarcel db_taken_bkpt = 0; 2844Srgrimes } 2854Srgrimes} 2864Srgrimes 28781670Sobrien#endif /* SOFTWARE_SSTEP */ 2884Srgrimes 2894Srgrimesextern int db_cmd_loop_done; 2904Srgrimes 2914Srgrimes/* single-step */ 2924Srgrimes/*ARGSUSED*/ 2934Srgrimesvoid 2944Srgrimesdb_single_step_cmd(addr, have_addr, count, modif) 2954Srgrimes db_expr_t addr; 29612473Sbde boolean_t have_addr; 2974Srgrimes db_expr_t count; 2984Srgrimes char * modif; 2994Srgrimes{ 3004Srgrimes boolean_t print = FALSE; 3014Srgrimes 3024Srgrimes if (count == -1) 3034Srgrimes count = 1; 3044Srgrimes 3054Srgrimes if (modif[0] == 'p') 3064Srgrimes print = TRUE; 3074Srgrimes 3084Srgrimes db_run_mode = STEP_ONCE; 3094Srgrimes db_loop_count = count; 3104Srgrimes db_sstep_print = print; 3114Srgrimes db_inst_count = 0; 3124Srgrimes db_load_count = 0; 3134Srgrimes db_store_count = 0; 3144Srgrimes 3154Srgrimes db_cmd_loop_done = 1; 3164Srgrimes} 3174Srgrimes 3184Srgrimes/* trace and print until call/return */ 3194Srgrimes/*ARGSUSED*/ 3204Srgrimesvoid 3214Srgrimesdb_trace_until_call_cmd(addr, have_addr, count, modif) 3224Srgrimes db_expr_t addr; 32312473Sbde boolean_t have_addr; 3244Srgrimes db_expr_t count; 3254Srgrimes char * modif; 3264Srgrimes{ 3274Srgrimes boolean_t print = FALSE; 3284Srgrimes 3294Srgrimes if (modif[0] == 'p') 3304Srgrimes print = TRUE; 3314Srgrimes 3324Srgrimes db_run_mode = STEP_CALLT; 3334Srgrimes db_sstep_print = print; 3344Srgrimes db_inst_count = 0; 3354Srgrimes db_load_count = 0; 3364Srgrimes db_store_count = 0; 3374Srgrimes 3384Srgrimes db_cmd_loop_done = 1; 3394Srgrimes} 3404Srgrimes 3414Srgrimes/*ARGSUSED*/ 3424Srgrimesvoid 3434Srgrimesdb_trace_until_matching_cmd(addr, have_addr, count, modif) 3444Srgrimes db_expr_t addr; 34512473Sbde boolean_t have_addr; 3464Srgrimes db_expr_t count; 3474Srgrimes char * modif; 3484Srgrimes{ 3494Srgrimes boolean_t print = FALSE; 3504Srgrimes 3514Srgrimes if (modif[0] == 'p') 3524Srgrimes print = TRUE; 3534Srgrimes 3544Srgrimes db_run_mode = STEP_RETURN; 3554Srgrimes db_call_depth = 1; 3564Srgrimes db_sstep_print = print; 3574Srgrimes db_inst_count = 0; 3584Srgrimes db_load_count = 0; 3594Srgrimes db_store_count = 0; 3604Srgrimes 3614Srgrimes db_cmd_loop_done = 1; 3624Srgrimes} 3634Srgrimes 3644Srgrimes/* continue */ 3654Srgrimes/*ARGSUSED*/ 3664Srgrimesvoid 3674Srgrimesdb_continue_cmd(addr, have_addr, count, modif) 3684Srgrimes db_expr_t addr; 36912473Sbde boolean_t have_addr; 3704Srgrimes db_expr_t count; 3714Srgrimes char * modif; 3724Srgrimes{ 3734Srgrimes if (modif[0] == 'c') 3744Srgrimes db_run_mode = STEP_COUNT; 3754Srgrimes else 3764Srgrimes db_run_mode = STEP_CONTINUE; 3774Srgrimes db_inst_count = 0; 3784Srgrimes db_load_count = 0; 3794Srgrimes db_store_count = 0; 3804Srgrimes 3814Srgrimes db_cmd_loop_done = 1; 3824Srgrimes} 383