xref: /netbsd-src/sys/ddb/db_run.c (revision bada23909e740596d0a3785a73bd3583a9807fb8)
1 /*	$NetBSD: db_run.c,v 1.16 1998/11/25 06:38:03 mycroft 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@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