db_run.c revision 37392
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 * 2637392Sdfr * $Id: db_run.c,v 1.15 1998/06/28 00:52:50 dfr 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> 3812734Sbde 3912662Sdg#include <vm/vm.h> 4012734Sbde 412056Swollman#include <ddb/ddb.h> 424Srgrimes#include <ddb/db_break.h> 434Srgrimes#include <ddb/db_access.h> 444Srgrimes 4512720Sphkstatic int db_run_mode; 464Srgrimes#define STEP_NONE 0 474Srgrimes#define STEP_ONCE 1 484Srgrimes#define STEP_RETURN 2 494Srgrimes#define STEP_CALLT 3 504Srgrimes#define STEP_CONTINUE 4 514Srgrimes#define STEP_INVISIBLE 5 524Srgrimes#define STEP_COUNT 6 534Srgrimes 5412720Sphkstatic boolean_t db_sstep_print; 5512720Sphkstatic int db_loop_count; 5612720Sphkstatic int db_call_depth; 574Srgrimes 584Srgrimesint db_inst_count; 594Srgrimesint db_load_count; 604Srgrimesint db_store_count; 614Srgrimes 624Srgrimes#ifndef db_set_single_step 6336735Sdfrextern void db_set_single_step __P((db_regs_t *regs)); 644Srgrimes#endif 654Srgrimes#ifndef db_clear_single_step 6612473Sbdeextern void db_clear_single_step __P((db_regs_t *regs)); 674Srgrimes#endif 684Srgrimes 6912515Sphk#ifdef notused 7012515Sphkstatic void db_single_step __P((db_regs_t *regs)); 7112515Sphk#endif 7212515Sphk 734Srgrimesboolean_t 744Srgrimesdb_stop_at_pc(is_breakpoint) 754Srgrimes boolean_t *is_breakpoint; 764Srgrimes{ 774Srgrimes register db_addr_t pc; 784Srgrimes register db_breakpoint_t bkpt; 794Srgrimes 804Srgrimes db_clear_single_step(DDB_REGS); 814Srgrimes db_clear_breakpoints(); 824Srgrimes db_clear_watchpoints(); 834Srgrimes pc = PC_REGS(DDB_REGS); 844Srgrimes 854Srgrimes#ifdef FIXUP_PC_AFTER_BREAK 864Srgrimes if (*is_breakpoint) { 874Srgrimes /* 884Srgrimes * Breakpoint trap. Fix up the PC if the 894Srgrimes * machine requires it. 904Srgrimes */ 914Srgrimes FIXUP_PC_AFTER_BREAK 924Srgrimes pc = PC_REGS(DDB_REGS); 934Srgrimes } 944Srgrimes#endif 954Srgrimes 964Srgrimes /* 974Srgrimes * Now check for a breakpoint at this address. 984Srgrimes */ 994Srgrimes bkpt = db_find_breakpoint_here(pc); 1004Srgrimes if (bkpt) { 1014Srgrimes if (--bkpt->count == 0) { 1024Srgrimes bkpt->count = bkpt->init_count; 1034Srgrimes *is_breakpoint = TRUE; 1044Srgrimes return (TRUE); /* stop here */ 1054Srgrimes } 1064Srgrimes } else if (*is_breakpoint) { 10736735Sdfr#ifdef __i386__ /* XXx */ 1084Srgrimes ddb_regs.tf_eip += 1; 10936735Sdfr#endif 1104Srgrimes } 1118876Srgrimes 1124Srgrimes *is_breakpoint = FALSE; 1134Srgrimes 1144Srgrimes if (db_run_mode == STEP_INVISIBLE) { 1154Srgrimes db_run_mode = STEP_CONTINUE; 1164Srgrimes return (FALSE); /* continue */ 1174Srgrimes } 1184Srgrimes if (db_run_mode == STEP_COUNT) { 1194Srgrimes return (FALSE); /* continue */ 1204Srgrimes } 1214Srgrimes if (db_run_mode == STEP_ONCE) { 1224Srgrimes if (--db_loop_count > 0) { 1234Srgrimes if (db_sstep_print) { 1244Srgrimes db_printf("\t\t"); 1254Srgrimes db_print_loc_and_inst(pc); 1264Srgrimes db_printf("\n"); 1274Srgrimes } 1284Srgrimes return (FALSE); /* continue */ 1294Srgrimes } 1304Srgrimes } 1314Srgrimes if (db_run_mode == STEP_RETURN) { 1324Srgrimes db_expr_t ins = db_get_value(pc, sizeof(int), FALSE); 1334Srgrimes 1344Srgrimes /* continue until matching return */ 1354Srgrimes 1364Srgrimes if (!inst_trap_return(ins) && 1374Srgrimes (!inst_return(ins) || --db_call_depth != 0)) { 1384Srgrimes if (db_sstep_print) { 1394Srgrimes if (inst_call(ins) || inst_return(ins)) { 1404Srgrimes register int i; 1414Srgrimes 1424Srgrimes db_printf("[after %6d] ", db_inst_count); 1434Srgrimes for (i = db_call_depth; --i > 0; ) 1444Srgrimes db_printf(" "); 1454Srgrimes db_print_loc_and_inst(pc); 1464Srgrimes db_printf("\n"); 1474Srgrimes } 1484Srgrimes } 1494Srgrimes if (inst_call(ins)) 1504Srgrimes db_call_depth++; 1514Srgrimes return (FALSE); /* continue */ 1524Srgrimes } 1534Srgrimes } 1544Srgrimes if (db_run_mode == STEP_CALLT) { 1554Srgrimes db_expr_t ins = db_get_value(pc, sizeof(int), FALSE); 1564Srgrimes 1574Srgrimes /* continue until call or return */ 1584Srgrimes 1594Srgrimes if (!inst_call(ins) && 1604Srgrimes !inst_return(ins) && 1614Srgrimes !inst_trap_return(ins)) { 1624Srgrimes return (FALSE); /* continue */ 1634Srgrimes } 1644Srgrimes } 1654Srgrimes db_run_mode = STEP_NONE; 1664Srgrimes return (TRUE); 1674Srgrimes} 1684Srgrimes 1694Srgrimesvoid 1704Srgrimesdb_restart_at_pc(watchpt) 1714Srgrimes boolean_t watchpt; 1724Srgrimes{ 1734Srgrimes register db_addr_t pc = PC_REGS(DDB_REGS); 1744Srgrimes 1754Srgrimes if ((db_run_mode == STEP_COUNT) || 1764Srgrimes (db_run_mode == STEP_RETURN) || 1774Srgrimes (db_run_mode == STEP_CALLT)) { 1784Srgrimes db_expr_t ins; 1794Srgrimes 1804Srgrimes /* 1814Srgrimes * We are about to execute this instruction, 1824Srgrimes * so count it now. 1834Srgrimes */ 1844Srgrimes 1854Srgrimes ins = db_get_value(pc, sizeof(int), FALSE); 1864Srgrimes db_inst_count++; 1874Srgrimes db_load_count += inst_load(ins); 1884Srgrimes db_store_count += inst_store(ins); 1894Srgrimes#ifdef SOFTWARE_SSTEP 1904Srgrimes /* XXX works on mips, but... */ 1914Srgrimes if (inst_branch(ins) || inst_call(ins)) { 1924Srgrimes ins = db_get_value(next_instr_address(pc,1), 1934Srgrimes sizeof(int), FALSE); 1944Srgrimes db_inst_count++; 1954Srgrimes db_load_count += inst_load(ins); 1964Srgrimes db_store_count += inst_store(ins); 1974Srgrimes } 1984Srgrimes#endif SOFTWARE_SSTEP 1994Srgrimes } 2004Srgrimes 2014Srgrimes if (db_run_mode == STEP_CONTINUE) { 2024Srgrimes if (watchpt || db_find_breakpoint_here(pc)) { 2034Srgrimes /* 2044Srgrimes * Step over breakpoint/watchpoint. 2054Srgrimes */ 2064Srgrimes db_run_mode = STEP_INVISIBLE; 2074Srgrimes db_set_single_step(DDB_REGS); 2084Srgrimes } else { 2094Srgrimes db_set_breakpoints(); 2104Srgrimes db_set_watchpoints(); 2114Srgrimes } 2124Srgrimes } else { 2134Srgrimes db_set_single_step(DDB_REGS); 2144Srgrimes } 2154Srgrimes} 2164Srgrimes 21712515Sphk#ifdef notused 21812515Sphkstatic void 2194Srgrimesdb_single_step(regs) 2204Srgrimes db_regs_t *regs; 2214Srgrimes{ 2224Srgrimes if (db_run_mode == STEP_CONTINUE) { 2234Srgrimes db_run_mode = STEP_INVISIBLE; 2244Srgrimes db_set_single_step(regs); 2254Srgrimes } 2264Srgrimes} 22712515Sphk#endif 2284Srgrimes 2294Srgrimes#ifdef SOFTWARE_SSTEP 2304Srgrimes/* 2314Srgrimes * Software implementation of single-stepping. 2324Srgrimes * If your machine does not have a trace mode 2334Srgrimes * similar to the vax or sun ones you can use 2344Srgrimes * this implementation, done for the mips. 2354Srgrimes * Just define the above conditional and provide 2364Srgrimes * the functions/macros defined below. 2374Srgrimes * 2384Srgrimes * extern boolean_t 2394Srgrimes * inst_branch(), returns true if the instruction might branch 2404Srgrimes * extern unsigned 2414Srgrimes * branch_taken(), return the address the instruction might 2424Srgrimes * branch to 2434Srgrimes * db_getreg_val(); return the value of a user register, 2444Srgrimes * as indicated in the hardware instruction 2454Srgrimes * encoding, e.g. 8 for r8 2468876Srgrimes * 2474Srgrimes * next_instr_address(pc,bd) returns the address of the first 2484Srgrimes * instruction following the one at "pc", 2494Srgrimes * which is either in the taken path of 2504Srgrimes * the branch (bd==1) or not. This is 2514Srgrimes * for machines (mips) with branch delays. 2524Srgrimes * 2534Srgrimes * A single-step may involve at most 2 breakpoints - 2544Srgrimes * one for branch-not-taken and one for branch taken. 2554Srgrimes * If one of these addresses does not already have a breakpoint, 2564Srgrimes * we allocate a breakpoint and save it here. 2574Srgrimes * These breakpoints are deleted on return. 2588876Srgrimes */ 2594Srgrimesdb_breakpoint_t db_not_taken_bkpt = 0; 2604Srgrimesdb_breakpoint_t db_taken_bkpt = 0; 2614Srgrimes 2624Srgrimesvoid 2634Srgrimesdb_set_single_step(regs) 2644Srgrimes register db_regs_t *regs; 2654Srgrimes{ 26637217Sdfr db_addr_t pc = PC_REGS(regs), brpc; 26737217Sdfr unsigned inst; 2684Srgrimes 2694Srgrimes /* 2704Srgrimes * User was stopped at pc, e.g. the instruction 2714Srgrimes * at pc was not executed. 2724Srgrimes */ 2734Srgrimes inst = db_get_value(pc, sizeof(int), FALSE); 2744Srgrimes if (inst_branch(inst) || inst_call(inst)) { 27536735Sdfr brpc = branch_taken(inst, pc, regs); 2764Srgrimes if (brpc != pc) { /* self-branches are hopeless */ 2774Srgrimes db_taken_bkpt = db_set_temp_breakpoint(brpc); 2784Srgrimes } 2794Srgrimes pc = next_instr_address(pc,1); 2804Srgrimes } 2814Srgrimes pc = next_instr_address(pc,0); 2824Srgrimes db_not_taken_bkpt = db_set_temp_breakpoint(pc); 2834Srgrimes} 2844Srgrimes 2854Srgrimesvoid 2864Srgrimesdb_clear_single_step(regs) 2874Srgrimes db_regs_t *regs; 2884Srgrimes{ 2894Srgrimes register db_breakpoint_t bkpt; 2904Srgrimes 29137392Sdfr if (db_not_taken_bkpt != 0) { 29237392Sdfr db_delete_temp_breakpoint(db_not_taken_bkpt); 29337392Sdfr db_not_taken_bkpt = 0; 29437392Sdfr } 2954Srgrimes if (db_taken_bkpt != 0) { 2964Srgrimes db_delete_temp_breakpoint(db_taken_bkpt); 2974Srgrimes db_taken_bkpt = 0; 2984Srgrimes } 2994Srgrimes} 3004Srgrimes 3014Srgrimes#endif SOFTWARE_SSTEP 3024Srgrimes 3034Srgrimesextern int db_cmd_loop_done; 3044Srgrimes 3054Srgrimes/* single-step */ 3064Srgrimes/*ARGSUSED*/ 3074Srgrimesvoid 3084Srgrimesdb_single_step_cmd(addr, have_addr, count, modif) 3094Srgrimes db_expr_t addr; 31012473Sbde boolean_t have_addr; 3114Srgrimes db_expr_t count; 3124Srgrimes char * modif; 3134Srgrimes{ 3144Srgrimes boolean_t print = FALSE; 3154Srgrimes 3164Srgrimes if (count == -1) 3174Srgrimes count = 1; 3184Srgrimes 3194Srgrimes if (modif[0] == 'p') 3204Srgrimes print = TRUE; 3214Srgrimes 3224Srgrimes db_run_mode = STEP_ONCE; 3234Srgrimes db_loop_count = count; 3244Srgrimes db_sstep_print = print; 3254Srgrimes db_inst_count = 0; 3264Srgrimes db_load_count = 0; 3274Srgrimes db_store_count = 0; 3284Srgrimes 3294Srgrimes db_cmd_loop_done = 1; 3304Srgrimes} 3314Srgrimes 3324Srgrimes/* trace and print until call/return */ 3334Srgrimes/*ARGSUSED*/ 3344Srgrimesvoid 3354Srgrimesdb_trace_until_call_cmd(addr, have_addr, count, modif) 3364Srgrimes db_expr_t addr; 33712473Sbde boolean_t have_addr; 3384Srgrimes db_expr_t count; 3394Srgrimes char * modif; 3404Srgrimes{ 3414Srgrimes boolean_t print = FALSE; 3424Srgrimes 3434Srgrimes if (modif[0] == 'p') 3444Srgrimes print = TRUE; 3454Srgrimes 3464Srgrimes db_run_mode = STEP_CALLT; 3474Srgrimes db_sstep_print = print; 3484Srgrimes db_inst_count = 0; 3494Srgrimes db_load_count = 0; 3504Srgrimes db_store_count = 0; 3514Srgrimes 3524Srgrimes db_cmd_loop_done = 1; 3534Srgrimes} 3544Srgrimes 3554Srgrimes/*ARGSUSED*/ 3564Srgrimesvoid 3574Srgrimesdb_trace_until_matching_cmd(addr, have_addr, count, modif) 3584Srgrimes db_expr_t addr; 35912473Sbde boolean_t have_addr; 3604Srgrimes db_expr_t count; 3614Srgrimes char * modif; 3624Srgrimes{ 3634Srgrimes boolean_t print = FALSE; 3644Srgrimes 3654Srgrimes if (modif[0] == 'p') 3664Srgrimes print = TRUE; 3674Srgrimes 3684Srgrimes db_run_mode = STEP_RETURN; 3694Srgrimes db_call_depth = 1; 3704Srgrimes db_sstep_print = print; 3714Srgrimes db_inst_count = 0; 3724Srgrimes db_load_count = 0; 3734Srgrimes db_store_count = 0; 3744Srgrimes 3754Srgrimes db_cmd_loop_done = 1; 3764Srgrimes} 3774Srgrimes 3784Srgrimes/* continue */ 3794Srgrimes/*ARGSUSED*/ 3804Srgrimesvoid 3814Srgrimesdb_continue_cmd(addr, have_addr, count, modif) 3824Srgrimes db_expr_t addr; 38312473Sbde boolean_t have_addr; 3844Srgrimes db_expr_t count; 3854Srgrimes char * modif; 3864Srgrimes{ 3874Srgrimes if (modif[0] == 'c') 3884Srgrimes db_run_mode = STEP_COUNT; 3894Srgrimes else 3904Srgrimes db_run_mode = STEP_CONTINUE; 3914Srgrimes db_inst_count = 0; 3924Srgrimes db_load_count = 0; 3934Srgrimes db_store_count = 0; 3944Srgrimes 3954Srgrimes db_cmd_loop_done = 1; 3964Srgrimes} 397