xref: /netbsd-src/sys/ddb/db_run.c (revision 3b01aba77a7a698587faaae455bbfe740923c1f5)
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@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