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

Cache object: e37be8ebca758b6fe17af10686f573b1


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