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

Cache object: 79c6090a69c2baea8c5e99080eb37807


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