|
|
1.1 root 1: /*
2: * Mach Operating System
3: * Copyright (c) 1991,1990 Carnegie Mellon University
4: * All Rights Reserved.
5: *
6: * Permission to use, copy, modify and distribute this software and its
7: * documentation is hereby granted, provided that both the copyright
8: * notice and this permission notice appear in all copies of the
9: * software, derivative works or modified versions, and any portions
10: * thereof, and that both notices appear in supporting documentation.
11: *
12: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
13: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
15: *
16: * Carnegie Mellon requests users of this software to return to
17: *
18: * Software Distribution Coordinator or [email protected]
19: * School of Computer Science
20: * Carnegie Mellon University
21: * Pittsburgh PA 15213-3890
22: *
23: * any improvements or extensions that they make and grant Carnegie the
24: * rights to redistribute these changes.
25: */
26: /*
1.1.1.3 ! root 27: * db_run.c,v 1.2 1993/05/20 03:39:28 cgd Exp
! 28: *
1.1 root 29: * HISTORY
1.1.1.3 ! root 30: * db_run.c,v
! 31: * Revision 1.2 1993/05/20 03:39:28 cgd
! 32: * add explicit rcs id
! 33: *
! 34: * Revision 1.1.1.1 1993/03/21 09:46:27 cgd
1.1.1.2 root 35: * initial import of 386bsd-0.1 sources
36: *
1.1 root 37: * Revision 1.1 1992/03/25 21:45:24 pace
38: * Initial revision
39: *
40: * Revision 2.5 91/02/05 17:06:58 mrt
41: * Changed to new Mach copyright
42: * [91/01/31 16:19:05 mrt]
43: *
44: * Revision 2.4 91/01/08 15:09:10 rpd
45: * Fixed bug in db_restart_at_pc.
46: * [90/12/07 rpd]
47: * Added STEP_COUNT and count option to db_continue_cmd.
48: * Changed db_stop_at_pc to return (modified) is_breakpoint.
49: * Fixed db_stop_at_pc to print newlines in the right places.
50: * [90/11/27 rpd]
51: *
52: * Revision 2.3 90/10/25 14:43:59 rwd
53: * Changed db_find_breakpoint to db_find_breakpoint_here.
54: * [90/10/18 rpd]
55: *
56: * Fixed db_set_single_step to pass regs to branch_taken.
57: * Added watchpoint argument to db_restart_at_pc.
58: * [90/10/17 rpd]
59: * Generalized the watchpoint support.
60: * [90/10/16 rwd]
61: * Added watchpoint support.
62: * [90/10/16 rpd]
63: *
64: * Revision 2.2 90/08/27 21:51:59 dbg
65: * Fixed names for single-step functions.
66: * [90/08/20 af]
67: * Reduce lint.
68: * [90/08/07 dbg]
69: * Created.
70: * [90/07/25 dbg]
71: *
72: */
73: /*
74: * Author: David B. Golub, Carnegie Mellon University
75: * Date: 7/90
76: */
77:
78: /*
79: * Commands to run process.
80: */
81: #include "param.h"
82: #include "proc.h"
83: #include <machine/db_machdep.h>
84:
85: #include <ddb/db_lex.h>
86: #include <ddb/db_break.h>
87: #include <ddb/db_access.h>
88:
89: int db_run_mode;
90: #define STEP_NONE 0
91: #define STEP_ONCE 1
92: #define STEP_RETURN 2
93: #define STEP_CALLT 3
94: #define STEP_CONTINUE 4
95: #define STEP_INVISIBLE 5
96: #define STEP_COUNT 6
97:
98: boolean_t db_sstep_print;
99: int db_loop_count;
100: int db_call_depth;
101:
102: int db_inst_count;
103: int db_load_count;
104: int db_store_count;
105:
106: #ifndef db_set_single_step
107: void db_set_single_step(/* db_regs_t *regs */); /* forward */
108: #endif
109: #ifndef db_clear_single_step
110: void db_clear_single_step(/* db_regs_t *regs */);
111: #endif
112:
113: boolean_t
114: db_stop_at_pc(is_breakpoint)
115: boolean_t *is_breakpoint;
116: {
117: register db_addr_t pc;
118: register db_breakpoint_t bkpt;
119:
120: db_clear_single_step(DDB_REGS);
121: db_clear_breakpoints();
122: db_clear_watchpoints();
123: pc = PC_REGS(DDB_REGS);
124:
125: #ifdef FIXUP_PC_AFTER_BREAK
126: if (*is_breakpoint) {
127: /*
128: * Breakpoint trap. Fix up the PC if the
129: * machine requires it.
130: */
131: FIXUP_PC_AFTER_BREAK
132: pc = PC_REGS(DDB_REGS);
133: }
134: #endif
135:
136: /*
137: * Now check for a breakpoint at this address.
138: */
139: bkpt = db_find_breakpoint_here(pc);
140: if (bkpt) {
141: if (--bkpt->count == 0) {
142: bkpt->count = bkpt->init_count;
143: *is_breakpoint = TRUE;
144: return (TRUE); /* stop here */
145: }
146: } else if (*is_breakpoint) {
147: ddb_regs.tf_eip += 1;
148: }
149:
150: *is_breakpoint = FALSE;
151:
152: if (db_run_mode == STEP_INVISIBLE) {
153: db_run_mode = STEP_CONTINUE;
154: return (FALSE); /* continue */
155: }
156: if (db_run_mode == STEP_COUNT) {
157: return (FALSE); /* continue */
158: }
159: if (db_run_mode == STEP_ONCE) {
160: if (--db_loop_count > 0) {
161: if (db_sstep_print) {
162: db_printf("\t\t");
163: db_print_loc_and_inst(pc);
164: db_printf("\n");
165: }
166: return (FALSE); /* continue */
167: }
168: }
169: if (db_run_mode == STEP_RETURN) {
170: db_expr_t ins = db_get_value(pc, sizeof(int), FALSE);
171:
172: /* continue until matching return */
173:
174: if (!inst_trap_return(ins) &&
175: (!inst_return(ins) || --db_call_depth != 0)) {
176: if (db_sstep_print) {
177: if (inst_call(ins) || inst_return(ins)) {
178: register int i;
179:
180: db_printf("[after %6d] ", db_inst_count);
181: for (i = db_call_depth; --i > 0; )
182: db_printf(" ");
183: db_print_loc_and_inst(pc);
184: db_printf("\n");
185: }
186: }
187: if (inst_call(ins))
188: db_call_depth++;
189: return (FALSE); /* continue */
190: }
191: }
192: if (db_run_mode == STEP_CALLT) {
193: db_expr_t ins = db_get_value(pc, sizeof(int), FALSE);
194:
195: /* continue until call or return */
196:
197: if (!inst_call(ins) &&
198: !inst_return(ins) &&
199: !inst_trap_return(ins)) {
200: return (FALSE); /* continue */
201: }
202: }
203: db_run_mode = STEP_NONE;
204: return (TRUE);
205: }
206:
207: void
208: db_restart_at_pc(watchpt)
209: boolean_t watchpt;
210: {
211: register db_addr_t pc = PC_REGS(DDB_REGS);
212:
213: if ((db_run_mode == STEP_COUNT) ||
214: (db_run_mode == STEP_RETURN) ||
215: (db_run_mode == STEP_CALLT)) {
216: db_expr_t ins;
217:
218: /*
219: * We are about to execute this instruction,
220: * so count it now.
221: */
222:
223: ins = db_get_value(pc, sizeof(int), FALSE);
224: db_inst_count++;
225: db_load_count += inst_load(ins);
226: db_store_count += inst_store(ins);
227: #ifdef SOFTWARE_SSTEP
228: /* XXX works on mips, but... */
229: if (inst_branch(ins) || inst_call(ins)) {
230: ins = db_get_value(next_instr_address(pc,1),
231: sizeof(int), FALSE);
232: db_inst_count++;
233: db_load_count += inst_load(ins);
234: db_store_count += inst_store(ins);
235: }
236: #endif SOFTWARE_SSTEP
237: }
238:
239: if (db_run_mode == STEP_CONTINUE) {
240: if (watchpt || db_find_breakpoint_here(pc)) {
241: /*
242: * Step over breakpoint/watchpoint.
243: */
244: db_run_mode = STEP_INVISIBLE;
245: db_set_single_step(DDB_REGS);
246: } else {
247: db_set_breakpoints();
248: db_set_watchpoints();
249: }
250: } else {
251: db_set_single_step(DDB_REGS);
252: }
253: }
254:
255: void
256: db_single_step(regs)
257: db_regs_t *regs;
258: {
259: if (db_run_mode == STEP_CONTINUE) {
260: db_run_mode = STEP_INVISIBLE;
261: db_set_single_step(regs);
262: }
263: }
264:
265: #ifdef SOFTWARE_SSTEP
266: /*
267: * Software implementation of single-stepping.
268: * If your machine does not have a trace mode
269: * similar to the vax or sun ones you can use
270: * this implementation, done for the mips.
271: * Just define the above conditional and provide
272: * the functions/macros defined below.
273: *
274: * extern boolean_t
275: * inst_branch(), returns true if the instruction might branch
276: * extern unsigned
277: * branch_taken(), return the address the instruction might
278: * branch to
279: * db_getreg_val(); return the value of a user register,
280: * as indicated in the hardware instruction
281: * encoding, e.g. 8 for r8
282: *
283: * next_instr_address(pc,bd) returns the address of the first
284: * instruction following the one at "pc",
285: * which is either in the taken path of
286: * the branch (bd==1) or not. This is
287: * for machines (mips) with branch delays.
288: *
289: * A single-step may involve at most 2 breakpoints -
290: * one for branch-not-taken and one for branch taken.
291: * If one of these addresses does not already have a breakpoint,
292: * we allocate a breakpoint and save it here.
293: * These breakpoints are deleted on return.
294: */
295: db_breakpoint_t db_not_taken_bkpt = 0;
296: db_breakpoint_t db_taken_bkpt = 0;
297:
298: void
299: db_set_single_step(regs)
300: register db_regs_t *regs;
301: {
302: db_addr_t pc = PC_REGS(regs);
303: register unsigned inst, brpc;
304:
305: /*
306: * User was stopped at pc, e.g. the instruction
307: * at pc was not executed.
308: */
309: inst = db_get_value(pc, sizeof(int), FALSE);
310: if (inst_branch(inst) || inst_call(inst)) {
311: extern unsigned getreg_val();
312:
313: brpc = branch_taken(inst, pc, getreg_val, regs);
314: if (brpc != pc) { /* self-branches are hopeless */
315: db_taken_bkpt = db_set_temp_breakpoint(brpc);
316: }
317: pc = next_instr_address(pc,1);
318: }
319: pc = next_instr_address(pc,0);
320: db_not_taken_bkpt = db_set_temp_breakpoint(pc);
321: }
322:
323: void
324: db_clear_single_step(regs)
325: db_regs_t *regs;
326: {
327: register db_breakpoint_t bkpt;
328:
329: if (db_taken_bkpt != 0) {
330: db_delete_temp_breakpoint(db_taken_bkpt);
331: db_taken_bkpt = 0;
332: }
333: if (db_not_taken_bkpt != 0) {
334: db_delete_temp_breakpoint(db_not_taken_bkpt);
335: db_not_taken_bkpt = 0;
336: }
337: }
338:
339: #endif SOFTWARE_SSTEP
340:
341: extern int db_cmd_loop_done;
342:
343: /* single-step */
344: /*ARGSUSED*/
345: void
346: db_single_step_cmd(addr, have_addr, count, modif)
347: db_expr_t addr;
348: int have_addr;
349: db_expr_t count;
350: char * modif;
351: {
352: boolean_t print = FALSE;
353:
354: if (count == -1)
355: count = 1;
356:
357: if (modif[0] == 'p')
358: print = TRUE;
359:
360: db_run_mode = STEP_ONCE;
361: db_loop_count = count;
362: db_sstep_print = print;
363: db_inst_count = 0;
364: db_load_count = 0;
365: db_store_count = 0;
366:
367: db_cmd_loop_done = 1;
368: }
369:
370: /* trace and print until call/return */
371: /*ARGSUSED*/
372: void
373: db_trace_until_call_cmd(addr, have_addr, count, modif)
374: db_expr_t addr;
375: int have_addr;
376: db_expr_t count;
377: char * modif;
378: {
379: boolean_t print = FALSE;
380:
381: if (modif[0] == 'p')
382: print = TRUE;
383:
384: db_run_mode = STEP_CALLT;
385: db_sstep_print = print;
386: db_inst_count = 0;
387: db_load_count = 0;
388: db_store_count = 0;
389:
390: db_cmd_loop_done = 1;
391: }
392:
393: /*ARGSUSED*/
394: void
395: db_trace_until_matching_cmd(addr, have_addr, count, modif)
396: db_expr_t addr;
397: int have_addr;
398: db_expr_t count;
399: char * modif;
400: {
401: boolean_t print = FALSE;
402:
403: if (modif[0] == 'p')
404: print = TRUE;
405:
406: db_run_mode = STEP_RETURN;
407: db_call_depth = 1;
408: db_sstep_print = print;
409: db_inst_count = 0;
410: db_load_count = 0;
411: db_store_count = 0;
412:
413: db_cmd_loop_done = 1;
414: }
415:
416: /* continue */
417: /*ARGSUSED*/
418: void
419: db_continue_cmd(addr, have_addr, count, modif)
420: db_expr_t addr;
421: int have_addr;
422: db_expr_t count;
423: char * modif;
424: {
425: if (modif[0] == 'c')
426: db_run_mode = STEP_COUNT;
427: else
428: db_run_mode = STEP_CONTINUE;
429: db_inst_count = 0;
430: db_load_count = 0;
431: db_store_count = 0;
432:
433: db_cmd_loop_done = 1;
434: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.