Deleted Added
full compact
db_run.c (273006) db_run.c (283088)
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>
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: head/sys/ddb/db_run.c 273006 2014-10-12 18:01:52Z pfg $");
36__FBSDID("$FreeBSD: head/sys/ddb/db_run.c 283088 2015-05-18 22:27:46Z pfg $");
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
51static 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
60static boolean_t db_sstep_print;
61static int db_loop_count;
62static int db_call_depth;
63
64int db_inst_count;
65int db_load_count;
66int db_store_count;
67
68#ifndef db_set_single_step
69void db_set_single_step(void);
70#endif
71#ifndef db_clear_single_step
72void db_clear_single_step(void);
73#endif
74
75#ifdef SOFTWARE_SSTEP
76db_breakpoint_t db_not_taken_bkpt = 0;
77db_breakpoint_t db_taken_bkpt = 0;
78#endif
79
80boolean_t
81db_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))
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
51static 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
60static boolean_t db_sstep_print;
61static int db_loop_count;
62static int db_call_depth;
63
64int db_inst_count;
65int db_load_count;
66int db_store_count;
67
68#ifndef db_set_single_step
69void db_set_single_step(void);
70#endif
71#ifndef db_clear_single_step
72void db_clear_single_step(void);
73#endif
74
75#ifdef SOFTWARE_SSTEP
76db_breakpoint_t db_not_taken_bkpt = 0;
77db_breakpoint_t db_taken_bkpt = 0;
78#endif
79
80boolean_t
81db_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;
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;
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 */
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
117 }
118 } else if (*is_breakpoint) {
119#ifdef BKPT_SKIP
120 BKPT_SKIP;
121#endif
122 }
123
124 *is_breakpoint = FALSE;
124 *is_breakpoint = false;
125
126 if (db_run_mode == STEP_INVISIBLE) {
127 db_run_mode = STEP_CONTINUE;
125
126 if (db_run_mode == STEP_INVISIBLE) {
127 db_run_mode = STEP_CONTINUE;
128 return (FALSE); /* continue */
128 return (false); /* continue */
129 }
130 if (db_run_mode == STEP_COUNT) {
129 }
130 if (db_run_mode == STEP_COUNT) {
131 return (FALSE); /* continue */
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 }
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 */
140 return (false); /* continue */
141 }
142 }
143 if (db_run_mode == STEP_RETURN) {
144 /* continue until matching return */
145 db_expr_t ins;
146
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);
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++;
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 */
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
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);
170 ins = db_get_value(pc, sizeof(int), false);
171 if (!inst_call(ins) &&
172 !inst_return(ins) &&
173 !inst_trap_return(ins)) {
171 if (!inst_call(ins) &&
172 !inst_return(ins) &&
173 !inst_trap_return(ins)) {
174 return (FALSE); /* continue */
174 return (false); /* continue */
175 }
176 }
177 db_run_mode = STEP_NONE;
175 }
176 }
177 db_run_mode = STEP_NONE;
178 return (TRUE);
178 return (true);
179}
180
181void
182db_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 /*
190 * We are about to execute this instruction,
191 * so count it now.
192 */
193#ifdef SOFTWARE_SSTEP
194 db_expr_t ins =
195#endif
179}
180
181void
182db_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 /*
190 * We are about to execute this instruction,
191 * so count it now.
192 */
193#ifdef SOFTWARE_SSTEP
194 db_expr_t ins =
195#endif
196 db_get_value(pc, sizeof(int), FALSE);
196 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),
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);
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
259void
260db_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 */
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
259void
260db_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);
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
281void
282db_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
297extern int db_cmd_loop_done;
298
299/* single-step */
300/*ARGSUSED*/
301void
302db_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{
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
281void
282db_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
297extern int db_cmd_loop_done;
298
299/* single-step */
300/*ARGSUSED*/
301void
302db_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;
308 boolean_t print = false;
309
310 if (count == -1)
311 count = 1;
312
313 if (modif[0] == 'p')
309
310 if (count == -1)
311 count = 1;
312
313 if (modif[0] == 'p')
314 print = TRUE;
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*/
328void
329db_trace_until_call_cmd(db_expr_t addr, boolean_t have_addr, db_expr_t count,
330 char *modif)
331{
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*/
328void
329db_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;
332 boolean_t print = false;
333
334 if (modif[0] == 'p')
333
334 if (modif[0] == 'p')
335 print = TRUE;
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*/
347void
348db_trace_until_matching_cmd(db_expr_t addr, boolean_t have_addr,
349 db_expr_t count, char *modif)
350{
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*/
347void
348db_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;
351 boolean_t print = false;
352
353 if (modif[0] == 'p')
352
353 if (modif[0] == 'p')
354 print = TRUE;
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*/
368void
369db_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}
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*/
368void
369db_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}