diff options
author | rgrimes <rgrimes@FreeBSD.org> | 1993-06-12 14:58:17 +0000 |
---|---|---|
committer | rgrimes <rgrimes@FreeBSD.org> | 1993-06-12 14:58:17 +0000 |
commit | 25062ba061871945759b3baa833fe64969383e40 (patch) | |
tree | 2d1c31051ed0dbaad984013c9fe695b1a01e1c39 /sys/ddb/db_run.c | |
parent | f078b88a160c467761b3f3641f05dfd0aa3f7753 (diff) | |
download | FreeBSD-src-25062ba061871945759b3baa833fe64969383e40.zip FreeBSD-src-25062ba061871945759b3baa833fe64969383e40.tar.gz |
Initial import, 0.1 + pk 0.2.4-B1
Diffstat (limited to 'sys/ddb/db_run.c')
-rw-r--r-- | sys/ddb/db_run.c | 426 |
1 files changed, 426 insertions, 0 deletions
diff --git a/sys/ddb/db_run.c b/sys/ddb/db_run.c new file mode 100644 index 0000000..b8e33aa --- /dev/null +++ b/sys/ddb/db_run.c @@ -0,0 +1,426 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990 Carnegie Mellon University + * All Rights Reserved. + * + * 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. + */ +/* + * HISTORY + * $Log: db_run.c,v $ + * Revision 1.1 1992/03/25 21:45:24 pace + * Initial revision + * + * Revision 2.5 91/02/05 17:06:58 mrt + * Changed to new Mach copyright + * [91/01/31 16:19:05 mrt] + * + * Revision 2.4 91/01/08 15:09:10 rpd + * Fixed bug in db_restart_at_pc. + * [90/12/07 rpd] + * Added STEP_COUNT and count option to db_continue_cmd. + * Changed db_stop_at_pc to return (modified) is_breakpoint. + * Fixed db_stop_at_pc to print newlines in the right places. + * [90/11/27 rpd] + * + * Revision 2.3 90/10/25 14:43:59 rwd + * Changed db_find_breakpoint to db_find_breakpoint_here. + * [90/10/18 rpd] + * + * Fixed db_set_single_step to pass regs to branch_taken. + * Added watchpoint argument to db_restart_at_pc. + * [90/10/17 rpd] + * Generalized the watchpoint support. + * [90/10/16 rwd] + * Added watchpoint support. + * [90/10/16 rpd] + * + * Revision 2.2 90/08/27 21:51:59 dbg + * Fixed names for single-step functions. + * [90/08/20 af] + * Reduce lint. + * [90/08/07 dbg] + * Created. + * [90/07/25 dbg] + * + */ +/* + * Author: David B. Golub, Carnegie Mellon University + * Date: 7/90 + */ + +/* + * Commands to run process. + */ +#include "param.h" +#include "proc.h" +#include <machine/db_machdep.h> + +#include <ddb/db_lex.h> +#include <ddb/db_break.h> +#include <ddb/db_access.h> + +int db_run_mode; +#define STEP_NONE 0 +#define STEP_ONCE 1 +#define STEP_RETURN 2 +#define STEP_CALLT 3 +#define STEP_CONTINUE 4 +#define STEP_INVISIBLE 5 +#define STEP_COUNT 6 + +boolean_t db_sstep_print; +int db_loop_count; +int db_call_depth; + +int db_inst_count; +int db_load_count; +int db_store_count; + +#ifndef db_set_single_step +void db_set_single_step(/* db_regs_t *regs */); /* forward */ +#endif +#ifndef db_clear_single_step +void db_clear_single_step(/* db_regs_t *regs */); +#endif + +boolean_t +db_stop_at_pc(is_breakpoint) + boolean_t *is_breakpoint; +{ + register db_addr_t pc; + register db_breakpoint_t bkpt; + + db_clear_single_step(DDB_REGS); + db_clear_breakpoints(); + db_clear_watchpoints(); + pc = PC_REGS(DDB_REGS); + +#ifdef FIXUP_PC_AFTER_BREAK + if (*is_breakpoint) { + /* + * Breakpoint trap. Fix up the PC if the + * machine requires it. + */ + FIXUP_PC_AFTER_BREAK + pc = PC_REGS(DDB_REGS); + } +#endif + + /* + * Now check for a breakpoint at this address. + */ + bkpt = db_find_breakpoint_here(pc); + if (bkpt) { + if (--bkpt->count == 0) { + bkpt->count = bkpt->init_count; + *is_breakpoint = TRUE; + return (TRUE); /* stop here */ + } + } else if (*is_breakpoint) { + ddb_regs.tf_eip += 1; + } + + *is_breakpoint = FALSE; + + 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) { + if (db_sstep_print) { + db_printf("\t\t"); + db_print_loc_and_inst(pc); + db_printf("\n"); + } + 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 (db_sstep_print) { + if (inst_call(ins) || inst_return(ins)) { + register int i; + + db_printf("[after %6d] ", db_inst_count); + for (i = db_call_depth; --i > 0; ) + db_printf(" "); + db_print_loc_and_inst(pc); + db_printf("\n"); + } + } + if (inst_call(ins)) + db_call_depth++; + 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 */ + + if (!inst_call(ins) && + !inst_return(ins) && + !inst_trap_return(ins)) { + return (FALSE); /* continue */ + } + } + db_run_mode = STEP_NONE; + return (TRUE); +} + +void +db_restart_at_pc(watchpt) + boolean_t 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)) { + db_expr_t ins; + + /* + * We are about to execute this instruction, + * so count it now. + */ + + ins = db_get_value(pc, sizeof(int), FALSE); + db_inst_count++; + db_load_count += inst_load(ins); + db_store_count += inst_store(ins); +#ifdef SOFTWARE_SSTEP + /* XXX works on mips, but... */ + if (inst_branch(ins) || inst_call(ins)) { + ins = db_get_value(next_instr_address(pc,1), + sizeof(int), FALSE); + db_inst_count++; + db_load_count += inst_load(ins); + db_store_count += inst_store(ins); + } +#endif SOFTWARE_SSTEP + } + + 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); + } else { + db_set_breakpoints(); + db_set_watchpoints(); + } + } else { + db_set_single_step(DDB_REGS); + } +} + +void +db_single_step(regs) + db_regs_t *regs; +{ + if (db_run_mode == STEP_CONTINUE) { + db_run_mode = STEP_INVISIBLE; + db_set_single_step(regs); + } +} + +#ifdef SOFTWARE_SSTEP +/* + * 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. + * + * extern boolean_t + * inst_branch(), returns true if the instruction might branch + * extern unsigned + * branch_taken(), return the address the instruction might + * branch to + * 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; + +void +db_set_single_step(regs) + 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); +} + +void +db_clear_single_step(regs) + db_regs_t *regs; +{ + register db_breakpoint_t bkpt; + + if (db_taken_bkpt != 0) { + db_delete_temp_breakpoint(db_taken_bkpt); + db_taken_bkpt = 0; + } + if (db_not_taken_bkpt != 0) { + db_delete_temp_breakpoint(db_not_taken_bkpt); + db_not_taken_bkpt = 0; + } +} + +#endif SOFTWARE_SSTEP + +extern int db_cmd_loop_done; + +/* single-step */ +/*ARGSUSED*/ +void +db_single_step_cmd(addr, have_addr, count, modif) + db_expr_t addr; + int have_addr; + db_expr_t count; + char * modif; +{ + boolean_t print = FALSE; + + if (count == -1) + count = 1; + + if (modif[0] == 'p') + print = TRUE; + + db_run_mode = STEP_ONCE; + db_loop_count = count; + db_sstep_print = print; + db_inst_count = 0; + db_load_count = 0; + db_store_count = 0; + + db_cmd_loop_done = 1; +} + +/* trace and print until call/return */ +/*ARGSUSED*/ +void +db_trace_until_call_cmd(addr, have_addr, count, modif) + db_expr_t addr; + int have_addr; + db_expr_t count; + char * modif; +{ + boolean_t print = FALSE; + + if (modif[0] == 'p') + print = TRUE; + + db_run_mode = STEP_CALLT; + db_sstep_print = print; + db_inst_count = 0; + db_load_count = 0; + db_store_count = 0; + + db_cmd_loop_done = 1; +} + +/*ARGSUSED*/ +void +db_trace_until_matching_cmd(addr, have_addr, count, modif) + db_expr_t addr; + int have_addr; + db_expr_t count; + char * modif; +{ + boolean_t print = FALSE; + + if (modif[0] == 'p') + print = TRUE; + + db_run_mode = STEP_RETURN; + db_call_depth = 1; + db_sstep_print = print; + db_inst_count = 0; + db_load_count = 0; + db_store_count = 0; + + db_cmd_loop_done = 1; +} + +/* continue */ +/*ARGSUSED*/ +void +db_continue_cmd(addr, have_addr, count, modif) + db_expr_t addr; + int have_addr; + db_expr_t count; + char * modif; +{ + if (modif[0] == 'c') + db_run_mode = STEP_COUNT; + else + db_run_mode = STEP_CONTINUE; + db_inst_count = 0; + db_load_count = 0; + db_store_count = 0; + + db_cmd_loop_done = 1; +} |