Home | History | Annotate | Line # | Download | only in ddb
db_run.c revision 1.6
      1 /*	$NetBSD: db_run.c,v 1.6 1994/10/09 08:19:37 mycroft Exp $	*/
      2 
      3 /*
      4  * Mach Operating System
      5  * Copyright (c) 1991,1990 Carnegie Mellon University
      6  * All Rights Reserved.
      7  *
      8  * Permission to use, copy, modify and distribute this software and its
      9  * documentation is hereby granted, provided that both the copyright
     10  * notice and this permission notice appear in all copies of the
     11  * software, derivative works or modified versions, and any portions
     12  * thereof, and that both notices appear in supporting documentation.
     13  *
     14  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
     15  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
     16  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
     17  *
     18  * Carnegie Mellon requests users of this software to return to
     19  *
     20  *  Software Distribution Coordinator  or  Software.Distribution (at) CS.CMU.EDU
     21  *  School of Computer Science
     22  *  Carnegie Mellon University
     23  *  Pittsburgh PA 15213-3890
     24  *
     25  * any improvements or extensions that they make and grant Carnegie the
     26  * rights to redistribute these changes.
     27  *
     28  * 	Author: David B. Golub, Carnegie Mellon University
     29  *	Date:	7/90
     30  */
     31 
     32 /*
     33  * Commands to run process.
     34  */
     35 #include <ddb/db_run.h>
     36 #include <ddb/db_lex.h>
     37 #include <ddb/db_break.h>
     38 #include <ddb/db_access.h>
     39 
     40 int	db_run_mode;
     41 #define	STEP_NONE	0
     42 #define	STEP_ONCE	1
     43 #define	STEP_RETURN	2
     44 #define	STEP_CALLT	3
     45 #define	STEP_CONTINUE	4
     46 #define STEP_INVISIBLE	5
     47 #define	STEP_COUNT	6
     48 
     49 boolean_t	db_sstep_print;
     50 int		db_loop_count;
     51 int		db_call_depth;
     52 
     53 boolean_t
     54 db_stop_at_pc(regs, is_breakpoint)
     55 	db_regs_t *regs;
     56 	boolean_t	*is_breakpoint;
     57 {
     58 	register db_addr_t	pc;
     59 	register db_breakpoint_t bkpt;
     60 
     61 	db_clear_single_step(regs);
     62 	db_clear_breakpoints();
     63 	db_clear_watchpoints();
     64 	pc = PC_REGS(regs);
     65 
     66 #ifdef	FIXUP_PC_AFTER_BREAK
     67 	if (*is_breakpoint) {
     68 	    /*
     69 	     * Breakpoint trap.  Fix up the PC if the
     70 	     * machine requires it.
     71 	     */
     72 	    FIXUP_PC_AFTER_BREAK
     73 	    pc = PC_REGS(regs);
     74 	}
     75 #endif
     76 
     77 	/*
     78 	 * Now check for a breakpoint at this address.
     79 	 */
     80 	bkpt = db_find_breakpoint_here(pc);
     81 	if (bkpt) {
     82 	    if (--bkpt->count == 0) {
     83 		bkpt->count = bkpt->init_count;
     84 		*is_breakpoint = TRUE;
     85 		return (TRUE);	/* stop here */
     86 	    }
     87 	} else if (*is_breakpoint) {
     88 		PC_REGS(regs) += BKPT_SIZE;
     89 	}
     90 
     91 	*is_breakpoint = FALSE;
     92 
     93 	if (db_run_mode == STEP_INVISIBLE) {
     94 	    db_run_mode = STEP_CONTINUE;
     95 	    return (FALSE);	/* continue */
     96 	}
     97 	if (db_run_mode == STEP_COUNT) {
     98 	    return (FALSE); /* continue */
     99 	}
    100 	if (db_run_mode == STEP_ONCE) {
    101 	    if (--db_loop_count > 0) {
    102 		if (db_sstep_print) {
    103 		    db_printf("\t\t");
    104 		    db_print_loc_and_inst(pc);
    105 		    db_printf("\n");
    106 		}
    107 		return (FALSE);	/* continue */
    108 	    }
    109 	}
    110 	if (db_run_mode == STEP_RETURN) {
    111 	    db_expr_t ins = db_get_value(pc, sizeof(int), FALSE);
    112 
    113 	    /* continue until matching return */
    114 
    115 	    if (!inst_trap_return(ins) &&
    116 		(!inst_return(ins) || --db_call_depth != 0)) {
    117 		if (db_sstep_print) {
    118 		    if (inst_call(ins) || inst_return(ins)) {
    119 			register int i;
    120 
    121 			db_printf("[after %6d]     ", db_inst_count);
    122 			for (i = db_call_depth; --i > 0; )
    123 			    db_printf("  ");
    124 			db_print_loc_and_inst(pc);
    125 			db_printf("\n");
    126 		    }
    127 		}
    128 		if (inst_call(ins))
    129 		    db_call_depth++;
    130 		return (FALSE);	/* continue */
    131 	    }
    132 	}
    133 	if (db_run_mode == STEP_CALLT) {
    134 	    db_expr_t ins = db_get_value(pc, sizeof(int), FALSE);
    135 
    136 	    /* continue until call or return */
    137 
    138 	    if (!inst_call(ins) &&
    139 		!inst_return(ins) &&
    140 		!inst_trap_return(ins)) {
    141 		return (FALSE);	/* continue */
    142 	    }
    143 	}
    144 	db_run_mode = STEP_NONE;
    145 	return (TRUE);
    146 }
    147 
    148 void
    149 db_restart_at_pc(regs, watchpt)
    150 	db_regs_t *regs;
    151 	boolean_t watchpt;
    152 {
    153 	register db_addr_t pc = PC_REGS(regs);
    154 
    155 	if ((db_run_mode == STEP_COUNT) ||
    156 	    (db_run_mode == STEP_RETURN) ||
    157 	    (db_run_mode == STEP_CALLT)) {
    158 	    db_expr_t		ins;
    159 
    160 	    /*
    161 	     * We are about to execute this instruction,
    162 	     * so count it now.
    163 	     */
    164 
    165 	    ins = db_get_value(pc, sizeof(int), FALSE);
    166 	    db_inst_count++;
    167 	    db_load_count += inst_load(ins);
    168 	    db_store_count += inst_store(ins);
    169 #ifdef	SOFTWARE_SSTEP
    170 	    /* XXX works on mips, but... */
    171 	    if (inst_branch(ins) || inst_call(ins)) {
    172 		ins = db_get_value(next_instr_address(pc,1),
    173 				   sizeof(int), FALSE);
    174 		db_inst_count++;
    175 		db_load_count += inst_load(ins);
    176 		db_store_count += inst_store(ins);
    177 	    }
    178 #endif	SOFTWARE_SSTEP
    179 	}
    180 
    181 	if (db_run_mode == STEP_CONTINUE) {
    182 	    if (watchpt || db_find_breakpoint_here(pc)) {
    183 		/*
    184 		 * Step over breakpoint/watchpoint.
    185 		 */
    186 		db_run_mode = STEP_INVISIBLE;
    187 		db_set_single_step(regs);
    188 	    } else {
    189 		db_set_breakpoints();
    190 		db_set_watchpoints();
    191 	    }
    192 	} else {
    193 	    db_set_single_step(regs);
    194 	}
    195 }
    196 
    197 void
    198 db_single_step(regs)
    199 	db_regs_t *regs;
    200 {
    201 	if (db_run_mode == STEP_CONTINUE) {
    202 	    db_run_mode = STEP_INVISIBLE;
    203 	    db_set_single_step(regs);
    204 	}
    205 }
    206 
    207 #ifdef	SOFTWARE_SSTEP
    208 /*
    209  *	Software implementation of single-stepping.
    210  *	If your machine does not have a trace mode
    211  *	similar to the vax or sun ones you can use
    212  *	this implementation, done for the mips.
    213  *	Just define the above conditional and provide
    214  *	the functions/macros defined below.
    215  *
    216  * extern boolean_t
    217  *	inst_branch(),		returns true if the instruction might branch
    218  * extern unsigned
    219  *	branch_taken(),		return the address the instruction might
    220  *				branch to
    221  *	db_getreg_val();	return the value of a user register,
    222  *				as indicated in the hardware instruction
    223  *				encoding, e.g. 8 for r8
    224  *
    225  * next_instr_address(pc,bd)	returns the address of the first
    226  *				instruction following the one at "pc",
    227  *				which is either in the taken path of
    228  *				the branch (bd==1) or not.  This is
    229  *				for machines (mips) with branch delays.
    230  *
    231  *	A single-step may involve at most 2 breakpoints -
    232  *	one for branch-not-taken and one for branch taken.
    233  *	If one of these addresses does not already have a breakpoint,
    234  *	we allocate a breakpoint and save it here.
    235  *	These breakpoints are deleted on return.
    236  */
    237 db_breakpoint_t	db_not_taken_bkpt = 0;
    238 db_breakpoint_t	db_taken_bkpt = 0;
    239 
    240 void
    241 db_set_single_step(regs)
    242 	register db_regs_t *regs;
    243 {
    244 	db_addr_t pc = PC_REGS(regs);
    245 	register unsigned	 inst, brpc;
    246 
    247 	/*
    248 	 *	User was stopped at pc, e.g. the instruction
    249 	 *	at pc was not executed.
    250 	 */
    251 	inst = db_get_value(pc, sizeof(int), FALSE);
    252 	if (inst_branch(inst) || inst_call(inst)) {
    253 	    extern unsigned getreg_val();
    254 
    255 	    brpc = branch_taken(inst, pc, getreg_val, regs);
    256 	    if (brpc != pc) {	/* self-branches are hopeless */
    257 		db_taken_bkpt = db_set_temp_breakpoint(brpc);
    258 	    }
    259 	    pc = next_instr_address(pc,1);
    260 	}
    261 	pc = next_instr_address(pc,0);
    262 	db_not_taken_bkpt = db_set_temp_breakpoint(pc);
    263 }
    264 
    265 void
    266 db_clear_single_step(regs)
    267 	db_regs_t *regs;
    268 {
    269 	register db_breakpoint_t	bkpt;
    270 
    271 	if (db_taken_bkpt != 0) {
    272 	    db_delete_temp_breakpoint(db_taken_bkpt);
    273 	    db_taken_bkpt = 0;
    274 	}
    275 	if (db_not_taken_bkpt != 0) {
    276 	    db_delete_temp_breakpoint(db_not_taken_bkpt);
    277 	    db_not_taken_bkpt = 0;
    278 	}
    279 }
    280 
    281 #endif	SOFTWARE_SSTEP
    282 
    283 extern int	db_cmd_loop_done;
    284 
    285 /* single-step */
    286 /*ARGSUSED*/
    287 void
    288 db_single_step_cmd(addr, have_addr, count, modif)
    289 	db_expr_t	addr;
    290 	int		have_addr;
    291 	db_expr_t	count;
    292 	char *		modif;
    293 {
    294 	boolean_t	print = FALSE;
    295 
    296 	if (count == -1)
    297 	    count = 1;
    298 
    299 	if (modif[0] == 'p')
    300 	    print = TRUE;
    301 
    302 	db_run_mode = STEP_ONCE;
    303 	db_loop_count = count;
    304 	db_sstep_print = print;
    305 	db_inst_count = 0;
    306 	db_load_count = 0;
    307 	db_store_count = 0;
    308 
    309 	db_cmd_loop_done = 1;
    310 }
    311 
    312 /* trace and print until call/return */
    313 /*ARGSUSED*/
    314 void
    315 db_trace_until_call_cmd(addr, have_addr, count, modif)
    316 	db_expr_t	addr;
    317 	int		have_addr;
    318 	db_expr_t	count;
    319 	char *		modif;
    320 {
    321 	boolean_t	print = FALSE;
    322 
    323 	if (modif[0] == 'p')
    324 	    print = TRUE;
    325 
    326 	db_run_mode = STEP_CALLT;
    327 	db_sstep_print = print;
    328 	db_inst_count = 0;
    329 	db_load_count = 0;
    330 	db_store_count = 0;
    331 
    332 	db_cmd_loop_done = 1;
    333 }
    334 
    335 /*ARGSUSED*/
    336 void
    337 db_trace_until_matching_cmd(addr, have_addr, count, modif)
    338 	db_expr_t	addr;
    339 	int		have_addr;
    340 	db_expr_t	count;
    341 	char *		modif;
    342 {
    343 	boolean_t	print = FALSE;
    344 
    345 	if (modif[0] == 'p')
    346 	    print = TRUE;
    347 
    348 	db_run_mode = STEP_RETURN;
    349 	db_call_depth = 1;
    350 	db_sstep_print = print;
    351 	db_inst_count = 0;
    352 	db_load_count = 0;
    353 	db_store_count = 0;
    354 
    355 	db_cmd_loop_done = 1;
    356 }
    357 
    358 /* continue */
    359 /*ARGSUSED*/
    360 void
    361 db_continue_cmd(addr, have_addr, count, modif)
    362 	db_expr_t	addr;
    363 	int		have_addr;
    364 	db_expr_t	count;
    365 	char *		modif;
    366 {
    367 	if (modif[0] == 'c')
    368 	    db_run_mode = STEP_COUNT;
    369 	else
    370 	    db_run_mode = STEP_CONTINUE;
    371 	db_inst_count = 0;
    372 	db_load_count = 0;
    373 	db_store_count = 0;
    374 
    375 	db_cmd_loop_done = 1;
    376 }
    377