db_run.c revision 1.29 1 1.29 matt /* $NetBSD: db_run.c,v 1.29 2007/02/22 04:38:06 matt Exp $ */
2 1.5 cgd
3 1.22 simonb /*
4 1.1 cgd * Mach Operating System
5 1.11 thorpej * Copyright (c) 1993-1990 Carnegie Mellon University
6 1.1 cgd * All Rights Reserved.
7 1.22 simonb *
8 1.1 cgd * Permission to use, copy, modify and distribute this software and its
9 1.1 cgd * documentation is hereby granted, provided that both the copyright
10 1.1 cgd * notice and this permission notice appear in all copies of the
11 1.1 cgd * software, derivative works or modified versions, and any portions
12 1.1 cgd * thereof, and that both notices appear in supporting documentation.
13 1.22 simonb *
14 1.18 pk * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
15 1.1 cgd * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
16 1.1 cgd * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
17 1.22 simonb *
18 1.1 cgd * Carnegie Mellon requests users of this software to return to
19 1.22 simonb *
20 1.1 cgd * Software Distribution Coordinator or Software.Distribution (at) CS.CMU.EDU
21 1.1 cgd * School of Computer Science
22 1.1 cgd * Carnegie Mellon University
23 1.1 cgd * Pittsburgh PA 15213-3890
24 1.22 simonb *
25 1.1 cgd * any improvements or extensions that they make and grant Carnegie the
26 1.1 cgd * rights to redistribute these changes.
27 1.2 cgd *
28 1.1 cgd * Author: David B. Golub, Carnegie Mellon University
29 1.1 cgd * Date: 7/90
30 1.1 cgd */
31 1.1 cgd
32 1.1 cgd /*
33 1.1 cgd * Commands to run process.
34 1.1 cgd */
35 1.21 lukem
36 1.21 lukem #include <sys/cdefs.h>
37 1.29 matt __KERNEL_RCSID(0, "$NetBSD: db_run.c,v 1.29 2007/02/22 04:38:06 matt Exp $");
38 1.15 jonathan
39 1.15 jonathan #include "opt_ddb.h"
40 1.15 jonathan
41 1.7 mycroft #include <sys/param.h>
42 1.7 mycroft #include <sys/proc.h>
43 1.7 mycroft
44 1.7 mycroft #include <machine/db_machdep.h>
45 1.7 mycroft
46 1.6 mycroft #include <ddb/db_run.h>
47 1.14 pk #include <ddb/db_access.h>
48 1.14 pk #include <ddb/db_break.h>
49 1.14 pk
50 1.22 simonb int db_inst_count;
51 1.22 simonb int db_load_count;
52 1.22 simonb int db_store_count;
53 1.22 simonb
54 1.14 pk #ifdef SOFTWARE_SSTEP
55 1.22 simonb static void db_set_temp_breakpoint(db_breakpoint_t, db_addr_t);
56 1.22 simonb static void db_delete_temp_breakpoint(db_breakpoint_t);
57 1.14 pk static struct db_breakpoint db_not_taken_bkpt;
58 1.14 pk static struct db_breakpoint db_taken_bkpt;
59 1.14 pk #endif
60 1.14 pk
61 1.14 pk #if defined(DDB)
62 1.1 cgd #include <ddb/db_lex.h>
63 1.8 christos #include <ddb/db_watch.h>
64 1.8 christos #include <ddb/db_output.h>
65 1.8 christos #include <ddb/db_sym.h>
66 1.8 christos #include <ddb/db_extern.h>
67 1.1 cgd
68 1.22 simonb static int db_run_mode;
69 1.1 cgd #define STEP_NONE 0
70 1.1 cgd #define STEP_ONCE 1
71 1.1 cgd #define STEP_RETURN 2
72 1.1 cgd #define STEP_CALLT 3
73 1.1 cgd #define STEP_CONTINUE 4
74 1.1 cgd #define STEP_INVISIBLE 5
75 1.1 cgd #define STEP_COUNT 6
76 1.1 cgd
77 1.28 thorpej static bool db_sstep_print;
78 1.22 simonb static int db_loop_count;
79 1.22 simonb static int db_call_depth;
80 1.1 cgd
81 1.28 thorpej bool
82 1.28 thorpej db_stop_at_pc(db_regs_t *regs, bool *is_breakpoint)
83 1.1 cgd {
84 1.20 augustss db_addr_t pc;
85 1.20 augustss db_breakpoint_t bkpt;
86 1.1 cgd
87 1.13 pk pc = PC_REGS(regs);
88 1.13 pk
89 1.19 thorpej #ifdef FIXUP_PC_AFTER_BREAK
90 1.19 thorpej if (*is_breakpoint) {
91 1.19 thorpej /*
92 1.19 thorpej * Breakpoint trap. Regardless if we treat this as a
93 1.19 thorpej * real breakpoint (e.g. software single-step), fix up the PC.
94 1.19 thorpej */
95 1.19 thorpej FIXUP_PC_AFTER_BREAK(regs);
96 1.19 thorpej pc = PC_REGS(regs);
97 1.19 thorpej }
98 1.19 thorpej #endif
99 1.19 thorpej
100 1.13 pk #ifdef SOFTWARE_SSTEP
101 1.13 pk /*
102 1.19 thorpej * If we stopped at one of the single-step breakpoints, say it's not
103 1.19 thorpej * really a breakpoint so that we don't skip over the real instruction.
104 1.13 pk */
105 1.14 pk if (db_taken_bkpt.address == pc || db_not_taken_bkpt.address == pc)
106 1.13 pk *is_breakpoint = FALSE;
107 1.19 thorpej #endif /* SOFTWARE_SSTEP */
108 1.13 pk
109 1.6 mycroft db_clear_single_step(regs);
110 1.1 cgd db_clear_breakpoints();
111 1.1 cgd db_clear_watchpoints();
112 1.1 cgd
113 1.1 cgd /*
114 1.1 cgd * Now check for a breakpoint at this address.
115 1.1 cgd */
116 1.1 cgd bkpt = db_find_breakpoint_here(pc);
117 1.1 cgd if (bkpt) {
118 1.22 simonb if (--bkpt->count == 0) {
119 1.22 simonb bkpt->count = bkpt->init_count;
120 1.22 simonb *is_breakpoint = TRUE;
121 1.22 simonb return (TRUE); /* stop here */
122 1.22 simonb }
123 1.1 cgd } else if (*is_breakpoint) {
124 1.12 pk #ifdef PC_ADVANCE
125 1.12 pk PC_ADVANCE(regs);
126 1.12 pk #else
127 1.6 mycroft PC_REGS(regs) += BKPT_SIZE;
128 1.12 pk #endif
129 1.1 cgd }
130 1.22 simonb
131 1.1 cgd *is_breakpoint = FALSE;
132 1.1 cgd
133 1.1 cgd if (db_run_mode == STEP_INVISIBLE) {
134 1.22 simonb db_run_mode = STEP_CONTINUE;
135 1.22 simonb return (FALSE); /* continue */
136 1.1 cgd }
137 1.1 cgd if (db_run_mode == STEP_COUNT) {
138 1.22 simonb return (FALSE); /* continue */
139 1.1 cgd }
140 1.1 cgd if (db_run_mode == STEP_ONCE) {
141 1.22 simonb if (--db_loop_count > 0) {
142 1.22 simonb if (db_sstep_print) {
143 1.22 simonb db_printf("\t\t");
144 1.22 simonb db_print_loc_and_inst(pc);
145 1.22 simonb db_printf("\n");
146 1.22 simonb }
147 1.22 simonb return (FALSE); /* continue */
148 1.1 cgd }
149 1.1 cgd }
150 1.1 cgd if (db_run_mode == STEP_RETURN) {
151 1.22 simonb db_expr_t ins = db_get_value(pc, sizeof(int), FALSE);
152 1.1 cgd
153 1.22 simonb /* continue until matching return */
154 1.1 cgd
155 1.22 simonb if (!inst_trap_return(ins) &&
156 1.22 simonb (!inst_return(ins) || --db_call_depth != 0)) {
157 1.22 simonb if (db_sstep_print) {
158 1.22 simonb if (inst_call(ins) || inst_return(ins)) {
159 1.22 simonb int i;
160 1.22 simonb
161 1.22 simonb db_printf("[after %6d] ",
162 1.22 simonb db_inst_count);
163 1.22 simonb for (i = db_call_depth; --i > 0; )
164 1.22 simonb db_printf(" ");
165 1.22 simonb db_print_loc_and_inst(pc);
166 1.22 simonb db_printf("\n");
167 1.22 simonb }
168 1.22 simonb }
169 1.22 simonb if (inst_call(ins))
170 1.22 simonb db_call_depth++;
171 1.22 simonb return (FALSE); /* continue */
172 1.1 cgd }
173 1.1 cgd }
174 1.1 cgd if (db_run_mode == STEP_CALLT) {
175 1.22 simonb db_expr_t ins = db_get_value(pc, sizeof(int), FALSE);
176 1.1 cgd
177 1.22 simonb /* continue until call or return */
178 1.1 cgd
179 1.22 simonb if (!inst_call(ins) &&
180 1.22 simonb !inst_return(ins) &&
181 1.22 simonb !inst_trap_return(ins)) {
182 1.22 simonb return (FALSE); /* continue */
183 1.22 simonb }
184 1.1 cgd }
185 1.1 cgd db_run_mode = STEP_NONE;
186 1.1 cgd return (TRUE);
187 1.1 cgd }
188 1.1 cgd
189 1.1 cgd void
190 1.28 thorpej db_restart_at_pc(db_regs_t *regs, bool watchpt)
191 1.1 cgd {
192 1.20 augustss db_addr_t pc = PC_REGS(regs);
193 1.22 simonb #ifdef SOFTWARE_SSTEP
194 1.22 simonb db_addr_t brpc;
195 1.22 simonb #endif
196 1.1 cgd
197 1.1 cgd if ((db_run_mode == STEP_COUNT) ||
198 1.1 cgd (db_run_mode == STEP_RETURN) ||
199 1.1 cgd (db_run_mode == STEP_CALLT)) {
200 1.22 simonb db_expr_t ins;
201 1.1 cgd
202 1.22 simonb /*
203 1.22 simonb * We are about to execute this instruction,
204 1.22 simonb * so count it now.
205 1.22 simonb */
206 1.22 simonb ins = db_get_value(pc, sizeof(int), FALSE);
207 1.22 simonb db_inst_count++;
208 1.22 simonb db_load_count += inst_load(ins);
209 1.22 simonb db_store_count += inst_store(ins);
210 1.11 thorpej
211 1.11 thorpej #ifdef SOFTWARE_SSTEP
212 1.22 simonb /*
213 1.22 simonb * Account for instructions in delay slots.
214 1.22 simonb */
215 1.11 thorpej brpc = next_instr_address(pc, TRUE);
216 1.16 mycroft if ((brpc != pc) &&
217 1.16 mycroft (inst_branch(ins) || inst_call(ins) || inst_return(ins))) {
218 1.22 simonb ins = db_get_value(brpc, sizeof(int), FALSE);
219 1.22 simonb db_inst_count++;
220 1.22 simonb db_load_count += inst_load(ins);
221 1.22 simonb db_store_count += inst_store(ins);
222 1.11 thorpej }
223 1.9 cgd #endif
224 1.1 cgd }
225 1.1 cgd
226 1.1 cgd if (db_run_mode == STEP_CONTINUE) {
227 1.22 simonb if (watchpt || db_find_breakpoint_here(pc)) {
228 1.22 simonb /*
229 1.22 simonb * Step over breakpoint/watchpoint.
230 1.22 simonb */
231 1.22 simonb db_run_mode = STEP_INVISIBLE;
232 1.22 simonb db_set_single_step(regs);
233 1.22 simonb } else {
234 1.22 simonb db_set_breakpoints();
235 1.22 simonb db_set_watchpoints();
236 1.22 simonb }
237 1.22 simonb } else {
238 1.6 mycroft db_set_single_step(regs);
239 1.1 cgd }
240 1.1 cgd }
241 1.1 cgd
242 1.1 cgd void
243 1.22 simonb db_single_step(db_regs_t *regs)
244 1.1 cgd {
245 1.22 simonb
246 1.1 cgd if (db_run_mode == STEP_CONTINUE) {
247 1.22 simonb db_run_mode = STEP_INVISIBLE;
248 1.22 simonb db_set_single_step(regs);
249 1.1 cgd }
250 1.1 cgd }
251 1.1 cgd
252 1.14 pk /* single-step */
253 1.14 pk /*ARGSUSED*/
254 1.14 pk void
255 1.29 matt db_single_step_cmd(db_expr_t addr, bool have_addr,
256 1.26 christos db_expr_t count, const char *modif)
257 1.14 pk {
258 1.28 thorpej bool print = FALSE;
259 1.14 pk
260 1.14 pk if (count == -1)
261 1.22 simonb count = 1;
262 1.14 pk
263 1.14 pk if (modif[0] == 'p')
264 1.22 simonb print = TRUE;
265 1.14 pk
266 1.14 pk db_run_mode = STEP_ONCE;
267 1.14 pk db_loop_count = count;
268 1.14 pk db_sstep_print = print;
269 1.14 pk db_inst_count = 0;
270 1.14 pk db_load_count = 0;
271 1.14 pk db_store_count = 0;
272 1.14 pk
273 1.14 pk db_cmd_loop_done = 1;
274 1.14 pk }
275 1.14 pk
276 1.14 pk /* trace and print until call/return */
277 1.14 pk /*ARGSUSED*/
278 1.14 pk void
279 1.29 matt db_trace_until_call_cmd(db_expr_t addr, bool have_addr,
280 1.27 christos db_expr_t count, const char *modif)
281 1.14 pk {
282 1.28 thorpej bool print = FALSE;
283 1.14 pk
284 1.14 pk if (modif[0] == 'p')
285 1.22 simonb print = TRUE;
286 1.14 pk
287 1.14 pk db_run_mode = STEP_CALLT;
288 1.14 pk db_sstep_print = print;
289 1.14 pk db_inst_count = 0;
290 1.14 pk db_load_count = 0;
291 1.14 pk db_store_count = 0;
292 1.14 pk
293 1.14 pk db_cmd_loop_done = 1;
294 1.14 pk }
295 1.14 pk
296 1.14 pk /*ARGSUSED*/
297 1.14 pk void
298 1.29 matt db_trace_until_matching_cmd(db_expr_t addr, bool have_addr,
299 1.27 christos db_expr_t count, const char *modif)
300 1.14 pk {
301 1.28 thorpej bool print = FALSE;
302 1.14 pk
303 1.14 pk if (modif[0] == 'p')
304 1.22 simonb print = TRUE;
305 1.14 pk
306 1.14 pk db_run_mode = STEP_RETURN;
307 1.14 pk db_call_depth = 1;
308 1.14 pk db_sstep_print = print;
309 1.14 pk db_inst_count = 0;
310 1.14 pk db_load_count = 0;
311 1.14 pk db_store_count = 0;
312 1.14 pk
313 1.14 pk db_cmd_loop_done = 1;
314 1.14 pk }
315 1.14 pk
316 1.14 pk /* continue */
317 1.14 pk /*ARGSUSED*/
318 1.14 pk void
319 1.29 matt db_continue_cmd(db_expr_t addr, bool have_addr,
320 1.27 christos db_expr_t count, const char *modif)
321 1.14 pk {
322 1.22 simonb
323 1.14 pk if (modif[0] == 'c')
324 1.22 simonb db_run_mode = STEP_COUNT;
325 1.14 pk else
326 1.22 simonb db_run_mode = STEP_CONTINUE;
327 1.14 pk db_inst_count = 0;
328 1.14 pk db_load_count = 0;
329 1.14 pk db_store_count = 0;
330 1.14 pk
331 1.14 pk db_cmd_loop_done = 1;
332 1.14 pk }
333 1.14 pk #endif /* DDB */
334 1.14 pk
335 1.11 thorpej #ifdef SOFTWARE_SSTEP
336 1.1 cgd /*
337 1.1 cgd * Software implementation of single-stepping.
338 1.1 cgd * If your machine does not have a trace mode
339 1.1 cgd * similar to the vax or sun ones you can use
340 1.1 cgd * this implementation, done for the mips.
341 1.1 cgd * Just define the above conditional and provide
342 1.1 cgd * the functions/macros defined below.
343 1.1 cgd *
344 1.28 thorpej * bool inst_branch(int inst)
345 1.28 thorpej * bool inst_call(int inst)
346 1.11 thorpej * returns TRUE if the instruction might branch
347 1.11 thorpej *
348 1.28 thorpej * bool inst_unconditional_flow_transfer(int inst)
349 1.11 thorpej * returns TRUE if the instruction is an unconditional
350 1.11 thorpej * transter of flow (i.e. unconditional branch)
351 1.11 thorpej *
352 1.11 thorpej * db_addr_t branch_taken(int inst, db_addr_t pc, db_regs_t *regs)
353 1.11 thorpej * returns the target address of the branch
354 1.11 thorpej *
355 1.28 thorpej * db_addr_t next_instr_address(db_addr_t pc, bool bd)
356 1.11 thorpej * returns the address of the first instruction following the
357 1.11 thorpej * one at "pc", which is either in the taken path of the branch
358 1.11 thorpej * (bd == TRUE) or not. This is for machines (e.g. mips) with
359 1.11 thorpej * branch delays.
360 1.1 cgd *
361 1.1 cgd * A single-step may involve at most 2 breakpoints -
362 1.1 cgd * one for branch-not-taken and one for branch taken.
363 1.1 cgd * If one of these addresses does not already have a breakpoint,
364 1.1 cgd * we allocate a breakpoint and save it here.
365 1.1 cgd * These breakpoints are deleted on return.
366 1.22 simonb */
367 1.1 cgd
368 1.14 pk #if !defined(DDB)
369 1.14 pk /* XXX - don't check for existing breakpoints in KGDB-only case */
370 1.14 pk #define db_find_breakpoint_here(pc) (0)
371 1.14 pk #endif
372 1.14 pk
373 1.1 cgd void
374 1.22 simonb db_set_single_step(db_regs_t *regs)
375 1.1 cgd {
376 1.13 pk db_addr_t pc = PC_REGS(regs), brpc = pc;
377 1.28 thorpej bool unconditional;
378 1.11 thorpej unsigned int inst;
379 1.1 cgd
380 1.1 cgd /*
381 1.1 cgd * User was stopped at pc, e.g. the instruction
382 1.1 cgd * at pc was not executed.
383 1.1 cgd */
384 1.1 cgd inst = db_get_value(pc, sizeof(int), FALSE);
385 1.16 mycroft if (inst_branch(inst) || inst_call(inst) || inst_return(inst)) {
386 1.11 thorpej brpc = branch_taken(inst, pc, regs);
387 1.11 thorpej if (brpc != pc) { /* self-branches are hopeless */
388 1.14 pk db_set_temp_breakpoint(&db_taken_bkpt, brpc);
389 1.11 thorpej } else
390 1.14 pk db_taken_bkpt.address = 0;
391 1.11 thorpej pc = next_instr_address(pc, TRUE);
392 1.11 thorpej }
393 1.11 thorpej
394 1.11 thorpej /*
395 1.11 thorpej * Check if this control flow instruction is an
396 1.11 thorpej * unconditional transfer.
397 1.11 thorpej */
398 1.11 thorpej unconditional = inst_unconditional_flow_transfer(inst);
399 1.11 thorpej
400 1.11 thorpej pc = next_instr_address(pc, FALSE);
401 1.1 cgd
402 1.11 thorpej /*
403 1.11 thorpej * We only set the sequential breakpoint if previous
404 1.11 thorpej * instruction was not an unconditional change of flow
405 1.11 thorpej * control. If the previous instruction is an
406 1.11 thorpej * unconditional change of flow control, setting a
407 1.11 thorpej * breakpoint in the next sequential location may set
408 1.11 thorpej * a breakpoint in data or in another routine, which
409 1.11 thorpej * could screw up in either the program or the debugger.
410 1.11 thorpej * (Consider, for instance, that the next sequential
411 1.11 thorpej * instruction is the start of a routine needed by the
412 1.11 thorpej * debugger.)
413 1.13 pk *
414 1.13 pk * Also, don't set both the taken and not-taken breakpoints
415 1.13 pk * in the same place even if the MD code would otherwise
416 1.13 pk * have us do so.
417 1.11 thorpej */
418 1.13 pk if (unconditional == FALSE &&
419 1.13 pk db_find_breakpoint_here(pc) == 0 &&
420 1.13 pk pc != brpc)
421 1.14 pk db_set_temp_breakpoint(&db_not_taken_bkpt, pc);
422 1.11 thorpej else
423 1.14 pk db_not_taken_bkpt.address = 0;
424 1.1 cgd }
425 1.1 cgd
426 1.1 cgd void
427 1.22 simonb db_clear_single_step(db_regs_t *regs)
428 1.1 cgd {
429 1.1 cgd
430 1.14 pk if (db_taken_bkpt.address != 0)
431 1.14 pk db_delete_temp_breakpoint(&db_taken_bkpt);
432 1.1 cgd
433 1.14 pk if (db_not_taken_bkpt.address != 0)
434 1.14 pk db_delete_temp_breakpoint(&db_not_taken_bkpt);
435 1.1 cgd }
436 1.1 cgd
437 1.1 cgd void
438 1.22 simonb db_set_temp_breakpoint(db_breakpoint_t bkpt, db_addr_t addr)
439 1.1 cgd {
440 1.1 cgd
441 1.14 pk bkpt->map = NULL;
442 1.14 pk bkpt->address = addr;
443 1.14 pk /* bkpt->flags = BKPT_TEMP; - this is not used */
444 1.14 pk bkpt->init_count = 1;
445 1.14 pk bkpt->count = 1;
446 1.1 cgd
447 1.14 pk bkpt->bkpt_inst = db_get_value(bkpt->address, BKPT_SIZE, FALSE);
448 1.25 he db_put_value(bkpt->address, BKPT_SIZE,
449 1.25 he BKPT_SET(bkpt->bkpt_inst, bkpt->address));
450 1.1 cgd }
451 1.1 cgd
452 1.1 cgd void
453 1.22 simonb db_delete_temp_breakpoint(db_breakpoint_t bkpt)
454 1.1 cgd {
455 1.22 simonb
456 1.14 pk db_put_value(bkpt->address, BKPT_SIZE, bkpt->bkpt_inst);
457 1.14 pk bkpt->address = 0;
458 1.1 cgd }
459 1.14 pk #endif /* SOFTWARE_SSTEP */
460