Annotation of sys/arch/m88k/m88k/db_sstep.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: db_sstep.c,v 1.5 2006/05/03 18:12:52 miod Exp $ */
2: /*
3: * Mach Operating System
4: * Copyright (c) 1993-1991 Carnegie Mellon University
5: * Copyright (c) 1991 OMRON Corporation
6: * All Rights Reserved.
7: *
8: * Permission to use, copy, modify and distribute this software and its
9: * documentation is hereby granted, provided that both the copyright
10: * notice and this permission notice appear in all copies of the
11: * software, derivative works or modified versions, and any portions
12: * thereof, and that both notices appear in supporting documentation.
13: *
14: * CARNEGIE MELLON AND OMRON ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS"
15: * CONDITION. CARNEGIE MELLON AND OMRON DISCLAIM ANY LIABILITY OF ANY KIND
16: * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
17: *
18: * Carnegie Mellon requests users of this software to return to
19: *
20: * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
21: * School of Computer Science
22: * Carnegie Mellon University
23: * Pittsburgh PA 15213-3890
24: *
25: * any improvements or extensions that they make and grant Carnegie the
26: * rights to redistribute these changes.
27: */
28:
29: #include <sys/param.h>
30: #include <sys/systm.h>
31:
32: #include <machine/db_machdep.h>
33:
34: #include <ddb/db_access.h> /* db_get_value() */
35: #include <ddb/db_break.h> /* db_breakpoint_t */
36: #include <ddb/db_run.h>
37:
38: /*
39: * Support routines for software single step.
40: *
41: * Author: Daniel Stodolsky (danner@cs.cmu.edu)
42: *
43: */
44:
45: /*
46: * inst_load(ins)
47: * Returns the number of words the instruction loads. byte,
48: * half and word count as 1; double word as 2
49: */
50: int
51: inst_load(u_int ins)
52: {
53: /* look at the top six bits, for starters */
54: switch (ins >> (32 - 6)) {
55: case 0x0: /* xmem byte imm */
56: case 0x1: /* xmem word imm */
57: case 0x2: /* unsigned half-word load imm */
58: case 0x3: /* unsigned byte load imm */
59: case 0x5: /* signed word load imm */
60: case 0x6: /* signed half-word load imm */
61: case 0x7: /* signed byte load imm */
62: return (1);
63:
64: case 0x4: /* signed double word load imm */
65: return (2);
66:
67: case 0x3d: /* load/store/xmem scaled/unscaled instruction */
68: if ((ins & 0x0000c0e0) == 0x00000000) /* is ld/st/xmem */
69: /* look at bits 15-10 */
70: switch ((ins & 0x0000fc00) >> 10) {
71: case 0x0: /* xmem byte */
72: case 0x1: /* xmem word */
73: case 0x2: /* unsigned half word */
74: case 0x3: /* unsigned byte load */
75: case 0x5: /* signed word load */
76: case 0x6: /* signed half-word load */
77: case 0x7: /* signed byte load */
78: return (1);
79:
80: case 0x4: /* signed double word load */
81: return (2);
82: }
83: break;
84: }
85:
86: return (0);
87: }
88:
89: /*
90: * inst_store
91: * Like inst_load, except for store instructions.
92: */
93: int
94: inst_store(u_int ins)
95: {
96: /* decode top 6 bits again */
97: switch (ins >> (32 - 6)) {
98: case 0x0: /* xmem byte imm */
99: case 0x1: /* xmem word imm */
100: case 0x9: /* store word imm */
101: case 0xa: /* store half-word imm */
102: case 0xb: /* store byte imm */
103: return (1);
104:
105: case 0x8: /* store double word */
106: return (2);
107:
108: case 0x3d: /* load/store/xmem scaled/unscaled instruction */
109: if ((ins & 0x0000c0e0) == 0x00000000) /* is ld/st/xmem */
110: /* look at bits 15-10 */
111: switch ((ins & 0x0000fc00) >> 10) {
112: case 0x0: /* xmem byte imm */
113: case 0x1: /* xmem word imm */
114: case 0x9: /* store word */
115: case 0xa: /* store half-word */
116: case 0xb: /* store byte */
117: return (1);
118:
119: case 0x8: /* store double word */
120: return (2);
121: }
122: break;
123: }
124:
125: return (0);
126: }
127:
128: /*
129: * We can not use the MI ddb SOFTWARE_SSTEP facility, since the 88110 will use
130: * hardware single stepping.
131: * Moreover, our software single stepping implementation is tailor-made for the
132: * 88100 and faster than the MI code.
133: */
134:
135: #ifdef M88100
136:
137: boolean_t inst_branch_or_call(u_int);
138: db_addr_t branch_taken(u_int, db_addr_t, db_regs_t *);
139:
140: db_breakpoint_t db_not_taken_bkpt = 0;
141: db_breakpoint_t db_taken_bkpt = 0;
142:
143: /*
144: * Returns TRUE is the instruction a branch, jump or call instruction
145: * (br, bb0, bb1, bcnd, jmp, bsr, jsr)
146: */
147: boolean_t
148: inst_branch_or_call(u_int ins)
149: {
150: /* check high five bits */
151: switch (ins >> (32 - 5)) {
152: case 0x18: /* br */
153: case 0x19: /* bsr */
154: case 0x1a: /* bb0 */
155: case 0x1b: /* bb1 */
156: case 0x1d: /* bcnd */
157: return (TRUE);
158: case 0x1e: /* could be jmp or jsr */
159: if ((ins & 0xfffff3e0) == 0xf400c000)
160: return (TRUE);
161: }
162:
163: return (FALSE);
164: }
165:
166: /*
167: * branch_taken(instruction, program counter, regs)
168: *
169: * instruction will be a control flow instruction location at address pc.
170: * Branch taken is supposed to return the address to which the instruction
171: * would jump if the branch is taken.
172: */
173: db_addr_t
174: branch_taken(u_int inst, db_addr_t pc, db_regs_t *regs)
175: {
176: u_int regno;
177:
178: /*
179: * Quick check of the instruction. Note that we know we are only
180: * invoked if inst_branch_or_call() returns TRUE, so we do not
181: * need to repeat the jmp and jsr stricter checks here.
182: */
183: switch (inst >> (32 - 5)) {
184: case 0x18: /* br */
185: case 0x19: /* bsr */
186: /* signed 26 bit pc relative displacement, shift left two bits */
187: inst = (inst & 0x03ffffff) << 2;
188: /* check if sign extension is needed */
189: if (inst & 0x08000000)
190: inst |= 0xf0000000;
191: return (pc + inst);
192:
193: case 0x1a: /* bb0 */
194: case 0x1b: /* bb1 */
195: case 0x1d: /* bcnd */
196: /* signed 16 bit pc relative displacement, shift left two bits */
197: inst = (inst & 0x0000ffff) << 2;
198: /* check if sign extension is needed */
199: if (inst & 0x00020000)
200: inst |= 0xfffc0000;
201: return (pc + inst);
202:
203: default: /* jmp or jsr */
204: regno = inst & 0x1f;
205: return (regno == 0 ? 0 : regs->r[regno]);
206: }
207: }
208:
209: #endif /* M88100 */
210:
211: void
212: db_set_single_step(db_regs_t *regs)
213: {
214: #ifdef M88110
215: if (CPU_IS88110) {
216: /*
217: * On the 88110, we can use the hardware tracing facility...
218: */
219: regs->epsr |= PSR_TRACE | PSR_SER;
220: }
221: #endif
222: #ifdef M88100
223: if (CPU_IS88100) {
224: /*
225: * ... while the 88100 will use two breakpoints.
226: */
227: db_addr_t pc = PC_REGS(regs);
228: db_addr_t brpc;
229: u_int inst;
230:
231: /*
232: * User was stopped at pc, e.g. the instruction
233: * at pc was not executed.
234: */
235: db_read_bytes(pc, sizeof(inst), (caddr_t)&inst);
236:
237: /*
238: * Find if this instruction may cause a branch, and set up a
239: * breakpoint at the branch location.
240: */
241: if (inst_branch_or_call(inst)) {
242: brpc = branch_taken(inst, pc, regs);
243:
244: /* self-branches are hopeless */
245: if (brpc != pc && brpc != 0)
246: db_taken_bkpt = db_set_temp_breakpoint(brpc);
247: }
248:
249: db_not_taken_bkpt = db_set_temp_breakpoint(pc + 4);
250: }
251: #endif
252: }
253:
254: void
255: db_clear_single_step(regs)
256: db_regs_t *regs;
257: {
258: #ifdef M88110
259: if (CPU_IS88110) {
260: /* do not remove PSR_SER as we don't enable OoO */
261: regs->epsr &= ~PSR_TRACE;
262: }
263: #endif
264: #ifdef M88100
265: if (CPU_IS88100) {
266: if (db_taken_bkpt != 0) {
267: db_delete_temp_breakpoint(db_taken_bkpt);
268: db_taken_bkpt = 0;
269: }
270: if (db_not_taken_bkpt != 0) {
271: db_delete_temp_breakpoint(db_not_taken_bkpt);
272: db_not_taken_bkpt = 0;
273: }
274: }
275: #endif
276: }
CVSweb