db_run.c revision 139747
1132718Skan/*-
2132718Skan * Mach Operating System
3169689Skan * Copyright (c) 1991,1990 Carnegie Mellon University
4132718Skan * All Rights Reserved.
5132718Skan *
6132718Skan * Permission to use, copy, modify and distribute this software and its
7132718Skan * documentation is hereby granted, provided that both the copyright
8132718Skan * notice and this permission notice appear in all copies of the
9132718Skan * software, derivative works or modified versions, and any portions
10132718Skan * thereof, and that both notices appear in supporting documentation.
11132718Skan *
12132718Skan * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
13132718Skan * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14132718Skan * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
15132718Skan *
16132718Skan * Carnegie Mellon requests users of this software to return to
17132718Skan *
18132718Skan *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
19169689Skan *  School of Computer Science
20169689Skan *  Carnegie Mellon University
21132718Skan *  Pittsburgh PA 15213-3890
22132718Skan *
23132718Skan * any improvements or extensions that they make and grant Carnegie the
24132718Skan * rights to redistribute these changes.
25132718Skan */
26132718Skan/*
27132718Skan * 	Author: David B. Golub, Carnegie Mellon University
28132718Skan *	Date:	7/90
29132718Skan */
30132718Skan
31132718Skan/*
32132718Skan * Commands to run process.
33132718Skan */
34132718Skan
35132718Skan#include <sys/cdefs.h>
36146895Skan__FBSDID("$FreeBSD: head/sys/ddb/db_run.c 139747 2005-01-06 01:34:41Z imp $");
37132718Skan
38146895Skan#include <sys/param.h>
39132718Skan#include <sys/kdb.h>
40132718Skan
41132718Skan#include <machine/kdb.h>
42132718Skan#include <machine/pcb.h>
43132718Skan
44132718Skan#include <vm/vm.h>
45132718Skan
46132718Skan#include <ddb/ddb.h>
47132718Skan#include <ddb/db_break.h>
48132718Skan#include <ddb/db_access.h>
49132718Skan
50132718Skanstatic int	db_run_mode;
51132718Skan#define	STEP_NONE	0
52132718Skan#define	STEP_ONCE	1
53146895Skan#define	STEP_RETURN	2
54146895Skan#define	STEP_CALLT	3
55146895Skan#define	STEP_CONTINUE	4
56169689Skan#define STEP_INVISIBLE	5
57169689Skan#define	STEP_COUNT	6
58146895Skan
59146895Skanstatic boolean_t	db_sstep_print;
60146895Skanstatic int		db_loop_count;
61146895Skanstatic int		db_call_depth;
62146895Skan
63132718Skanint		db_inst_count;
64132718Skanint		db_load_count;
65132718Skanint		db_store_count;
66132718Skan
67132718Skan#ifndef db_set_single_step
68132718Skanvoid db_set_single_step(void);
69132718Skan#endif
70132718Skan#ifndef db_clear_single_step
71132718Skanvoid db_clear_single_step(void);
72132718Skan#endif
73132718Skan
74132718Skan#ifdef SOFTWARE_SSTEP
75169689Skandb_breakpoint_t	db_not_taken_bkpt = 0;
76146895Skandb_breakpoint_t	db_taken_bkpt = 0;
77132718Skan#endif
78132718Skan
79132718Skanboolean_t
80132718Skandb_stop_at_pc(is_breakpoint)
81132718Skan	boolean_t	*is_breakpoint;
82132718Skan{
83132718Skan	register db_addr_t	pc;
84132718Skan	register db_breakpoint_t bkpt;
85132718Skan
86132718Skan	pc = PC_REGS();
87132718Skan#ifdef SOFTWARE_SSTEP
88132718Skan	if ((db_not_taken_bkpt != 0 && pc == db_not_taken_bkpt->address)
89132718Skan	    || (db_taken_bkpt != 0 && pc == db_taken_bkpt->address))
90132718Skan		*is_breakpoint = FALSE;
91132718Skan#endif
92132718Skan
93132718Skan	db_clear_single_step();
94132718Skan	db_clear_breakpoints();
95132718Skan	db_clear_watchpoints();
96132718Skan
97132718Skan#ifdef	FIXUP_PC_AFTER_BREAK
98132718Skan	if (*is_breakpoint) {
99132718Skan	    /*
100132718Skan	     * Breakpoint trap.  Fix up the PC if the
101132718Skan	     * machine requires it.
102132718Skan	     */
103132718Skan	    FIXUP_PC_AFTER_BREAK
104132718Skan	    pc = PC_REGS();
105132718Skan	}
106132718Skan#endif
107132718Skan
108132718Skan	/*
109132718Skan	 * Now check for a breakpoint at this address.
110132718Skan	 */
111132718Skan	bkpt = db_find_breakpoint_here(pc);
112146895Skan	if (bkpt) {
113146895Skan	    if (--bkpt->count == 0) {
114146895Skan		bkpt->count = bkpt->init_count;
115146895Skan		*is_breakpoint = TRUE;
116146895Skan		return (TRUE);	/* stop here */
117146895Skan	    }
118169689Skan	} else if (*is_breakpoint) {
119146895Skan#ifdef BKPT_SKIP
120146895Skan		BKPT_SKIP;
121146895Skan#endif
122146895Skan	}
123146895Skan
124146895Skan	*is_breakpoint = FALSE;
125146895Skan
126146895Skan	if (db_run_mode == STEP_INVISIBLE) {
127146895Skan	    db_run_mode = STEP_CONTINUE;
128146895Skan	    return (FALSE);	/* continue */
129146895Skan	}
130146895Skan	if (db_run_mode == STEP_COUNT) {
131146895Skan	    return (FALSE); /* continue */
132146895Skan	}
133146895Skan	if (db_run_mode == STEP_ONCE) {
134146895Skan	    if (--db_loop_count > 0) {
135146895Skan		if (db_sstep_print) {
136146895Skan		    db_printf("\t\t");
137146895Skan		    db_print_loc_and_inst(pc);
138146895Skan		    db_printf("\n");
139146895Skan		}
140146895Skan		return (FALSE);	/* continue */
141146895Skan	    }
142146895Skan	}
143146895Skan	if (db_run_mode == STEP_RETURN) {
144146895Skan	    /* continue until matching return */
145146895Skan	    db_expr_t ins;
146146895Skan
147146895Skan	    ins = db_get_value(pc, sizeof(int), FALSE);
148146895Skan	    if (!inst_trap_return(ins) &&
149146895Skan		(!inst_return(ins) || --db_call_depth != 0)) {
150146895Skan		if (db_sstep_print) {
151132718Skan		    if (inst_call(ins) || inst_return(ins)) {
152132718Skan			register int i;
153132718Skan
154132718Skan			db_printf("[after %6d]     ", db_inst_count);
155132718Skan			for (i = db_call_depth; --i > 0; )
156132718Skan			    db_printf("  ");
157132718Skan			db_print_loc_and_inst(pc);
158169689Skan			db_printf("\n");
159132718Skan		    }
160132718Skan		}
161132718Skan		if (inst_call(ins))
162132718Skan		    db_call_depth++;
163132718Skan		return (FALSE);	/* continue */
164132718Skan	    }
165132718Skan	}
166132718Skan	if (db_run_mode == STEP_CALLT) {
167132718Skan	    /* continue until call or return */
168169689Skan	    db_expr_t ins;
169132718Skan
170132718Skan	    ins = db_get_value(pc, sizeof(int), FALSE);
171132718Skan	    if (!inst_call(ins) &&
172132718Skan		!inst_return(ins) &&
173132718Skan		!inst_trap_return(ins)) {
174132718Skan		return (FALSE);	/* continue */
175132718Skan	    }
176132718Skan	}
177132718Skan	db_run_mode = STEP_NONE;
178132718Skan	return (TRUE);
179132718Skan}
180132718Skan
181132718Skanvoid
182132718Skandb_restart_at_pc(watchpt)
183132718Skan	boolean_t watchpt;
184132718Skan{
185132718Skan	register db_addr_t	pc = PC_REGS();
186132718Skan
187132718Skan	if ((db_run_mode == STEP_COUNT) ||
188132718Skan	    (db_run_mode == STEP_RETURN) ||
189132718Skan	    (db_run_mode == STEP_CALLT)) {
190132718Skan	    db_expr_t		ins;
191132718Skan
192132718Skan	    /*
193132718Skan	     * We are about to execute this instruction,
194132718Skan	     * so count it now.
195132718Skan	     */
196132718Skan
197132718Skan	    ins = db_get_value(pc, sizeof(int), FALSE);
198132718Skan	    db_inst_count++;
199132718Skan	    db_load_count += inst_load(ins);
200132718Skan	    db_store_count += inst_store(ins);
201132718Skan#ifdef	SOFTWARE_SSTEP
202132718Skan	    /* XXX works on mips, but... */
203132718Skan	    if (inst_branch(ins) || inst_call(ins)) {
204132718Skan		ins = db_get_value(next_instr_address(pc,1),
205132718Skan				   sizeof(int), FALSE);
206132718Skan		db_inst_count++;
207132718Skan		db_load_count += inst_load(ins);
208132718Skan		db_store_count += inst_store(ins);
209132718Skan	    }
210132718Skan#endif	/* SOFTWARE_SSTEP */
211132718Skan	}
212146895Skan
213146895Skan	if (db_run_mode == STEP_CONTINUE) {
214146895Skan	    if (watchpt || db_find_breakpoint_here(pc)) {
215146895Skan		/*
216146895Skan		 * Step over breakpoint/watchpoint.
217146895Skan		 */
218146895Skan		db_run_mode = STEP_INVISIBLE;
219146895Skan		db_set_single_step();
220146895Skan	    } else {
221146895Skan		db_set_breakpoints();
222146895Skan		db_set_watchpoints();
223146895Skan	    }
224146895Skan	} else {
225146895Skan	    db_set_single_step();
226146895Skan	}
227146895Skan}
228146895Skan
229146895Skan#ifdef	SOFTWARE_SSTEP
230146895Skan/*
231146895Skan *	Software implementation of single-stepping.
232146895Skan *	If your machine does not have a trace mode
233146895Skan *	similar to the vax or sun ones you can use
234146895Skan *	this implementation, done for the mips.
235146895Skan *	Just define the above conditional and provide
236146895Skan *	the functions/macros defined below.
237146895Skan *
238146895Skan * extern boolean_t
239146895Skan *	inst_branch(),		returns true if the instruction might branch
240146895Skan * extern unsigned
241146895Skan *	branch_taken(),		return the address the instruction might
242146895Skan *				branch to
243146895Skan *	db_getreg_val();	return the value of a user register,
244146895Skan *				as indicated in the hardware instruction
245146895Skan *				encoding, e.g. 8 for r8
246146895Skan *
247146895Skan * next_instr_address(pc,bd)	returns the address of the first
248146895Skan *				instruction following the one at "pc",
249146895Skan *				which is either in the taken path of
250146895Skan *				the branch (bd==1) or not.  This is
251146895Skan *				for machines (mips) with branch delays.
252146895Skan *
253146895Skan *	A single-step may involve at most 2 breakpoints -
254146895Skan *	one for branch-not-taken and one for branch taken.
255146895Skan *	If one of these addresses does not already have a breakpoint,
256169689Skan *	we allocate a breakpoint and save it here.
257169689Skan *	These breakpoints are deleted on return.
258146895Skan */
259146895Skan
260146895Skanvoid
261146895Skandb_set_single_step(void)
262146895Skan{
263146895Skan	db_addr_t pc = PC_REGS(), brpc;
264132718Skan	unsigned inst;
265132718Skan
266132718Skan	/*
267132718Skan	 *	User was stopped at pc, e.g. the instruction
268132718Skan	 *	at pc was not executed.
269132718Skan	 */
270132718Skan	inst = db_get_value(pc, sizeof(int), FALSE);
271132718Skan	if (inst_branch(inst) || inst_call(inst)) {
272132718Skan		brpc = branch_taken(inst, pc);
273132718Skan		if (brpc != pc) {	/* self-branches are hopeless */
274132718Skan			db_taken_bkpt = db_set_temp_breakpoint(brpc);
275132718Skan		}
276169689Skan		pc = next_instr_address(pc, 1);
277132718Skan	}
278132718Skan	pc = next_instr_address(pc, 0);
279132718Skan	db_not_taken_bkpt = db_set_temp_breakpoint(pc);
280132718Skan}
281169689Skan
282132718Skanvoid
283132718Skandb_clear_single_step(void)
284132718Skan{
285132718Skan
286132718Skan	if (db_not_taken_bkpt != 0) {
287132718Skan		db_delete_temp_breakpoint(db_not_taken_bkpt);
288132718Skan		db_not_taken_bkpt = 0;
289132718Skan	}
290169689Skan	if (db_taken_bkpt != 0) {
291169689Skan		db_delete_temp_breakpoint(db_taken_bkpt);
292169689Skan		db_taken_bkpt = 0;
293169689Skan	}
294169689Skan}
295169689Skan
296169689Skan#endif	/* SOFTWARE_SSTEP */
297169689Skan
298169689Skanextern int	db_cmd_loop_done;
299169689Skan
300169689Skan/* single-step */
301169689Skan/*ARGSUSED*/
302169689Skanvoid
303169689Skandb_single_step_cmd(addr, have_addr, count, modif)
304169689Skan	db_expr_t	addr;
305169689Skan	boolean_t	have_addr;
306169689Skan	db_expr_t	count;
307169689Skan	char *		modif;
308169689Skan{
309169689Skan	boolean_t	print = FALSE;
310132718Skan
311132718Skan	if (count == -1)
312132718Skan	    count = 1;
313169689Skan
314169689Skan	if (modif[0] == 'p')
315132718Skan	    print = TRUE;
316132718Skan
317132718Skan	db_run_mode = STEP_ONCE;
318132718Skan	db_loop_count = count;
319132718Skan	db_sstep_print = print;
320132718Skan	db_inst_count = 0;
321132718Skan	db_load_count = 0;
322132718Skan	db_store_count = 0;
323132718Skan
324132718Skan	db_cmd_loop_done = 1;
325132718Skan}
326132718Skan
327132718Skan/* trace and print until call/return */
328132718Skan/*ARGSUSED*/
329132718Skanvoid
330132718Skandb_trace_until_call_cmd(addr, have_addr, count, modif)
331169689Skan	db_expr_t	addr;
332132718Skan	boolean_t	have_addr;
333169689Skan	db_expr_t	count;
334132718Skan	char *		modif;
335132718Skan{
336132718Skan	boolean_t	print = FALSE;
337132718Skan
338169689Skan	if (modif[0] == 'p')
339132718Skan	    print = TRUE;
340169689Skan
341132718Skan	db_run_mode = STEP_CALLT;
342132718Skan	db_sstep_print = print;
343132718Skan	db_inst_count = 0;
344132718Skan	db_load_count = 0;
345132718Skan	db_store_count = 0;
346132718Skan
347132718Skan	db_cmd_loop_done = 1;
348132718Skan}
349132718Skan
350169689Skan/*ARGSUSED*/
351169689Skanvoid
352169689Skandb_trace_until_matching_cmd(addr, have_addr, count, modif)
353169689Skan	db_expr_t	addr;
354169689Skan	boolean_t	have_addr;
355169689Skan	db_expr_t	count;
356132718Skan	char *		modif;
357132718Skan{
358132718Skan	boolean_t	print = FALSE;
359132718Skan
360132718Skan	if (modif[0] == 'p')
361132718Skan	    print = TRUE;
362132718Skan
363132718Skan	db_run_mode = STEP_RETURN;
364132718Skan	db_call_depth = 1;
365169689Skan	db_sstep_print = print;
366169689Skan	db_inst_count = 0;
367169689Skan	db_load_count = 0;
368169689Skan	db_store_count = 0;
369169689Skan
370169689Skan	db_cmd_loop_done = 1;
371132718Skan}
372132718Skan
373132718Skan/* continue */
374132718Skan/*ARGSUSED*/
375169689Skanvoid
376169689Skandb_continue_cmd(addr, have_addr, count, modif)
377169689Skan	db_expr_t	addr;
378169689Skan	boolean_t	have_addr;
379169689Skan	db_expr_t	count;
380169689Skan	char *		modif;
381132718Skan{
382132718Skan	if (modif[0] == 'c')
383132718Skan	    db_run_mode = STEP_COUNT;
384132718Skan	else
385132718Skan	    db_run_mode = STEP_CONTINUE;
386132718Skan	db_inst_count = 0;
387132718Skan	db_load_count = 0;
388132718Skan	db_store_count = 0;
389132718Skan
390132718Skan	db_cmd_loop_done = 1;
391132718Skan}
392132718Skan