Annotation of src/sys/ddb/db_run.c, Revision 1.20
1.20 ! augustss 1: /* $NetBSD: db_run.c,v 1.19 1999/04/21 00:00:06 thorpej Exp $ */
1.5 cgd 2:
1.1 cgd 3: /*
4: * Mach Operating System
1.11 thorpej 5: * Copyright (c) 1993-1990 Carnegie Mellon University
1.1 cgd 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: *
1.18 pk 14: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
1.1 cgd 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@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.
1.2 cgd 27: *
1.1 cgd 28: * Author: David B. Golub, Carnegie Mellon University
29: * Date: 7/90
30: */
31:
32: /*
33: * Commands to run process.
34: */
1.15 jonathan 35:
36: #include "opt_ddb.h"
37:
1.7 mycroft 38: #include <sys/param.h>
39: #include <sys/proc.h>
40:
41: #include <machine/db_machdep.h>
42:
1.6 mycroft 43: #include <ddb/db_run.h>
1.14 pk 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)
1.1 cgd 55: #include <ddb/db_lex.h>
1.8 christos 56: #include <ddb/db_watch.h>
57: #include <ddb/db_output.h>
58: #include <ddb/db_sym.h>
59: #include <ddb/db_extern.h>
1.1 cgd 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
1.6 mycroft 75: db_stop_at_pc(regs, is_breakpoint)
76: db_regs_t *regs;
1.1 cgd 77: boolean_t *is_breakpoint;
78: {
1.20 ! augustss 79: db_addr_t pc;
! 80: db_breakpoint_t bkpt;
1.1 cgd 81:
1.13 pk 82: pc = PC_REGS(regs);
83:
1.19 thorpej 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:
1.13 pk 95: #ifdef SOFTWARE_SSTEP
96: /*
1.19 thorpej 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.
1.13 pk 99: */
1.14 pk 100: if (db_taken_bkpt.address == pc || db_not_taken_bkpt.address == pc)
1.13 pk 101: *is_breakpoint = FALSE;
1.19 thorpej 102: #endif /* SOFTWARE_SSTEP */
1.13 pk 103:
1.6 mycroft 104: db_clear_single_step(regs);
1.1 cgd 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) {
1.12 pk 119: #ifdef PC_ADVANCE
120: PC_ADVANCE(regs);
121: #else
1.6 mycroft 122: PC_REGS(regs) += BKPT_SIZE;
1.12 pk 123: #endif
1.1 cgd 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)) {
1.20 ! augustss 154: int i;
1.1 cgd 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
1.6 mycroft 184: db_restart_at_pc(regs, watchpt)
185: db_regs_t *regs;
1.1 cgd 186: boolean_t watchpt;
187: {
1.20 ! augustss 188: db_addr_t pc = PC_REGS(regs);
1.1 cgd 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);
1.11 thorpej 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);
1.16 mycroft 212: if ((brpc != pc) &&
213: (inst_branch(ins) || inst_call(ins) || inst_return(ins))) {
1.11 thorpej 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: }
1.1 cgd 219: }
1.9 cgd 220: #endif
1.1 cgd 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;
1.6 mycroft 229: db_set_single_step(regs);
1.1 cgd 230: } else {
231: db_set_breakpoints();
232: db_set_watchpoints();
233: }
234: } else {
1.6 mycroft 235: db_set_single_step(regs);
1.1 cgd 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:
1.14 pk 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:
1.11 thorpej 346: #ifdef SOFTWARE_SSTEP
1.1 cgd 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: *
1.11 thorpej 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.
1.1 cgd 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:
1.14 pk 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:
1.1 cgd 384: void
385: db_set_single_step(regs)
1.20 ! augustss 386: db_regs_t *regs;
1.1 cgd 387: {
1.13 pk 388: db_addr_t pc = PC_REGS(regs), brpc = pc;
1.11 thorpej 389: boolean_t unconditional;
390: unsigned int inst;
1.1 cgd 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);
1.16 mycroft 397: if (inst_branch(inst) || inst_call(inst) || inst_return(inst)) {
1.11 thorpej 398: brpc = branch_taken(inst, pc, regs);
399: if (brpc != pc) { /* self-branches are hopeless */
1.14 pk 400: db_set_temp_breakpoint(&db_taken_bkpt, brpc);
1.11 thorpej 401: } else
1.14 pk 402: db_taken_bkpt.address = 0;
1.11 thorpej 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);
1.1 cgd 413:
1.11 thorpej 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.)
1.13 pk 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.
1.11 thorpej 429: */
1.13 pk 430: if (unconditional == FALSE &&
431: db_find_breakpoint_here(pc) == 0 &&
432: pc != brpc)
1.14 pk 433: db_set_temp_breakpoint(&db_not_taken_bkpt, pc);
1.11 thorpej 434: else
1.14 pk 435: db_not_taken_bkpt.address = 0;
1.1 cgd 436: }
437:
438: void
439: db_clear_single_step(regs)
440: db_regs_t *regs;
441: {
442:
1.14 pk 443: if (db_taken_bkpt.address != 0)
444: db_delete_temp_breakpoint(&db_taken_bkpt);
1.1 cgd 445:
1.14 pk 446: if (db_not_taken_bkpt.address != 0)
447: db_delete_temp_breakpoint(&db_not_taken_bkpt);
1.1 cgd 448: }
449:
450: void
1.14 pk 451: db_set_temp_breakpoint(bkpt, addr)
452: db_breakpoint_t bkpt;
453: db_addr_t addr;
1.1 cgd 454: {
455:
1.14 pk 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;
1.1 cgd 461:
1.14 pk 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));
1.1 cgd 464: }
465:
466: void
1.14 pk 467: db_delete_temp_breakpoint(bkpt)
468: db_breakpoint_t bkpt;
1.1 cgd 469: {
1.14 pk 470: db_put_value(bkpt->address, BKPT_SIZE, bkpt->bkpt_inst);
471: bkpt->address = 0;
1.1 cgd 472: }
473:
1.14 pk 474: #endif /* SOFTWARE_SSTEP */
CVSweb <webmaster@jp.NetBSD.org>