Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/ddb/db_run.c
39476 views
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 [email protected]
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/param.h>
38
#include <sys/kdb.h>
39
#include <sys/proc.h>
40
#include <sys/reg.h>
41
#include <sys/systm.h>
42
43
#include <machine/kdb.h>
44
#include <machine/pcb.h>
45
46
#include <vm/vm.h>
47
48
#include <ddb/ddb.h>
49
#include <ddb/db_access.h>
50
#include <ddb/db_break.h>
51
#include <ddb/db_command.h>
52
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
static int db_run_mode = STEP_CONTINUE;
60
61
static bool db_sstep_multiple;
62
static bool db_sstep_print;
63
static int db_loop_count;
64
static int db_call_depth;
65
66
int db_inst_count;
67
int db_load_count;
68
int db_store_count;
69
70
bool
71
db_stop_at_pc(int type, int code, bool *is_breakpoint, bool *is_watchpoint)
72
{
73
db_addr_t pc;
74
db_breakpoint_t bkpt;
75
76
*is_breakpoint = IS_BREAKPOINT_TRAP(type, code);
77
*is_watchpoint = IS_WATCHPOINT_TRAP(type, code);
78
pc = PC_REGS();
79
80
db_clear_single_step();
81
db_clear_breakpoints();
82
db_clear_watchpoints();
83
84
#ifdef FIXUP_PC_AFTER_BREAK
85
if (*is_breakpoint) {
86
/*
87
* Breakpoint trap. Fix up the PC if the
88
* machine requires it.
89
*/
90
FIXUP_PC_AFTER_BREAK
91
pc = PC_REGS();
92
}
93
#endif
94
95
/*
96
* Now check for a breakpoint at this address.
97
*/
98
bkpt = db_find_breakpoint_here(pc);
99
if (bkpt) {
100
if (--bkpt->count == 0) {
101
bkpt->count = bkpt->init_count;
102
*is_breakpoint = true;
103
return (true); /* stop here */
104
}
105
return (false); /* continue the countdown */
106
} else if (*is_breakpoint) {
107
#ifdef BKPT_SKIP
108
BKPT_SKIP;
109
#endif
110
}
111
112
*is_breakpoint = false; /* might be a breakpoint, but not ours */
113
114
/*
115
* If not stepping, then silently ignore single-step traps
116
* (except for clearing the single-step-flag above).
117
*
118
* If stepping, then abort if the trap type is unexpected.
119
* Breakpoints owned by us are expected and were handled above.
120
* Single-steps are expected and are handled below. All others
121
* are unexpected.
122
*
123
* Only do either of these if the MD layer claims to classify
124
* single-step traps unambiguously (by defining IS_SSTEP_TRAP).
125
* Otherwise, fall through to the bad historical behaviour
126
* given by turning unexpected traps into expected traps: if not
127
* stepping, then expect only breakpoints and stop, and if
128
* stepping, then expect only single-steps and step.
129
*/
130
#ifdef IS_SSTEP_TRAP
131
if (db_run_mode == STEP_CONTINUE && IS_SSTEP_TRAP(type, code))
132
return (false);
133
if (db_run_mode != STEP_CONTINUE && !IS_SSTEP_TRAP(type, code)) {
134
printf("Stepping aborted\n");
135
return (true);
136
}
137
#endif
138
139
if (db_run_mode == STEP_INVISIBLE) {
140
db_run_mode = STEP_CONTINUE;
141
return (false); /* continue */
142
}
143
if (db_run_mode == STEP_COUNT) {
144
return (false); /* continue */
145
}
146
if (db_run_mode == STEP_ONCE) {
147
if (--db_loop_count > 0) {
148
if (db_sstep_print) {
149
db_printf("\t\t");
150
db_print_loc_and_inst(pc);
151
}
152
return (false); /* continue */
153
}
154
}
155
if (db_run_mode == STEP_RETURN) {
156
/* continue until matching return */
157
db_expr_t ins;
158
159
ins = db_get_value(pc, sizeof(int), false);
160
if (!inst_trap_return(ins) &&
161
(!inst_return(ins) || --db_call_depth != 0)) {
162
if (db_sstep_print) {
163
if (inst_call(ins) || inst_return(ins)) {
164
int i;
165
166
db_printf("[after %6d] ", db_inst_count);
167
for (i = db_call_depth; --i > 0; )
168
db_printf(" ");
169
db_print_loc_and_inst(pc);
170
}
171
}
172
if (inst_call(ins))
173
db_call_depth++;
174
return (false); /* continue */
175
}
176
}
177
if (db_run_mode == STEP_CALLT) {
178
/* continue until call or return */
179
db_expr_t ins;
180
181
ins = db_get_value(pc, sizeof(int), false);
182
if (!inst_call(ins) &&
183
!inst_return(ins) &&
184
!inst_trap_return(ins)) {
185
return (false); /* continue */
186
}
187
}
188
return (true);
189
}
190
191
void
192
db_restart_at_pc(bool watchpt)
193
{
194
db_addr_t pc = PC_REGS();
195
196
if ((db_run_mode == STEP_COUNT) ||
197
((db_run_mode == STEP_ONCE) && db_sstep_multiple) ||
198
(db_run_mode == STEP_RETURN) ||
199
(db_run_mode == STEP_CALLT)) {
200
/*
201
* We are about to execute this instruction,
202
* so count it now.
203
*/
204
db_get_value(pc, sizeof(int), false);
205
db_inst_count++;
206
db_load_count += inst_load(ins);
207
db_store_count += inst_store(ins);
208
}
209
210
if (db_run_mode == STEP_CONTINUE) {
211
if (watchpt || db_find_breakpoint_here(pc)) {
212
/*
213
* Step over breakpoint/watchpoint.
214
*/
215
db_run_mode = STEP_INVISIBLE;
216
db_set_single_step();
217
} else {
218
db_set_breakpoints();
219
db_set_watchpoints();
220
}
221
} else {
222
db_set_single_step();
223
}
224
}
225
226
/* single-step */
227
/*ARGSUSED*/
228
void
229
db_single_step_cmd(db_expr_t addr, bool have_addr, db_expr_t count, char *modif)
230
{
231
bool print = false;
232
233
if (count == -1)
234
count = 1;
235
236
if (modif[0] == 'p')
237
print = true;
238
239
db_run_mode = STEP_ONCE;
240
db_loop_count = count;
241
db_sstep_multiple = (count != 1);
242
db_sstep_print = print;
243
db_inst_count = 0;
244
db_load_count = 0;
245
db_store_count = 0;
246
247
db_cmd_loop_done = 1;
248
}
249
250
/* trace and print until call/return */
251
/*ARGSUSED*/
252
void
253
db_trace_until_call_cmd(db_expr_t addr, bool have_addr, db_expr_t count,
254
char *modif)
255
{
256
bool print = false;
257
258
if (modif[0] == 'p')
259
print = true;
260
261
db_run_mode = STEP_CALLT;
262
db_sstep_print = print;
263
db_inst_count = 0;
264
db_load_count = 0;
265
db_store_count = 0;
266
267
db_cmd_loop_done = 1;
268
}
269
270
/*ARGSUSED*/
271
void
272
db_trace_until_matching_cmd(db_expr_t addr, bool have_addr, db_expr_t count,
273
char *modif)
274
{
275
bool print = false;
276
277
if (modif[0] == 'p')
278
print = true;
279
280
db_run_mode = STEP_RETURN;
281
db_call_depth = 1;
282
db_sstep_print = print;
283
db_inst_count = 0;
284
db_load_count = 0;
285
db_store_count = 0;
286
287
db_cmd_loop_done = 1;
288
}
289
290
/* continue */
291
/*ARGSUSED*/
292
void
293
db_continue_cmd(db_expr_t addr, bool have_addr, db_expr_t count, char *modif)
294
{
295
if (modif[0] == 'c')
296
db_run_mode = STEP_COUNT;
297
else
298
db_run_mode = STEP_CONTINUE;
299
db_inst_count = 0;
300
db_load_count = 0;
301
db_store_count = 0;
302
303
db_cmd_loop_done = 1;
304
}
305
306