Annotation of sys/ddb/db_run.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: db_run.c,v 1.19 2006/03/13 06:23:20 jsg Exp $ */
2: /* $NetBSD: db_run.c,v 1.8 1996/02/05 01:57:12 christos Exp $ */
3:
4: /*
5: * Mach Operating System
6: * Copyright (c) 1993,1992,1991,1990 Carnegie Mellon University
7: * All Rights Reserved.
8: *
9: * Permission to use, copy, modify and distribute this software and its
10: * documentation is hereby granted, provided that both the copyright
11: * notice and this permission notice appear in all copies of the
12: * software, derivative works or modified versions, and any portions
13: * thereof, and that both notices appear in supporting documentation.
14: *
15: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
16: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
17: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
18: *
19: * Carnegie Mellon requests users of this software to return to
20: *
21: * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
22: * School of Computer Science
23: * Carnegie Mellon University
24: * Pittsburgh PA 15213-3890
25: *
26: * any improvements or extensions that they make and grant Carnegie Mellon
27: * the rights to redistribute these changes.
28: *
29: * Author: David B. Golub, Carnegie Mellon University
30: * Date: 7/90
31: */
32:
33: /*
34: * Commands to run process.
35: */
36: #include <sys/param.h>
37: #include <sys/proc.h>
38:
39: #include <uvm/uvm_extern.h>
40:
41: #include <machine/db_machdep.h>
42:
43: #include <ddb/db_run.h>
44: #include <ddb/db_break.h>
45: #include <ddb/db_access.h>
46:
47: #ifdef SOFTWARE_SSTEP
48: db_breakpoint_t db_not_taken_bkpt = 0;
49: db_breakpoint_t db_taken_bkpt = 0;
50: #endif
51:
52: int db_inst_count;
53: int db_load_count;
54: int db_store_count;
55:
56: #ifndef KGDB
57:
58: #include <ddb/db_lex.h>
59: #include <ddb/db_watch.h>
60: #include <ddb/db_output.h>
61: #include <ddb/db_sym.h>
62: #include <ddb/db_extern.h>
63:
64: int db_run_mode;
65: #define STEP_NONE 0
66: #define STEP_ONCE 1
67: #define STEP_RETURN 2
68: #define STEP_CALLT 3
69: #define STEP_CONTINUE 4
70: #define STEP_INVISIBLE 5
71: #define STEP_COUNT 6
72:
73: boolean_t db_sstep_print;
74: int db_loop_count;
75: int db_call_depth;
76:
77: boolean_t
78: db_stop_at_pc(db_regs_t *regs, boolean_t *is_breakpoint)
79: {
80: db_addr_t pc, old_pc;
81: db_breakpoint_t bkpt;
82:
83: db_clear_breakpoints();
84: db_clear_watchpoints();
85: old_pc = pc = PC_REGS(regs);
86:
87: #ifdef FIXUP_PC_AFTER_BREAK
88: if (*is_breakpoint) {
89: /*
90: * Breakpoint trap. Fix up the PC if the
91: * machine requires it.
92: */
93: FIXUP_PC_AFTER_BREAK(regs);
94: pc = PC_REGS(regs);
95: }
96: #endif
97:
98: /*
99: * Now check for a breakpoint at this address.
100: */
101: bkpt = db_find_breakpoint_here(pc);
102: if (bkpt) {
103: if (--bkpt->count == 0) {
104: db_clear_single_step(regs);
105: bkpt->count = bkpt->init_count;
106: *is_breakpoint = TRUE;
107: return (TRUE); /* stop here */
108: }
109: } else if (*is_breakpoint
110: #ifdef SOFTWARE_SSTEP
111: && !((db_taken_bkpt && db_taken_bkpt->address == pc) ||
112: (db_not_taken_bkpt && db_not_taken_bkpt->address == pc))
113: #endif
114: ) {
115: #ifdef PC_ADVANCE
116: PC_ADVANCE(regs);
117: #else
118: # ifdef SET_PC_REGS
119: SET_PC_REGS(regs, old_pc);
120: # else
121: PC_REGS(regs) = old_pc;
122: # endif
123: #endif
124: }
125: db_clear_single_step(regs);
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: 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) && !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(db_regs_t *regs, boolean_t watchpt)
185: {
186: db_addr_t pc = PC_REGS(regs);
187:
188: if ((db_run_mode == STEP_COUNT) || (db_run_mode == STEP_RETURN) ||
189: (db_run_mode == STEP_CALLT)) {
190: db_expr_t ins;
191:
192: /*
193: * We are about to execute this instruction,
194: * so count it now.
195: */
196: ins = 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),
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(regs);
219: } else {
220: db_set_breakpoints();
221: db_set_watchpoints();
222: }
223: } else {
224: db_set_single_step(regs);
225: }
226: }
227:
228: void
229: db_single_step(db_regs_t *regs)
230: {
231: if (db_run_mode == STEP_CONTINUE) {
232: db_run_mode = STEP_INVISIBLE;
233: db_set_single_step(regs);
234: }
235: }
236:
237: extern int db_cmd_loop_done;
238:
239: /* single-step */
240: /*ARGSUSED*/
241: void
242: db_single_step_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
243: {
244: boolean_t print = FALSE;
245:
246: if (count == -1)
247: count = 1;
248:
249: if (modif[0] == 'p')
250: print = TRUE;
251:
252: db_run_mode = STEP_ONCE;
253: db_loop_count = count;
254: db_sstep_print = print;
255: db_inst_count = 0;
256: db_load_count = 0;
257: db_store_count = 0;
258:
259: db_cmd_loop_done = 1;
260: }
261:
262: /* trace and print until call/return */
263: /*ARGSUSED*/
264: void
265: db_trace_until_call_cmd(db_expr_t addr, int have_addr, db_expr_t count,
266: char *modif)
267: {
268: boolean_t print = FALSE;
269:
270: if (modif[0] == 'p')
271: print = TRUE;
272:
273: db_run_mode = STEP_CALLT;
274: db_sstep_print = print;
275: db_inst_count = 0;
276: db_load_count = 0;
277: db_store_count = 0;
278:
279: db_cmd_loop_done = 1;
280: }
281:
282: /*ARGSUSED*/
283: void
284: db_trace_until_matching_cmd(db_expr_t addr, int have_addr, db_expr_t count,
285: char *modif)
286: {
287: boolean_t print = FALSE;
288:
289: if (modif[0] == 'p')
290: print = TRUE;
291:
292: db_run_mode = STEP_RETURN;
293: db_call_depth = 1;
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: /* continue */
303: /*ARGSUSED*/
304: void
305: db_continue_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
306: {
307: if (modif[0] == 'c')
308: db_run_mode = STEP_COUNT;
309: else
310: db_run_mode = STEP_CONTINUE;
311: db_inst_count = 0;
312: db_load_count = 0;
313: db_store_count = 0;
314:
315: db_cmd_loop_done = 1;
316: }
317: #endif /* NO KGDB */
318:
319: #ifdef SOFTWARE_SSTEP
320: /*
321: * Software implementation of single-stepping.
322: * If your machine does not have a trace mode
323: * similar to the vax or sun ones you can use
324: * this implementation, done for the mips.
325: * Just define the above conditional and provide
326: * the functions/macros defined below.
327: *
328: * extern boolean_t
329: * inst_branch(ins), returns true if the instruction might branch
330: * extern unsigned
331: * branch_taken(ins, pc, getreg_val, regs),
332: * return the address the instruction might
333: * branch to
334: * getreg_val(regs, reg), return the value of a user register,
335: * as indicated in the hardware instruction
336: * encoding, e.g. 8 for r8
337: *
338: * next_instr_address(pc, bd) returns the address of the first
339: * instruction following the one at "pc",
340: * which is either in the taken path of
341: * the branch (bd==1) or not. This is
342: * for machines (mips) with branch delays.
343: *
344: * A single-step may involve at most 2 breakpoints -
345: * one for branch-not-taken and one for branch taken.
346: * If one of these addresses does not already have a breakpoint,
347: * we allocate a breakpoint and save it here.
348: * These breakpoints are deleted on return.
349: */
350:
351: void
352: db_set_single_step(db_regs_t *regs)
353: {
354: db_addr_t pc = PC_REGS(regs);
355: #ifndef SOFTWARE_SSTEP_EMUL
356: db_addr_t brpc;
357: u_int inst;
358:
359: /*
360: * User was stopped at pc, e.g. the instruction
361: * at pc was not executed.
362: */
363: inst = db_get_value(pc, sizeof(int), FALSE);
364: if (inst_branch(inst) || inst_call(inst) || inst_return(inst)) {
365: brpc = branch_taken(inst, pc, getreg_val, regs);
366: if (brpc != pc) { /* self-branches are hopeless */
367: db_taken_bkpt = db_set_temp_breakpoint(brpc);
368: }
369: #if 0
370: /* XXX this seems like a true bug, no? */
371: pc = next_instr_address(pc, 1);
372: #endif
373: }
374: #endif /*SOFTWARE_SSTEP_EMUL*/
375: pc = next_instr_address(pc, 0);
376: db_not_taken_bkpt = db_set_temp_breakpoint(pc);
377: }
378:
379: void
380: db_clear_single_step(db_regs_t *regs)
381: {
382: if (db_taken_bkpt != 0) {
383: db_delete_temp_breakpoint(db_taken_bkpt);
384: db_taken_bkpt = 0;
385: }
386: if (db_not_taken_bkpt != 0) {
387: db_delete_temp_breakpoint(db_not_taken_bkpt);
388: db_not_taken_bkpt = 0;
389: }
390: }
391:
392: #endif /* SOFTWARE_SSTEP */
CVSweb