The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/ddb/db_run.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 1d7ecfdd44a71b0fd879e9d3fcfaefc2


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.