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

Cache object: 3a09e4a524feb1371c0dd9750a1df3a0


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