* Copyright (c) 1991,1990 Carnegie Mellon University
* Permission to use, copy, modify and distribute this software and its
* documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
* ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
* Carnegie Mellon requests users of this software to return to
* Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
* any improvements or extensions that they make and grant Carnegie the
* rights to redistribute these changes.
* $Id: db_run.c,v 1.2 1993/10/16 16:47:24 rgrimes Exp $
* Author: David B. Golub, Carnegie Mellon University
* Commands to run process.
#include <ddb/db_break.h>
#include <ddb/db_access.h>
boolean_t db_sstep_print
;
#ifndef db_set_single_step
void db_set_single_step(/* db_regs_t *regs */); /* forward */
#ifndef db_clear_single_step
void db_clear_single_step(/* db_regs_t *regs */);
db_stop_at_pc(is_breakpoint
)
boolean_t
*is_breakpoint
;
register db_breakpoint_t bkpt
;
db_clear_single_step(DDB_REGS
);
#ifdef FIXUP_PC_AFTER_BREAK
* Breakpoint trap. Fix up the PC if the
* Now check for a breakpoint at this address.
bkpt
= db_find_breakpoint_here(pc
);
if (--bkpt
->count
== 0) {
bkpt
->count
= bkpt
->init_count
;
return (TRUE
); /* stop here */
} else if (*is_breakpoint
) {
if (db_run_mode
== STEP_INVISIBLE
) {
db_run_mode
= STEP_CONTINUE
;
return (FALSE
); /* continue */
if (db_run_mode
== STEP_COUNT
) {
return (FALSE
); /* continue */
if (db_run_mode
== STEP_ONCE
) {
if (--db_loop_count
> 0) {
db_print_loc_and_inst(pc
);
return (FALSE
); /* continue */
if (db_run_mode
== STEP_RETURN
) {
db_expr_t ins
= db_get_value(pc
, sizeof(int), FALSE
);
/* continue until matching return */
if (!inst_trap_return(ins
) &&
(!inst_return(ins
) || --db_call_depth
!= 0)) {
if (inst_call(ins
) || inst_return(ins
)) {
db_printf("[after %6d] ", db_inst_count
);
for (i
= db_call_depth
; --i
> 0; )
db_print_loc_and_inst(pc
);
return (FALSE
); /* continue */
if (db_run_mode
== STEP_CALLT
) {
db_expr_t ins
= db_get_value(pc
, sizeof(int), FALSE
);
/* continue until call or return */
!inst_trap_return(ins
)) {
return (FALSE
); /* continue */
db_restart_at_pc(watchpt
)
register db_addr_t pc
= PC_REGS(DDB_REGS
);
if ((db_run_mode
== STEP_COUNT
) ||
(db_run_mode
== STEP_RETURN
) ||
(db_run_mode
== STEP_CALLT
)) {
* We are about to execute this instruction,
ins
= db_get_value(pc
, sizeof(int), FALSE
);
db_load_count
+= inst_load(ins
);
db_store_count
+= inst_store(ins
);
/* XXX works on mips, but... */
if (inst_branch(ins
) || inst_call(ins
)) {
ins
= db_get_value(next_instr_address(pc
,1),
db_load_count
+= inst_load(ins
);
db_store_count
+= inst_store(ins
);
if (db_run_mode
== STEP_CONTINUE
) {
if (watchpt
|| db_find_breakpoint_here(pc
)) {
* Step over breakpoint/watchpoint.
db_run_mode
= STEP_INVISIBLE
;
db_set_single_step(DDB_REGS
);
db_set_single_step(DDB_REGS
);
if (db_run_mode
== STEP_CONTINUE
) {
db_run_mode
= STEP_INVISIBLE
;
db_set_single_step(regs
);
* Software implementation of single-stepping.
* If your machine does not have a trace mode
* similar to the vax or sun ones you can use
* this implementation, done for the mips.
* Just define the above conditional and provide
* the functions/macros defined below.
* inst_branch(), returns true if the instruction might branch
* branch_taken(), return the address the instruction might
* db_getreg_val(); return the value of a user register,
* as indicated in the hardware instruction
* encoding, e.g. 8 for r8
* next_instr_address(pc,bd) returns the address of the first
* instruction following the one at "pc",
* which is either in the taken path of
* the branch (bd==1) or not. This is
* for machines (mips) with branch delays.
* A single-step may involve at most 2 breakpoints -
* one for branch-not-taken and one for branch taken.
* If one of these addresses does not already have a breakpoint,
* we allocate a breakpoint and save it here.
* These breakpoints are deleted on return.
db_breakpoint_t db_not_taken_bkpt
= 0;
db_breakpoint_t db_taken_bkpt
= 0;
register db_regs_t
*regs
;
db_addr_t pc
= PC_REGS(regs
);
register unsigned inst
, brpc
;
* User was stopped at pc, e.g. the instruction
* at pc was not executed.
inst
= db_get_value(pc
, sizeof(int), FALSE
);
if (inst_branch(inst
) || inst_call(inst
)) {
extern unsigned getreg_val();
brpc
= branch_taken(inst
, pc
, getreg_val
, regs
);
if (brpc
!= pc
) { /* self-branches are hopeless */
db_taken_bkpt
= db_set_temp_breakpoint(brpc
);
pc
= next_instr_address(pc
,1);
pc
= next_instr_address(pc
,0);
db_not_taken_bkpt
= db_set_temp_breakpoint(pc
);
db_clear_single_step(regs
)
register db_breakpoint_t bkpt
;
if (db_taken_bkpt
!= 0) {
db_delete_temp_breakpoint(db_taken_bkpt
);
if (db_not_taken_bkpt
!= 0) {
db_delete_temp_breakpoint(db_not_taken_bkpt
);
extern int db_cmd_loop_done
;
db_single_step_cmd(addr
, have_addr
, count
, modif
)
/* trace and print until call/return */
db_trace_until_call_cmd(addr
, have_addr
, count
, modif
)
db_run_mode
= STEP_CALLT
;
db_trace_until_matching_cmd(addr
, have_addr
, count
, modif
)
db_run_mode
= STEP_RETURN
;
db_continue_cmd(addr
, have_addr
, count
, modif
)
db_run_mode
= STEP_COUNT
;
db_run_mode
= STEP_CONTINUE
;