|
|
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: boolean_t
1.1.1.4 ! root 63: db_stop_at_pc(
! 64: boolean_t *is_breakpoint,
! 65: task_t task)
1.1 root 66: {
1.1.1.4 ! root 67: db_addr_t pc;
! 68: db_thread_breakpoint_t bkpt;
1.1 root 69:
70: db_clear_task_single_step(DDB_REGS, task);
71: db_clear_breakpoints();
72: db_clear_watchpoints();
73: pc = PC_REGS(DDB_REGS);
74:
75: #ifdef FIXUP_PC_AFTER_BREAK
76: if (*is_breakpoint) {
77: /*
78: * Breakpoint trap. Fix up the PC if the
79: * machine requires it.
80: */
81: FIXUP_PC_AFTER_BREAK
82: pc = PC_REGS(DDB_REGS);
83: }
1.1.1.4 ! root 84: #endif /* FIXUP_PC_AFTER_BREAK */
1.1 root 85:
86: /*
87: * Now check for a breakpoint at this address.
88: */
89: bkpt = db_find_thread_breakpoint_here(task, pc);
90: if (bkpt) {
91: if (db_cond_check(bkpt)) {
92: *is_breakpoint = TRUE;
93: return (TRUE); /* stop here */
94: }
95: }
96: *is_breakpoint = FALSE;
97:
98: if (db_run_mode == STEP_INVISIBLE) {
99: db_run_mode = STEP_CONTINUE;
100: return (FALSE); /* continue */
101: }
102: if (db_run_mode == STEP_COUNT) {
103: return (FALSE); /* continue */
104: }
105: if (db_run_mode == STEP_ONCE) {
106: if (--db_loop_count > 0) {
107: if (db_sstep_print) {
108: db_print_loc_and_inst(pc, task);
109: }
110: return (FALSE); /* continue */
111: }
112: }
113: if (db_run_mode == STEP_RETURN) {
114: /* WARNING: the following assumes an instruction fits an int */
115: db_expr_t ins = db_get_task_value(pc, sizeof(int), FALSE, task);
116:
117: /* continue until matching return */
118:
119: if (!inst_trap_return(ins) &&
120: (!inst_return(ins) || --db_call_depth != 0)) {
121: if (db_sstep_print) {
122: if (inst_call(ins) || inst_return(ins)) {
1.1.1.4 ! root 123: int i;
1.1 root 124:
125: db_printf("[after %6d /%4d] ",
126: db_inst_count,
127: db_inst_count - db_last_inst_count);
128: db_last_inst_count = db_inst_count;
129: for (i = db_call_depth; --i > 0; )
130: db_printf(" ");
131: db_print_loc_and_inst(pc, task);
132: db_printf("\n");
133: }
134: }
135: if (inst_call(ins))
136: db_call_depth++;
137: return (FALSE); /* continue */
138: }
139: }
140: if (db_run_mode == STEP_CALLT) {
141: /* WARNING: the following assumes an instruction fits an int */
142: db_expr_t ins = db_get_task_value(pc, sizeof(int), FALSE, task);
143:
144: /* continue until call or return */
145:
146: if (!inst_call(ins) &&
147: !inst_return(ins) &&
148: !inst_trap_return(ins)) {
149: return (FALSE); /* continue */
150: }
151: }
152: if (db_find_breakpoint_here(task, pc))
153: return(FALSE);
154: db_run_mode = STEP_NONE;
155: return (TRUE);
156: }
157:
158: void
1.1.1.4 ! root 159: db_restart_at_pc(
! 160: boolean_t watchpt,
! 161: task_t task)
1.1 root 162: {
1.1.1.4 ! root 163: db_addr_t pc = PC_REGS(DDB_REGS);
1.1 root 164:
165: if ((db_run_mode == STEP_COUNT) ||
166: (db_run_mode == STEP_RETURN) ||
167: (db_run_mode == STEP_CALLT)) {
168:
169: /*
170: * We are about to execute this instruction,
171: * so count it now.
172: */
173:
1.1.1.4 ! root 174: db_get_task_value(pc, sizeof(int), FALSE, task);
1.1 root 175: db_inst_count++;
176: db_load_count += inst_load(ins);
177: db_store_count += inst_store(ins);
178: #ifdef SOFTWARE_SSTEP
1.1.1.4 ! root 179: db_addr_t brpc;
1.1 root 180: /* Account for instructions in delay slots */
1.1.1.4 ! root 181: brpc = next_instr_address(pc, 1, task);
1.1 root 182: if ((brpc != pc) && (inst_branch(ins) || inst_call(ins))) {
183: /* Note: this ~assumes an instruction <= sizeof(int) */
1.1.1.4 ! root 184: db_get_task_value(brpc, sizeof(int), FALSE, task);
1.1 root 185: db_inst_count++;
186: db_load_count += inst_load(ins);
187: db_store_count += inst_store(ins);
188: }
189: #endif /* SOFTWARE_SSTEP */
190: }
191:
192: if (db_run_mode == STEP_CONTINUE) {
193: if (watchpt || db_find_breakpoint_here(task, pc)) {
194: /*
195: * Step over breakpoint/watchpoint.
196: */
197: db_run_mode = STEP_INVISIBLE;
198: db_set_task_single_step(DDB_REGS, task);
199: } else {
200: db_set_breakpoints();
201: db_set_watchpoints();
202: }
203: } else {
204: db_set_task_single_step(DDB_REGS, task);
205: }
206: }
207:
208: void
1.1.1.4 ! root 209: db_single_step(
! 210: db_regs_t *regs,
! 211: task_t task)
1.1 root 212: {
213: if (db_run_mode == STEP_CONTINUE) {
214: db_run_mode = STEP_INVISIBLE;
215: db_set_task_single_step(regs, task);
216: }
217: }
218:
219: #ifdef SOFTWARE_SSTEP
220: /*
221: * Software implementation of single-stepping.
222: * If your machine does not have a trace mode
223: * similar to the vax or sun ones you can use
224: * this implementation, done for the mips.
225: * Just define the above conditional and provide
226: * the functions/macros defined below.
227: *
228: * extern boolean_t
229: * inst_branch(), returns true if the instruction might branch
230: * extern unsigned
231: * branch_taken(), return the address the instruction might
232: * branch to
233: * db_getreg_val(); return the value of a user register,
234: * as indicated in the hardware instruction
235: * encoding, e.g. 8 for r8
1.1.1.2 root 236: *
1.1 root 237: * next_instr_address(pc,bd,task) returns the address of the first
238: * instruction following the one at "pc",
239: * which is either in the taken path of
240: * the branch (bd==1) or not. This is
241: * for machines (mips) with branch delays.
242: *
243: * A single-step may involve at most 2 breakpoints -
244: * one for branch-not-taken and one for branch taken.
245: * If one of these addresses does not already have a breakpoint,
246: * we allocate a breakpoint and save it here.
247: * These breakpoints are deleted on return.
1.1.1.2 root 248: */
1.1 root 249: db_breakpoint_t db_not_taken_bkpt = 0;
250: db_breakpoint_t db_taken_bkpt = 0;
251:
1.1.1.4 ! root 252: db_breakpoint_t __attribute__ ((pure))
1.1 root 253: db_find_temp_breakpoint(task, addr)
1.1.1.4 ! root 254: const task_t task;
! 255: db_addr_t addr;
1.1 root 256: {
257: if (db_taken_bkpt && (db_taken_bkpt->address == addr) &&
258: db_taken_bkpt->task == task)
259: return db_taken_bkpt;
260: if (db_not_taken_bkpt && (db_not_taken_bkpt->address == addr) &&
261: db_not_taken_bkpt->task == task)
262: return db_not_taken_bkpt;
263: return 0;
264: }
265:
266: void
1.1.1.4 ! root 267: db_set_task_single_step(
! 268: db_regs_t *regs,
! 269: task_t task)
1.1 root 270: {
271: db_addr_t pc = PC_REGS(regs), brpc;
1.1.1.4 ! root 272: unsigned int inst;
! 273: boolean_t unconditional;
1.1 root 274:
275: /*
276: * User was stopped at pc, e.g. the instruction
277: * at pc was not executed.
278: */
279: inst = db_get_task_value(pc, sizeof(int), FALSE, task);
280: if (inst_branch(inst) || inst_call(inst)) {
281: extern db_expr_t getreg_val();
282:
283: brpc = branch_taken(inst, pc, getreg_val, regs);
284: if (brpc != pc) { /* self-branches are hopeless */
285: db_taken_bkpt = db_set_temp_breakpoint(task, brpc);
286: } else
287: db_taken_bkpt = 0;
288: pc = next_instr_address(pc,1,task);
289: }
1.1.1.2 root 290:
1.1 root 291: /* check if this control flow instruction is an unconditional transfer */
292: unconditional = inst_unconditional_flow_transfer(inst);
293:
294: pc = next_instr_address(pc,0,task);
1.1.1.2 root 295: /*
1.1 root 296: We only set the sequential breakpoint if previous instruction was not
297: an unconditional change of flow of control. If the previous instruction
298: is an unconditional change of flow of control, setting a breakpoint in the
299: next sequential location may set a breakpoint in data or in another routine,
1.1.1.2 root 300: which could screw up either the program or the debugger.
301: (Consider, for instance, that the next sequential instruction is the
1.1 root 302: start of a routine needed by the debugger.)
303: */
304: if (!unconditional && db_find_breakpoint_here(task, pc) == 0) {
305: db_not_taken_bkpt = db_set_temp_breakpoint(task, pc);
306: }
307: else
308: db_not_taken_bkpt = 0;
309: }
310:
311: void
312: db_clear_task_single_step(regs, task)
1.1.1.4 ! root 313: const db_regs_t *regs;
! 314: task_t task;
1.1 root 315: {
316: if (db_taken_bkpt != 0) {
317: db_delete_temp_breakpoint(task, db_taken_bkpt);
318: db_taken_bkpt = 0;
319: }
320: if (db_not_taken_bkpt != 0) {
321: db_delete_temp_breakpoint(task, db_not_taken_bkpt);
322: db_not_taken_bkpt = 0;
323: }
324: }
325:
326: #endif /* SOFTWARE_SSTEP */
327:
328:
329: extern int db_cmd_loop_done;
330:
331: /* single-step */
332: /*ARGSUSED*/
333: void
334: db_single_step_cmd(addr, have_addr, count, modif)
335: db_expr_t addr;
336: int have_addr;
337: db_expr_t count;
1.1.1.4 ! root 338: const char * modif;
1.1 root 339: {
340: boolean_t print = FALSE;
341:
342: if (count == -1)
343: count = 1;
344:
345: if (modif[0] == 'p')
346: print = TRUE;
347:
348: db_run_mode = STEP_ONCE;
349: db_loop_count = count;
350: db_sstep_print = print;
351: db_inst_count = 0;
352: db_last_inst_count = 0;
353: db_load_count = 0;
354: db_store_count = 0;
355:
356: db_cmd_loop_done = 1;
357: }
358:
359: /* trace and print until call/return */
360: /*ARGSUSED*/
361: void
362: db_trace_until_call_cmd(addr, have_addr, count, modif)
363: db_expr_t addr;
364: int have_addr;
365: db_expr_t count;
1.1.1.4 ! root 366: const char * modif;
1.1 root 367: {
368: boolean_t print = FALSE;
369:
370: if (modif[0] == 'p')
371: print = TRUE;
372:
373: db_run_mode = STEP_CALLT;
374: db_sstep_print = print;
375: db_inst_count = 0;
376: db_last_inst_count = 0;
377: db_load_count = 0;
378: db_store_count = 0;
379:
380: db_cmd_loop_done = 1;
381: }
382:
383: /*ARGSUSED*/
384: void
385: db_trace_until_matching_cmd(addr, have_addr, count, modif)
386: db_expr_t addr;
387: int have_addr;
388: db_expr_t count;
1.1.1.4 ! root 389: const char * modif;
1.1 root 390: {
391: boolean_t print = FALSE;
392:
393: if (modif[0] == 'p')
394: print = TRUE;
395:
396: db_run_mode = STEP_RETURN;
397: db_call_depth = 1;
398: db_sstep_print = print;
399: db_inst_count = 0;
400: db_last_inst_count = 0;
401: db_load_count = 0;
402: db_store_count = 0;
403:
404: db_cmd_loop_done = 1;
405: }
406:
407: /* continue */
408: /*ARGSUSED*/
409: void
410: db_continue_cmd(addr, have_addr, count, modif)
411: db_expr_t addr;
412: int have_addr;
413: db_expr_t count;
1.1.1.4 ! root 414: const char * modif;
1.1 root 415: {
416: if (modif[0] == 'c')
417: db_run_mode = STEP_COUNT;
418: else
419: db_run_mode = STEP_CONTINUE;
420: db_inst_count = 0;
421: db_last_inst_count = 0;
422: db_load_count = 0;
423: db_store_count = 0;
424:
425: db_cmd_loop_done = 1;
426: }
427:
428: boolean_t
1.1.1.4 ! root 429: db_in_single_step(void)
1.1 root 430: {
431: return(db_run_mode != STEP_NONE && db_run_mode != STEP_CONTINUE);
432: }
433:
1.1.1.2 root 434: #endif /* MACH_KDB */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.