db_run.c revision 36735
132785Speter/* 232785Speter * Mach Operating System 332785Speter * Copyright (c) 1991,1990 Carnegie Mellon University 432785Speter * All Rights Reserved. 532785Speter * 632785Speter * Permission to use, copy, modify and distribute this software and its 732785Speter * documentation is hereby granted, provided that both the copyright 832785Speter * notice and this permission notice appear in all copies of the 932785Speter * software, derivative works or modified versions, and any portions 1032785Speter * thereof, and that both notices appear in supporting documentation. 1132785Speter * 1232785Speter * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS 1332785Speter * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 1432785Speter * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 1532785Speter * 1654427Speter * Carnegie Mellon requests users of this software to return to 1732785Speter * 1832785Speter * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 1932785Speter * School of Computer Science 2032785Speter * Carnegie Mellon University 2132785Speter * Pittsburgh PA 15213-3890 2232785Speter * 2332785Speter * any improvements or extensions that they make and grant Carnegie the 2432785Speter * rights to redistribute these changes. 2532785Speter * 2632785Speter * $Id: db_run.c,v 1.13 1997/06/14 11:52:37 bde Exp $ 2732785Speter */ 2832785Speter 2932785Speter/* 3032785Speter * Author: David B. Golub, Carnegie Mellon University 3132785Speter * Date: 7/90 3232785Speter */ 3332785Speter 3432785Speter/* 3532785Speter * Commands to run process. 3632785Speter */ 3732785Speter#include <sys/param.h> 3832785Speter 3932785Speter#include <vm/vm.h> 4032785Speter 4132785Speter#include <ddb/ddb.h> 4232785Speter#include <ddb/db_break.h> 4332785Speter#include <ddb/db_access.h> 4432785Speter 4532785Speterstatic int db_run_mode; 4632785Speter#define STEP_NONE 0 4732785Speter#define STEP_ONCE 1 4832785Speter#define STEP_RETURN 2 4932785Speter#define STEP_CALLT 3 5032785Speter#define STEP_CONTINUE 4 5132785Speter#define STEP_INVISIBLE 5 5232785Speter#define STEP_COUNT 6 5332785Speter 5432785Speterstatic boolean_t db_sstep_print; 5532785Speterstatic int db_loop_count; 5632785Speterstatic int db_call_depth; 5732785Speter 5832785Speterint db_inst_count; 5932785Speterint db_load_count; 6032785Speterint db_store_count; 6132785Speter 6232785Speter#ifndef db_set_single_step 6332785Speterextern void db_set_single_step __P((db_regs_t *regs)); 6432785Speter#endif 6532785Speter#ifndef db_clear_single_step 6632785Speterextern void db_clear_single_step __P((db_regs_t *regs)); 6732785Speter#endif 6832785Speter 6932785Speter#ifdef notused 7032785Speterstatic void db_single_step __P((db_regs_t *regs)); 7132785Speter#endif 7232785Speter 7332785Speterboolean_t 7432785Speterdb_stop_at_pc(is_breakpoint) 7532785Speter boolean_t *is_breakpoint; 7632785Speter{ 7732785Speter register db_addr_t pc; 7832785Speter register db_breakpoint_t bkpt; 7932785Speter 8032785Speter db_clear_single_step(DDB_REGS); 8132785Speter db_clear_breakpoints(); 8232785Speter db_clear_watchpoints(); 8332785Speter pc = PC_REGS(DDB_REGS); 8432785Speter 8532785Speter#ifdef FIXUP_PC_AFTER_BREAK 8632785Speter if (*is_breakpoint) { 8732785Speter /* 8832785Speter * Breakpoint trap. Fix up the PC if the 8932785Speter * machine requires it. 9032785Speter */ 9132785Speter FIXUP_PC_AFTER_BREAK 9232785Speter pc = PC_REGS(DDB_REGS); 9332785Speter } 9432785Speter#endif 9532785Speter 9632785Speter /* 9732785Speter * Now check for a breakpoint at this address. 9832785Speter */ 9932785Speter bkpt = db_find_breakpoint_here(pc); 10032785Speter if (bkpt) { 10132785Speter if (--bkpt->count == 0) { 10232785Speter bkpt->count = bkpt->init_count; 10332785Speter *is_breakpoint = TRUE; 104102840Speter return (TRUE); /* stop here */ 10532785Speter } 10632785Speter } else if (*is_breakpoint) { 10732785Speter#ifdef __i386__ /* XXx */ 10832785Speter ddb_regs.tf_eip += 1; 10932785Speter#endif 11032785Speter } 11132785Speter 11232785Speter *is_breakpoint = FALSE; 11332785Speter 11432785Speter if (db_run_mode == STEP_INVISIBLE) { 11532785Speter db_run_mode = STEP_CONTINUE; 11632785Speter return (FALSE); /* continue */ 11732785Speter } 11832785Speter if (db_run_mode == STEP_COUNT) { 11932785Speter return (FALSE); /* continue */ 12032785Speter } 12132785Speter if (db_run_mode == STEP_ONCE) { 12232785Speter if (--db_loop_count > 0) { 12332785Speter if (db_sstep_print) { 12432785Speter db_printf("\t\t"); 12532785Speter db_print_loc_and_inst(pc); 12632785Speter db_printf("\n"); 12732785Speter } 12832785Speter return (FALSE); /* continue */ 12932785Speter } 13032785Speter } 131102840Speter if (db_run_mode == STEP_RETURN) { 13232785Speter db_expr_t ins = db_get_value(pc, sizeof(int), FALSE); 13332785Speter 13432785Speter /* continue until matching return */ 13532785Speter 13632785Speter if (!inst_trap_return(ins) && 13732785Speter (!inst_return(ins) || --db_call_depth != 0)) { 13832785Speter if (db_sstep_print) { 13932785Speter if (inst_call(ins) || inst_return(ins)) { 14032785Speter register int i; 14132785Speter 14232785Speter db_printf("[after %6d] ", db_inst_count); 14332785Speter for (i = db_call_depth; --i > 0; ) 14432785Speter db_printf(" "); 14532785Speter db_print_loc_and_inst(pc); 14632785Speter db_printf("\n"); 14732785Speter } 14832785Speter } 14932785Speter if (inst_call(ins)) 15032785Speter db_call_depth++; 15132785Speter return (FALSE); /* continue */ 15232785Speter } 15332785Speter } 15432785Speter if (db_run_mode == STEP_CALLT) { 15532785Speter db_expr_t ins = db_get_value(pc, sizeof(int), FALSE); 15632785Speter 15732785Speter /* continue until call or return */ 15832785Speter 15932785Speter if (!inst_call(ins) && 16032785Speter !inst_return(ins) && 16132785Speter !inst_trap_return(ins)) { 16232785Speter return (FALSE); /* continue */ 16332785Speter } 16432785Speter } 16532785Speter db_run_mode = STEP_NONE; 16632785Speter return (TRUE); 16732785Speter} 16832785Speter 16932785Spetervoid 17032785Speterdb_restart_at_pc(watchpt) 17132785Speter boolean_t watchpt; 17232785Speter{ 17332785Speter register db_addr_t pc = PC_REGS(DDB_REGS); 17432785Speter 17532785Speter if ((db_run_mode == STEP_COUNT) || 17632785Speter (db_run_mode == STEP_RETURN) || 17732785Speter (db_run_mode == STEP_CALLT)) { 17832785Speter db_expr_t ins; 17932785Speter 18032785Speter /* 18132785Speter * We are about to execute this instruction, 18232785Speter * so count it now. 18332785Speter */ 18432785Speter 18532785Speter ins = db_get_value(pc, sizeof(int), FALSE); 18632785Speter db_inst_count++; 18732785Speter db_load_count += inst_load(ins); 18832785Speter db_store_count += inst_store(ins); 18932785Speter#ifdef SOFTWARE_SSTEP 19032785Speter /* XXX works on mips, but... */ 19132785Speter if (inst_branch(ins) || inst_call(ins)) { 19232785Speter ins = db_get_value(next_instr_address(pc,1), 19332785Speter sizeof(int), FALSE); 19432785Speter db_inst_count++; 19532785Speter db_load_count += inst_load(ins); 19632785Speter db_store_count += inst_store(ins); 19732785Speter } 19832785Speter#endif SOFTWARE_SSTEP 19932785Speter } 20032785Speter 20132785Speter if (db_run_mode == STEP_CONTINUE) { 20232785Speter if (watchpt || db_find_breakpoint_here(pc)) { 20332785Speter /* 20432785Speter * Step over breakpoint/watchpoint. 20532785Speter */ 20632785Speter db_run_mode = STEP_INVISIBLE; 20732785Speter db_set_single_step(DDB_REGS); 20832785Speter } else { 20932785Speter db_set_breakpoints(); 21032785Speter db_set_watchpoints(); 21132785Speter } 21232785Speter } else { 21332785Speter db_set_single_step(DDB_REGS); 21432785Speter } 21532785Speter} 21632785Speter 21732785Speter#ifdef notused 21832785Speterstatic void 21932785Speterdb_single_step(regs) 22032785Speter db_regs_t *regs; 22132785Speter{ 22232785Speter if (db_run_mode == STEP_CONTINUE) { 22332785Speter db_run_mode = STEP_INVISIBLE; 22432785Speter db_set_single_step(regs); 22532785Speter } 22632785Speter} 22732785Speter#endif 22832785Speter 22932785Speter#ifdef SOFTWARE_SSTEP 23032785Speter/* 23132785Speter * Software implementation of single-stepping. 23232785Speter * If your machine does not have a trace mode 23332785Speter * similar to the vax or sun ones you can use 23432785Speter * this implementation, done for the mips. 23532785Speter * Just define the above conditional and provide 23632785Speter * the functions/macros defined below. 23732785Speter * 23832785Speter * extern boolean_t 23932785Speter * inst_branch(), returns true if the instruction might branch 24032785Speter * extern unsigned 24132785Speter * branch_taken(), return the address the instruction might 24232785Speter * branch to 24332785Speter * db_getreg_val(); return the value of a user register, 24432785Speter * as indicated in the hardware instruction 24532785Speter * encoding, e.g. 8 for r8 24632785Speter * 24732785Speter * next_instr_address(pc,bd) returns the address of the first 24832785Speter * instruction following the one at "pc", 24932785Speter * which is either in the taken path of 25032785Speter * the branch (bd==1) or not. This is 25132785Speter * for machines (mips) with branch delays. 25232785Speter * 25332785Speter * A single-step may involve at most 2 breakpoints - 25432785Speter * one for branch-not-taken and one for branch taken. 25532785Speter * If one of these addresses does not already have a breakpoint, 25632785Speter * we allocate a breakpoint and save it here. 25732785Speter * These breakpoints are deleted on return. 25832785Speter */ 25932785Speterdb_breakpoint_t db_not_taken_bkpt = 0; 26032785Speterdb_breakpoint_t db_taken_bkpt = 0; 26132785Speter 26232785Spetervoid 26332785Speterdb_set_single_step(regs) 26432785Speter register db_regs_t *regs; 26532785Speter{ 26632785Speter db_addr_t pc = PC_REGS(regs); 26732785Speter register unsigned inst, brpc; 26832785Speter 26932785Speter /* 27032785Speter * User was stopped at pc, e.g. the instruction 27132785Speter * at pc was not executed. 27232785Speter */ 27332785Speter inst = db_get_value(pc, sizeof(int), FALSE); 27432785Speter if (inst_branch(inst) || inst_call(inst)) { 27532785Speter brpc = branch_taken(inst, pc, regs); 27632785Speter if (brpc != pc) { /* self-branches are hopeless */ 27732785Speter db_taken_bkpt = db_set_temp_breakpoint(brpc); 27832785Speter } 27932785Speter pc = next_instr_address(pc,1); 28032785Speter } 28132785Speter pc = next_instr_address(pc,0); 28232785Speter db_not_taken_bkpt = db_set_temp_breakpoint(pc); 28332785Speter} 28432785Speter 28532785Spetervoid 28632785Speterdb_clear_single_step(regs) 28732785Speter db_regs_t *regs; 28832785Speter{ 28932785Speter register db_breakpoint_t bkpt; 29032785Speter 29132785Speter if (db_taken_bkpt != 0) { 29232785Speter db_delete_temp_breakpoint(db_taken_bkpt); 29332785Speter db_taken_bkpt = 0; 29432785Speter } 29532785Speter if (db_not_taken_bkpt != 0) { 29632785Speter db_delete_temp_breakpoint(db_not_taken_bkpt); 29732785Speter db_not_taken_bkpt = 0; 29832785Speter } 29932785Speter} 30032785Speter 30132785Speter#endif SOFTWARE_SSTEP 30232785Speter 30332785Speterextern int db_cmd_loop_done; 30432785Speter 30532785Speter/* single-step */ 30632785Speter/*ARGSUSED*/ 30732785Spetervoid 30832785Speterdb_single_step_cmd(addr, have_addr, count, modif) 30932785Speter db_expr_t addr; 31032785Speter boolean_t have_addr; 31132785Speter db_expr_t count; 31232785Speter char * modif; 31332785Speter{ 31432785Speter boolean_t print = FALSE; 31532785Speter 31632785Speter if (count == -1) 31732785Speter count = 1; 31832785Speter 31932785Speter if (modif[0] == 'p') 32032785Speter print = TRUE; 32132785Speter 32232785Speter db_run_mode = STEP_ONCE; 32332785Speter db_loop_count = count; 32432785Speter db_sstep_print = print; 32532785Speter db_inst_count = 0; 32632785Speter db_load_count = 0; 32732785Speter db_store_count = 0; 32832785Speter 32932785Speter db_cmd_loop_done = 1; 33032785Speter} 33132785Speter 33232785Speter/* trace and print until call/return */ 33332785Speter/*ARGSUSED*/ 33432785Spetervoid 33532785Speterdb_trace_until_call_cmd(addr, have_addr, count, modif) 33632785Speter db_expr_t addr; 33732785Speter boolean_t have_addr; 33832785Speter db_expr_t count; 33932785Speter char * modif; 34032785Speter{ 34132785Speter boolean_t print = FALSE; 34232785Speter 34332785Speter if (modif[0] == 'p') 34432785Speter print = TRUE; 34532785Speter 34632785Speter db_run_mode = STEP_CALLT; 34732785Speter db_sstep_print = print; 34832785Speter db_inst_count = 0; 34932785Speter db_load_count = 0; 35032785Speter db_store_count = 0; 35132785Speter 35232785Speter db_cmd_loop_done = 1; 35332785Speter} 35432785Speter 35532785Speter/*ARGSUSED*/ 35632785Spetervoid 35732785Speterdb_trace_until_matching_cmd(addr, have_addr, count, modif) 35832785Speter db_expr_t addr; 35932785Speter boolean_t have_addr; 36032785Speter db_expr_t count; 36132785Speter char * modif; 36232785Speter{ 36332785Speter boolean_t print = FALSE; 36432785Speter 36532785Speter if (modif[0] == 'p') 36632785Speter print = TRUE; 36732785Speter 36832785Speter db_run_mode = STEP_RETURN; 36932785Speter db_call_depth = 1; 37032785Speter db_sstep_print = print; 37132785Speter db_inst_count = 0; 37232785Speter db_load_count = 0; 37332785Speter db_store_count = 0; 37432785Speter 37532785Speter db_cmd_loop_done = 1; 37632785Speter} 37732785Speter 37832785Speter/* continue */ 37932785Speter/*ARGSUSED*/ 38032785Spetervoid 38132785Speterdb_continue_cmd(addr, have_addr, count, modif) 38232785Speter db_expr_t addr; 38332785Speter boolean_t have_addr; 38432785Speter db_expr_t count; 38532785Speter char * modif; 38632785Speter{ 38732785Speter if (modif[0] == 'c') 38832785Speter db_run_mode = STEP_COUNT; 38932785Speter else 39032785Speter db_run_mode = STEP_CONTINUE; 39132785Speter db_inst_count = 0; 39232785Speter db_load_count = 0; 39332785Speter db_store_count = 0; 39432785Speter 39532785Speter db_cmd_loop_done = 1; 39632785Speter} 39732785Speter