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

Cache object: 310059ac70c6786bbb86cda6165a02ed


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