Home | History | Annotate | Line # | Download | only in ddb
db_run.c revision 1.12
      1 /*	$NetBSD: db_run.c,v 1.12 1997/09/10 19:37:31 pk Exp $	*/
      2 
      3 /*
      4  * Mach Operating System
      5  * Copyright (c) 1993-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 <sys/param.h>
     36 #include <sys/proc.h>
     37 
     38 #include <machine/db_machdep.h>
     39 
     40 #include <ddb/db_run.h>
     41 #include <ddb/db_lex.h>
     42 #include <ddb/db_break.h>
     43 #include <ddb/db_access.h>
     44 #include <ddb/db_watch.h>
     45 #include <ddb/db_output.h>
     46 #include <ddb/db_sym.h>
     47 #include <ddb/db_extern.h>
     48 
     49 int	db_run_mode;
     50 #define	STEP_NONE	0
     51 #define	STEP_ONCE	1
     52 #define	STEP_RETURN	2
     53 #define	STEP_CALLT	3
     54 #define	STEP_CONTINUE	4
     55 #define STEP_INVISIBLE	5
     56 #define	STEP_COUNT	6
     57 
     58 boolean_t	db_sstep_print;
     59 int		db_loop_count;
     60 int		db_call_depth;
     61 
     62 boolean_t
     63 db_stop_at_pc(regs, is_breakpoint)
     64 	db_regs_t *regs;
     65 	boolean_t	*is_breakpoint;
     66 {
     67 	register db_addr_t	pc;
     68 	register db_breakpoint_t bkpt;
     69 
     70 	db_clear_single_step(regs);
     71 	db_clear_breakpoints();
     72 	db_clear_watchpoints();
     73 	pc = PC_REGS(regs);
     74 
     75 #ifdef	FIXUP_PC_AFTER_BREAK
     76 	if (*is_breakpoint) {
     77 	    /*
     78 	     * Breakpoint trap.  Fix up the PC if the
     79 	     * machine requires it.
     80 	     */
     81 	    FIXUP_PC_AFTER_BREAK(regs);
     82 	    pc = PC_REGS(regs);
     83 	}
     84 #endif
     85 
     86 	/*
     87 	 * Now check for a breakpoint at this address.
     88 	 */
     89 	bkpt = db_find_breakpoint_here(pc);
     90 	if (bkpt) {
     91 	    if (--bkpt->count == 0) {
     92 		bkpt->count = bkpt->init_count;
     93 		*is_breakpoint = TRUE;
     94 		return (TRUE);	/* stop here */
     95 	    }
     96 	} else if (*is_breakpoint) {
     97 #ifdef PC_ADVANCE
     98 		PC_ADVANCE(regs);
     99 #else
    100 		PC_REGS(regs) += BKPT_SIZE;
    101 #endif
    102 	}
    103 
    104 	*is_breakpoint = FALSE;
    105 
    106 	if (db_run_mode == STEP_INVISIBLE) {
    107 	    db_run_mode = STEP_CONTINUE;
    108 	    return (FALSE);	/* continue */
    109 	}
    110 	if (db_run_mode == STEP_COUNT) {
    111 	    return (FALSE); /* continue */
    112 	}
    113 	if (db_run_mode == STEP_ONCE) {
    114 	    if (--db_loop_count > 0) {
    115 		if (db_sstep_print) {
    116 		    db_printf("\t\t");
    117 		    db_print_loc_and_inst(pc);
    118 		    db_printf("\n");
    119 		}
    120 		return (FALSE);	/* continue */
    121 	    }
    122 	}
    123 	if (db_run_mode == STEP_RETURN) {
    124 	    db_expr_t ins = db_get_value(pc, sizeof(int), FALSE);
    125 
    126 	    /* continue until matching return */
    127 
    128 	    if (!inst_trap_return(ins) &&
    129 		(!inst_return(ins) || --db_call_depth != 0)) {
    130 		if (db_sstep_print) {
    131 		    if (inst_call(ins) || inst_return(ins)) {
    132 			register int i;
    133 
    134 			db_printf("[after %6d]     ", db_inst_count);
    135 			for (i = db_call_depth; --i > 0; )
    136 			    db_printf("  ");
    137 			db_print_loc_and_inst(pc);
    138 			db_printf("\n");
    139 		    }
    140 		}
    141 		if (inst_call(ins))
    142 		    db_call_depth++;
    143 		return (FALSE);	/* continue */
    144 	    }
    145 	}
    146 	if (db_run_mode == STEP_CALLT) {
    147 	    db_expr_t ins = db_get_value(pc, sizeof(int), FALSE);
    148 
    149 	    /* continue until call or return */
    150 
    151 	    if (!inst_call(ins) &&
    152 		!inst_return(ins) &&
    153 		!inst_trap_return(ins)) {
    154 		return (FALSE);	/* continue */
    155 	    }
    156 	}
    157 	db_run_mode = STEP_NONE;
    158 	return (TRUE);
    159 }
    160 
    161 void
    162 db_restart_at_pc(regs, watchpt)
    163 	db_regs_t *regs;
    164 	boolean_t watchpt;
    165 {
    166 	register db_addr_t pc = PC_REGS(regs);
    167 
    168 	if ((db_run_mode == STEP_COUNT) ||
    169 	    (db_run_mode == STEP_RETURN) ||
    170 	    (db_run_mode == STEP_CALLT)) {
    171 	    db_expr_t		ins;
    172 
    173 	    /*
    174 	     * We are about to execute this instruction,
    175 	     * so count it now.
    176 	     */
    177 	    ins = db_get_value(pc, sizeof(int), FALSE);
    178 	    db_inst_count++;
    179 	    db_load_count += inst_load(ins);
    180 	    db_store_count += inst_store(ins);
    181 
    182 #ifdef SOFTWARE_SSTEP
    183 	    /*
    184 	     * Account for instructions in delay slots.
    185 	     */
    186 	    {
    187 		db_addr_t brpc;
    188 
    189 		brpc = next_instr_address(pc, TRUE);
    190 		if ((brpc != pc) && (inst_branch(ins) || inst_call(ins))) {
    191 		    ins = db_get_value(brpc, sizeof(int), FALSE);
    192 		    db_inst_count++;
    193 		    db_load_count += inst_load(ins);
    194 		    db_store_count += inst_store(ins);
    195 		}
    196 	    }
    197 #endif
    198 	}
    199 
    200 	if (db_run_mode == STEP_CONTINUE) {
    201 	    if (watchpt || db_find_breakpoint_here(pc)) {
    202 		/*
    203 		 * Step over breakpoint/watchpoint.
    204 		 */
    205 		db_run_mode = STEP_INVISIBLE;
    206 		db_set_single_step(regs);
    207 	    } else {
    208 		db_set_breakpoints();
    209 		db_set_watchpoints();
    210 	    }
    211 	} else {
    212 	    db_set_single_step(regs);
    213 	}
    214 }
    215 
    216 void
    217 db_single_step(regs)
    218 	db_regs_t *regs;
    219 {
    220 	if (db_run_mode == STEP_CONTINUE) {
    221 	    db_run_mode = STEP_INVISIBLE;
    222 	    db_set_single_step(regs);
    223 	}
    224 }
    225 
    226 #ifdef SOFTWARE_SSTEP
    227 /*
    228  *	Software implementation of single-stepping.
    229  *	If your machine does not have a trace mode
    230  *	similar to the vax or sun ones you can use
    231  *	this implementation, done for the mips.
    232  *	Just define the above conditional and provide
    233  *	the functions/macros defined below.
    234  *
    235  * boolean_t inst_branch(int inst)
    236  * boolean_t inst_call(int inst)
    237  *	returns TRUE if the instruction might branch
    238  *
    239  * boolean_t inst_unconditional_flow_transfer(int inst)
    240  *	returns TRUE if the instruction is an unconditional
    241  *	transter of flow (i.e. unconditional branch)
    242  *
    243  * db_addr_t branch_taken(int inst, db_addr_t pc, db_regs_t *regs)
    244  *	returns the target address of the branch
    245  *
    246  * db_addr_t next_instr_address(db_addr_t pc, boolean_t bd)
    247  *	returns the address of the first instruction following the
    248  *	one at "pc", which is either in the taken path of the branch
    249  *	(bd == TRUE) or not.  This is for machines (e.g. mips) with
    250  *	branch delays.
    251  *
    252  *	A single-step may involve at most 2 breakpoints -
    253  *	one for branch-not-taken and one for branch taken.
    254  *	If one of these addresses does not already have a breakpoint,
    255  *	we allocate a breakpoint and save it here.
    256  *	These breakpoints are deleted on return.
    257  */
    258 db_breakpoint_t	db_not_taken_bkpt = 0;
    259 db_breakpoint_t	db_taken_bkpt = 0;
    260 
    261 void
    262 db_set_single_step(regs)
    263 	register db_regs_t *regs;
    264 {
    265 	db_addr_t pc = PC_REGS(regs), brpc;
    266 	boolean_t unconditional;
    267 	unsigned int inst;
    268 
    269 	/*
    270 	 *	User was stopped at pc, e.g. the instruction
    271 	 *	at pc was not executed.
    272 	 */
    273 	inst = db_get_value(pc, sizeof(int), FALSE);
    274 	if (inst_branch(inst) || inst_call(inst)) {
    275 		brpc = branch_taken(inst, pc, regs);
    276 		if (brpc != pc) {	/* self-branches are hopeless */
    277 			db_taken_bkpt = db_set_temp_breakpoint(brpc);
    278 		} else
    279 			db_taken_bkpt = 0;
    280 		pc = next_instr_address(pc, TRUE);
    281 	}
    282 
    283 	/*
    284 	 *	Check if this control flow instruction is an
    285 	 *	unconditional transfer.
    286 	 */
    287 	unconditional = inst_unconditional_flow_transfer(inst);
    288 
    289 	pc = next_instr_address(pc, FALSE);
    290 
    291 	/*
    292 	 *	We only set the sequential breakpoint if previous
    293 	 *	instruction was not an unconditional change of flow
    294 	 *	control.  If the previous instruction is an
    295 	 *	unconditional change of flow control, setting a
    296 	 *	breakpoint in the next sequential location may set
    297 	 *	a breakpoint in data or in another routine, which
    298 	 *	could screw up in either the program or the debugger.
    299 	 *	(Consider, for instance, that the next sequential
    300 	 *	instruction is the start of a routine needed by the
    301 	 *	debugger.)
    302 	 */
    303 	if (unconditional == FALSE && db_find_breakpoint_here(pc) == 0)
    304 		db_not_taken_bkpt = db_set_temp_breakpoint(pc);
    305 	else
    306 		db_not_taken_bkpt = 0;
    307 }
    308 
    309 void
    310 db_clear_single_step(regs)
    311 	db_regs_t *regs;
    312 {
    313 
    314 	if (db_taken_bkpt != 0) {
    315 	    db_delete_temp_breakpoint(db_taken_bkpt);
    316 	    db_taken_bkpt = 0;
    317 	}
    318 	if (db_not_taken_bkpt != 0) {
    319 	    db_delete_temp_breakpoint(db_not_taken_bkpt);
    320 	    db_not_taken_bkpt = 0;
    321 	}
    322 }
    323 
    324 #endif /* SOFTWARE_SSTEP */
    325 
    326 extern int	db_cmd_loop_done;
    327 
    328 /* single-step */
    329 /*ARGSUSED*/
    330 void
    331 db_single_step_cmd(addr, have_addr, count, modif)
    332 	db_expr_t	addr;
    333 	int		have_addr;
    334 	db_expr_t	count;
    335 	char *		modif;
    336 {
    337 	boolean_t	print = FALSE;
    338 
    339 	if (count == -1)
    340 	    count = 1;
    341 
    342 	if (modif[0] == 'p')
    343 	    print = TRUE;
    344 
    345 	db_run_mode = STEP_ONCE;
    346 	db_loop_count = count;
    347 	db_sstep_print = print;
    348 	db_inst_count = 0;
    349 	db_load_count = 0;
    350 	db_store_count = 0;
    351 
    352 	db_cmd_loop_done = 1;
    353 }
    354 
    355 /* trace and print until call/return */
    356 /*ARGSUSED*/
    357 void
    358 db_trace_until_call_cmd(addr, have_addr, count, modif)
    359 	db_expr_t	addr;
    360 	int		have_addr;
    361 	db_expr_t	count;
    362 	char *		modif;
    363 {
    364 	boolean_t	print = FALSE;
    365 
    366 	if (modif[0] == 'p')
    367 	    print = TRUE;
    368 
    369 	db_run_mode = STEP_CALLT;
    370 	db_sstep_print = print;
    371 	db_inst_count = 0;
    372 	db_load_count = 0;
    373 	db_store_count = 0;
    374 
    375 	db_cmd_loop_done = 1;
    376 }
    377 
    378 /*ARGSUSED*/
    379 void
    380 db_trace_until_matching_cmd(addr, have_addr, count, modif)
    381 	db_expr_t	addr;
    382 	int		have_addr;
    383 	db_expr_t	count;
    384 	char *		modif;
    385 {
    386 	boolean_t	print = FALSE;
    387 
    388 	if (modif[0] == 'p')
    389 	    print = TRUE;
    390 
    391 	db_run_mode = STEP_RETURN;
    392 	db_call_depth = 1;
    393 	db_sstep_print = print;
    394 	db_inst_count = 0;
    395 	db_load_count = 0;
    396 	db_store_count = 0;
    397 
    398 	db_cmd_loop_done = 1;
    399 }
    400 
    401 /* continue */
    402 /*ARGSUSED*/
    403 void
    404 db_continue_cmd(addr, have_addr, count, modif)
    405 	db_expr_t	addr;
    406 	int		have_addr;
    407 	db_expr_t	count;
    408 	char *		modif;
    409 {
    410 	if (modif[0] == 'c')
    411 	    db_run_mode = STEP_COUNT;
    412 	else
    413 	    db_run_mode = STEP_CONTINUE;
    414 	db_inst_count = 0;
    415 	db_load_count = 0;
    416 	db_store_count = 0;
    417 
    418 	db_cmd_loop_done = 1;
    419 }
    420