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