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) 1993-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 "AS IS"
   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 Mellon
   24  * the rights to redistribute these changes.
   25  */
   26 /*
   27  * HISTORY
   28  * $Log:        db_run.c,v $
   29  * Revision 2.15  93/11/17  16:24:43  dbg
   30  *      Added ANSI function prototypes.
   31  *      [93/10/11            dbg]
   32  * 
   33  * Revision 2.14  93/01/19  09:00:47  danner
   34  *      64bit cleanup. software single step code revision.
   35  *      comment correction (jfriedl).
   36  *      [92/12/10  16:20:16  af]
   37  * 
   38  * Revision 2.13  93/01/14  17:25:38  danner
   39  *      added use of db_branch_is_delayed in db_restart_at_pc. 
   40  *      [92/11/28            jfriedl]
   41  *      64bit cleanup.
   42  *      [92/12/10  16:20:16  af]
   43  * 
   44  * Revision 2.12  92/08/03  17:31:57  jfriedl
   45  *      removed silly prototypes
   46  *      [92/08/02            jfriedl]
   47  * 
   48  * Revision 2.11  92/05/21  17:07:41  jfriedl
   49  *      Removed unused variable 'bkpt' from db_clear_task_single_step().
   50  *      [92/05/16            jfriedl]
   51  * 
   52  * Revision 2.10  92/04/01  10:54:05  rpd
   53  *      Added missing newline print in n/p command.
   54  *      [92/03/20            danner]
   55  * 
   56  * Revision 2.9  91/10/09  16:02:08  af
   57  *      Added task parameter for user space break point, and changed
   58  *       db_find_breakpoint_here to db_find_thread_breakpoint_here
   59  *       to support thread based break point.
   60  *      Changed db_{set,clear}_single_step to db_{set,clear}_task_single
   61  *       _step to add task paramter and to maintain compatibility.
   62  *      [91/08/29            tak]
   63  * 
   64  * Revision 2.8  91/07/09  23:16:01  danner
   65  *      Added logic to db_set_single_step not to set a breakpoint at the
   66  *       next sequential instruction if the current instruction is an
   67  *       unconditional transfer of flow of control instruction. This
   68  *       avoids problems with the debugger overwriting data or clobbering
   69  *       routines that the debugger itself might need. This is determined
   70  *       by calling the predicate inst_unconditional_flow_transfer. This
   71  *       predicate now needs to be defined for all architectures using
   72  *       the software single step. 
   73  * 
   74  *           Added include of ddb/db_run.h, where all the STEP defines have been
   75  *            moved.
   76  *       
   77  *      [91/07/08            danner]
   78  * 
   79  * Revision 2.7  91/06/06  17:03:51  jsb
   80  *      Removed redundant newlines and tabs.
   81  *      Added delta to instruction count printf.
   82  *      [91/05/25  10:55:01  jsb]
   83  * 
   84  * Revision 2.6  91/05/14  15:35:39  mrt
   85  *      Correcting copyright
   86  * 
   87  * Revision 2.5  91/02/05  17:06:58  mrt
   88  *      Changed to new Mach copyright
   89  *      [91/01/31  16:19:05  mrt]
   90  * 
   91  * Revision 2.4  91/01/08  15:09:10  rpd
   92  *      Fixed bug in db_restart_at_pc.
   93  *      [90/12/07            rpd]
   94  *      Added STEP_COUNT and count option to db_continue_cmd.
   95  *      Changed db_stop_at_pc to return (modified) is_breakpoint.
   96  *      Fixed db_stop_at_pc to print newlines in the right places.
   97  *      [90/11/27            rpd]
   98  * 
   99  * Revision 2.3  90/10/25  14:43:59  rwd
  100  *      Changed db_find_breakpoint to db_find_breakpoint_here.
  101  *      [90/10/18            rpd]
  102  * 
  103  *      Fixed db_set_single_step to pass regs to branch_taken.
  104  *      Added watchpoint argument to db_restart_at_pc.
  105  *      [90/10/17            rpd]
  106  *      Generalized the watchpoint support.
  107  *      [90/10/16            rwd]
  108  *      Added watchpoint support.
  109  *      [90/10/16            rpd]
  110  * 
  111  * Revision 2.2  90/08/27  21:51:59  dbg
  112  *      Fixed names for single-step functions.
  113  *      [90/08/20            af]
  114  *      Reduce lint.
  115  *      [90/08/07            dbg]
  116  *      Created.
  117  *      [90/07/25            dbg]
  118  * 
  119  */
  120 /*
  121  *      Author: David B. Golub, Carnegie Mellon University
  122  *      Date:   7/90
  123  */
  124 
  125 /*
  126  * Commands to run process.
  127  */
  128 #include <mach/boolean.h>
  129 #include <machine/db_machdep.h>
  130 
  131 #include <ddb/db_access.h>
  132 #include <ddb/db_break.h>
  133 #include <ddb/db_examine.h>
  134 #include <ddb/db_lex.h>
  135 #include <ddb/db_output.h>
  136 #include <ddb/db_run.h>
  137 #include <ddb/db_task_thread.h>
  138 #include <ddb/db_watch.h>
  139 
  140 int     db_run_mode;
  141 
  142 boolean_t       db_sstep_print;
  143 int             db_loop_count;
  144 int             db_call_depth;
  145 
  146 int             db_inst_count;
  147 int             db_last_inst_count;
  148 int             db_load_count;
  149 int             db_store_count;
  150 
  151 #ifndef db_set_single_step
  152 void            db_set_task_single_step(db_regs_t *, task_t); /* forward */
  153 #else
  154 #define db_set_task_single_step(regs,task)      db_set_single_step(regs)
  155 #endif
  156 #ifndef db_clear_single_step
  157 void            db_clear_task_single_step(db_regs_t *, task_t);
  158 #else
  159 #define db_clear_task_single_step(regs,task)    db_clear_single_step(regs)
  160 #endif
  161 
  162 boolean_t
  163 db_stop_at_pc(
  164         boolean_t       *is_breakpoint,
  165         task_t          task)
  166 {
  167         register  db_addr_t     pc;
  168         register  db_thread_breakpoint_t bkpt;
  169         boolean_t db_cond_check();
  170 
  171         db_clear_task_single_step(DDB_REGS, task);
  172         db_clear_breakpoints();
  173         db_clear_watchpoints();
  174         pc = PC_REGS(DDB_REGS);
  175 
  176 #ifdef  FIXUP_PC_AFTER_BREAK
  177         if (*is_breakpoint) {
  178             /*
  179              * Breakpoint trap.  Fix up the PC if the
  180              * machine requires it.
  181              */
  182             FIXUP_PC_AFTER_BREAK
  183             pc = PC_REGS(DDB_REGS);
  184         }
  185 #endif
  186 
  187         /*
  188          * Now check for a breakpoint at this address.
  189          */
  190         bkpt = db_find_thread_breakpoint_here(task, pc);
  191         if (bkpt) {
  192             if (db_cond_check(bkpt)) {
  193                 *is_breakpoint = TRUE;
  194                 return TRUE;    /* stop here */
  195             }
  196         }
  197         *is_breakpoint = FALSE;
  198 
  199         if (db_run_mode == STEP_INVISIBLE) {
  200             db_run_mode = STEP_CONTINUE;
  201             return FALSE;       /* continue */
  202         }
  203         if (db_run_mode == STEP_COUNT) {
  204             return FALSE;       /* continue */
  205         }
  206         if (db_run_mode == STEP_ONCE) {
  207             if (--db_loop_count > 0) {
  208                 if (db_sstep_print) {
  209                     db_print_loc_and_inst(pc, task);
  210                 }
  211                 return FALSE;   /* continue */
  212             }
  213         }
  214         if (db_run_mode == STEP_RETURN) {
  215             /* WARNING: the following assumes an instruction fits an int */
  216             db_expr_t ins = db_get_task_value(pc, sizeof(int), FALSE, task);
  217 
  218             /* continue until matching return */
  219 
  220             if (!inst_trap_return(ins) &&
  221                 (!inst_return(ins) || --db_call_depth != 0)) {
  222                 if (db_sstep_print) {
  223                     if (inst_call(ins) || inst_return(ins)) {
  224                         register int i;
  225 
  226                         db_printf("[after %6d /%4d] ",
  227                                   db_inst_count,
  228                                   db_inst_count - db_last_inst_count);
  229                         db_last_inst_count = db_inst_count;
  230                         for (i = db_call_depth; --i > 0; )
  231                             db_printf("  ");
  232                         db_print_loc_and_inst(pc, task);
  233                         db_printf("\n");
  234                     }
  235                 }
  236                 if (inst_call(ins))
  237                     db_call_depth++;
  238                 return FALSE;   /* continue */
  239             }
  240         }
  241         if (db_run_mode == STEP_CALLT) {
  242             /* WARNING: the following assumes an instruction fits an int */
  243             db_expr_t ins = db_get_task_value(pc, sizeof(int), FALSE, task);
  244 
  245             /* continue until call or return */
  246 
  247             if (!inst_call(ins) &&
  248                 !inst_return(ins) &&
  249                 !inst_trap_return(ins)) {
  250                 return FALSE;   /* continue */
  251             }
  252         }
  253         if (db_find_breakpoint_here(task, pc))
  254             return FALSE;
  255 
  256         db_run_mode = STEP_NONE;
  257         return TRUE;
  258 }
  259 
  260 void
  261 db_restart_at_pc(
  262         boolean_t watchpt,
  263         task_t    task)
  264 {
  265         register db_addr_t pc = PC_REGS(DDB_REGS);
  266 
  267         if ((db_run_mode == STEP_COUNT) ||
  268             (db_run_mode == STEP_RETURN) ||
  269             (db_run_mode == STEP_CALLT)) {
  270             db_expr_t           ins;
  271 
  272             /*
  273              * We are about to execute this instruction,
  274              * so count it now.
  275              */
  276 
  277             ins = db_get_task_value(pc, sizeof(int), FALSE, task);
  278             db_inst_count++;
  279             db_load_count += inst_load(ins);
  280             db_store_count += inst_store(ins);
  281 #ifdef  SOFTWARE_SSTEP
  282             /* Account for instructions in delay slots */
  283         {
  284             db_addr_t brpc;
  285 
  286             brpc = next_instr_address(pc,1,task);
  287             if ((brpc != pc) && (inst_branch(ins) || inst_call(ins))) {
  288                 /* Note: this ~assumes an instruction <= sizeof(int) */
  289                 ins = db_get_task_value(brpc, sizeof(int), FALSE, task);
  290                 db_inst_count++;
  291                 db_load_count += inst_load(ins);
  292                 db_store_count += inst_store(ins);
  293             }
  294         }
  295 #endif  /* SOFTWARE_SSTEP */
  296         }
  297 
  298         if (db_run_mode == STEP_CONTINUE) {
  299             if (watchpt || db_find_breakpoint_here(task, pc)) {
  300                 /*
  301                  * Step over breakpoint/watchpoint.
  302                  */
  303                 db_run_mode = STEP_INVISIBLE;
  304                 db_set_task_single_step(DDB_REGS, task);
  305             } else {
  306                 db_set_breakpoints();
  307                 db_set_watchpoints();
  308             }
  309         } else {
  310             db_set_task_single_step(DDB_REGS, task);
  311         }
  312 }
  313 
  314 void
  315 db_single_step(
  316         db_regs_t *regs,
  317         task_t    task)
  318 {
  319         if (db_run_mode == STEP_CONTINUE) {
  320             db_run_mode = STEP_INVISIBLE;
  321             db_set_task_single_step(regs, task);
  322         }
  323 }
  324 
  325 #ifdef  SOFTWARE_SSTEP
  326 /*
  327  *      Software implementation of single-stepping.
  328  *      If your machine does not have a trace mode
  329  *      similar to the vax or sun ones you can use
  330  *      this implementation, done for the mips.
  331  *      Just define the above conditional and provide
  332  *      the functions/macros defined below.
  333  *
  334  * extern boolean_t
  335  *      inst_branch(),          returns true if the instruction might branch
  336  * extern unsigned
  337  *      branch_taken(),         return the address the instruction might
  338  *                              branch to
  339  *      db_getreg_val();        return the value of a user register,
  340  *                              as indicated in the hardware instruction
  341  *                              encoding, e.g. 8 for r8
  342  *                      
  343  * next_instr_address(pc,bd,task) returns the address of the first
  344  *                              instruction following the one at "pc",
  345  *                              which is either in the taken path of
  346  *                              the branch (bd==1) or not.  This is
  347  *                              for machines (mips) with branch delays.
  348  *
  349  *      A single-step may involve at most 2 breakpoints -
  350  *      one for branch-not-taken and one for branch taken.
  351  *      If one of these addresses does not already have a breakpoint,
  352  *      we allocate a breakpoint and save it here.
  353  *      These breakpoints are deleted on return.
  354  */                     
  355 db_breakpoint_t db_not_taken_bkpt = 0;
  356 db_breakpoint_t db_taken_bkpt = 0;
  357 
  358 db_breakpoint_t
  359 db_find_temp_breakpoint(
  360         task_t             task,
  361         db_addr_t          addr)
  362 {
  363         if (db_taken_bkpt && (db_taken_bkpt->address == addr) &&
  364             db_taken_bkpt->task == task)
  365                 return db_taken_bkpt;
  366         if (db_not_taken_bkpt && (db_not_taken_bkpt->address == addr) &&
  367             db_not_taken_bkpt->task == task)
  368                 return db_not_taken_bkpt;
  369         return 0;
  370 }
  371 
  372 void
  373 db_set_task_single_step(
  374         register db_regs_t *regs,
  375         task_t             task)
  376 {
  377         db_addr_t pc = PC_REGS(regs), brpc;
  378         register unsigned int    inst;
  379         register boolean_t       unconditional;
  380 
  381         /*
  382          *      User was stopped at pc, e.g. the instruction
  383          *      at pc was not executed.
  384          */
  385         inst = db_get_task_value(pc, sizeof(int), FALSE, task);
  386         if (inst_branch(inst) || inst_call(inst)) {
  387             extern db_expr_t getreg_val(unsigned int regno,
  388                                         db_regs_t *regs);
  389 
  390             brpc = branch_taken(inst, pc, getreg_val, regs);
  391             if (brpc != pc) {   /* self-branches are hopeless */
  392                 db_taken_bkpt = db_set_temp_breakpoint(task, brpc);
  393             } else
  394                 db_taken_bkpt = 0;
  395             pc = next_instr_address(pc,1,task);
  396         }
  397         
  398         /* check if this control flow instruction is an unconditional transfer */
  399         unconditional = inst_unconditional_flow_transfer(inst);
  400 
  401         pc = next_instr_address(pc,0,task);
  402         /* 
  403           We only set the sequential breakpoint if previous instruction was not
  404           an unconditional change of flow of control. If the previous instruction
  405           is an unconditional change of flow of control, setting a breakpoint in the
  406           next sequential location may set a breakpoint in data or in another routine,
  407           which could screw up either the program or the debugger. 
  408           (Consider, for instance, that the next sequential instruction is the 
  409           start of a routine needed by the debugger.)
  410         */
  411         if (!unconditional && db_find_breakpoint_here(task, pc) == 0) {
  412             db_not_taken_bkpt = db_set_temp_breakpoint(task, pc);
  413         }
  414         else
  415             db_not_taken_bkpt = 0;
  416 }
  417 
  418 void
  419 db_clear_task_single_step(
  420         db_regs_t *regs,
  421         task_t    task)
  422 {
  423         if (db_taken_bkpt != 0) {
  424             db_delete_temp_breakpoint(task, db_taken_bkpt);
  425             db_taken_bkpt = 0;
  426         }
  427         if (db_not_taken_bkpt != 0) {
  428             db_delete_temp_breakpoint(task, db_not_taken_bkpt);
  429             db_not_taken_bkpt = 0;
  430         }
  431 }
  432 
  433 #endif  /* SOFTWARE_SSTEP */
  434 
  435 
  436 extern int      db_cmd_loop_done;
  437 
  438 /* single-step */
  439 /*ARGSUSED*/
  440 void
  441 db_single_step_cmd(
  442         db_expr_t       addr,
  443         int             have_addr,
  444         db_expr_t       count,
  445         char *          modif)
  446 {
  447         boolean_t       print = FALSE;
  448 
  449         if (count == -1)
  450             count = 1;
  451 
  452         if (modif[0] == 'p')
  453             print = TRUE;
  454 
  455         db_run_mode = STEP_ONCE;
  456         db_loop_count = count;
  457         db_sstep_print = print;
  458         db_inst_count = 0;
  459         db_last_inst_count = 0;
  460         db_load_count = 0;
  461         db_store_count = 0;
  462 
  463         db_cmd_loop_done = 1;
  464 }
  465 
  466 /* trace and print until call/return */
  467 /*ARGSUSED*/
  468 void
  469 db_trace_until_call_cmd(
  470         db_expr_t       addr,
  471         int             have_addr,
  472         db_expr_t       count,
  473         char *          modif)
  474 {
  475         boolean_t       print = FALSE;
  476 
  477         if (modif[0] == 'p')
  478             print = TRUE;
  479 
  480         db_run_mode = STEP_CALLT;
  481         db_sstep_print = print;
  482         db_inst_count = 0;
  483         db_last_inst_count = 0;
  484         db_load_count = 0;
  485         db_store_count = 0;
  486 
  487         db_cmd_loop_done = 1;
  488 }
  489 
  490 /*ARGSUSED*/
  491 void
  492 db_trace_until_matching_cmd(
  493         db_expr_t       addr,
  494         int             have_addr,
  495         db_expr_t       count,
  496         char *          modif)
  497 {
  498         boolean_t       print = FALSE;
  499 
  500         if (modif[0] == 'p')
  501             print = TRUE;
  502 
  503         db_run_mode = STEP_RETURN;
  504         db_call_depth = 1;
  505         db_sstep_print = print;
  506         db_inst_count = 0;
  507         db_last_inst_count = 0;
  508         db_load_count = 0;
  509         db_store_count = 0;
  510 
  511         db_cmd_loop_done = 1;
  512 }
  513 
  514 /* continue */
  515 /*ARGSUSED*/
  516 void
  517 db_continue_cmd(
  518         db_expr_t       addr,
  519         int             have_addr,
  520         db_expr_t       count,
  521         char *          modif)
  522 {
  523         if (modif[0] == 'c')
  524             db_run_mode = STEP_COUNT;
  525         else
  526             db_run_mode = STEP_CONTINUE;
  527         db_inst_count = 0;
  528         db_last_inst_count = 0;
  529         db_load_count = 0;
  530         db_store_count = 0;
  531 
  532         db_cmd_loop_done = 1;
  533 }
  534 
  535 boolean_t
  536 db_in_single_step(void)
  537 {
  538         return (db_run_mode != STEP_NONE && db_run_mode != STEP_CONTINUE);
  539 }

Cache object: af85bdc21ff5865a39a015cdf4d76536


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