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