LCOV - code coverage report
Current view: top level - ddb - db_run.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 112 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 7 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*      $OpenBSD: db_run.c,v 1.27 2017/04/30 13:04:49 mpi 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             : boolean_t       db_sstep_print;
      67             : int             db_loop_count;
      68             : int             db_call_depth;
      69             : 
      70             : boolean_t
      71           0 : db_stop_at_pc(db_regs_t *regs, boolean_t *is_breakpoint)
      72             : {
      73             :         db_addr_t       pc, old_pc;
      74             :         db_breakpoint_t bkpt;
      75             : 
      76           0 :         db_clear_breakpoints();
      77           0 :         db_clear_watchpoints();
      78           0 :         old_pc = pc = PC_REGS(regs);
      79             : 
      80             : #ifdef  FIXUP_PC_AFTER_BREAK
      81           0 :         if (*is_breakpoint) {
      82             :                 /*
      83             :                  * Breakpoint trap.  Fix up the PC if the
      84             :                  * machine requires it.
      85             :                  */
      86           0 :                 FIXUP_PC_AFTER_BREAK(regs);
      87             :                 pc = PC_REGS(regs);
      88           0 :         }
      89             : #endif
      90             : 
      91             :         /*
      92             :          * Now check for a breakpoint at this address.
      93             :          */
      94           0 :         bkpt = db_find_breakpoint(pc);
      95           0 :         if (bkpt) {
      96           0 :                 if (--bkpt->count == 0) {
      97           0 :                         db_clear_single_step(regs);
      98           0 :                         bkpt->count = bkpt->init_count;
      99           0 :                         *is_breakpoint = TRUE;
     100           0 :                         return (TRUE);  /* stop here */
     101             :                 }
     102           0 :         } 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           0 :                 SET_PC_REGS(regs, old_pc);
     113             : # else
     114             :                 PC_REGS(regs) = old_pc;
     115             : # endif
     116             : #endif
     117           0 :         }
     118           0 :         db_clear_single_step(regs);
     119             : 
     120           0 :         *is_breakpoint = FALSE;
     121             : 
     122           0 :         if (db_run_mode == STEP_INVISIBLE) {
     123           0 :                 db_run_mode = STEP_CONTINUE;
     124           0 :                 return (FALSE); /* continue */
     125             :         }
     126           0 :         if (db_run_mode == STEP_COUNT) {
     127           0 :                 return (FALSE); /* continue */
     128             :         }
     129           0 :         if (db_run_mode == STEP_ONCE) {
     130           0 :                 if (--db_loop_count > 0) {
     131           0 :                         if (db_sstep_print) {
     132           0 :                                 db_printf("\t\t");
     133           0 :                                 db_print_loc_and_inst(pc);
     134           0 :                                 db_printf("\n");
     135           0 :                         }
     136           0 :                         return (FALSE); /* continue */
     137             :                 }
     138             :         }
     139           0 :         if (db_run_mode == STEP_RETURN) {
     140           0 :             db_expr_t ins = db_get_value(pc, sizeof(int), FALSE);
     141             : 
     142             :             /* continue until matching return */
     143             : 
     144           0 :             if (!inst_trap_return(ins) &&
     145           0 :                 (!inst_return(ins) || --db_call_depth != 0)) {
     146           0 :                 if (db_sstep_print) {
     147           0 :                     if (inst_call(ins) || inst_return(ins)) {
     148             :                         int i;
     149             : 
     150           0 :                         db_printf("[after %6d]     ", db_inst_count);
     151           0 :                         for (i = db_call_depth; --i > 0; )
     152           0 :                             db_printf("  ");
     153           0 :                         db_print_loc_and_inst(pc);
     154           0 :                         db_printf("\n");
     155           0 :                     }
     156             :                 }
     157           0 :                 if (inst_call(ins))
     158           0 :                     db_call_depth++;
     159           0 :                 return (FALSE); /* continue */
     160             :             }
     161           0 :         }
     162           0 :         if (db_run_mode == STEP_CALLT) {
     163           0 :             db_expr_t ins = db_get_value(pc, sizeof(int), FALSE);
     164             : 
     165             :             /* continue until call or return */
     166             : 
     167           0 :             if (!inst_call(ins) && !inst_return(ins) &&
     168           0 :                 !inst_trap_return(ins)) {
     169           0 :                 return (FALSE); /* continue */
     170             :             }
     171           0 :         }
     172           0 :         db_run_mode = STEP_NONE;
     173           0 :         return (TRUE);
     174           0 : }
     175             : 
     176             : void
     177           0 : db_restart_at_pc(db_regs_t *regs, boolean_t watchpt)
     178             : {
     179           0 :         db_addr_t pc = PC_REGS(regs);
     180             : 
     181           0 :         if ((db_run_mode == STEP_COUNT) || (db_run_mode == STEP_RETURN) ||
     182           0 :             (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           0 :                 ins = db_get_value(pc, sizeof(int), FALSE);
     190           0 :                 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), FALSE);
     196             :                         db_inst_count++;
     197             :                 }
     198             : #endif  /* SOFTWARE_SSTEP */
     199           0 :         }
     200             : 
     201           0 :         if (db_run_mode == STEP_CONTINUE) {
     202           0 :                 if (watchpt || db_find_breakpoint(pc)) {
     203             :                         /*
     204             :                          * Step over breakpoint/watchpoint.
     205             :                          */
     206           0 :                         db_run_mode = STEP_INVISIBLE;
     207           0 :                         db_set_single_step(regs);
     208           0 :                 } else {
     209           0 :                         db_set_breakpoints();
     210           0 :                         db_set_watchpoints();
     211             :                 }
     212             :         } else {
     213           0 :                 db_set_single_step(regs);
     214             :         }
     215           0 : }
     216             : 
     217             : void
     218           0 : db_single_step(db_regs_t *regs)
     219             : {
     220           0 :         if (db_run_mode == STEP_CONTINUE) {
     221           0 :             db_run_mode = STEP_INVISIBLE;
     222           0 :             db_set_single_step(regs);
     223           0 :         }
     224           0 : }
     225             : 
     226             : /* single-step */
     227             : /*ARGSUSED*/
     228             : void
     229           0 : db_single_step_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
     230             : {
     231             :         boolean_t       print = FALSE;
     232             : 
     233           0 :         if (count == -1)
     234           0 :             count = 1;
     235             : 
     236           0 :         if (modif[0] == 'p')
     237           0 :             print = TRUE;
     238             : 
     239           0 :         db_run_mode = STEP_ONCE;
     240           0 :         db_loop_count = count;
     241           0 :         db_sstep_print = print;
     242           0 :         db_inst_count = 0;
     243             : 
     244           0 :         db_cmd_loop_done = 1;
     245           0 : }
     246             : 
     247             : /* trace and print until call/return */
     248             : /*ARGSUSED*/
     249             : void
     250           0 : db_trace_until_call_cmd(db_expr_t addr, int have_addr, db_expr_t count,
     251             :     char *modif)
     252             : {
     253             :         boolean_t       print = FALSE;
     254             : 
     255           0 :         if (modif[0] == 'p')
     256             :             print = TRUE;
     257             : 
     258           0 :         db_run_mode = STEP_CALLT;
     259           0 :         db_sstep_print = print;
     260           0 :         db_inst_count = 0;
     261             : 
     262           0 :         db_cmd_loop_done = 1;
     263           0 : }
     264             : 
     265             : /*ARGSUSED*/
     266             : void
     267           0 : db_trace_until_matching_cmd(db_expr_t addr, int have_addr, db_expr_t count,
     268             :     char *modif)
     269             : {
     270             :         boolean_t       print = FALSE;
     271             : 
     272           0 :         if (modif[0] == 'p')
     273             :             print = TRUE;
     274             : 
     275           0 :         db_run_mode = STEP_RETURN;
     276           0 :         db_call_depth = 1;
     277           0 :         db_sstep_print = print;
     278           0 :         db_inst_count = 0;
     279             : 
     280           0 :         db_cmd_loop_done = 1;
     281           0 : }
     282             : 
     283             : /* continue */
     284             : /*ARGSUSED*/
     285             : void
     286           0 : db_continue_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
     287             : {
     288           0 :         if (modif[0] == 'c')
     289           0 :             db_run_mode = STEP_COUNT;
     290             :         else
     291           0 :             db_run_mode = STEP_CONTINUE;
     292           0 :         db_inst_count = 0;
     293             : 
     294           0 :         db_cmd_loop_done = 1;
     295           0 : }
     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 boolean_t
     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             :         db_addr_t pc = PC_REGS(regs);
     333             : #ifndef SOFTWARE_SSTEP_EMUL
     334             :         db_addr_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), FALSE);
     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 */

Generated by: LCOV version 1.13