aboutsummaryrefslogtreecommitdiff
path: root/sys/ddb/db_run.c
diff options
context:
space:
mode:
authorRodney W. Grimes <rgrimes@FreeBSD.org>1993-06-12 14:58:17 +0000
committerRodney W. Grimes <rgrimes@FreeBSD.org>1993-06-12 14:58:17 +0000
commit5b81b6b301437eb9a6df491c829475bd29ae5d6c (patch)
treede2d7c6726a45428d4a310da2acd8839daf9f85f /sys/ddb/db_run.c
parent9002c02abc587664acb357c6879d8ca08664dd0b (diff)
downloadsrc-5b81b6b301437eb9a6df491c829475bd29ae5d6c.tar.gz
src-5b81b6b301437eb9a6df491c829475bd29ae5d6c.zip
Initial import, 0.1 + pk 0.2.4-B1
Notes
Notes: svn path=/cvs2svn/branches/unlabeled-1.1.1/; revision=4
Diffstat (limited to 'sys/ddb/db_run.c')
-rw-r--r--sys/ddb/db_run.c426
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 000000000000..b8e33aa75ec9
--- /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;
+}