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 /*      $NetBSD: db_run.c,v 1.22 2002/02/15 07:33:52 simonb Exp $       */
    2 
    3 /*
    4  * Mach Operating System
    5  * Copyright (c) 1993-1990 Carnegie Mellon University
    6  * All Rights Reserved.
    7  *
    8  * Permission to use, copy, modify and distribute this software and its
    9  * documentation is hereby granted, provided that both the copyright
   10  * notice and this permission notice appear in all copies of the
   11  * software, derivative works or modified versions, and any portions
   12  * thereof, and that both notices appear in supporting documentation.
   13  *
   14  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
   15  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
   16  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
   17  *
   18  * Carnegie Mellon requests users of this software to return to
   19  *
   20  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
   21  *  School of Computer Science
   22  *  Carnegie Mellon University
   23  *  Pittsburgh PA 15213-3890
   24  *
   25  * any improvements or extensions that they make and grant Carnegie the
   26  * rights to redistribute these changes.
   27  *
   28  *      Author: David B. Golub, Carnegie Mellon University
   29  *      Date:   7/90
   30  */
   31 
   32 /*
   33  * Commands to run process.
   34  */
   35 
   36 #include <sys/cdefs.h>
   37 __KERNEL_RCSID(0, "$NetBSD: db_run.c,v 1.22 2002/02/15 07:33:52 simonb Exp $");
   38 
   39 #include "opt_ddb.h"
   40 
   41 #include <sys/param.h>
   42 #include <sys/proc.h>
   43 
   44 #include <machine/db_machdep.h>
   45 
   46 #include <ddb/db_run.h>
   47 #include <ddb/db_access.h>
   48 #include <ddb/db_break.h>
   49 
   50 int     db_inst_count;
   51 int     db_load_count;
   52 int     db_store_count;
   53 
   54 #ifdef  SOFTWARE_SSTEP
   55 static void     db_set_temp_breakpoint(db_breakpoint_t, db_addr_t);
   56 static void     db_delete_temp_breakpoint(db_breakpoint_t);
   57 static struct   db_breakpoint   db_not_taken_bkpt;
   58 static struct   db_breakpoint   db_taken_bkpt;
   59 #endif
   60 
   61 #if defined(DDB)
   62 #include <ddb/db_lex.h>
   63 #include <ddb/db_watch.h>
   64 #include <ddb/db_output.h>
   65 #include <ddb/db_sym.h>
   66 #include <ddb/db_extern.h>
   67 
   68 static int      db_run_mode;
   69 #define STEP_NONE       0
   70 #define STEP_ONCE       1
   71 #define STEP_RETURN     2
   72 #define STEP_CALLT      3
   73 #define STEP_CONTINUE   4
   74 #define STEP_INVISIBLE  5
   75 #define STEP_COUNT      6
   76 
   77 static boolean_t        db_sstep_print;
   78 static int              db_loop_count;
   79 static int              db_call_depth;
   80 
   81 boolean_t
   82 db_stop_at_pc(db_regs_t *regs, boolean_t *is_breakpoint)
   83 {
   84         db_addr_t       pc;
   85         db_breakpoint_t bkpt;
   86 
   87         pc = PC_REGS(regs);
   88 
   89 #ifdef  FIXUP_PC_AFTER_BREAK
   90         if (*is_breakpoint) {
   91                 /*
   92                  * Breakpoint trap.  Regardless if we treat this as a
   93                  * real breakpoint (e.g. software single-step), fix up the PC.
   94                  */
   95                 FIXUP_PC_AFTER_BREAK(regs);
   96                 pc = PC_REGS(regs);
   97         }
   98 #endif
   99 
  100 #ifdef  SOFTWARE_SSTEP
  101         /*
  102          * If we stopped at one of the single-step breakpoints, say it's not
  103          * really a breakpoint so that we don't skip over the real instruction.
  104          */
  105         if (db_taken_bkpt.address == pc || db_not_taken_bkpt.address == pc)
  106                 *is_breakpoint = FALSE;
  107 #endif  /* SOFTWARE_SSTEP */
  108 
  109         db_clear_single_step(regs);
  110         db_clear_breakpoints();
  111         db_clear_watchpoints();
  112 
  113         /*
  114          * Now check for a breakpoint at this address.
  115          */
  116         bkpt = db_find_breakpoint_here(pc);
  117         if (bkpt) {
  118                 if (--bkpt->count == 0) {
  119                         bkpt->count = bkpt->init_count;
  120                         *is_breakpoint = TRUE;
  121                         return (TRUE);  /* stop here */
  122                 }
  123         } else if (*is_breakpoint) {
  124 #ifdef PC_ADVANCE
  125                 PC_ADVANCE(regs);
  126 #else
  127                 PC_REGS(regs) += BKPT_SIZE;
  128 #endif
  129         }
  130 
  131         *is_breakpoint = FALSE;
  132 
  133         if (db_run_mode == STEP_INVISIBLE) {
  134                 db_run_mode = STEP_CONTINUE;
  135                 return (FALSE); /* continue */
  136         }
  137         if (db_run_mode == STEP_COUNT) {
  138                 return (FALSE); /* continue */
  139         }
  140         if (db_run_mode == STEP_ONCE) {
  141                 if (--db_loop_count > 0) {
  142                         if (db_sstep_print) {
  143                                 db_printf("\t\t");
  144                                 db_print_loc_and_inst(pc);
  145                                 db_printf("\n");
  146                         }
  147                         return (FALSE); /* continue */
  148                 }
  149         }
  150         if (db_run_mode == STEP_RETURN) {
  151                 db_expr_t ins = db_get_value(pc, sizeof(int), FALSE);
  152 
  153                 /* continue until matching return */
  154 
  155                 if (!inst_trap_return(ins) &&
  156                     (!inst_return(ins) || --db_call_depth != 0)) {
  157                         if (db_sstep_print) {
  158                                 if (inst_call(ins) || inst_return(ins)) {
  159                                         int i;
  160 
  161                                         db_printf("[after %6d]     ",
  162                                             db_inst_count);
  163                                         for (i = db_call_depth; --i > 0; )
  164                                                 db_printf("  ");
  165                                         db_print_loc_and_inst(pc);
  166                                         db_printf("\n");
  167                                 }
  168                         }
  169                         if (inst_call(ins))
  170                                 db_call_depth++;
  171                         return (FALSE); /* continue */
  172                 }
  173         }
  174         if (db_run_mode == STEP_CALLT) {
  175                 db_expr_t ins = db_get_value(pc, sizeof(int), FALSE);
  176 
  177                 /* continue until call or return */
  178 
  179                 if (!inst_call(ins) &&
  180                     !inst_return(ins) &&
  181                     !inst_trap_return(ins)) {
  182                         return (FALSE); /* continue */
  183                 }
  184         }
  185         db_run_mode = STEP_NONE;
  186         return (TRUE);
  187 }
  188 
  189 void
  190 db_restart_at_pc(db_regs_t *regs, boolean_t watchpt)
  191 {
  192         db_addr_t pc = PC_REGS(regs);
  193 #ifdef SOFTWARE_SSTEP
  194         db_addr_t brpc;
  195 #endif
  196 
  197         if ((db_run_mode == STEP_COUNT) ||
  198             (db_run_mode == STEP_RETURN) ||
  199             (db_run_mode == STEP_CALLT)) {
  200                 db_expr_t               ins;
  201 
  202                 /*
  203                  * We are about to execute this instruction,
  204                  * so count it now.
  205                  */
  206                 ins = db_get_value(pc, sizeof(int), FALSE);
  207                 db_inst_count++;
  208                 db_load_count += inst_load(ins);
  209                 db_store_count += inst_store(ins);
  210 
  211 #ifdef SOFTWARE_SSTEP
  212                 /*
  213                  * Account for instructions in delay slots.
  214                  */
  215                 brpc = next_instr_address(pc, TRUE);
  216                 if ((brpc != pc) &&
  217                     (inst_branch(ins) || inst_call(ins) || inst_return(ins))) {
  218                         ins = db_get_value(brpc, sizeof(int), FALSE);
  219                         db_inst_count++;
  220                         db_load_count += inst_load(ins);
  221                         db_store_count += inst_store(ins);
  222                 }
  223 #endif
  224         }
  225 
  226         if (db_run_mode == STEP_CONTINUE) {
  227                 if (watchpt || db_find_breakpoint_here(pc)) {
  228                         /*
  229                          * Step over breakpoint/watchpoint.
  230                          */
  231                         db_run_mode = STEP_INVISIBLE;
  232                         db_set_single_step(regs);
  233                 } else {
  234                         db_set_breakpoints();
  235                         db_set_watchpoints();
  236                 }
  237         } else {
  238                 db_set_single_step(regs);
  239         }
  240 }
  241 
  242 void
  243 db_single_step(db_regs_t *regs)
  244 {
  245 
  246         if (db_run_mode == STEP_CONTINUE) {
  247                 db_run_mode = STEP_INVISIBLE;
  248                 db_set_single_step(regs);
  249         }
  250 }
  251 
  252 /* single-step */
  253 /*ARGSUSED*/
  254 void
  255 db_single_step_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
  256 {
  257         boolean_t print = FALSE;
  258 
  259         if (count == -1)
  260                 count = 1;
  261 
  262         if (modif[0] == 'p')
  263                 print = TRUE;
  264 
  265         db_run_mode = STEP_ONCE;
  266         db_loop_count = count;
  267         db_sstep_print = print;
  268         db_inst_count = 0;
  269         db_load_count = 0;
  270         db_store_count = 0;
  271 
  272         db_cmd_loop_done = 1;
  273 }
  274 
  275 /* trace and print until call/return */
  276 /*ARGSUSED*/
  277 void
  278 db_trace_until_call_cmd(db_expr_t addr, int have_addr, db_expr_t count,
  279     char *modif)
  280 {
  281         boolean_t print = FALSE;
  282 
  283         if (modif[0] == 'p')
  284                 print = TRUE;
  285 
  286         db_run_mode = STEP_CALLT;
  287         db_sstep_print = print;
  288         db_inst_count = 0;
  289         db_load_count = 0;
  290         db_store_count = 0;
  291 
  292         db_cmd_loop_done = 1;
  293 }
  294 
  295 /*ARGSUSED*/
  296 void
  297 db_trace_until_matching_cmd(db_expr_t addr, int have_addr, db_expr_t count,
  298     char *modif)
  299 {
  300         boolean_t print = FALSE;
  301 
  302         if (modif[0] == 'p')
  303                 print = TRUE;
  304 
  305         db_run_mode = STEP_RETURN;
  306         db_call_depth = 1;
  307         db_sstep_print = print;
  308         db_inst_count = 0;
  309         db_load_count = 0;
  310         db_store_count = 0;
  311 
  312         db_cmd_loop_done = 1;
  313 }
  314 
  315 /* continue */
  316 /*ARGSUSED*/
  317 void
  318 db_continue_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
  319 {
  320 
  321         if (modif[0] == 'c')
  322                 db_run_mode = STEP_COUNT;
  323         else
  324                 db_run_mode = STEP_CONTINUE;
  325         db_inst_count = 0;
  326         db_load_count = 0;
  327         db_store_count = 0;
  328 
  329         db_cmd_loop_done = 1;
  330 }
  331 #endif /* DDB */
  332 
  333 #ifdef SOFTWARE_SSTEP
  334 /*
  335  *      Software implementation of single-stepping.
  336  *      If your machine does not have a trace mode
  337  *      similar to the vax or sun ones you can use
  338  *      this implementation, done for the mips.
  339  *      Just define the above conditional and provide
  340  *      the functions/macros defined below.
  341  *
  342  * boolean_t inst_branch(int inst)
  343  * boolean_t inst_call(int inst)
  344  *      returns TRUE if the instruction might branch
  345  *
  346  * boolean_t inst_unconditional_flow_transfer(int inst)
  347  *      returns TRUE if the instruction is an unconditional
  348  *      transter of flow (i.e. unconditional branch)
  349  *
  350  * db_addr_t branch_taken(int inst, db_addr_t pc, db_regs_t *regs)
  351  *      returns the target address of the branch
  352  *
  353  * db_addr_t next_instr_address(db_addr_t pc, boolean_t bd)
  354  *      returns the address of the first instruction following the
  355  *      one at "pc", which is either in the taken path of the branch
  356  *      (bd == TRUE) or not.  This is for machines (e.g. mips) with
  357  *      branch delays.
  358  *
  359  *      A single-step may involve at most 2 breakpoints -
  360  *      one for branch-not-taken and one for branch taken.
  361  *      If one of these addresses does not already have a breakpoint,
  362  *      we allocate a breakpoint and save it here.
  363  *      These breakpoints are deleted on return.
  364  */
  365 
  366 #if !defined(DDB)
  367 /* XXX - don't check for existing breakpoints in KGDB-only case */
  368 #define db_find_breakpoint_here(pc)     (0)
  369 #endif
  370 
  371 void
  372 db_set_single_step(db_regs_t *regs)
  373 {
  374         db_addr_t pc = PC_REGS(regs), brpc = pc;
  375         boolean_t unconditional;
  376         unsigned int inst;
  377 
  378         /*
  379          *      User was stopped at pc, e.g. the instruction
  380          *      at pc was not executed.
  381          */
  382         inst = db_get_value(pc, sizeof(int), FALSE);
  383         if (inst_branch(inst) || inst_call(inst) || inst_return(inst)) {
  384                 brpc = branch_taken(inst, pc, regs);
  385                 if (brpc != pc) {       /* self-branches are hopeless */
  386                         db_set_temp_breakpoint(&db_taken_bkpt, brpc);
  387                 } else
  388                         db_taken_bkpt.address = 0;
  389                 pc = next_instr_address(pc, TRUE);
  390         }
  391 
  392         /*
  393          *      Check if this control flow instruction is an
  394          *      unconditional transfer.
  395          */
  396         unconditional = inst_unconditional_flow_transfer(inst);
  397 
  398         pc = next_instr_address(pc, FALSE);
  399 
  400         /*
  401          *      We only set the sequential breakpoint if previous
  402          *      instruction was not an unconditional change of flow
  403          *      control.  If the previous instruction is an
  404          *      unconditional change of flow control, setting a
  405          *      breakpoint in the next sequential location may set
  406          *      a breakpoint in data or in another routine, which
  407          *      could screw up in either the program or the debugger.
  408          *      (Consider, for instance, that the next sequential
  409          *      instruction is the start of a routine needed by the
  410          *      debugger.)
  411          *
  412          *      Also, don't set both the taken and not-taken breakpoints
  413          *      in the same place even if the MD code would otherwise
  414          *      have us do so.
  415          */
  416         if (unconditional == FALSE &&
  417             db_find_breakpoint_here(pc) == 0 &&
  418             pc != brpc)
  419                 db_set_temp_breakpoint(&db_not_taken_bkpt, pc);
  420         else
  421                 db_not_taken_bkpt.address = 0;
  422 }
  423 
  424 void
  425 db_clear_single_step(db_regs_t *regs)
  426 {
  427 
  428         if (db_taken_bkpt.address != 0)
  429                 db_delete_temp_breakpoint(&db_taken_bkpt);
  430 
  431         if (db_not_taken_bkpt.address != 0)
  432                 db_delete_temp_breakpoint(&db_not_taken_bkpt);
  433 }
  434 
  435 void
  436 db_set_temp_breakpoint(db_breakpoint_t bkpt, db_addr_t addr)
  437 {
  438 
  439         bkpt->map = NULL;
  440         bkpt->address = addr;
  441         /* bkpt->flags = BKPT_TEMP;     - this is not used */
  442         bkpt->init_count = 1;
  443         bkpt->count = 1;
  444 
  445         bkpt->bkpt_inst = db_get_value(bkpt->address, BKPT_SIZE, FALSE);
  446         db_put_value(bkpt->address, BKPT_SIZE, BKPT_SET(bkpt->bkpt_inst));
  447 }
  448 
  449 void
  450 db_delete_temp_breakpoint(db_breakpoint_t bkpt)
  451 {
  452 
  453         db_put_value(bkpt->address, BKPT_SIZE, bkpt->bkpt_inst);
  454         bkpt->address = 0;
  455 }
  456 #endif /* SOFTWARE_SSTEP */

Cache object: 509cee2f7f8a6d9a758639f59c6eec74


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