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