db_run.c revision 12720
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 * 2612720Sphk * $Id: db_run.c,v 1.8 1995/12/07 12:44:57 davidg Exp $ 274Srgrimes */ 28623Srgrimes 294Srgrimes/* 304Srgrimes * Author: David B. Golub, Carnegie Mellon University 314Srgrimes * Date: 7/90 324Srgrimes */ 334Srgrimes 344Srgrimes/* 354Srgrimes * Commands to run process. 364Srgrimes */ 372056Swollman#include <sys/param.h> 382056Swollman#include <sys/systm.h> 392056Swollman#include <sys/proc.h> 4012662Sdg#include <vm/vm.h> 4112662Sdg#include <vm/vm_param.h> 422056Swollman#include <ddb/ddb.h> 434Srgrimes 444Srgrimes#include <ddb/db_lex.h> 454Srgrimes#include <ddb/db_break.h> 464Srgrimes#include <ddb/db_access.h> 474Srgrimes 4812720Sphkstatic int db_run_mode; 494Srgrimes#define STEP_NONE 0 504Srgrimes#define STEP_ONCE 1 514Srgrimes#define STEP_RETURN 2 524Srgrimes#define STEP_CALLT 3 534Srgrimes#define STEP_CONTINUE 4 544Srgrimes#define STEP_INVISIBLE 5 554Srgrimes#define STEP_COUNT 6 564Srgrimes 5712720Sphkstatic boolean_t db_sstep_print; 5812720Sphkstatic int db_loop_count; 5912720Sphkstatic int db_call_depth; 604Srgrimes 614Srgrimesint db_inst_count; 624Srgrimesint db_load_count; 634Srgrimesint db_store_count; 644Srgrimes 654Srgrimes#ifndef db_set_single_step 6612473Sbdeextern void db_set_single_step __P((db_regs_t *regs); 674Srgrimes#endif 684Srgrimes#ifndef db_clear_single_step 6912473Sbdeextern void db_clear_single_step __P((db_regs_t *regs)); 704Srgrimes#endif 714Srgrimes 7212515Sphk#ifdef notused 7312515Sphkstatic void db_single_step __P((db_regs_t *regs)); 7412515Sphk#endif 7512515Sphk 764Srgrimesboolean_t 774Srgrimesdb_stop_at_pc(is_breakpoint) 784Srgrimes boolean_t *is_breakpoint; 794Srgrimes{ 804Srgrimes register db_addr_t pc; 814Srgrimes register db_breakpoint_t bkpt; 824Srgrimes 834Srgrimes db_clear_single_step(DDB_REGS); 844Srgrimes db_clear_breakpoints(); 854Srgrimes db_clear_watchpoints(); 864Srgrimes pc = PC_REGS(DDB_REGS); 874Srgrimes 884Srgrimes#ifdef FIXUP_PC_AFTER_BREAK 894Srgrimes if (*is_breakpoint) { 904Srgrimes /* 914Srgrimes * Breakpoint trap. Fix up the PC if the 924Srgrimes * machine requires it. 934Srgrimes */ 944Srgrimes FIXUP_PC_AFTER_BREAK 954Srgrimes pc = PC_REGS(DDB_REGS); 964Srgrimes } 974Srgrimes#endif 984Srgrimes 994Srgrimes /* 1004Srgrimes * Now check for a breakpoint at this address. 1014Srgrimes */ 1024Srgrimes bkpt = db_find_breakpoint_here(pc); 1034Srgrimes if (bkpt) { 1044Srgrimes if (--bkpt->count == 0) { 1054Srgrimes bkpt->count = bkpt->init_count; 1064Srgrimes *is_breakpoint = TRUE; 1074Srgrimes return (TRUE); /* stop here */ 1084Srgrimes } 1094Srgrimes } else if (*is_breakpoint) { 1104Srgrimes ddb_regs.tf_eip += 1; 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 db_expr_t ins = db_get_value(pc, sizeof(int), FALSE); 1344Srgrimes 1354Srgrimes /* continue until matching return */ 1364Srgrimes 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 db_expr_t ins = db_get_value(pc, sizeof(int), FALSE); 1574Srgrimes 1584Srgrimes /* continue until call or return */ 1594Srgrimes 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{ 1744Srgrimes register db_addr_t pc = PC_REGS(DDB_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 } 1994Srgrimes#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; 2084Srgrimes db_set_single_step(DDB_REGS); 2094Srgrimes } else { 2104Srgrimes db_set_breakpoints(); 2114Srgrimes db_set_watchpoints(); 2124Srgrimes } 2134Srgrimes } else { 2144Srgrimes db_set_single_step(DDB_REGS); 2154Srgrimes } 2164Srgrimes} 2174Srgrimes 21812515Sphk#ifdef notused 21912515Sphkstatic void 2204Srgrimesdb_single_step(regs) 2214Srgrimes db_regs_t *regs; 2224Srgrimes{ 2234Srgrimes if (db_run_mode == STEP_CONTINUE) { 2244Srgrimes db_run_mode = STEP_INVISIBLE; 2254Srgrimes db_set_single_step(regs); 2264Srgrimes } 2274Srgrimes} 22812515Sphk#endif 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 */ 2604Srgrimesdb_breakpoint_t db_not_taken_bkpt = 0; 2614Srgrimesdb_breakpoint_t db_taken_bkpt = 0; 2624Srgrimes 2634Srgrimesvoid 2644Srgrimesdb_set_single_step(regs) 2654Srgrimes register db_regs_t *regs; 2664Srgrimes{ 2674Srgrimes db_addr_t pc = PC_REGS(regs); 2684Srgrimes register unsigned inst, brpc; 2694Srgrimes 2704Srgrimes /* 2714Srgrimes * User was stopped at pc, e.g. the instruction 2724Srgrimes * at pc was not executed. 2734Srgrimes */ 2744Srgrimes inst = db_get_value(pc, sizeof(int), FALSE); 2754Srgrimes if (inst_branch(inst) || inst_call(inst)) { 2764Srgrimes extern unsigned getreg_val(); 2774Srgrimes 2784Srgrimes brpc = branch_taken(inst, pc, getreg_val, regs); 2794Srgrimes if (brpc != pc) { /* self-branches are hopeless */ 2804Srgrimes db_taken_bkpt = db_set_temp_breakpoint(brpc); 2814Srgrimes } 2824Srgrimes pc = next_instr_address(pc,1); 2834Srgrimes } 2844Srgrimes pc = next_instr_address(pc,0); 2854Srgrimes db_not_taken_bkpt = db_set_temp_breakpoint(pc); 2864Srgrimes} 2874Srgrimes 2884Srgrimesvoid 2894Srgrimesdb_clear_single_step(regs) 2904Srgrimes db_regs_t *regs; 2914Srgrimes{ 2924Srgrimes register db_breakpoint_t bkpt; 2934Srgrimes 2944Srgrimes if (db_taken_bkpt != 0) { 2954Srgrimes db_delete_temp_breakpoint(db_taken_bkpt); 2964Srgrimes db_taken_bkpt = 0; 2974Srgrimes } 2984Srgrimes if (db_not_taken_bkpt != 0) { 2994Srgrimes db_delete_temp_breakpoint(db_not_taken_bkpt); 3004Srgrimes db_not_taken_bkpt = 0; 3014Srgrimes } 3024Srgrimes} 3034Srgrimes 3044Srgrimes#endif SOFTWARE_SSTEP 3054Srgrimes 3064Srgrimesextern int db_cmd_loop_done; 3074Srgrimes 3084Srgrimes/* single-step */ 3094Srgrimes/*ARGSUSED*/ 3104Srgrimesvoid 3114Srgrimesdb_single_step_cmd(addr, have_addr, count, modif) 3124Srgrimes db_expr_t addr; 31312473Sbde boolean_t have_addr; 3144Srgrimes db_expr_t count; 3154Srgrimes char * modif; 3164Srgrimes{ 3174Srgrimes boolean_t print = FALSE; 3184Srgrimes 3194Srgrimes if (count == -1) 3204Srgrimes count = 1; 3214Srgrimes 3224Srgrimes if (modif[0] == 'p') 3234Srgrimes print = TRUE; 3244Srgrimes 3254Srgrimes db_run_mode = STEP_ONCE; 3264Srgrimes db_loop_count = count; 3274Srgrimes db_sstep_print = print; 3284Srgrimes db_inst_count = 0; 3294Srgrimes db_load_count = 0; 3304Srgrimes db_store_count = 0; 3314Srgrimes 3324Srgrimes db_cmd_loop_done = 1; 3334Srgrimes} 3344Srgrimes 3354Srgrimes/* trace and print until call/return */ 3364Srgrimes/*ARGSUSED*/ 3374Srgrimesvoid 3384Srgrimesdb_trace_until_call_cmd(addr, have_addr, count, modif) 3394Srgrimes db_expr_t addr; 34012473Sbde boolean_t have_addr; 3414Srgrimes db_expr_t count; 3424Srgrimes char * modif; 3434Srgrimes{ 3444Srgrimes boolean_t print = FALSE; 3454Srgrimes 3464Srgrimes if (modif[0] == 'p') 3474Srgrimes print = TRUE; 3484Srgrimes 3494Srgrimes db_run_mode = STEP_CALLT; 3504Srgrimes db_sstep_print = print; 3514Srgrimes db_inst_count = 0; 3524Srgrimes db_load_count = 0; 3534Srgrimes db_store_count = 0; 3544Srgrimes 3554Srgrimes db_cmd_loop_done = 1; 3564Srgrimes} 3574Srgrimes 3584Srgrimes/*ARGSUSED*/ 3594Srgrimesvoid 3604Srgrimesdb_trace_until_matching_cmd(addr, have_addr, count, modif) 3614Srgrimes db_expr_t addr; 36212473Sbde boolean_t have_addr; 3634Srgrimes db_expr_t count; 3644Srgrimes char * modif; 3654Srgrimes{ 3664Srgrimes boolean_t print = FALSE; 3674Srgrimes 3684Srgrimes if (modif[0] == 'p') 3694Srgrimes print = TRUE; 3704Srgrimes 3714Srgrimes db_run_mode = STEP_RETURN; 3724Srgrimes db_call_depth = 1; 3734Srgrimes db_sstep_print = print; 3744Srgrimes db_inst_count = 0; 3754Srgrimes db_load_count = 0; 3764Srgrimes db_store_count = 0; 3774Srgrimes 3784Srgrimes db_cmd_loop_done = 1; 3794Srgrimes} 3804Srgrimes 3814Srgrimes/* continue */ 3824Srgrimes/*ARGSUSED*/ 3834Srgrimesvoid 3844Srgrimesdb_continue_cmd(addr, have_addr, count, modif) 3854Srgrimes db_expr_t addr; 38612473Sbde boolean_t have_addr; 3874Srgrimes db_expr_t count; 3884Srgrimes char * modif; 3894Srgrimes{ 3904Srgrimes if (modif[0] == 'c') 3914Srgrimes db_run_mode = STEP_COUNT; 3924Srgrimes else 3934Srgrimes db_run_mode = STEP_CONTINUE; 3944Srgrimes db_inst_count = 0; 3954Srgrimes db_load_count = 0; 3964Srgrimes db_store_count = 0; 3974Srgrimes 3984Srgrimes db_cmd_loop_done = 1; 3994Srgrimes} 400