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