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