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.33 2014/09/19 17:29:01 matt 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.33 2014/09/19 17:29:01 matt 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 bool             db_sstep_print;
   78 static int              db_loop_count;
   79 static int              db_call_depth;
   80 
   81 bool
   82 db_stop_at_pc(db_regs_t *regs, bool *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, bool 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 __unused;
  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, bool have_addr,
  256     db_expr_t count, const char *modif)
  257 {
  258         bool print = false;
  259 
  260         if (count == -1)
  261                 count = 1;
  262 
  263         if (modif[0] == 'p')
  264                 print = true;
  265 
  266         db_run_mode = STEP_ONCE;
  267         db_loop_count = count;
  268         db_sstep_print = print;
  269         db_inst_count = 0;
  270         db_load_count = 0;
  271         db_store_count = 0;
  272 
  273         db_cmd_loop_done = true;
  274 }
  275 
  276 /* trace and print until call/return */
  277 /*ARGSUSED*/
  278 void
  279 db_trace_until_call_cmd(db_expr_t addr, bool have_addr,
  280     db_expr_t count, const char *modif)
  281 {
  282         bool print = false;
  283 
  284         if (modif[0] == 'p')
  285                 print = true;
  286 
  287         db_run_mode = STEP_CALLT;
  288         db_sstep_print = print;
  289         db_inst_count = 0;
  290         db_load_count = 0;
  291         db_store_count = 0;
  292 
  293         db_cmd_loop_done = true;
  294 }
  295 
  296 /*ARGSUSED*/
  297 void
  298 db_trace_until_matching_cmd(db_expr_t addr, bool have_addr,
  299     db_expr_t count, const char *modif)
  300 {
  301         bool print = false;
  302 
  303         if (modif[0] == 'p')
  304                 print = true;
  305 
  306         db_run_mode = STEP_RETURN;
  307         db_call_depth = 1;
  308         db_sstep_print = print;
  309         db_inst_count = 0;
  310         db_load_count = 0;
  311         db_store_count = 0;
  312 
  313         db_cmd_loop_done = true;
  314 }
  315 
  316 /* continue */
  317 /*ARGSUSED*/
  318 void
  319 db_continue_cmd(db_expr_t addr, bool have_addr,
  320     db_expr_t count, const char *modif)
  321 {
  322 
  323         if (modif[0] == 'c')
  324                 db_run_mode = STEP_COUNT;
  325         else
  326                 db_run_mode = STEP_CONTINUE;
  327         db_inst_count = 0;
  328         db_load_count = 0;
  329         db_store_count = 0;
  330 
  331         db_cmd_loop_done = true;
  332 }
  333 #endif /* DDB */
  334 
  335 #ifdef SOFTWARE_SSTEP
  336 /*
  337  *      Software implementation of single-stepping.
  338  *      If your machine does not have a trace mode
  339  *      similar to the vax or sun ones you can use
  340  *      this implementation, done for the mips.
  341  *      Just define the above conditional and provide
  342  *      the functions/macros defined below.
  343  *
  344  * bool inst_branch(int inst)
  345  * bool inst_call(int inst)
  346  *      returns true if the instruction might branch
  347  *
  348  * bool inst_return(int inst)
  349  *      returns true is the instruction will return to its caller
  350  *
  351  * bool inst_unconditional_flow_transfer(int inst)
  352  *      returns true if the instruction is an unconditional
  353  *      transter of flow (i.e. unconditional branch)
  354  *
  355  * db_addr_t branch_taken(int inst, db_addr_t pc, db_regs_t *regs)
  356  *      returns the target address of the branch
  357  *
  358  * db_addr_t next_instr_address(db_addr_t pc, bool bd)
  359  *      returns the address of the first instruction following the
  360  *      one at "pc", which is either in the taken path of the branch
  361  *      (bd == true) or not.  This is for machines (e.g. mips) with
  362  *      branch delays.
  363  *
  364  *      A single-step may involve at most 2 breakpoints -
  365  *      one for branch-not-taken and one for branch taken.
  366  *      If one of these addresses does not already have a breakpoint,
  367  *      we allocate a breakpoint and save it here.
  368  *      These breakpoints are deleted on return.
  369  */
  370 
  371 #if !defined(DDB)
  372 /* XXX - don't check for existing breakpoints in KGDB-only case */
  373 #define db_find_breakpoint_here(pc)     (0)
  374 #endif
  375 
  376 void
  377 db_set_single_step(db_regs_t *regs)
  378 {
  379         db_addr_t pc = PC_REGS(regs), brpc = pc;
  380         bool unconditional;
  381         unsigned int inst;
  382 
  383         /*
  384          *      User was stopped at pc, e.g. the instruction
  385          *      at pc was not executed.
  386          */
  387         inst = db_get_value(pc, sizeof(int), false);
  388         if (inst_branch(inst) || inst_call(inst) || inst_return(inst)) {
  389                 brpc = branch_taken(inst, pc, regs);
  390                 if (brpc != pc) {       /* self-branches are hopeless */
  391                         db_set_temp_breakpoint(&db_taken_bkpt, brpc);
  392                 } else
  393                         db_taken_bkpt.address = 0;
  394                 pc = next_instr_address(pc, true);
  395         }
  396 
  397         /*
  398          *      Check if this control flow instruction is an
  399          *      unconditional transfer.
  400          */
  401         unconditional = inst_unconditional_flow_transfer(inst);
  402 
  403         pc = next_instr_address(pc, false);
  404 
  405         /*
  406          *      We only set the sequential breakpoint if previous
  407          *      instruction was not an unconditional change of flow
  408          *      control.  If the previous instruction is an
  409          *      unconditional change of flow control, setting a
  410          *      breakpoint in the next sequential location may set
  411          *      a breakpoint in data or in another routine, which
  412          *      could screw up in either the program or the debugger.
  413          *      (Consider, for instance, that the next sequential
  414          *      instruction is the start of a routine needed by the
  415          *      debugger.)
  416          *
  417          *      Also, don't set both the taken and not-taken breakpoints
  418          *      in the same place even if the MD code would otherwise
  419          *      have us do so.
  420          */
  421         if (unconditional == false &&
  422             db_find_breakpoint_here(pc) == 0 &&
  423             pc != brpc)
  424                 db_set_temp_breakpoint(&db_not_taken_bkpt, pc);
  425         else
  426                 db_not_taken_bkpt.address = 0;
  427 }
  428 
  429 void
  430 db_clear_single_step(db_regs_t *regs)
  431 {
  432 
  433         if (db_taken_bkpt.address != 0)
  434                 db_delete_temp_breakpoint(&db_taken_bkpt);
  435 
  436         if (db_not_taken_bkpt.address != 0)
  437                 db_delete_temp_breakpoint(&db_not_taken_bkpt);
  438 }
  439 
  440 void
  441 db_set_temp_breakpoint(db_breakpoint_t bkpt, db_addr_t addr)
  442 {
  443 
  444         bkpt->map = NULL;
  445         bkpt->address = addr;
  446         /* bkpt->flags = BKPT_TEMP;     - this is not used */
  447         bkpt->init_count = 1;
  448         bkpt->count = 1;
  449 
  450         bkpt->bkpt_inst = db_get_value(bkpt->address, BKPT_SIZE, false);
  451         db_put_value(bkpt->address, BKPT_SIZE,
  452                 BKPT_SET(bkpt->bkpt_inst, bkpt->address));
  453 }
  454 
  455 void
  456 db_delete_temp_breakpoint(db_breakpoint_t bkpt)
  457 {
  458 
  459         db_put_value(bkpt->address, BKPT_SIZE, bkpt->bkpt_inst);
  460         bkpt->address = 0;
  461 }
  462 #endif /* SOFTWARE_SSTEP */

Cache object: b7158650db8498b92e03b4f02f1f81a1


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