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: stable/11/sys/ddb/db_run.c 308418 2016-11-07 12:10:17Z kib $");
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
514Srgrimes#define	STEP_ONCE	1
524Srgrimes#define	STEP_RETURN	2
534Srgrimes#define	STEP_CALLT	3
544Srgrimes#define	STEP_CONTINUE	4
55272958Spfg#define	STEP_INVISIBLE	5
564Srgrimes#define	STEP_COUNT	6
57308418Skibstatic int	db_run_mode = STEP_CONTINUE;
584Srgrimes
59308418Skibstatic bool		db_sstep_multiple;
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
93308418Skibdb_stop_at_pc(int type, int code, bool *is_breakpoint, bool *is_watchpoint)
944Srgrimes{
95283315Spfg	db_addr_t	pc;
96283315Spfg	db_breakpoint_t bkpt;
974Srgrimes
98308418Skib	*is_breakpoint = IS_BREAKPOINT_TRAP(type, code);
99308418Skib	*is_watchpoint = IS_WATCHPOINT_TRAP(type, code);
100137974Scognet	pc = PC_REGS();
101291407Szbb	if (db_pc_is_singlestep(pc))
102283088Spfg		*is_breakpoint = false;
103137974Scognet
104131952Smarcel	db_clear_single_step();
1054Srgrimes	db_clear_breakpoints();
1064Srgrimes	db_clear_watchpoints();
1074Srgrimes
1084Srgrimes#ifdef	FIXUP_PC_AFTER_BREAK
1094Srgrimes	if (*is_breakpoint) {
1104Srgrimes	    /*
1114Srgrimes	     * Breakpoint trap.  Fix up the PC if the
1124Srgrimes	     * machine requires it.
1134Srgrimes	     */
1144Srgrimes	    FIXUP_PC_AFTER_BREAK
115131952Smarcel	    pc = PC_REGS();
1164Srgrimes	}
1174Srgrimes#endif
1184Srgrimes
1194Srgrimes	/*
1204Srgrimes	 * Now check for a breakpoint at this address.
1214Srgrimes	 */
1224Srgrimes	bkpt = db_find_breakpoint_here(pc);
1234Srgrimes	if (bkpt) {
1244Srgrimes	    if (--bkpt->count == 0) {
1254Srgrimes		bkpt->count = bkpt->init_count;
126283088Spfg		*is_breakpoint = true;
127283088Spfg		return (true);	/* stop here */
1284Srgrimes	    }
129308418Skib	    return (false);	/* continue the countdown */
1304Srgrimes	} else if (*is_breakpoint) {
13183506Sdfr#ifdef BKPT_SKIP
13283506Sdfr		BKPT_SKIP;
13336735Sdfr#endif
1344Srgrimes	}
1358876Srgrimes
136308418Skib	*is_breakpoint = false;	/* might be a breakpoint, but not ours */
1374Srgrimes
138308418Skib	/*
139308418Skib	 * If not stepping, then silently ignore single-step traps
140308418Skib	 * (except for clearing the single-step-flag above).
141308418Skib	 *
142308418Skib	 * If stepping, then abort if the trap type is unexpected.
143308418Skib	 * Breakpoints owned by us are expected and were handled above.
144308418Skib	 * Single-steps are expected and are handled below.  All others
145308418Skib	 * are unexpected.
146308418Skib	 *
147308418Skib	 * Only do either of these if the MD layer claims to classify
148308418Skib	 * single-step traps unambiguously (by defining IS_SSTEP_TRAP).
149308418Skib	 * Otherwise, fall through to the bad historical behaviour
150308418Skib	 * given by turning unexpected traps into expected traps: if not
151308418Skib	 * stepping, then expect only breakpoints and stop, and if
152308418Skib	 * stepping, then expect only single-steps and step.
153308418Skib	 */
154308418Skib#ifdef IS_SSTEP_TRAP
155308418Skib	if (db_run_mode == STEP_CONTINUE && IS_SSTEP_TRAP(type, code))
156308418Skib	    return (false);
157308418Skib	if (db_run_mode != STEP_CONTINUE && !IS_SSTEP_TRAP(type, code)) {
158308418Skib	    printf("Stepping aborted\n");
159308418Skib	    return (true);
160308418Skib	}
161308418Skib#endif
162308418Skib
1634Srgrimes	if (db_run_mode == STEP_INVISIBLE) {
1644Srgrimes	    db_run_mode = STEP_CONTINUE;
165283088Spfg	    return (false);	/* continue */
1664Srgrimes	}
1674Srgrimes	if (db_run_mode == STEP_COUNT) {
168283088Spfg	    return (false); /* continue */
1694Srgrimes	}
1704Srgrimes	if (db_run_mode == STEP_ONCE) {
1714Srgrimes	    if (--db_loop_count > 0) {
1724Srgrimes		if (db_sstep_print) {
1734Srgrimes		    db_printf("\t\t");
1744Srgrimes		    db_print_loc_and_inst(pc);
1754Srgrimes		    db_printf("\n");
1764Srgrimes		}
177283088Spfg		return (false);	/* continue */
1784Srgrimes	    }
1794Srgrimes	}
1804Srgrimes	if (db_run_mode == STEP_RETURN) {
1814Srgrimes	    /* continue until matching return */
18298694Smux	    db_expr_t ins;
1834Srgrimes
184283088Spfg	    ins = db_get_value(pc, sizeof(int), false);
1854Srgrimes	    if (!inst_trap_return(ins) &&
1864Srgrimes		(!inst_return(ins) || --db_call_depth != 0)) {
1874Srgrimes		if (db_sstep_print) {
1884Srgrimes		    if (inst_call(ins) || inst_return(ins)) {
189283315Spfg			int i;
1904Srgrimes
1914Srgrimes			db_printf("[after %6d]     ", db_inst_count);
1924Srgrimes			for (i = db_call_depth; --i > 0; )
1934Srgrimes			    db_printf("  ");
1944Srgrimes			db_print_loc_and_inst(pc);
1954Srgrimes			db_printf("\n");
1964Srgrimes		    }
1974Srgrimes		}
1984Srgrimes		if (inst_call(ins))
1994Srgrimes		    db_call_depth++;
200283088Spfg		return (false);	/* continue */
2014Srgrimes	    }
2024Srgrimes	}
2034Srgrimes	if (db_run_mode == STEP_CALLT) {
2044Srgrimes	    /* continue until call or return */
20598694Smux	    db_expr_t ins;
2064Srgrimes
207283088Spfg	    ins = db_get_value(pc, sizeof(int), false);
2084Srgrimes	    if (!inst_call(ins) &&
2094Srgrimes		!inst_return(ins) &&
2104Srgrimes		!inst_trap_return(ins)) {
211283088Spfg		return (false);	/* continue */
2124Srgrimes	    }
2134Srgrimes	}
214283088Spfg	return (true);
2154Srgrimes}
2164Srgrimes
2174Srgrimesvoid
218283248Spfgdb_restart_at_pc(bool watchpt)
2194Srgrimes{
220283315Spfg	db_addr_t	pc = PC_REGS();
2214Srgrimes
2224Srgrimes	if ((db_run_mode == STEP_COUNT) ||
223308418Skib	    ((db_run_mode == STEP_ONCE) && db_sstep_multiple) ||
2244Srgrimes	    (db_run_mode == STEP_RETURN) ||
2254Srgrimes	    (db_run_mode == STEP_CALLT)) {
2264Srgrimes	    /*
2274Srgrimes	     * We are about to execute this instruction,
2284Srgrimes	     * so count it now.
2294Srgrimes	     */
230269982Simp#ifdef	SOFTWARE_SSTEP
231269982Simp	    db_expr_t		ins =
232269982Simp#endif
233283088Spfg	    db_get_value(pc, sizeof(int), false);
2344Srgrimes	    db_inst_count++;
2354Srgrimes	    db_load_count += inst_load(ins);
2364Srgrimes	    db_store_count += inst_store(ins);
2374Srgrimes#ifdef	SOFTWARE_SSTEP
2384Srgrimes	    /* XXX works on mips, but... */
2394Srgrimes	    if (inst_branch(ins) || inst_call(ins)) {
2404Srgrimes		ins = db_get_value(next_instr_address(pc,1),
241283088Spfg				   sizeof(int), false);
2424Srgrimes		db_inst_count++;
2434Srgrimes		db_load_count += inst_load(ins);
2444Srgrimes		db_store_count += inst_store(ins);
2454Srgrimes	    }
24681670Sobrien#endif	/* SOFTWARE_SSTEP */
2474Srgrimes	}
2484Srgrimes
2494Srgrimes	if (db_run_mode == STEP_CONTINUE) {
2504Srgrimes	    if (watchpt || db_find_breakpoint_here(pc)) {
2514Srgrimes		/*
2524Srgrimes		 * Step over breakpoint/watchpoint.
2534Srgrimes		 */
2544Srgrimes		db_run_mode = STEP_INVISIBLE;
255131952Smarcel		db_set_single_step();
2564Srgrimes	    } else {
2574Srgrimes		db_set_breakpoints();
2584Srgrimes		db_set_watchpoints();
2594Srgrimes	    }
2604Srgrimes	} else {
261131952Smarcel	    db_set_single_step();
2624Srgrimes	}
2634Srgrimes}
2644Srgrimes
2654Srgrimes#ifdef	SOFTWARE_SSTEP
2664Srgrimes/*
2674Srgrimes *	Software implementation of single-stepping.
2684Srgrimes *	If your machine does not have a trace mode
2694Srgrimes *	similar to the vax or sun ones you can use
2704Srgrimes *	this implementation, done for the mips.
2714Srgrimes *	Just define the above conditional and provide
2724Srgrimes *	the functions/macros defined below.
2734Srgrimes *
274283248Spfg * extern bool
2754Srgrimes *	inst_branch(),		returns true if the instruction might branch
2764Srgrimes * extern unsigned
2774Srgrimes *	branch_taken(),		return the address the instruction might
2784Srgrimes *				branch to
2794Srgrimes *	db_getreg_val();	return the value of a user register,
2804Srgrimes *				as indicated in the hardware instruction
2814Srgrimes *				encoding, e.g. 8 for r8
2828876Srgrimes *
2834Srgrimes * next_instr_address(pc,bd)	returns the address of the first
2844Srgrimes *				instruction following the one at "pc",
2854Srgrimes *				which is either in the taken path of
2864Srgrimes *				the branch (bd==1) or not.  This is
2874Srgrimes *				for machines (mips) with branch delays.
2884Srgrimes *
2894Srgrimes *	A single-step may involve at most 2 breakpoints -
2904Srgrimes *	one for branch-not-taken and one for branch taken.
2914Srgrimes *	If one of these addresses does not already have a breakpoint,
2924Srgrimes *	we allocate a breakpoint and save it here.
2934Srgrimes *	These breakpoints are deleted on return.
2948876Srgrimes */
2954Srgrimes
2964Srgrimesvoid
297131952Smarceldb_set_single_step(void)
2984Srgrimes{
299131952Smarcel	db_addr_t pc = PC_REGS(), brpc;
300131952Smarcel	unsigned inst;
3014Srgrimes
3024Srgrimes	/*
3034Srgrimes	 *	User was stopped at pc, e.g. the instruction
3044Srgrimes	 *	at pc was not executed.
3054Srgrimes	 */
306283088Spfg	inst = db_get_value(pc, sizeof(int), false);
307181175Scognet	if (inst_branch(inst) || inst_call(inst) || inst_return(inst)) {
308131952Smarcel		brpc = branch_taken(inst, pc);
309131952Smarcel		if (brpc != pc) {	/* self-branches are hopeless */
310131952Smarcel			db_taken_bkpt = db_set_temp_breakpoint(brpc);
311131952Smarcel		}
312131952Smarcel		pc = next_instr_address(pc, 1);
3134Srgrimes	}
314131952Smarcel	pc = next_instr_address(pc, 0);
3154Srgrimes	db_not_taken_bkpt = db_set_temp_breakpoint(pc);
3164Srgrimes}
3174Srgrimes
3184Srgrimesvoid
319131952Smarceldb_clear_single_step(void)
3204Srgrimes{
3214Srgrimes
32237392Sdfr	if (db_not_taken_bkpt != 0) {
323131952Smarcel		db_delete_temp_breakpoint(db_not_taken_bkpt);
324131952Smarcel		db_not_taken_bkpt = 0;
32537392Sdfr	}
3264Srgrimes	if (db_taken_bkpt != 0) {
327131952Smarcel		db_delete_temp_breakpoint(db_taken_bkpt);
328131952Smarcel		db_taken_bkpt = 0;
3294Srgrimes	}
3304Srgrimes}
3314Srgrimes
33281670Sobrien#endif	/* SOFTWARE_SSTEP */
3334Srgrimes
3344Srgrimesextern int	db_cmd_loop_done;
3354Srgrimes
3364Srgrimes/* single-step */
3374Srgrimes/*ARGSUSED*/
3384Srgrimesvoid
339283248Spfgdb_single_step_cmd(db_expr_t addr, bool have_addr, db_expr_t count, char *modif)
3404Srgrimes{
341283248Spfg	bool		print = false;
3424Srgrimes
3434Srgrimes	if (count == -1)
3444Srgrimes	    count = 1;
3454Srgrimes
3464Srgrimes	if (modif[0] == 'p')
347283088Spfg	    print = true;
3484Srgrimes
3494Srgrimes	db_run_mode = STEP_ONCE;
3504Srgrimes	db_loop_count = count;
351308418Skib	db_sstep_multiple = (count != 1);
3524Srgrimes	db_sstep_print = print;
3534Srgrimes	db_inst_count = 0;
3544Srgrimes	db_load_count = 0;
3554Srgrimes	db_store_count = 0;
3564Srgrimes
3574Srgrimes	db_cmd_loop_done = 1;
3584Srgrimes}
3594Srgrimes
3604Srgrimes/* trace and print until call/return */
3614Srgrimes/*ARGSUSED*/
3624Srgrimesvoid
363283248Spfgdb_trace_until_call_cmd(db_expr_t addr, bool have_addr, db_expr_t count,
364273006Spfg    char *modif)
3654Srgrimes{
366283248Spfg	bool	print = false;
3674Srgrimes
3684Srgrimes	if (modif[0] == 'p')
369283088Spfg	    print = true;
3704Srgrimes
3714Srgrimes	db_run_mode = STEP_CALLT;
3724Srgrimes	db_sstep_print = print;
3734Srgrimes	db_inst_count = 0;
3744Srgrimes	db_load_count = 0;
3754Srgrimes	db_store_count = 0;
3764Srgrimes
3774Srgrimes	db_cmd_loop_done = 1;
3784Srgrimes}
3794Srgrimes
3804Srgrimes/*ARGSUSED*/
3814Srgrimesvoid
382283248Spfgdb_trace_until_matching_cmd(db_expr_t addr, bool have_addr, db_expr_t count,
383283248Spfg    char *modif)
3844Srgrimes{
385283248Spfg	bool	print = false;
3864Srgrimes
3874Srgrimes	if (modif[0] == 'p')
388283088Spfg	    print = true;
3894Srgrimes
3904Srgrimes	db_run_mode = STEP_RETURN;
3914Srgrimes	db_call_depth = 1;
3924Srgrimes	db_sstep_print = print;
3934Srgrimes	db_inst_count = 0;
3944Srgrimes	db_load_count = 0;
3954Srgrimes	db_store_count = 0;
3964Srgrimes
3974Srgrimes	db_cmd_loop_done = 1;
3984Srgrimes}
3994Srgrimes
4004Srgrimes/* continue */
4014Srgrimes/*ARGSUSED*/
4024Srgrimesvoid
403283248Spfgdb_continue_cmd(db_expr_t addr, bool have_addr, db_expr_t count, char *modif)
4044Srgrimes{
4054Srgrimes	if (modif[0] == 'c')
4064Srgrimes	    db_run_mode = STEP_COUNT;
4074Srgrimes	else
4084Srgrimes	    db_run_mode = STEP_CONTINUE;
4094Srgrimes	db_inst_count = 0;
4104Srgrimes	db_load_count = 0;
4114Srgrimes	db_store_count = 0;
4124Srgrimes
4134Srgrimes	db_cmd_loop_done = 1;
4144Srgrimes}
415