]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - sys/ddb/db_run.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / sys / ddb / db_run.c
1 /*-
2  * Mach Operating System
3  * Copyright (c) 1991,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
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 the
24  * rights to redistribute these changes.
25  */
26 /*
27  *      Author: David B. Golub, Carnegie Mellon University
28  *      Date:   7/90
29  */
30
31 /*
32  * Commands to run process.
33  */
34
35 #include <sys/cdefs.h>
36 __FBSDID("$FreeBSD$");
37
38 #include <sys/param.h>
39 #include <sys/kdb.h>
40 #include <sys/proc.h>
41
42 #include <machine/kdb.h>
43 #include <machine/pcb.h>
44
45 #include <vm/vm.h>
46
47 #include <ddb/ddb.h>
48 #include <ddb/db_break.h>
49 #include <ddb/db_access.h>
50
51 static int      db_run_mode;
52 #define STEP_NONE       0
53 #define STEP_ONCE       1
54 #define STEP_RETURN     2
55 #define STEP_CALLT      3
56 #define STEP_CONTINUE   4
57 #define STEP_INVISIBLE  5
58 #define STEP_COUNT      6
59
60 static boolean_t        db_sstep_print;
61 static int              db_loop_count;
62 static int              db_call_depth;
63
64 int             db_inst_count;
65 int             db_load_count;
66 int             db_store_count;
67
68 #ifndef db_set_single_step
69 void db_set_single_step(void);
70 #endif
71 #ifndef db_clear_single_step
72 void db_clear_single_step(void);
73 #endif
74
75 #ifdef SOFTWARE_SSTEP
76 db_breakpoint_t db_not_taken_bkpt = 0;
77 db_breakpoint_t db_taken_bkpt = 0;
78 #endif
79
80 boolean_t
81 db_stop_at_pc(boolean_t *is_breakpoint)
82 {
83         register db_addr_t      pc;
84         register db_breakpoint_t bkpt;
85
86         pc = PC_REGS();
87 #ifdef SOFTWARE_SSTEP
88         if ((db_not_taken_bkpt != 0 && pc == db_not_taken_bkpt->address)
89             || (db_taken_bkpt != 0 && pc == db_taken_bkpt->address))
90                 *is_breakpoint = FALSE;
91 #endif
92
93         db_clear_single_step();
94         db_clear_breakpoints();
95         db_clear_watchpoints();
96
97 #ifdef  FIXUP_PC_AFTER_BREAK
98         if (*is_breakpoint) {
99             /*
100              * Breakpoint trap.  Fix up the PC if the
101              * machine requires it.
102              */
103             FIXUP_PC_AFTER_BREAK
104             pc = PC_REGS();
105         }
106 #endif
107
108         /*
109          * Now check for a breakpoint at this address.
110          */
111         bkpt = db_find_breakpoint_here(pc);
112         if (bkpt) {
113             if (--bkpt->count == 0) {
114                 bkpt->count = bkpt->init_count;
115                 *is_breakpoint = TRUE;
116                 return (TRUE);  /* stop here */
117             }
118         } else if (*is_breakpoint) {
119 #ifdef BKPT_SKIP
120                 BKPT_SKIP;
121 #endif
122         }
123
124         *is_breakpoint = FALSE;
125
126         if (db_run_mode == STEP_INVISIBLE) {
127             db_run_mode = STEP_CONTINUE;
128             return (FALSE);     /* continue */
129         }
130         if (db_run_mode == STEP_COUNT) {
131             return (FALSE); /* continue */
132         }
133         if (db_run_mode == STEP_ONCE) {
134             if (--db_loop_count > 0) {
135                 if (db_sstep_print) {
136                     db_printf("\t\t");
137                     db_print_loc_and_inst(pc);
138                     db_printf("\n");
139                 }
140                 return (FALSE); /* continue */
141             }
142         }
143         if (db_run_mode == STEP_RETURN) {
144             /* continue until matching return */
145             db_expr_t ins;
146
147             ins = db_get_value(pc, sizeof(int), FALSE);
148             if (!inst_trap_return(ins) &&
149                 (!inst_return(ins) || --db_call_depth != 0)) {
150                 if (db_sstep_print) {
151                     if (inst_call(ins) || inst_return(ins)) {
152                         register int i;
153
154                         db_printf("[after %6d]     ", db_inst_count);
155                         for (i = db_call_depth; --i > 0; )
156                             db_printf("  ");
157                         db_print_loc_and_inst(pc);
158                         db_printf("\n");
159                     }
160                 }
161                 if (inst_call(ins))
162                     db_call_depth++;
163                 return (FALSE); /* continue */
164             }
165         }
166         if (db_run_mode == STEP_CALLT) {
167             /* continue until call or return */
168             db_expr_t ins;
169
170             ins = db_get_value(pc, sizeof(int), FALSE);
171             if (!inst_call(ins) &&
172                 !inst_return(ins) &&
173                 !inst_trap_return(ins)) {
174                 return (FALSE); /* continue */
175             }
176         }
177         db_run_mode = STEP_NONE;
178         return (TRUE);
179 }
180
181 void
182 db_restart_at_pc(boolean_t watchpt)
183 {
184         register db_addr_t      pc = PC_REGS();
185
186         if ((db_run_mode == STEP_COUNT) ||
187             (db_run_mode == STEP_RETURN) ||
188             (db_run_mode == STEP_CALLT)) {
189             db_expr_t           ins;
190
191             /*
192              * We are about to execute this instruction,
193              * so count it now.
194              */
195
196             ins = db_get_value(pc, sizeof(int), FALSE);
197             db_inst_count++;
198             db_load_count += inst_load(ins);
199             db_store_count += inst_store(ins);
200 #ifdef  SOFTWARE_SSTEP
201             /* XXX works on mips, but... */
202             if (inst_branch(ins) || inst_call(ins)) {
203                 ins = db_get_value(next_instr_address(pc,1),
204                                    sizeof(int), FALSE);
205                 db_inst_count++;
206                 db_load_count += inst_load(ins);
207                 db_store_count += inst_store(ins);
208             }
209 #endif  /* SOFTWARE_SSTEP */
210         }
211
212         if (db_run_mode == STEP_CONTINUE) {
213             if (watchpt || db_find_breakpoint_here(pc)) {
214                 /*
215                  * Step over breakpoint/watchpoint.
216                  */
217                 db_run_mode = STEP_INVISIBLE;
218                 db_set_single_step();
219             } else {
220                 db_set_breakpoints();
221                 db_set_watchpoints();
222             }
223         } else {
224             db_set_single_step();
225         }
226 }
227
228 #ifdef  SOFTWARE_SSTEP
229 /*
230  *      Software implementation of single-stepping.
231  *      If your machine does not have a trace mode
232  *      similar to the vax or sun ones you can use
233  *      this implementation, done for the mips.
234  *      Just define the above conditional and provide
235  *      the functions/macros defined below.
236  *
237  * extern boolean_t
238  *      inst_branch(),          returns true if the instruction might branch
239  * extern unsigned
240  *      branch_taken(),         return the address the instruction might
241  *                              branch to
242  *      db_getreg_val();        return the value of a user register,
243  *                              as indicated in the hardware instruction
244  *                              encoding, e.g. 8 for r8
245  *
246  * next_instr_address(pc,bd)    returns the address of the first
247  *                              instruction following the one at "pc",
248  *                              which is either in the taken path of
249  *                              the branch (bd==1) or not.  This is
250  *                              for machines (mips) with branch delays.
251  *
252  *      A single-step may involve at most 2 breakpoints -
253  *      one for branch-not-taken and one for branch taken.
254  *      If one of these addresses does not already have a breakpoint,
255  *      we allocate a breakpoint and save it here.
256  *      These breakpoints are deleted on return.
257  */
258
259 void
260 db_set_single_step(void)
261 {
262         db_addr_t pc = PC_REGS(), brpc;
263         unsigned inst;
264
265         /*
266          *      User was stopped at pc, e.g. the instruction
267          *      at pc was not executed.
268          */
269         inst = db_get_value(pc, sizeof(int), FALSE);
270         if (inst_branch(inst) || inst_call(inst) || inst_return(inst)) {
271                 brpc = branch_taken(inst, pc);
272                 if (brpc != pc) {       /* self-branches are hopeless */
273                         db_taken_bkpt = db_set_temp_breakpoint(brpc);
274                 }
275                 pc = next_instr_address(pc, 1);
276         }
277         pc = next_instr_address(pc, 0);
278         db_not_taken_bkpt = db_set_temp_breakpoint(pc);
279 }
280
281 void
282 db_clear_single_step(void)
283 {
284
285         if (db_not_taken_bkpt != 0) {
286                 db_delete_temp_breakpoint(db_not_taken_bkpt);
287                 db_not_taken_bkpt = 0;
288         }
289         if (db_taken_bkpt != 0) {
290                 db_delete_temp_breakpoint(db_taken_bkpt);
291                 db_taken_bkpt = 0;
292         }
293 }
294
295 #endif  /* SOFTWARE_SSTEP */
296
297 extern int      db_cmd_loop_done;
298
299 /* single-step */
300 /*ARGSUSED*/
301 void
302 db_single_step_cmd(addr, have_addr, count, modif)
303         db_expr_t       addr;
304         boolean_t       have_addr;
305         db_expr_t       count;
306         char *          modif;
307 {
308         boolean_t       print = FALSE;
309
310         if (count == -1)
311             count = 1;
312
313         if (modif[0] == 'p')
314             print = TRUE;
315
316         db_run_mode = STEP_ONCE;
317         db_loop_count = count;
318         db_sstep_print = print;
319         db_inst_count = 0;
320         db_load_count = 0;
321         db_store_count = 0;
322
323         db_cmd_loop_done = 1;
324 }
325
326 /* trace and print until call/return */
327 /*ARGSUSED*/
328 void
329 db_trace_until_call_cmd(db_expr_t addr, boolean_t have_addr, db_expr_t count,
330     char *modif)
331 {
332         boolean_t       print = FALSE;
333
334         if (modif[0] == 'p')
335             print = TRUE;
336
337         db_run_mode = STEP_CALLT;
338         db_sstep_print = print;
339         db_inst_count = 0;
340         db_load_count = 0;
341         db_store_count = 0;
342
343         db_cmd_loop_done = 1;
344 }
345
346 /*ARGSUSED*/
347 void
348 db_trace_until_matching_cmd(db_expr_t addr, boolean_t have_addr,
349     db_expr_t count, char *modif)
350 {
351         boolean_t       print = FALSE;
352
353         if (modif[0] == 'p')
354             print = TRUE;
355
356         db_run_mode = STEP_RETURN;
357         db_call_depth = 1;
358         db_sstep_print = print;
359         db_inst_count = 0;
360         db_load_count = 0;
361         db_store_count = 0;
362
363         db_cmd_loop_done = 1;
364 }
365
366 /* continue */
367 /*ARGSUSED*/
368 void
369 db_continue_cmd(db_expr_t addr, boolean_t have_addr, db_expr_t count,
370     char *modif)
371 {
372         if (modif[0] == 'c')
373             db_run_mode = STEP_COUNT;
374         else
375             db_run_mode = STEP_CONTINUE;
376         db_inst_count = 0;
377         db_load_count = 0;
378         db_store_count = 0;
379
380         db_cmd_loop_done = 1;
381 }