db_run.c revision 36735
132785Speter/*
232785Speter * Mach Operating System
332785Speter * Copyright (c) 1991,1990 Carnegie Mellon University
432785Speter * All Rights Reserved.
532785Speter *
632785Speter * Permission to use, copy, modify and distribute this software and its
732785Speter * documentation is hereby granted, provided that both the copyright
832785Speter * notice and this permission notice appear in all copies of the
932785Speter * software, derivative works or modified versions, and any portions
1032785Speter * thereof, and that both notices appear in supporting documentation.
1132785Speter *
1232785Speter * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
1332785Speter * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
1432785Speter * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
1532785Speter *
1654427Speter * Carnegie Mellon requests users of this software to return to
1732785Speter *
1832785Speter *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
1932785Speter *  School of Computer Science
2032785Speter *  Carnegie Mellon University
2132785Speter *  Pittsburgh PA 15213-3890
2232785Speter *
2332785Speter * any improvements or extensions that they make and grant Carnegie the
2432785Speter * rights to redistribute these changes.
2532785Speter *
2632785Speter *	$Id: db_run.c,v 1.13 1997/06/14 11:52:37 bde Exp $
2732785Speter */
2832785Speter
2932785Speter/*
3032785Speter * 	Author: David B. Golub, Carnegie Mellon University
3132785Speter *	Date:	7/90
3232785Speter */
3332785Speter
3432785Speter/*
3532785Speter * Commands to run process.
3632785Speter */
3732785Speter#include <sys/param.h>
3832785Speter
3932785Speter#include <vm/vm.h>
4032785Speter
4132785Speter#include <ddb/ddb.h>
4232785Speter#include <ddb/db_break.h>
4332785Speter#include <ddb/db_access.h>
4432785Speter
4532785Speterstatic int	db_run_mode;
4632785Speter#define	STEP_NONE	0
4732785Speter#define	STEP_ONCE	1
4832785Speter#define	STEP_RETURN	2
4932785Speter#define	STEP_CALLT	3
5032785Speter#define	STEP_CONTINUE	4
5132785Speter#define STEP_INVISIBLE	5
5232785Speter#define	STEP_COUNT	6
5332785Speter
5432785Speterstatic boolean_t	db_sstep_print;
5532785Speterstatic int		db_loop_count;
5632785Speterstatic int		db_call_depth;
5732785Speter
5832785Speterint		db_inst_count;
5932785Speterint		db_load_count;
6032785Speterint		db_store_count;
6132785Speter
6232785Speter#ifndef db_set_single_step
6332785Speterextern void	db_set_single_step __P((db_regs_t *regs));
6432785Speter#endif
6532785Speter#ifndef db_clear_single_step
6632785Speterextern void	db_clear_single_step __P((db_regs_t *regs));
6732785Speter#endif
6832785Speter
6932785Speter#ifdef notused
7032785Speterstatic void	db_single_step __P((db_regs_t *regs));
7132785Speter#endif
7232785Speter
7332785Speterboolean_t
7432785Speterdb_stop_at_pc(is_breakpoint)
7532785Speter	boolean_t	*is_breakpoint;
7632785Speter{
7732785Speter	register db_addr_t	pc;
7832785Speter	register db_breakpoint_t bkpt;
7932785Speter
8032785Speter	db_clear_single_step(DDB_REGS);
8132785Speter	db_clear_breakpoints();
8232785Speter	db_clear_watchpoints();
8332785Speter	pc = PC_REGS(DDB_REGS);
8432785Speter
8532785Speter#ifdef	FIXUP_PC_AFTER_BREAK
8632785Speter	if (*is_breakpoint) {
8732785Speter	    /*
8832785Speter	     * Breakpoint trap.  Fix up the PC if the
8932785Speter	     * machine requires it.
9032785Speter	     */
9132785Speter	    FIXUP_PC_AFTER_BREAK
9232785Speter	    pc = PC_REGS(DDB_REGS);
9332785Speter	}
9432785Speter#endif
9532785Speter
9632785Speter	/*
9732785Speter	 * Now check for a breakpoint at this address.
9832785Speter	 */
9932785Speter	bkpt = db_find_breakpoint_here(pc);
10032785Speter	if (bkpt) {
10132785Speter	    if (--bkpt->count == 0) {
10232785Speter		bkpt->count = bkpt->init_count;
10332785Speter		*is_breakpoint = TRUE;
104102840Speter		return (TRUE);	/* stop here */
10532785Speter	    }
10632785Speter	} else if (*is_breakpoint) {
10732785Speter#ifdef __i386__			/* XXx */
10832785Speter		ddb_regs.tf_eip += 1;
10932785Speter#endif
11032785Speter	}
11132785Speter
11232785Speter	*is_breakpoint = FALSE;
11332785Speter
11432785Speter	if (db_run_mode == STEP_INVISIBLE) {
11532785Speter	    db_run_mode = STEP_CONTINUE;
11632785Speter	    return (FALSE);	/* continue */
11732785Speter	}
11832785Speter	if (db_run_mode == STEP_COUNT) {
11932785Speter	    return (FALSE); /* continue */
12032785Speter	}
12132785Speter	if (db_run_mode == STEP_ONCE) {
12232785Speter	    if (--db_loop_count > 0) {
12332785Speter		if (db_sstep_print) {
12432785Speter		    db_printf("\t\t");
12532785Speter		    db_print_loc_and_inst(pc);
12632785Speter		    db_printf("\n");
12732785Speter		}
12832785Speter		return (FALSE);	/* continue */
12932785Speter	    }
13032785Speter	}
131102840Speter	if (db_run_mode == STEP_RETURN) {
13232785Speter	    db_expr_t ins = db_get_value(pc, sizeof(int), FALSE);
13332785Speter
13432785Speter	    /* continue until matching return */
13532785Speter
13632785Speter	    if (!inst_trap_return(ins) &&
13732785Speter		(!inst_return(ins) || --db_call_depth != 0)) {
13832785Speter		if (db_sstep_print) {
13932785Speter		    if (inst_call(ins) || inst_return(ins)) {
14032785Speter			register int i;
14132785Speter
14232785Speter			db_printf("[after %6d]     ", db_inst_count);
14332785Speter			for (i = db_call_depth; --i > 0; )
14432785Speter			    db_printf("  ");
14532785Speter			db_print_loc_and_inst(pc);
14632785Speter			db_printf("\n");
14732785Speter		    }
14832785Speter		}
14932785Speter		if (inst_call(ins))
15032785Speter		    db_call_depth++;
15132785Speter		return (FALSE);	/* continue */
15232785Speter	    }
15332785Speter	}
15432785Speter	if (db_run_mode == STEP_CALLT) {
15532785Speter	    db_expr_t ins = db_get_value(pc, sizeof(int), FALSE);
15632785Speter
15732785Speter	    /* continue until call or return */
15832785Speter
15932785Speter	    if (!inst_call(ins) &&
16032785Speter		!inst_return(ins) &&
16132785Speter		!inst_trap_return(ins)) {
16232785Speter		return (FALSE);	/* continue */
16332785Speter	    }
16432785Speter	}
16532785Speter	db_run_mode = STEP_NONE;
16632785Speter	return (TRUE);
16732785Speter}
16832785Speter
16932785Spetervoid
17032785Speterdb_restart_at_pc(watchpt)
17132785Speter	boolean_t watchpt;
17232785Speter{
17332785Speter	register db_addr_t	pc = PC_REGS(DDB_REGS);
17432785Speter
17532785Speter	if ((db_run_mode == STEP_COUNT) ||
17632785Speter	    (db_run_mode == STEP_RETURN) ||
17732785Speter	    (db_run_mode == STEP_CALLT)) {
17832785Speter	    db_expr_t		ins;
17932785Speter
18032785Speter	    /*
18132785Speter	     * We are about to execute this instruction,
18232785Speter	     * so count it now.
18332785Speter	     */
18432785Speter
18532785Speter	    ins = db_get_value(pc, sizeof(int), FALSE);
18632785Speter	    db_inst_count++;
18732785Speter	    db_load_count += inst_load(ins);
18832785Speter	    db_store_count += inst_store(ins);
18932785Speter#ifdef	SOFTWARE_SSTEP
19032785Speter	    /* XXX works on mips, but... */
19132785Speter	    if (inst_branch(ins) || inst_call(ins)) {
19232785Speter		ins = db_get_value(next_instr_address(pc,1),
19332785Speter				   sizeof(int), FALSE);
19432785Speter		db_inst_count++;
19532785Speter		db_load_count += inst_load(ins);
19632785Speter		db_store_count += inst_store(ins);
19732785Speter	    }
19832785Speter#endif	SOFTWARE_SSTEP
19932785Speter	}
20032785Speter
20132785Speter	if (db_run_mode == STEP_CONTINUE) {
20232785Speter	    if (watchpt || db_find_breakpoint_here(pc)) {
20332785Speter		/*
20432785Speter		 * Step over breakpoint/watchpoint.
20532785Speter		 */
20632785Speter		db_run_mode = STEP_INVISIBLE;
20732785Speter		db_set_single_step(DDB_REGS);
20832785Speter	    } else {
20932785Speter		db_set_breakpoints();
21032785Speter		db_set_watchpoints();
21132785Speter	    }
21232785Speter	} else {
21332785Speter	    db_set_single_step(DDB_REGS);
21432785Speter	}
21532785Speter}
21632785Speter
21732785Speter#ifdef notused
21832785Speterstatic void
21932785Speterdb_single_step(regs)
22032785Speter	db_regs_t *regs;
22132785Speter{
22232785Speter	if (db_run_mode == STEP_CONTINUE) {
22332785Speter	    db_run_mode = STEP_INVISIBLE;
22432785Speter	    db_set_single_step(regs);
22532785Speter	}
22632785Speter}
22732785Speter#endif
22832785Speter
22932785Speter#ifdef	SOFTWARE_SSTEP
23032785Speter/*
23132785Speter *	Software implementation of single-stepping.
23232785Speter *	If your machine does not have a trace mode
23332785Speter *	similar to the vax or sun ones you can use
23432785Speter *	this implementation, done for the mips.
23532785Speter *	Just define the above conditional and provide
23632785Speter *	the functions/macros defined below.
23732785Speter *
23832785Speter * extern boolean_t
23932785Speter *	inst_branch(),		returns true if the instruction might branch
24032785Speter * extern unsigned
24132785Speter *	branch_taken(),		return the address the instruction might
24232785Speter *				branch to
24332785Speter *	db_getreg_val();	return the value of a user register,
24432785Speter *				as indicated in the hardware instruction
24532785Speter *				encoding, e.g. 8 for r8
24632785Speter *
24732785Speter * next_instr_address(pc,bd)	returns the address of the first
24832785Speter *				instruction following the one at "pc",
24932785Speter *				which is either in the taken path of
25032785Speter *				the branch (bd==1) or not.  This is
25132785Speter *				for machines (mips) with branch delays.
25232785Speter *
25332785Speter *	A single-step may involve at most 2 breakpoints -
25432785Speter *	one for branch-not-taken and one for branch taken.
25532785Speter *	If one of these addresses does not already have a breakpoint,
25632785Speter *	we allocate a breakpoint and save it here.
25732785Speter *	These breakpoints are deleted on return.
25832785Speter */
25932785Speterdb_breakpoint_t	db_not_taken_bkpt = 0;
26032785Speterdb_breakpoint_t	db_taken_bkpt = 0;
26132785Speter
26232785Spetervoid
26332785Speterdb_set_single_step(regs)
26432785Speter	register db_regs_t *regs;
26532785Speter{
26632785Speter	db_addr_t pc = PC_REGS(regs);
26732785Speter	register unsigned	 inst, brpc;
26832785Speter
26932785Speter	/*
27032785Speter	 *	User was stopped at pc, e.g. the instruction
27132785Speter	 *	at pc was not executed.
27232785Speter	 */
27332785Speter	inst = db_get_value(pc, sizeof(int), FALSE);
27432785Speter	if (inst_branch(inst) || inst_call(inst)) {
27532785Speter	    brpc = branch_taken(inst, pc, regs);
27632785Speter	    if (brpc != pc) {	/* self-branches are hopeless */
27732785Speter		db_taken_bkpt = db_set_temp_breakpoint(brpc);
27832785Speter	    }
27932785Speter	    pc = next_instr_address(pc,1);
28032785Speter	}
28132785Speter	pc = next_instr_address(pc,0);
28232785Speter	db_not_taken_bkpt = db_set_temp_breakpoint(pc);
28332785Speter}
28432785Speter
28532785Spetervoid
28632785Speterdb_clear_single_step(regs)
28732785Speter	db_regs_t *regs;
28832785Speter{
28932785Speter	register db_breakpoint_t	bkpt;
29032785Speter
29132785Speter	if (db_taken_bkpt != 0) {
29232785Speter	    db_delete_temp_breakpoint(db_taken_bkpt);
29332785Speter	    db_taken_bkpt = 0;
29432785Speter	}
29532785Speter	if (db_not_taken_bkpt != 0) {
29632785Speter	    db_delete_temp_breakpoint(db_not_taken_bkpt);
29732785Speter	    db_not_taken_bkpt = 0;
29832785Speter	}
29932785Speter}
30032785Speter
30132785Speter#endif	SOFTWARE_SSTEP
30232785Speter
30332785Speterextern int	db_cmd_loop_done;
30432785Speter
30532785Speter/* single-step */
30632785Speter/*ARGSUSED*/
30732785Spetervoid
30832785Speterdb_single_step_cmd(addr, have_addr, count, modif)
30932785Speter	db_expr_t	addr;
31032785Speter	boolean_t	have_addr;
31132785Speter	db_expr_t	count;
31232785Speter	char *		modif;
31332785Speter{
31432785Speter	boolean_t	print = FALSE;
31532785Speter
31632785Speter	if (count == -1)
31732785Speter	    count = 1;
31832785Speter
31932785Speter	if (modif[0] == 'p')
32032785Speter	    print = TRUE;
32132785Speter
32232785Speter	db_run_mode = STEP_ONCE;
32332785Speter	db_loop_count = count;
32432785Speter	db_sstep_print = print;
32532785Speter	db_inst_count = 0;
32632785Speter	db_load_count = 0;
32732785Speter	db_store_count = 0;
32832785Speter
32932785Speter	db_cmd_loop_done = 1;
33032785Speter}
33132785Speter
33232785Speter/* trace and print until call/return */
33332785Speter/*ARGSUSED*/
33432785Spetervoid
33532785Speterdb_trace_until_call_cmd(addr, have_addr, count, modif)
33632785Speter	db_expr_t	addr;
33732785Speter	boolean_t	have_addr;
33832785Speter	db_expr_t	count;
33932785Speter	char *		modif;
34032785Speter{
34132785Speter	boolean_t	print = FALSE;
34232785Speter
34332785Speter	if (modif[0] == 'p')
34432785Speter	    print = TRUE;
34532785Speter
34632785Speter	db_run_mode = STEP_CALLT;
34732785Speter	db_sstep_print = print;
34832785Speter	db_inst_count = 0;
34932785Speter	db_load_count = 0;
35032785Speter	db_store_count = 0;
35132785Speter
35232785Speter	db_cmd_loop_done = 1;
35332785Speter}
35432785Speter
35532785Speter/*ARGSUSED*/
35632785Spetervoid
35732785Speterdb_trace_until_matching_cmd(addr, have_addr, count, modif)
35832785Speter	db_expr_t	addr;
35932785Speter	boolean_t	have_addr;
36032785Speter	db_expr_t	count;
36132785Speter	char *		modif;
36232785Speter{
36332785Speter	boolean_t	print = FALSE;
36432785Speter
36532785Speter	if (modif[0] == 'p')
36632785Speter	    print = TRUE;
36732785Speter
36832785Speter	db_run_mode = STEP_RETURN;
36932785Speter	db_call_depth = 1;
37032785Speter	db_sstep_print = print;
37132785Speter	db_inst_count = 0;
37232785Speter	db_load_count = 0;
37332785Speter	db_store_count = 0;
37432785Speter
37532785Speter	db_cmd_loop_done = 1;
37632785Speter}
37732785Speter
37832785Speter/* continue */
37932785Speter/*ARGSUSED*/
38032785Spetervoid
38132785Speterdb_continue_cmd(addr, have_addr, count, modif)
38232785Speter	db_expr_t	addr;
38332785Speter	boolean_t	have_addr;
38432785Speter	db_expr_t	count;
38532785Speter	char *		modif;
38632785Speter{
38732785Speter	if (modif[0] == 'c')
38832785Speter	    db_run_mode = STEP_COUNT;
38932785Speter	else
39032785Speter	    db_run_mode = STEP_CONTINUE;
39132785Speter	db_inst_count = 0;
39232785Speter	db_load_count = 0;
39332785Speter	db_store_count = 0;
39432785Speter
39532785Speter	db_cmd_loop_done = 1;
39632785Speter}
39732785Speter