2 * Mach Operating System
3 * Copyright (c) 1991,1990 Carnegie Mellon University
6 * Permission to use, copy, modify and distribute this software and its
7 * documentation is hereby granted, provided that both the copyright
8 * notice and this permission notice appear in all copies of the
9 * software, derivative works or modified versions, and any portions
10 * thereof, and that both notices appear in supporting documentation.
12 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
13 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
16 * Carnegie Mellon requests users of this software to return to
18 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
19 * School of Computer Science
20 * Carnegie Mellon University
21 * Pittsburgh PA 15213-3890
23 * any improvements or extensions that they make and grant Carnegie the
24 * rights to redistribute these changes.
26 * $FreeBSD: src/sys/ddb/db_run.c,v 1.18 1999/08/28 00:41:10 peter Exp $
27 * $DragonFly: src/sys/ddb/db_run.c,v 1.7 2005/12/23 22:35:44 swildner Exp $
31 * Author: David B. Golub, Carnegie Mellon University
36 * Commands to run process.
38 #include <sys/param.h>
43 #include <ddb/db_break.h>
44 #include <ddb/db_access.h>
46 static int db_run_mode
;
51 #define STEP_CONTINUE 4
52 #define STEP_INVISIBLE 5
55 static boolean_t db_sstep_print
;
56 static int db_loop_count
;
57 static int db_call_depth
;
63 #ifndef db_set_single_step
64 extern void db_set_single_step (db_regs_t
*regs
);
66 #ifndef db_clear_single_step
67 extern void db_clear_single_step (db_regs_t
*regs
);
71 static void db_single_step (db_regs_t
*regs
);
75 db_stop_at_pc(boolean_t
*is_breakpoint
)
80 db_clear_single_step(DDB_REGS
);
81 db_clear_breakpoints();
82 db_clear_watchpoints();
83 pc
= PC_REGS(DDB_REGS
);
85 #ifdef FIXUP_PC_AFTER_BREAK
88 * Breakpoint trap. Fix up the PC if the
89 * machine requires it.
92 pc
= PC_REGS(DDB_REGS
);
97 * Now check for a breakpoint at this address.
99 bkpt
= db_find_breakpoint_here(pc
);
101 if (--bkpt
->count
== 0) {
102 bkpt
->count
= bkpt
->init_count
;
103 *is_breakpoint
= TRUE
;
104 return (TRUE
); /* stop here */
106 } else if (*is_breakpoint
) {
107 #ifdef __i386__ /* XXx */
108 ddb_regs
.tf_eip
+= 1;
112 *is_breakpoint
= FALSE
;
114 if (db_run_mode
== STEP_INVISIBLE
) {
115 db_run_mode
= STEP_CONTINUE
;
116 return (FALSE
); /* continue */
118 if (db_run_mode
== STEP_COUNT
) {
119 return (FALSE
); /* continue */
121 if (db_run_mode
== STEP_ONCE
) {
122 if (--db_loop_count
> 0) {
123 if (db_sstep_print
) {
125 db_print_loc_and_inst(pc
, DDB_REGS
);
128 return (FALSE
); /* continue */
131 if (db_run_mode
== STEP_RETURN
) {
132 db_expr_t ins
= db_get_value(pc
, sizeof(int), FALSE
);
134 /* continue until matching return */
136 if (!inst_trap_return(ins
) &&
137 (!inst_return(ins
) || --db_call_depth
!= 0)) {
138 if (db_sstep_print
) {
139 if (inst_call(ins
) || inst_return(ins
)) {
142 db_printf("[after %6d] ", db_inst_count
);
143 for (i
= db_call_depth
; --i
> 0; )
145 db_print_loc_and_inst(pc
, DDB_REGS
);
151 return (FALSE
); /* continue */
154 if (db_run_mode
== STEP_CALLT
) {
155 db_expr_t ins
= db_get_value(pc
, sizeof(int), FALSE
);
157 /* continue until call or return */
159 if (!inst_call(ins
) &&
161 !inst_trap_return(ins
)) {
162 return (FALSE
); /* continue */
165 db_run_mode
= STEP_NONE
;
170 db_restart_at_pc(boolean_t watchpt
)
172 db_addr_t pc
= PC_REGS(DDB_REGS
);
174 if ((db_run_mode
== STEP_COUNT
) ||
175 (db_run_mode
== STEP_RETURN
) ||
176 (db_run_mode
== STEP_CALLT
)) {
180 * We are about to execute this instruction,
184 ins
= db_get_value(pc
, sizeof(int), FALSE
);
186 db_load_count
+= inst_load(ins
);
187 db_store_count
+= inst_store(ins
);
188 #ifdef SOFTWARE_SSTEP
189 /* XXX works on mips, but... */
190 if (inst_branch(ins
) || inst_call(ins
)) {
191 ins
= db_get_value(next_instr_address(pc
,1),
194 db_load_count
+= inst_load(ins
);
195 db_store_count
+= inst_store(ins
);
197 #endif /* SOFTWARE_SSTEP */
200 if (db_run_mode
== STEP_CONTINUE
) {
201 if (watchpt
|| db_find_breakpoint_here(pc
)) {
203 * Step over breakpoint/watchpoint.
205 db_run_mode
= STEP_INVISIBLE
;
206 db_set_single_step(DDB_REGS
);
208 db_set_breakpoints();
209 db_set_watchpoints();
212 db_set_single_step(DDB_REGS
);
218 db_single_step(db_regs_t
*regs
)
220 if (db_run_mode
== STEP_CONTINUE
) {
221 db_run_mode
= STEP_INVISIBLE
;
222 db_set_single_step(regs
);
227 #ifdef SOFTWARE_SSTEP
229 * Software implementation of single-stepping.
230 * If your machine does not have a trace mode
231 * similar to the vax or sun ones you can use
232 * this implementation, done for the mips.
233 * Just define the above conditional and provide
234 * the functions/macros defined below.
237 * inst_branch(), returns true if the instruction might branch
239 * branch_taken(), return the address the instruction might
241 * db_getreg_val(); return the value of a user register,
242 * as indicated in the hardware instruction
243 * encoding, e.g. 8 for r8
245 * next_instr_address(pc,bd) returns the address of the first
246 * instruction following the one at "pc",
247 * which is either in the taken path of
248 * the branch (bd==1) or not. This is
249 * for machines (mips) with branch delays.
251 * A single-step may involve at most 2 breakpoints -
252 * one for branch-not-taken and one for branch taken.
253 * If one of these addresses does not already have a breakpoint,
254 * we allocate a breakpoint and save it here.
255 * These breakpoints are deleted on return.
257 db_breakpoint_t db_not_taken_bkpt
= 0;
258 db_breakpoint_t db_taken_bkpt
= 0;
261 db_set_single_step(db_regs_t
*regs
)
263 db_addr_t pc
= PC_REGS(regs
), brpc
;
267 * User was stopped at pc, e.g. the instruction
268 * at pc was not executed.
270 inst
= db_get_value(pc
, sizeof(int), FALSE
);
271 if (inst_branch(inst
) || inst_call(inst
)) {
272 brpc
= branch_taken(inst
, pc
, regs
);
273 if (brpc
!= pc
) { /* self-branches are hopeless */
274 db_taken_bkpt
= db_set_temp_breakpoint(brpc
);
276 pc
= next_instr_address(pc
,1);
278 pc
= next_instr_address(pc
,0);
279 db_not_taken_bkpt
= db_set_temp_breakpoint(pc
);
283 db_clear_single_step(db_regs_t
*regs
)
286 if (db_not_taken_bkpt
!= 0) {
287 db_delete_temp_breakpoint(db_not_taken_bkpt
);
288 db_not_taken_bkpt
= 0;
290 if (db_taken_bkpt
!= 0) {
291 db_delete_temp_breakpoint(db_taken_bkpt
);
296 #endif /* SOFTWARE_SSTEP */
298 extern int db_cmd_loop_done
;
303 db_single_step_cmd(db_expr_t addr
, boolean_t have_addr
, db_expr_t count
,
306 boolean_t print
= FALSE
;
314 db_run_mode
= STEP_ONCE
;
315 db_loop_count
= count
;
316 db_sstep_print
= print
;
321 db_cmd_loop_done
= 1;
324 /* trace and print until call/return */
327 db_trace_until_call_cmd(db_expr_t addr
, boolean_t have_addr
, db_expr_t count
,
330 boolean_t print
= FALSE
;
335 db_run_mode
= STEP_CALLT
;
336 db_sstep_print
= print
;
341 db_cmd_loop_done
= 1;
346 db_trace_until_matching_cmd(db_expr_t addr
, boolean_t have_addr
,
347 db_expr_t count
, char *modif
)
349 boolean_t print
= FALSE
;
354 db_run_mode
= STEP_RETURN
;
356 db_sstep_print
= print
;
361 db_cmd_loop_done
= 1;
367 db_continue_cmd(db_expr_t addr
, boolean_t have_addr
, db_expr_t count
,
371 db_run_mode
= STEP_COUNT
;
373 db_run_mode
= STEP_CONTINUE
;
378 db_cmd_loop_done
= 1;