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/11.2/sys/ddb/db_run.c 308418 2016-11-07 12:10:17Z kib $");
   37 
   38 #include <sys/param.h>
   39 #include <sys/kdb.h>
   40 #include <sys/proc.h>
   41 
   42 #include <machine/kdb.h>
   43 #include <machine/pcb.h>
   44 
   45 #include <vm/vm.h>
   46 
   47 #include <ddb/ddb.h>
   48 #include <ddb/db_break.h>
   49 #include <ddb/db_access.h>
   50 
   51 #define STEP_ONCE       1
   52 #define STEP_RETURN     2
   53 #define STEP_CALLT      3
   54 #define STEP_CONTINUE   4
   55 #define STEP_INVISIBLE  5
   56 #define STEP_COUNT      6
   57 static int      db_run_mode = STEP_CONTINUE;
   58 
   59 static bool             db_sstep_multiple;
   60 static bool             db_sstep_print;
   61 static int              db_loop_count;
   62 static int              db_call_depth;
   63 
   64 int             db_inst_count;
   65 int             db_load_count;
   66 int             db_store_count;
   67 
   68 #ifdef SOFTWARE_SSTEP
   69 db_breakpoint_t db_not_taken_bkpt = 0;
   70 db_breakpoint_t db_taken_bkpt = 0;
   71 #endif
   72 
   73 #ifndef db_set_single_step
   74 void db_set_single_step(void);
   75 #endif
   76 #ifndef db_clear_single_step
   77 void db_clear_single_step(void);
   78 #endif
   79 #ifndef db_pc_is_singlestep
   80 static bool
   81 db_pc_is_singlestep(db_addr_t pc)
   82 {
   83 #ifdef SOFTWARE_SSTEP
   84         if ((db_not_taken_bkpt != 0 && pc == db_not_taken_bkpt->address)
   85             || (db_taken_bkpt != 0 && pc == db_taken_bkpt->address))
   86                 return (true);
   87 #endif
   88         return (false);
   89 }
   90 #endif
   91 
   92 bool
   93 db_stop_at_pc(int type, int code, bool *is_breakpoint, bool *is_watchpoint)
   94 {
   95         db_addr_t       pc;
   96         db_breakpoint_t bkpt;
   97 
   98         *is_breakpoint = IS_BREAKPOINT_TRAP(type, code);
   99         *is_watchpoint = IS_WATCHPOINT_TRAP(type, code);
  100         pc = PC_REGS();
  101         if (db_pc_is_singlestep(pc))
  102                 *is_breakpoint = false;
  103 
  104         db_clear_single_step();
  105         db_clear_breakpoints();
  106         db_clear_watchpoints();
  107 
  108 #ifdef  FIXUP_PC_AFTER_BREAK
  109         if (*is_breakpoint) {
  110             /*
  111              * Breakpoint trap.  Fix up the PC if the
  112              * machine requires it.
  113              */
  114             FIXUP_PC_AFTER_BREAK
  115             pc = PC_REGS();
  116         }
  117 #endif
  118 
  119         /*
  120          * Now check for a breakpoint at this address.
  121          */
  122         bkpt = db_find_breakpoint_here(pc);
  123         if (bkpt) {
  124             if (--bkpt->count == 0) {
  125                 bkpt->count = bkpt->init_count;
  126                 *is_breakpoint = true;
  127                 return (true);  /* stop here */
  128             }
  129             return (false);     /* continue the countdown */
  130         } else if (*is_breakpoint) {
  131 #ifdef BKPT_SKIP
  132                 BKPT_SKIP;
  133 #endif
  134         }
  135 
  136         *is_breakpoint = false; /* might be a breakpoint, but not ours */
  137 
  138         /*
  139          * If not stepping, then silently ignore single-step traps
  140          * (except for clearing the single-step-flag above).
  141          *
  142          * If stepping, then abort if the trap type is unexpected.
  143          * Breakpoints owned by us are expected and were handled above.
  144          * Single-steps are expected and are handled below.  All others
  145          * are unexpected.
  146          *
  147          * Only do either of these if the MD layer claims to classify
  148          * single-step traps unambiguously (by defining IS_SSTEP_TRAP).
  149          * Otherwise, fall through to the bad historical behaviour
  150          * given by turning unexpected traps into expected traps: if not
  151          * stepping, then expect only breakpoints and stop, and if
  152          * stepping, then expect only single-steps and step.
  153          */
  154 #ifdef IS_SSTEP_TRAP
  155         if (db_run_mode == STEP_CONTINUE && IS_SSTEP_TRAP(type, code))
  156             return (false);
  157         if (db_run_mode != STEP_CONTINUE && !IS_SSTEP_TRAP(type, code)) {
  158             printf("Stepping aborted\n");
  159             return (true);
  160         }
  161 #endif
  162 
  163         if (db_run_mode == STEP_INVISIBLE) {
  164             db_run_mode = STEP_CONTINUE;
  165             return (false);     /* continue */
  166         }
  167         if (db_run_mode == STEP_COUNT) {
  168             return (false); /* continue */
  169         }
  170         if (db_run_mode == STEP_ONCE) {
  171             if (--db_loop_count > 0) {
  172                 if (db_sstep_print) {
  173                     db_printf("\t\t");
  174                     db_print_loc_and_inst(pc);
  175                     db_printf("\n");
  176                 }
  177                 return (false); /* continue */
  178             }
  179         }
  180         if (db_run_mode == STEP_RETURN) {
  181             /* continue until matching return */
  182             db_expr_t ins;
  183 
  184             ins = db_get_value(pc, sizeof(int), false);
  185             if (!inst_trap_return(ins) &&
  186                 (!inst_return(ins) || --db_call_depth != 0)) {
  187                 if (db_sstep_print) {
  188                     if (inst_call(ins) || inst_return(ins)) {
  189                         int i;
  190 
  191                         db_printf("[after %6d]     ", db_inst_count);
  192                         for (i = db_call_depth; --i > 0; )
  193                             db_printf("  ");
  194                         db_print_loc_and_inst(pc);
  195                         db_printf("\n");
  196                     }
  197                 }
  198                 if (inst_call(ins))
  199                     db_call_depth++;
  200                 return (false); /* continue */
  201             }
  202         }
  203         if (db_run_mode == STEP_CALLT) {
  204             /* continue until call or return */
  205             db_expr_t ins;
  206 
  207             ins = db_get_value(pc, sizeof(int), false);
  208             if (!inst_call(ins) &&
  209                 !inst_return(ins) &&
  210                 !inst_trap_return(ins)) {
  211                 return (false); /* continue */
  212             }
  213         }
  214         return (true);
  215 }
  216 
  217 void
  218 db_restart_at_pc(bool watchpt)
  219 {
  220         db_addr_t       pc = PC_REGS();
  221 
  222         if ((db_run_mode == STEP_COUNT) ||
  223             ((db_run_mode == STEP_ONCE) && db_sstep_multiple) ||
  224             (db_run_mode == STEP_RETURN) ||
  225             (db_run_mode == STEP_CALLT)) {
  226             /*
  227              * We are about to execute this instruction,
  228              * so count it now.
  229              */
  230 #ifdef  SOFTWARE_SSTEP
  231             db_expr_t           ins =
  232 #endif
  233             db_get_value(pc, sizeof(int), false);
  234             db_inst_count++;
  235             db_load_count += inst_load(ins);
  236             db_store_count += inst_store(ins);
  237 #ifdef  SOFTWARE_SSTEP
  238             /* XXX works on mips, but... */
  239             if (inst_branch(ins) || inst_call(ins)) {
  240                 ins = db_get_value(next_instr_address(pc,1),
  241                                    sizeof(int), false);
  242                 db_inst_count++;
  243                 db_load_count += inst_load(ins);
  244                 db_store_count += inst_store(ins);
  245             }
  246 #endif  /* SOFTWARE_SSTEP */
  247         }
  248 
  249         if (db_run_mode == STEP_CONTINUE) {
  250             if (watchpt || db_find_breakpoint_here(pc)) {
  251                 /*
  252                  * Step over breakpoint/watchpoint.
  253                  */
  254                 db_run_mode = STEP_INVISIBLE;
  255                 db_set_single_step();
  256             } else {
  257                 db_set_breakpoints();
  258                 db_set_watchpoints();
  259             }
  260         } else {
  261             db_set_single_step();
  262         }
  263 }
  264 
  265 #ifdef  SOFTWARE_SSTEP
  266 /*
  267  *      Software implementation of single-stepping.
  268  *      If your machine does not have a trace mode
  269  *      similar to the vax or sun ones you can use
  270  *      this implementation, done for the mips.
  271  *      Just define the above conditional and provide
  272  *      the functions/macros defined below.
  273  *
  274  * extern bool
  275  *      inst_branch(),          returns true if the instruction might branch
  276  * extern unsigned
  277  *      branch_taken(),         return the address the instruction might
  278  *                              branch to
  279  *      db_getreg_val();        return the value of a user register,
  280  *                              as indicated in the hardware instruction
  281  *                              encoding, e.g. 8 for r8
  282  *
  283  * next_instr_address(pc,bd)    returns the address of the first
  284  *                              instruction following the one at "pc",
  285  *                              which is either in the taken path of
  286  *                              the branch (bd==1) or not.  This is
  287  *                              for machines (mips) with branch delays.
  288  *
  289  *      A single-step may involve at most 2 breakpoints -
  290  *      one for branch-not-taken and one for branch taken.
  291  *      If one of these addresses does not already have a breakpoint,
  292  *      we allocate a breakpoint and save it here.
  293  *      These breakpoints are deleted on return.
  294  */
  295 
  296 void
  297 db_set_single_step(void)
  298 {
  299         db_addr_t pc = PC_REGS(), brpc;
  300         unsigned inst;
  301 
  302         /*
  303          *      User was stopped at pc, e.g. the instruction
  304          *      at pc was not executed.
  305          */
  306         inst = db_get_value(pc, sizeof(int), false);
  307         if (inst_branch(inst) || inst_call(inst) || inst_return(inst)) {
  308                 brpc = branch_taken(inst, pc);
  309                 if (brpc != pc) {       /* self-branches are hopeless */
  310                         db_taken_bkpt = db_set_temp_breakpoint(brpc);
  311                 }
  312                 pc = next_instr_address(pc, 1);
  313         }
  314         pc = next_instr_address(pc, 0);
  315         db_not_taken_bkpt = db_set_temp_breakpoint(pc);
  316 }
  317 
  318 void
  319 db_clear_single_step(void)
  320 {
  321 
  322         if (db_not_taken_bkpt != 0) {
  323                 db_delete_temp_breakpoint(db_not_taken_bkpt);
  324                 db_not_taken_bkpt = 0;
  325         }
  326         if (db_taken_bkpt != 0) {
  327                 db_delete_temp_breakpoint(db_taken_bkpt);
  328                 db_taken_bkpt = 0;
  329         }
  330 }
  331 
  332 #endif  /* SOFTWARE_SSTEP */
  333 
  334 extern int      db_cmd_loop_done;
  335 
  336 /* single-step */
  337 /*ARGSUSED*/
  338 void
  339 db_single_step_cmd(db_expr_t addr, bool have_addr, db_expr_t count, char *modif)
  340 {
  341         bool            print = false;
  342 
  343         if (count == -1)
  344             count = 1;
  345 
  346         if (modif[0] == 'p')
  347             print = true;
  348 
  349         db_run_mode = STEP_ONCE;
  350         db_loop_count = count;
  351         db_sstep_multiple = (count != 1);
  352         db_sstep_print = print;
  353         db_inst_count = 0;
  354         db_load_count = 0;
  355         db_store_count = 0;
  356 
  357         db_cmd_loop_done = 1;
  358 }
  359 
  360 /* trace and print until call/return */
  361 /*ARGSUSED*/
  362 void
  363 db_trace_until_call_cmd(db_expr_t addr, bool have_addr, db_expr_t count,
  364     char *modif)
  365 {
  366         bool    print = false;
  367 
  368         if (modif[0] == 'p')
  369             print = true;
  370 
  371         db_run_mode = STEP_CALLT;
  372         db_sstep_print = print;
  373         db_inst_count = 0;
  374         db_load_count = 0;
  375         db_store_count = 0;
  376 
  377         db_cmd_loop_done = 1;
  378 }
  379 
  380 /*ARGSUSED*/
  381 void
  382 db_trace_until_matching_cmd(db_expr_t addr, bool have_addr, db_expr_t count,
  383     char *modif)
  384 {
  385         bool    print = false;
  386 
  387         if (modif[0] == 'p')
  388             print = true;
  389 
  390         db_run_mode = STEP_RETURN;
  391         db_call_depth = 1;
  392         db_sstep_print = print;
  393         db_inst_count = 0;
  394         db_load_count = 0;
  395         db_store_count = 0;
  396 
  397         db_cmd_loop_done = 1;
  398 }
  399 
  400 /* continue */
  401 /*ARGSUSED*/
  402 void
  403 db_continue_cmd(db_expr_t addr, bool have_addr, db_expr_t count, char *modif)
  404 {
  405         if (modif[0] == 'c')
  406             db_run_mode = STEP_COUNT;
  407         else
  408             db_run_mode = STEP_CONTINUE;
  409         db_inst_count = 0;
  410         db_load_count = 0;
  411         db_store_count = 0;
  412 
  413         db_cmd_loop_done = 1;
  414 }

Cache object: e1d2008a08628b1b7b6fbd79cc66056d


[ 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.