|
|
1.1.1.2 root 1: /*
1.1 root 2: * Mach Operating System
3: * Copyright (c) 1993-1990 Carnegie Mellon University
4: * All Rights Reserved.
1.1.1.2 root 5: *
1.1 root 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.
1.1.1.2 root 11: *
1.1 root 12: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
13: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
1.1.1.2 root 15: *
1.1 root 16: * Carnegie Mellon requests users of this software to return to
1.1.1.2 root 17: *
1.1 root 18: * Software Distribution Coordinator or [email protected]
19: * School of Computer Science
20: * Carnegie Mellon University
21: * Pittsburgh PA 15213-3890
1.1.1.2 root 22: *
1.1 root 23: * any improvements or extensions that they make and grant Carnegie Mellon
24: * the rights to redistribute these changes.
25: */
26: /*
27: * Author: David B. Golub, Carnegie Mellon University
28: * Date: 7/90
29: */
30:
31: #if MACH_KDB
32:
33: /*
34: * Commands to run process.
35: */
36: #include <mach/boolean.h>
37: #include <machine/db_machdep.h>
38:
39: #include <ddb/db_lex.h>
40: #include <ddb/db_break.h>
41: #include <ddb/db_access.h>
42: #include <ddb/db_run.h>
43: #include <ddb/db_task_thread.h>
1.1.1.3 ! root 44: #include <ddb/db_command.h>
! 45: #include <ddb/db_examine.h>
! 46: #include <ddb/db_output.h>
! 47: #include <ddb/db_watch.h>
! 48: #include <ddb/db_cond.h>
! 49:
1.1 root 50:
51: int db_run_mode;
52:
53: boolean_t db_sstep_print;
54: int db_loop_count;
55: int db_call_depth;
56:
57: int db_inst_count;
58: int db_last_inst_count;
59: int db_load_count;
60: int db_store_count;
61:
62: #ifndef db_set_single_step
63: void db_set_task_single_step(/* db_regs_t *, task_t */);/* forward */
64: #else
65: #define db_set_task_single_step(regs,task) db_set_single_step(regs)
66: #endif
67: #ifndef db_clear_single_step
68: void db_clear_task_single_step(/* db_regs_t *, task_t */);
69: #else
70: #define db_clear_task_single_step(regs,task) db_clear_single_step(regs)
71: #endif
72:
73: boolean_t
74: db_stop_at_pc(is_breakpoint, task)
75: boolean_t *is_breakpoint;
76: task_t task;
77: {
78: register db_addr_t pc;
79: register db_thread_breakpoint_t bkpt;
80:
81: db_clear_task_single_step(DDB_REGS, task);
82: db_clear_breakpoints();
83: db_clear_watchpoints();
84: pc = PC_REGS(DDB_REGS);
85:
86: #ifdef FIXUP_PC_AFTER_BREAK
87: if (*is_breakpoint) {
88: /*
89: * Breakpoint trap. Fix up the PC if the
90: * machine requires it.
91: */
92: FIXUP_PC_AFTER_BREAK
93: pc = PC_REGS(DDB_REGS);
94: }
95: #endif
96:
97: /*
98: * Now check for a breakpoint at this address.
99: */
100: bkpt = db_find_thread_breakpoint_here(task, pc);
101: if (bkpt) {
102: if (db_cond_check(bkpt)) {
103: *is_breakpoint = TRUE;
104: return (TRUE); /* stop here */
105: }
106: }
107: *is_breakpoint = FALSE;
108:
109: if (db_run_mode == STEP_INVISIBLE) {
110: db_run_mode = STEP_CONTINUE;
111: return (FALSE); /* continue */
112: }
113: if (db_run_mode == STEP_COUNT) {
114: return (FALSE); /* continue */
115: }
116: if (db_run_mode == STEP_ONCE) {
117: if (--db_loop_count > 0) {
118: if (db_sstep_print) {
119: db_print_loc_and_inst(pc, task);
120: }
121: return (FALSE); /* continue */
122: }
123: }
124: if (db_run_mode == STEP_RETURN) {
125: /* WARNING: the following assumes an instruction fits an int */
126: db_expr_t ins = db_get_task_value(pc, sizeof(int), FALSE, task);
127:
128: /* continue until matching return */
129:
130: if (!inst_trap_return(ins) &&
131: (!inst_return(ins) || --db_call_depth != 0)) {
132: if (db_sstep_print) {
133: if (inst_call(ins) || inst_return(ins)) {
134: register int i;
135:
136: db_printf("[after %6d /%4d] ",
137: db_inst_count,
138: db_inst_count - db_last_inst_count);
139: db_last_inst_count = db_inst_count;
140: for (i = db_call_depth; --i > 0; )
141: db_printf(" ");
142: db_print_loc_and_inst(pc, task);
143: db_printf("\n");
144: }
145: }
146: if (inst_call(ins))
147: db_call_depth++;
148: return (FALSE); /* continue */
149: }
150: }
151: if (db_run_mode == STEP_CALLT) {
152: /* WARNING: the following assumes an instruction fits an int */
153: db_expr_t ins = db_get_task_value(pc, sizeof(int), FALSE, task);
154:
155: /* continue until call or return */
156:
157: if (!inst_call(ins) &&
158: !inst_return(ins) &&
159: !inst_trap_return(ins)) {
160: return (FALSE); /* continue */
161: }
162: }
163: if (db_find_breakpoint_here(task, pc))
164: return(FALSE);
165: db_run_mode = STEP_NONE;
166: return (TRUE);
167: }
168:
169: void
170: db_restart_at_pc(watchpt, task)
171: boolean_t watchpt;
172: task_t task;
173: {
174: register db_addr_t pc = PC_REGS(DDB_REGS), brpc;
175:
176: if ((db_run_mode == STEP_COUNT) ||
177: (db_run_mode == STEP_RETURN) ||
178: (db_run_mode == STEP_CALLT)) {
179: db_expr_t ins;
180:
181: /*
182: * We are about to execute this instruction,
183: * so count it now.
184: */
185:
186: ins = db_get_task_value(pc, sizeof(int), FALSE, task);
187: db_inst_count++;
188: db_load_count += inst_load(ins);
189: db_store_count += inst_store(ins);
190: #ifdef SOFTWARE_SSTEP
191: /* Account for instructions in delay slots */
192: brpc = next_instr_address(pc,1,task);
193: if ((brpc != pc) && (inst_branch(ins) || inst_call(ins))) {
194: /* Note: this ~assumes an instruction <= sizeof(int) */
195: ins = db_get_task_value(brpc, sizeof(int), FALSE, task);
196: db_inst_count++;
197: db_load_count += inst_load(ins);
198: db_store_count += inst_store(ins);
199: }
200: #endif /* SOFTWARE_SSTEP */
201: }
202:
203: if (db_run_mode == STEP_CONTINUE) {
204: if (watchpt || db_find_breakpoint_here(task, pc)) {
205: /*
206: * Step over breakpoint/watchpoint.
207: */
208: db_run_mode = STEP_INVISIBLE;
209: db_set_task_single_step(DDB_REGS, task);
210: } else {
211: db_set_breakpoints();
212: db_set_watchpoints();
213: }
214: } else {
215: db_set_task_single_step(DDB_REGS, task);
216: }
217: }
218:
219: void
220: db_single_step(regs, task)
221: db_regs_t *regs;
222: task_t task;
223: {
224: if (db_run_mode == STEP_CONTINUE) {
225: db_run_mode = STEP_INVISIBLE;
226: db_set_task_single_step(regs, task);
227: }
228: }
229:
230: #ifdef SOFTWARE_SSTEP
231: /*
232: * Software implementation of single-stepping.
233: * If your machine does not have a trace mode
234: * similar to the vax or sun ones you can use
235: * this implementation, done for the mips.
236: * Just define the above conditional and provide
237: * the functions/macros defined below.
238: *
239: * extern boolean_t
240: * inst_branch(), returns true if the instruction might branch
241: * extern unsigned
242: * branch_taken(), return the address the instruction might
243: * branch to
244: * db_getreg_val(); return the value of a user register,
245: * as indicated in the hardware instruction
246: * encoding, e.g. 8 for r8
1.1.1.2 root 247: *
1.1 root 248: * next_instr_address(pc,bd,task) returns the address of the first
249: * instruction following the one at "pc",
250: * which is either in the taken path of
251: * the branch (bd==1) or not. This is
252: * for machines (mips) with branch delays.
253: *
254: * A single-step may involve at most 2 breakpoints -
255: * one for branch-not-taken and one for branch taken.
256: * If one of these addresses does not already have a breakpoint,
257: * we allocate a breakpoint and save it here.
258: * These breakpoints are deleted on return.
1.1.1.2 root 259: */
1.1 root 260: db_breakpoint_t db_not_taken_bkpt = 0;
261: db_breakpoint_t db_taken_bkpt = 0;
262:
263: db_breakpoint_t
264: db_find_temp_breakpoint(task, addr)
265: task_t task;
266: db_addr_t addr;
267: {
268: if (db_taken_bkpt && (db_taken_bkpt->address == addr) &&
269: db_taken_bkpt->task == task)
270: return db_taken_bkpt;
271: if (db_not_taken_bkpt && (db_not_taken_bkpt->address == addr) &&
272: db_not_taken_bkpt->task == task)
273: return db_not_taken_bkpt;
274: return 0;
275: }
276:
277: void
278: db_set_task_single_step(regs, task)
279: register db_regs_t *regs;
280: task_t task;
281: {
282: db_addr_t pc = PC_REGS(regs), brpc;
283: register unsigned int inst;
284: register boolean_t unconditional;
285:
286: /*
287: * User was stopped at pc, e.g. the instruction
288: * at pc was not executed.
289: */
290: inst = db_get_task_value(pc, sizeof(int), FALSE, task);
291: if (inst_branch(inst) || inst_call(inst)) {
292: extern db_expr_t getreg_val();
293:
294: brpc = branch_taken(inst, pc, getreg_val, regs);
295: if (brpc != pc) { /* self-branches are hopeless */
296: db_taken_bkpt = db_set_temp_breakpoint(task, brpc);
297: } else
298: db_taken_bkpt = 0;
299: pc = next_instr_address(pc,1,task);
300: }
1.1.1.2 root 301:
1.1 root 302: /* check if this control flow instruction is an unconditional transfer */
303: unconditional = inst_unconditional_flow_transfer(inst);
304:
305: pc = next_instr_address(pc,0,task);
1.1.1.2 root 306: /*
1.1 root 307: We only set the sequential breakpoint if previous instruction was not
308: an unconditional change of flow of control. If the previous instruction
309: is an unconditional change of flow of control, setting a breakpoint in the
310: next sequential location may set a breakpoint in data or in another routine,
1.1.1.2 root 311: which could screw up either the program or the debugger.
312: (Consider, for instance, that the next sequential instruction is the
1.1 root 313: start of a routine needed by the debugger.)
314: */
315: if (!unconditional && db_find_breakpoint_here(task, pc) == 0) {
316: db_not_taken_bkpt = db_set_temp_breakpoint(task, pc);
317: }
318: else
319: db_not_taken_bkpt = 0;
320: }
321:
322: void
323: db_clear_task_single_step(regs, task)
324: db_regs_t *regs;
325: task_t task;
326: {
327: if (db_taken_bkpt != 0) {
328: db_delete_temp_breakpoint(task, db_taken_bkpt);
329: db_taken_bkpt = 0;
330: }
331: if (db_not_taken_bkpt != 0) {
332: db_delete_temp_breakpoint(task, db_not_taken_bkpt);
333: db_not_taken_bkpt = 0;
334: }
335: }
336:
337: #endif /* SOFTWARE_SSTEP */
338:
339:
340: extern int db_cmd_loop_done;
341:
342: /* single-step */
343: /*ARGSUSED*/
344: void
345: db_single_step_cmd(addr, have_addr, count, modif)
346: db_expr_t addr;
347: int have_addr;
348: db_expr_t count;
349: char * modif;
350: {
351: boolean_t print = FALSE;
352:
353: if (count == -1)
354: count = 1;
355:
356: if (modif[0] == 'p')
357: print = TRUE;
358:
359: db_run_mode = STEP_ONCE;
360: db_loop_count = count;
361: db_sstep_print = print;
362: db_inst_count = 0;
363: db_last_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_last_inst_count = 0;
388: db_load_count = 0;
389: db_store_count = 0;
390:
391: db_cmd_loop_done = 1;
392: }
393:
394: /*ARGSUSED*/
395: void
396: db_trace_until_matching_cmd(addr, have_addr, count, modif)
397: db_expr_t addr;
398: int have_addr;
399: db_expr_t count;
400: char * modif;
401: {
402: boolean_t print = FALSE;
403:
404: if (modif[0] == 'p')
405: print = TRUE;
406:
407: db_run_mode = STEP_RETURN;
408: db_call_depth = 1;
409: db_sstep_print = print;
410: db_inst_count = 0;
411: db_last_inst_count = 0;
412: db_load_count = 0;
413: db_store_count = 0;
414:
415: db_cmd_loop_done = 1;
416: }
417:
418: /* continue */
419: /*ARGSUSED*/
420: void
421: db_continue_cmd(addr, have_addr, count, modif)
422: db_expr_t addr;
423: int have_addr;
424: db_expr_t count;
425: char * modif;
426: {
427: if (modif[0] == 'c')
428: db_run_mode = STEP_COUNT;
429: else
430: db_run_mode = STEP_CONTINUE;
431: db_inst_count = 0;
432: db_last_inst_count = 0;
433: db_load_count = 0;
434: db_store_count = 0;
435:
436: db_cmd_loop_done = 1;
437: }
438:
439: boolean_t
440: db_in_single_step()
441: {
442: return(db_run_mode != STEP_NONE && db_run_mode != STEP_CONTINUE);
443: }
444:
1.1.1.2 root 445: #endif /* MACH_KDB */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.