root/ddb/db_run.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. db_stop_at_pc
  2. db_restart_at_pc
  3. db_single_step
  4. db_single_step_cmd
  5. db_trace_until_call_cmd
  6. db_trace_until_matching_cmd
  7. db_continue_cmd
  8. db_set_single_step
  9. db_clear_single_step

    1 /*      $OpenBSD: db_run.c,v 1.19 2006/03/13 06:23:20 jsg Exp $ */
    2 /*      $NetBSD: db_run.c,v 1.8 1996/02/05 01:57:12 christos Exp $      */
    3 
    4 /* 
    5  * Mach Operating System
    6  * Copyright (c) 1993,1992,1991,1990 Carnegie Mellon University
    7  * All Rights Reserved.
    8  * 
    9  * Permission to use, copy, modify and distribute this software and its
   10  * documentation is hereby granted, provided that both the copyright
   11  * notice and this permission notice appear in all copies of the
   12  * software, derivative works or modified versions, and any portions
   13  * thereof, and that both notices appear in supporting documentation.
   14  * 
   15  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
   16  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
   17  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
   18  * 
   19  * Carnegie Mellon requests users of this software to return to
   20  * 
   21  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
   22  *  School of Computer Science
   23  *  Carnegie Mellon University
   24  *  Pittsburgh PA 15213-3890
   25  * 
   26  * any improvements or extensions that they make and grant Carnegie Mellon
   27  * the rights to redistribute these changes.
   28  *
   29  *      Author: David B. Golub, Carnegie Mellon University
   30  *      Date:   7/90
   31  */
   32 
   33 /*
   34  * Commands to run process.
   35  */
   36 #include <sys/param.h>
   37 #include <sys/proc.h>
   38 
   39 #include <uvm/uvm_extern.h>
   40 
   41 #include <machine/db_machdep.h>
   42 
   43 #include <ddb/db_run.h>
   44 #include <ddb/db_break.h>
   45 #include <ddb/db_access.h>
   46 
   47 #ifdef SOFTWARE_SSTEP
   48 db_breakpoint_t db_not_taken_bkpt = 0;
   49 db_breakpoint_t db_taken_bkpt = 0;
   50 #endif
   51 
   52 int             db_inst_count;
   53 int             db_load_count;
   54 int             db_store_count;
   55 
   56 #ifndef KGDB
   57 
   58 #include <ddb/db_lex.h>
   59 #include <ddb/db_watch.h>
   60 #include <ddb/db_output.h>
   61 #include <ddb/db_sym.h>
   62 #include <ddb/db_extern.h>
   63 
   64 int     db_run_mode;
   65 #define STEP_NONE       0
   66 #define STEP_ONCE       1
   67 #define STEP_RETURN     2
   68 #define STEP_CALLT      3
   69 #define STEP_CONTINUE   4
   70 #define STEP_INVISIBLE  5
   71 #define STEP_COUNT      6
   72 
   73 boolean_t       db_sstep_print;
   74 int             db_loop_count;
   75 int             db_call_depth;
   76 
   77 boolean_t
   78 db_stop_at_pc(db_regs_t *regs, boolean_t *is_breakpoint)
   79 {
   80         db_addr_t       pc, old_pc;
   81         db_breakpoint_t bkpt;
   82 
   83         db_clear_breakpoints();
   84         db_clear_watchpoints();
   85         old_pc = pc = PC_REGS(regs);
   86 
   87 #ifdef  FIXUP_PC_AFTER_BREAK
   88         if (*is_breakpoint) {
   89                 /*
   90                  * Breakpoint trap.  Fix up the PC if the
   91                  * machine requires it.
   92                  */
   93                 FIXUP_PC_AFTER_BREAK(regs);
   94                 pc = PC_REGS(regs);
   95         }
   96 #endif
   97 
   98         /*
   99          * Now check for a breakpoint at this address.
  100          */
  101         bkpt = db_find_breakpoint_here(pc);
  102         if (bkpt) {
  103                 if (--bkpt->count == 0) {
  104                         db_clear_single_step(regs);
  105                         bkpt->count = bkpt->init_count;
  106                         *is_breakpoint = TRUE;
  107                         return (TRUE);  /* stop here */
  108                 }
  109         } else if (*is_breakpoint
  110 #ifdef SOFTWARE_SSTEP
  111             && !((db_taken_bkpt && db_taken_bkpt->address == pc) ||
  112             (db_not_taken_bkpt && db_not_taken_bkpt->address == pc))
  113 #endif
  114             ) {
  115 #ifdef PC_ADVANCE
  116                 PC_ADVANCE(regs);
  117 #else
  118 # ifdef SET_PC_REGS
  119                 SET_PC_REGS(regs, old_pc);
  120 # else
  121                 PC_REGS(regs) = old_pc;
  122 # endif
  123 #endif
  124         }
  125         db_clear_single_step(regs);
  126                 
  127         *is_breakpoint = FALSE;
  128 
  129         if (db_run_mode == STEP_INVISIBLE) {
  130                 db_run_mode = STEP_CONTINUE;
  131                 return (FALSE); /* continue */
  132         }
  133         if (db_run_mode == STEP_COUNT) {
  134                 return (FALSE); /* continue */
  135         }
  136         if (db_run_mode == STEP_ONCE) {
  137                 if (--db_loop_count > 0) {
  138                         if (db_sstep_print) {
  139                                 db_printf("\t\t");
  140                                 db_print_loc_and_inst(pc);
  141                                 db_printf("\n");
  142                         }
  143                         return (FALSE); /* continue */
  144                 }
  145         }
  146         if (db_run_mode == STEP_RETURN) {
  147             db_expr_t ins = db_get_value(pc, sizeof(int), FALSE);
  148 
  149             /* continue until matching return */
  150 
  151             if (!inst_trap_return(ins) &&
  152                 (!inst_return(ins) || --db_call_depth != 0)) {
  153                 if (db_sstep_print) {
  154                     if (inst_call(ins) || inst_return(ins)) {
  155                         int i;
  156 
  157                         db_printf("[after %6d]     ", db_inst_count);
  158                         for (i = db_call_depth; --i > 0; )
  159                             db_printf("  ");
  160                         db_print_loc_and_inst(pc);
  161                         db_printf("\n");
  162                     }
  163                 }
  164                 if (inst_call(ins))
  165                     db_call_depth++;
  166                 return (FALSE); /* continue */
  167             }
  168         }
  169         if (db_run_mode == STEP_CALLT) {
  170             db_expr_t ins = db_get_value(pc, sizeof(int), FALSE);
  171 
  172             /* continue until call or return */
  173 
  174             if (!inst_call(ins) && !inst_return(ins) &&
  175                 !inst_trap_return(ins)) {
  176                 return (FALSE); /* continue */
  177             }
  178         }
  179         db_run_mode = STEP_NONE;
  180         return (TRUE);
  181 }
  182 
  183 void
  184 db_restart_at_pc(db_regs_t *regs, boolean_t watchpt)
  185 {
  186         db_addr_t pc = PC_REGS(regs);
  187 
  188         if ((db_run_mode == STEP_COUNT) || (db_run_mode == STEP_RETURN) ||
  189             (db_run_mode == STEP_CALLT)) {
  190                 db_expr_t       ins;
  191 
  192                 /*
  193                  * We are about to execute this instruction,
  194                  * so count it now.
  195                  */
  196                 ins = db_get_value(pc, sizeof(int), FALSE);
  197                 db_inst_count++;
  198                 db_load_count += inst_load(ins);
  199                 db_store_count += inst_store(ins);
  200 #ifdef  SOFTWARE_SSTEP
  201                 /* XXX works on mips, but... */
  202                 if (inst_branch(ins) || inst_call(ins)) {
  203                         ins = db_get_value(next_instr_address(pc, 1),
  204                             sizeof(int), FALSE);
  205                         db_inst_count++;
  206                         db_load_count += inst_load(ins);
  207                         db_store_count += inst_store(ins);
  208                 }
  209 #endif  /* SOFTWARE_SSTEP */
  210         }
  211 
  212         if (db_run_mode == STEP_CONTINUE) {
  213                 if (watchpt || db_find_breakpoint_here(pc)) {
  214                         /*
  215                          * Step over breakpoint/watchpoint.
  216                          */
  217                         db_run_mode = STEP_INVISIBLE;
  218                         db_set_single_step(regs);
  219                 } else {
  220                         db_set_breakpoints();
  221                         db_set_watchpoints();
  222                 }
  223         } else {
  224                 db_set_single_step(regs);
  225         }
  226 }
  227 
  228 void
  229 db_single_step(db_regs_t *regs)
  230 {
  231         if (db_run_mode == STEP_CONTINUE) {
  232             db_run_mode = STEP_INVISIBLE;
  233             db_set_single_step(regs);
  234         }
  235 }
  236 
  237 extern int      db_cmd_loop_done;
  238 
  239 /* single-step */
  240 /*ARGSUSED*/
  241 void
  242 db_single_step_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
  243 {
  244         boolean_t       print = FALSE;
  245 
  246         if (count == -1)
  247             count = 1;
  248 
  249         if (modif[0] == 'p')
  250             print = TRUE;
  251 
  252         db_run_mode = STEP_ONCE;
  253         db_loop_count = count;
  254         db_sstep_print = print;
  255         db_inst_count = 0;
  256         db_load_count = 0;
  257         db_store_count = 0;
  258 
  259         db_cmd_loop_done = 1;
  260 }
  261 
  262 /* trace and print until call/return */
  263 /*ARGSUSED*/
  264 void
  265 db_trace_until_call_cmd(db_expr_t addr, int have_addr, db_expr_t count,
  266     char *modif)
  267 {
  268         boolean_t       print = FALSE;
  269 
  270         if (modif[0] == 'p')
  271             print = TRUE;
  272 
  273         db_run_mode = STEP_CALLT;
  274         db_sstep_print = print;
  275         db_inst_count = 0;
  276         db_load_count = 0;
  277         db_store_count = 0;
  278 
  279         db_cmd_loop_done = 1;
  280 }
  281 
  282 /*ARGSUSED*/
  283 void
  284 db_trace_until_matching_cmd(db_expr_t addr, int have_addr, db_expr_t count,
  285     char *modif)
  286 {
  287         boolean_t       print = FALSE;
  288 
  289         if (modif[0] == 'p')
  290             print = TRUE;
  291 
  292         db_run_mode = STEP_RETURN;
  293         db_call_depth = 1;
  294         db_sstep_print = print;
  295         db_inst_count = 0;
  296         db_load_count = 0;
  297         db_store_count = 0;
  298 
  299         db_cmd_loop_done = 1;
  300 }
  301 
  302 /* continue */
  303 /*ARGSUSED*/
  304 void
  305 db_continue_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
  306 {
  307         if (modif[0] == 'c')
  308             db_run_mode = STEP_COUNT;
  309         else
  310             db_run_mode = STEP_CONTINUE;
  311         db_inst_count = 0;
  312         db_load_count = 0;
  313         db_store_count = 0;
  314 
  315         db_cmd_loop_done = 1;
  316 }
  317 #endif /* NO KGDB */
  318 
  319 #ifdef  SOFTWARE_SSTEP
  320 /*
  321  *      Software implementation of single-stepping.
  322  *      If your machine does not have a trace mode
  323  *      similar to the vax or sun ones you can use
  324  *      this implementation, done for the mips.
  325  *      Just define the above conditional and provide
  326  *      the functions/macros defined below.
  327  *
  328  * extern boolean_t
  329  *      inst_branch(ins),       returns true if the instruction might branch
  330  * extern unsigned
  331  *      branch_taken(ins, pc, getreg_val, regs),
  332  *                              return the address the instruction might
  333  *                              branch to
  334  *      getreg_val(regs, reg),  return the value of a user register,
  335  *                              as indicated in the hardware instruction
  336  *                              encoding, e.g. 8 for r8
  337  *                      
  338  * next_instr_address(pc, bd)   returns the address of the first
  339  *                              instruction following the one at "pc",
  340  *                              which is either in the taken path of
  341  *                              the branch (bd==1) or not.  This is
  342  *                              for machines (mips) with branch delays.
  343  *
  344  *      A single-step may involve at most 2 breakpoints -
  345  *      one for branch-not-taken and one for branch taken.
  346  *      If one of these addresses does not already have a breakpoint,
  347  *      we allocate a breakpoint and save it here.
  348  *      These breakpoints are deleted on return.
  349  */                     
  350 
  351 void
  352 db_set_single_step(db_regs_t *regs)
  353 {
  354         db_addr_t pc = PC_REGS(regs);
  355 #ifndef SOFTWARE_SSTEP_EMUL
  356         db_addr_t brpc;
  357         u_int inst;
  358 
  359         /*
  360          * User was stopped at pc, e.g. the instruction
  361          * at pc was not executed.
  362          */
  363         inst = db_get_value(pc, sizeof(int), FALSE);
  364         if (inst_branch(inst) || inst_call(inst) || inst_return(inst)) {
  365             brpc = branch_taken(inst, pc, getreg_val, regs);
  366             if (brpc != pc) {   /* self-branches are hopeless */
  367                 db_taken_bkpt = db_set_temp_breakpoint(brpc);
  368             }
  369 #if 0
  370             /* XXX this seems like a true bug, no?  */
  371             pc = next_instr_address(pc, 1);
  372 #endif
  373         }
  374 #endif /*SOFTWARE_SSTEP_EMUL*/
  375         pc = next_instr_address(pc, 0);
  376         db_not_taken_bkpt = db_set_temp_breakpoint(pc);
  377 }
  378 
  379 void
  380 db_clear_single_step(db_regs_t *regs)
  381 {
  382         if (db_taken_bkpt != 0) {
  383             db_delete_temp_breakpoint(db_taken_bkpt);
  384             db_taken_bkpt = 0;
  385         }
  386         if (db_not_taken_bkpt != 0) {
  387             db_delete_temp_breakpoint(db_not_taken_bkpt);
  388             db_not_taken_bkpt = 0;
  389         }
  390 }
  391 
  392 #endif  /* SOFTWARE_SSTEP */

/* [<][>][^][v][top][bottom][index][help] */