2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
29 * Mach Operating System
30 * Copyright (c) 1991,1990 Carnegie Mellon University
31 * All Rights Reserved.
33 * Permission to use, copy, modify and distribute this software and its
34 * documentation is hereby granted, provided that both the copyright
35 * notice and this permission notice appear in all copies of the
36 * software, derivative works or modified versions, and any portions
37 * thereof, and that both notices appear in supporting documentation.
39 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
40 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
41 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
43 * Carnegie Mellon requests users of this software to return to
45 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
46 * School of Computer Science
47 * Carnegie Mellon University
48 * Pittsburgh PA 15213-3890
50 * any improvements or extensions that they make and grant Carnegie Mellon
51 * the rights to redistribute these changes.
56 * Author: David B. Golub, Carnegie Mellon University
61 * Commands to run process.
63 #include <mach/boolean.h>
64 #include <machine/db_machdep.h>
66 #include <ddb/db_lex.h>
67 #include <ddb/db_break.h>
68 #include <ddb/db_access.h>
69 #include <ddb/db_run.h>
70 #include <ddb/db_cond.h>
71 #include <ddb/db_examine.h>
72 #include <ddb/db_output.h> /* For db_printf() */
73 #include <ddb/db_watch.h>
74 #include <kern/misc_protos.h>
75 #include <kern/debug.h>
77 boolean_t db_sstep_print
;
82 int db_last_inst_count
;
85 int db_max_inst_count
= 1000;
87 #ifndef db_set_single_step
88 void db_set_task_single_step(
89 register db_regs_t
*regs
,
92 #define db_set_task_single_step(regs,task) db_set_single_step(regs)
94 #ifndef db_clear_single_step
95 void db_clear_task_single_step(
99 #define db_clear_task_single_step(regs,task) db_clear_single_step(regs)
102 extern jmp_buf_t
*db_recover
;
103 boolean_t
db_step_again(void);
107 boolean_t
*is_breakpoint
,
111 register db_addr_t pc
;
112 register db_thread_breakpoint_t bkpt
;
114 db_clear_task_single_step(DDB_REGS
, space
);
115 db_clear_breakpoints();
116 db_clear_watchpoints();
117 pc
= PC_REGS(DDB_REGS
);
119 #ifdef FIXUP_PC_AFTER_BREAK
120 if (*is_breakpoint
) {
122 * Breakpoint trap. Fix up the PC if the
123 * machine requires it.
126 pc
= PC_REGS(DDB_REGS
);
131 * Now check for a breakpoint at this address.
133 bkpt
= db_find_thread_breakpoint_here(space
, pc
);
135 if (db_cond_check(bkpt
)) {
136 *is_breakpoint
= TRUE
;
137 return (TRUE
); /* stop here */
140 *is_breakpoint
= FALSE
;
142 if (db_run_mode
== STEP_INVISIBLE
) {
143 db_run_mode
= STEP_CONTINUE
;
144 return (FALSE
); /* continue */
146 if (db_run_mode
== STEP_COUNT
) {
147 return (FALSE
); /* continue */
149 if (db_run_mode
== STEP_ONCE
) {
150 if (--db_loop_count
> 0) {
151 if (db_sstep_print
) {
152 db_print_loc_and_inst(pc
, task
);
154 return (FALSE
); /* continue */
157 if (db_run_mode
== STEP_RETURN
) {
160 /* WARNING: the following assumes an instruction fits an int */
161 db_expr_t ins
= db_get_task_value(pc
, sizeof(int), FALSE
, space
);
163 /* continue until matching return */
166 if (_setjmp(db_recover
= &db_jmpbuf
) == 0) {
167 if (!inst_trap_return(ins
) &&
168 (!inst_return(ins
) || --db_call_depth
!= 0)) {
169 if (db_sstep_print
) {
170 if (inst_call(ins
) || inst_return(ins
)) {
173 db_printf("[after %6d /%4d] ",
175 db_inst_count
- db_last_inst_count
);
176 db_last_inst_count
= db_inst_count
;
177 for (i
= db_call_depth
; --i
> 0; )
179 db_print_loc_and_inst(pc
, task
);
187 return (FALSE
); /* continue */
192 if (db_run_mode
== STEP_CALLT
) {
193 /* WARNING: the following assumes an instruction fits an int */
194 db_expr_t ins
= db_get_task_value(pc
, sizeof(int), FALSE
, space
);
196 /* continue until call or return */
198 if (!inst_call(ins
) &&
200 !inst_trap_return(ins
)) {
202 return (FALSE
); /* continue */
205 if (db_find_breakpoint_here(space
, pc
))
207 db_run_mode
= STEP_NONE
;
216 register db_addr_t pc
= PC_REGS(DDB_REGS
), brpc
;
218 if ((db_run_mode
== STEP_COUNT
) ||
219 (db_run_mode
== STEP_RETURN
) ||
220 (db_run_mode
== STEP_CALLT
)) {
224 * We are about to execute this instruction,
228 ins
= db_get_task_value(pc
, sizeof(int), FALSE
, task
);
230 db_load_count
+= db_inst_load(ins
);
231 db_store_count
+= db_inst_store(ins
);
232 #ifdef SOFTWARE_SSTEP
233 /* Account for instructions in delay slots */
234 brpc
= next_instr_address(pc
,1,task
);
235 if ((brpc
!= pc
) && (inst_branch(ins
) || inst_call(ins
))) {
236 /* Note: this ~assumes an instruction <= sizeof(int) */
237 ins
= db_get_task_value(brpc
, sizeof(int), FALSE
, task
);
239 db_load_count
+= db_inst_load(ins
);
240 db_store_count
+= db_inst_store(ins
);
242 #endif /* SOFTWARE_SSTEP */
245 if (db_run_mode
== STEP_CONTINUE
) {
246 if (watchpt
|| db_find_breakpoint_here(task
, pc
)) {
248 * Step over breakpoint/watchpoint.
250 db_run_mode
= STEP_INVISIBLE
;
251 db_set_task_single_step(DDB_REGS
, task
);
253 db_set_breakpoints();
254 db_set_watchpoints();
257 db_set_task_single_step(DDB_REGS
, task
);
262 * 'n' and 'u' commands might never return.
263 * Limit the maximum number of steps.
269 if (db_inst_count
&& !(db_inst_count%db_max_inst_count
)) {
271 db_printf("%d instructions, continue ? (y/n) ",
286 if (db_run_mode
== STEP_CONTINUE
) {
287 db_run_mode
= STEP_INVISIBLE
;
288 db_set_task_single_step(regs
, task
);
292 #ifdef SOFTWARE_SSTEP
294 * Software implementation of single-stepping.
295 * If your machine does not have a trace mode
296 * similar to the vax or sun ones you can use
297 * this implementation, done for the mips.
298 * Just define the above conditional and provide
299 * the functions/macros defined below.
302 * inst_branch(), returns true if the instruction might branch
304 * branch_taken(), return the address the instruction might
306 * db_getreg_val(); return the value of a user register,
307 * as indicated in the hardware instruction
308 * encoding, e.g. 8 for r8
310 * next_instr_address(pc,bd,task) returns the address of the first
311 * instruction following the one at "pc",
312 * which is either in the taken path of
313 * the branch (bd==1) or not. This is
314 * for machines (mips) with branch delays.
316 * A single-step may involve at most 2 breakpoints -
317 * one for branch-not-taken and one for branch taken.
318 * If one of these addresses does not already have a breakpoint,
319 * we allocate a breakpoint and save it here.
320 * These breakpoints are deleted on return.
322 db_breakpoint_t db_not_taken_bkpt
= 0;
323 db_breakpoint_t db_taken_bkpt
= 0;
326 db_find_temp_breakpoint(
330 if (db_taken_bkpt
&& (db_taken_bkpt
->address
== addr
) &&
331 db_taken_bkpt
->task
== task
)
332 return db_taken_bkpt
;
333 if (db_not_taken_bkpt
&& (db_not_taken_bkpt
->address
== addr
) &&
334 db_not_taken_bkpt
->task
== task
)
335 return db_not_taken_bkpt
;
340 db_set_task_single_step(
341 register db_regs_t
*regs
,
344 db_addr_t pc
= PC_REGS(regs
), brpc
;
345 register unsigned int inst
;
346 register boolean_t unconditional
;
349 * User was stopped at pc, e.g. the instruction
350 * at pc was not executed.
352 inst
= db_get_task_value(pc
, sizeof(int), FALSE
, task
);
353 if (inst_branch(inst
) || inst_call(inst
)) {
354 extern db_expr_t
getreg_val(); /* XXX -- need prototype! */
356 brpc
= branch_taken(inst
, pc
, getreg_val
, (unsigned char*)regs
);
357 if (brpc
!= pc
) { /* self-branches are hopeless */
358 db_taken_bkpt
= db_set_temp_breakpoint(task
, brpc
);
361 pc
= next_instr_address(pc
,1,task
);
363 pc
= next_instr_address(pc
,0,task
);
366 * check if this control flow instruction is an
367 * unconditional transfer
370 unconditional
= inst_unconditional_flow_transfer(inst
);
373 We only set the sequential breakpoint if previous instruction was not
374 an unconditional change of flow of control. If the previous instruction
375 is an unconditional change of flow of control, setting a breakpoint in the
376 next sequential location may set a breakpoint in data or in another routine,
377 which could screw up either the program or the debugger.
378 (Consider, for instance, that the next sequential instruction is the
379 start of a routine needed by the debugger.)
381 if (!unconditional
&& db_find_breakpoint_here(task
, pc
) == 0 &&
382 (db_taken_bkpt
== 0 || db_taken_bkpt
->address
!= pc
)) {
383 db_not_taken_bkpt
= db_set_temp_breakpoint(task
, pc
);
385 db_not_taken_bkpt
= 0;
389 db_clear_task_single_step(
393 if (db_taken_bkpt
!= 0) {
394 db_delete_temp_breakpoint(task
, db_taken_bkpt
);
397 if (db_not_taken_bkpt
!= 0) {
398 db_delete_temp_breakpoint(task
, db_not_taken_bkpt
);
399 db_not_taken_bkpt
= 0;
403 #endif /* SOFTWARE_SSTEP */
405 extern int db_cmd_loop_done
;
415 boolean_t print
= FALSE
;
423 db_run_mode
= STEP_ONCE
;
424 db_loop_count
= count
;
425 db_sstep_print
= print
;
427 db_last_inst_count
= 0;
431 db_cmd_loop_done
= 1;
434 /* trace and print until call/return */
436 db_trace_until_call_cmd(
442 boolean_t print
= FALSE
;
447 db_run_mode
= STEP_CALLT
;
448 db_sstep_print
= print
;
450 db_last_inst_count
= 0;
454 db_cmd_loop_done
= 1;
458 db_trace_until_matching_cmd(
464 boolean_t print
= FALSE
;
469 db_run_mode
= STEP_RETURN
;
471 db_sstep_print
= print
;
473 db_last_inst_count
= 0;
477 db_cmd_loop_done
= 1;
489 * Though "cont/c" works fairly well, it's not really robust
490 * enough to use in arbitrary situations, so disable it.
491 * (Doesn't seem cost-effective to debug and fix what ails
496 db_run_mode
= STEP_COUNT
;
498 db_run_mode
= STEP_CONTINUE
;
500 db_run_mode
= STEP_CONTINUE
;
503 db_last_inst_count
= 0;
507 db_cmd_loop_done
= 1;
521 db_run_mode
= STEP_CONTINUE
;
523 db_last_inst_count
= 0;
527 db_cmd_loop_done
= 1;
533 db_in_single_step(void)
535 return(db_run_mode
!= STEP_NONE
&& db_run_mode
!= STEP_CONTINUE
);