db_run.c revision 291407
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: head/sys/ddb/db_run.c 291407 2015-11-27 19:03:59Z zbb $");
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
57272958Spfg#define	STEP_INVISIBLE	5
584Srgrimes#define	STEP_COUNT	6
594Srgrimes
60283248Spfgstatic bool		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
68291407Szbb#ifdef SOFTWARE_SSTEP
69291407Szbbdb_breakpoint_t	db_not_taken_bkpt = 0;
70291407Szbbdb_breakpoint_t	db_taken_bkpt = 0;
71291407Szbb#endif
72291407Szbb
734Srgrimes#ifndef db_set_single_step
74131952Smarcelvoid db_set_single_step(void);
754Srgrimes#endif
764Srgrimes#ifndef db_clear_single_step
77131952Smarcelvoid db_clear_single_step(void);
784Srgrimes#endif
79291407Szbb#ifndef db_pc_is_singlestep
80291407Szbbstatic bool
81291407Szbbdb_pc_is_singlestep(db_addr_t pc)
82291407Szbb{
83137974Scognet#ifdef SOFTWARE_SSTEP
84291407Szbb	if ((db_not_taken_bkpt != 0 && pc == db_not_taken_bkpt->address)
85291407Szbb	    || (db_taken_bkpt != 0 && pc == db_taken_bkpt->address))
86291407Szbb		return (true);
87137974Scognet#endif
88291407Szbb	return (false);
89291407Szbb}
90291407Szbb#endif
91137974Scognet
92283248Spfgbool
93283248Spfgdb_stop_at_pc(bool *is_breakpoint)
944Srgrimes{
95283315Spfg	db_addr_t	pc;
96283315Spfg	db_breakpoint_t bkpt;
974Srgrimes
98137974Scognet	pc = PC_REGS();
99291407Szbb
100291407Szbb	if (db_pc_is_singlestep(pc))
101283088Spfg		*is_breakpoint = false;
102137974Scognet
103131952Smarcel	db_clear_single_step();
1044Srgrimes	db_clear_breakpoints();
1054Srgrimes	db_clear_watchpoints();
1064Srgrimes
1074Srgrimes#ifdef	FIXUP_PC_AFTER_BREAK
1084Srgrimes	if (*is_breakpoint) {
1094Srgrimes	    /*
1104Srgrimes	     * Breakpoint trap.  Fix up the PC if the
1114Srgrimes	     * machine requires it.
1124Srgrimes	     */
1134Srgrimes	    FIXUP_PC_AFTER_BREAK
114131952Smarcel	    pc = PC_REGS();
1154Srgrimes	}
1164Srgrimes#endif
1174Srgrimes
1184Srgrimes	/*
1194Srgrimes	 * Now check for a breakpoint at this address.
1204Srgrimes	 */
1214Srgrimes	bkpt = db_find_breakpoint_here(pc);
1224Srgrimes	if (bkpt) {
1234Srgrimes	    if (--bkpt->count == 0) {
1244Srgrimes		bkpt->count = bkpt->init_count;
125283088Spfg		*is_breakpoint = true;
126283088Spfg		return (true);	/* stop here */
1274Srgrimes	    }
1284Srgrimes	} else if (*is_breakpoint) {
12983506Sdfr#ifdef BKPT_SKIP
13083506Sdfr		BKPT_SKIP;
13136735Sdfr#endif
1324Srgrimes	}
1338876Srgrimes
134283088Spfg	*is_breakpoint = false;
1354Srgrimes
1364Srgrimes	if (db_run_mode == STEP_INVISIBLE) {
1374Srgrimes	    db_run_mode = STEP_CONTINUE;
138283088Spfg	    return (false);	/* continue */
1394Srgrimes	}
1404Srgrimes	if (db_run_mode == STEP_COUNT) {
141283088Spfg	    return (false); /* continue */
1424Srgrimes	}
1434Srgrimes	if (db_run_mode == STEP_ONCE) {
1444Srgrimes	    if (--db_loop_count > 0) {
1454Srgrimes		if (db_sstep_print) {
1464Srgrimes		    db_printf("\t\t");
1474Srgrimes		    db_print_loc_and_inst(pc);
1484Srgrimes		    db_printf("\n");
1494Srgrimes		}
150283088Spfg		return (false);	/* continue */
1514Srgrimes	    }
1524Srgrimes	}
1534Srgrimes	if (db_run_mode == STEP_RETURN) {
1544Srgrimes	    /* continue until matching return */
15598694Smux	    db_expr_t ins;
1564Srgrimes
157283088Spfg	    ins = db_get_value(pc, sizeof(int), false);
1584Srgrimes	    if (!inst_trap_return(ins) &&
1594Srgrimes		(!inst_return(ins) || --db_call_depth != 0)) {
1604Srgrimes		if (db_sstep_print) {
1614Srgrimes		    if (inst_call(ins) || inst_return(ins)) {
162283315Spfg			int i;
1634Srgrimes
1644Srgrimes			db_printf("[after %6d]     ", db_inst_count);
1654Srgrimes			for (i = db_call_depth; --i > 0; )
1664Srgrimes			    db_printf("  ");
1674Srgrimes			db_print_loc_and_inst(pc);
1684Srgrimes			db_printf("\n");
1694Srgrimes		    }
1704Srgrimes		}
1714Srgrimes		if (inst_call(ins))
1724Srgrimes		    db_call_depth++;
173283088Spfg		return (false);	/* continue */
1744Srgrimes	    }
1754Srgrimes	}
1764Srgrimes	if (db_run_mode == STEP_CALLT) {
1774Srgrimes	    /* continue until call or return */
17898694Smux	    db_expr_t ins;
1794Srgrimes
180283088Spfg	    ins = db_get_value(pc, sizeof(int), false);
1814Srgrimes	    if (!inst_call(ins) &&
1824Srgrimes		!inst_return(ins) &&
1834Srgrimes		!inst_trap_return(ins)) {
184283088Spfg		return (false);	/* continue */
1854Srgrimes	    }
1864Srgrimes	}
1874Srgrimes	db_run_mode = STEP_NONE;
188283088Spfg	return (true);
1894Srgrimes}
1904Srgrimes
1914Srgrimesvoid
192283248Spfgdb_restart_at_pc(bool watchpt)
1934Srgrimes{
194283315Spfg	db_addr_t	pc = PC_REGS();
1954Srgrimes
1964Srgrimes	if ((db_run_mode == STEP_COUNT) ||
1974Srgrimes	    (db_run_mode == STEP_RETURN) ||
1984Srgrimes	    (db_run_mode == STEP_CALLT)) {
1994Srgrimes	    /*
2004Srgrimes	     * We are about to execute this instruction,
2014Srgrimes	     * so count it now.
2024Srgrimes	     */
203269982Simp#ifdef	SOFTWARE_SSTEP
204269982Simp	    db_expr_t		ins =
205269982Simp#endif
206283088Spfg	    db_get_value(pc, sizeof(int), false);
2074Srgrimes	    db_inst_count++;
2084Srgrimes	    db_load_count += inst_load(ins);
2094Srgrimes	    db_store_count += inst_store(ins);
2104Srgrimes#ifdef	SOFTWARE_SSTEP
2114Srgrimes	    /* XXX works on mips, but... */
2124Srgrimes	    if (inst_branch(ins) || inst_call(ins)) {
2134Srgrimes		ins = db_get_value(next_instr_address(pc,1),
214283088Spfg				   sizeof(int), false);
2154Srgrimes		db_inst_count++;
2164Srgrimes		db_load_count += inst_load(ins);
2174Srgrimes		db_store_count += inst_store(ins);
2184Srgrimes	    }
21981670Sobrien#endif	/* SOFTWARE_SSTEP */
2204Srgrimes	}
2214Srgrimes
2224Srgrimes	if (db_run_mode == STEP_CONTINUE) {
2234Srgrimes	    if (watchpt || db_find_breakpoint_here(pc)) {
2244Srgrimes		/*
2254Srgrimes		 * Step over breakpoint/watchpoint.
2264Srgrimes		 */
2274Srgrimes		db_run_mode = STEP_INVISIBLE;
228131952Smarcel		db_set_single_step();
2294Srgrimes	    } else {
2304Srgrimes		db_set_breakpoints();
2314Srgrimes		db_set_watchpoints();
2324Srgrimes	    }
2334Srgrimes	} else {
234131952Smarcel	    db_set_single_step();
2354Srgrimes	}
2364Srgrimes}
2374Srgrimes
2384Srgrimes#ifdef	SOFTWARE_SSTEP
2394Srgrimes/*
2404Srgrimes *	Software implementation of single-stepping.
2414Srgrimes *	If your machine does not have a trace mode
2424Srgrimes *	similar to the vax or sun ones you can use
2434Srgrimes *	this implementation, done for the mips.
2444Srgrimes *	Just define the above conditional and provide
2454Srgrimes *	the functions/macros defined below.
2464Srgrimes *
247283248Spfg * extern bool
2484Srgrimes *	inst_branch(),		returns true if the instruction might branch
2494Srgrimes * extern unsigned
2504Srgrimes *	branch_taken(),		return the address the instruction might
2514Srgrimes *				branch to
2524Srgrimes *	db_getreg_val();	return the value of a user register,
2534Srgrimes *				as indicated in the hardware instruction
2544Srgrimes *				encoding, e.g. 8 for r8
2558876Srgrimes *
2564Srgrimes * next_instr_address(pc,bd)	returns the address of the first
2574Srgrimes *				instruction following the one at "pc",
2584Srgrimes *				which is either in the taken path of
2594Srgrimes *				the branch (bd==1) or not.  This is
2604Srgrimes *				for machines (mips) with branch delays.
2614Srgrimes *
2624Srgrimes *	A single-step may involve at most 2 breakpoints -
2634Srgrimes *	one for branch-not-taken and one for branch taken.
2644Srgrimes *	If one of these addresses does not already have a breakpoint,
2654Srgrimes *	we allocate a breakpoint and save it here.
2664Srgrimes *	These breakpoints are deleted on return.
2678876Srgrimes */
2684Srgrimes
2694Srgrimesvoid
270131952Smarceldb_set_single_step(void)
2714Srgrimes{
272131952Smarcel	db_addr_t pc = PC_REGS(), brpc;
273131952Smarcel	unsigned inst;
2744Srgrimes
2754Srgrimes	/*
2764Srgrimes	 *	User was stopped at pc, e.g. the instruction
2774Srgrimes	 *	at pc was not executed.
2784Srgrimes	 */
279283088Spfg	inst = db_get_value(pc, sizeof(int), false);
280181175Scognet	if (inst_branch(inst) || inst_call(inst) || inst_return(inst)) {
281131952Smarcel		brpc = branch_taken(inst, pc);
282131952Smarcel		if (brpc != pc) {	/* self-branches are hopeless */
283131952Smarcel			db_taken_bkpt = db_set_temp_breakpoint(brpc);
284131952Smarcel		}
285131952Smarcel		pc = next_instr_address(pc, 1);
2864Srgrimes	}
287131952Smarcel	pc = next_instr_address(pc, 0);
2884Srgrimes	db_not_taken_bkpt = db_set_temp_breakpoint(pc);
2894Srgrimes}
2904Srgrimes
2914Srgrimesvoid
292131952Smarceldb_clear_single_step(void)
2934Srgrimes{
2944Srgrimes
29537392Sdfr	if (db_not_taken_bkpt != 0) {
296131952Smarcel		db_delete_temp_breakpoint(db_not_taken_bkpt);
297131952Smarcel		db_not_taken_bkpt = 0;
29837392Sdfr	}
2994Srgrimes	if (db_taken_bkpt != 0) {
300131952Smarcel		db_delete_temp_breakpoint(db_taken_bkpt);
301131952Smarcel		db_taken_bkpt = 0;
3024Srgrimes	}
3034Srgrimes}
3044Srgrimes
30581670Sobrien#endif	/* SOFTWARE_SSTEP */
3064Srgrimes
3074Srgrimesextern int	db_cmd_loop_done;
3084Srgrimes
3094Srgrimes/* single-step */
3104Srgrimes/*ARGSUSED*/
3114Srgrimesvoid
312283248Spfgdb_single_step_cmd(db_expr_t addr, bool have_addr, db_expr_t count, char *modif)
3134Srgrimes{
314283248Spfg	bool		print = false;
3154Srgrimes
3164Srgrimes	if (count == -1)
3174Srgrimes	    count = 1;
3184Srgrimes
3194Srgrimes	if (modif[0] == 'p')
320283088Spfg	    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
335283248Spfgdb_trace_until_call_cmd(db_expr_t addr, bool have_addr, db_expr_t count,
336273006Spfg    char *modif)
3374Srgrimes{
338283248Spfg	bool	print = false;
3394Srgrimes
3404Srgrimes	if (modif[0] == 'p')
341283088Spfg	    print = true;
3424Srgrimes
3434Srgrimes	db_run_mode = STEP_CALLT;
3444Srgrimes	db_sstep_print = print;
3454Srgrimes	db_inst_count = 0;
3464Srgrimes	db_load_count = 0;
3474Srgrimes	db_store_count = 0;
3484Srgrimes
3494Srgrimes	db_cmd_loop_done = 1;
3504Srgrimes}
3514Srgrimes
3524Srgrimes/*ARGSUSED*/
3534Srgrimesvoid
354283248Spfgdb_trace_until_matching_cmd(db_expr_t addr, bool have_addr, db_expr_t count,
355283248Spfg    char *modif)
3564Srgrimes{
357283248Spfg	bool	print = false;
3584Srgrimes
3594Srgrimes	if (modif[0] == 'p')
360283088Spfg	    print = true;
3614Srgrimes
3624Srgrimes	db_run_mode = STEP_RETURN;
3634Srgrimes	db_call_depth = 1;
3644Srgrimes	db_sstep_print = print;
3654Srgrimes	db_inst_count = 0;
3664Srgrimes	db_load_count = 0;
3674Srgrimes	db_store_count = 0;
3684Srgrimes
3694Srgrimes	db_cmd_loop_done = 1;
3704Srgrimes}
3714Srgrimes
3724Srgrimes/* continue */
3734Srgrimes/*ARGSUSED*/
3744Srgrimesvoid
375283248Spfgdb_continue_cmd(db_expr_t addr, bool have_addr, db_expr_t count, char *modif)
3764Srgrimes{
3774Srgrimes	if (modif[0] == 'c')
3784Srgrimes	    db_run_mode = STEP_COUNT;
3794Srgrimes	else
3804Srgrimes	    db_run_mode = STEP_CONTINUE;
3814Srgrimes	db_inst_count = 0;
3824Srgrimes	db_load_count = 0;
3834Srgrimes	db_store_count = 0;
3844Srgrimes
3854Srgrimes	db_cmd_loop_done = 1;
3864Srgrimes}
387