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