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