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