1
2
3
4
5
6
7
8
9
10
11
12#include <linux/linkage.h>
13#include <linux/sched.h>
14#include <asm/ptrace.h>
15
16#define CCR_MASK 0x6f
17#define BREAKINST 0x5730
18
19
20
21
22static const int h8300_register_offset[] = {
23 PT_REG(er1), PT_REG(er2), PT_REG(er3), PT_REG(er4),
24 PT_REG(er5), PT_REG(er6), PT_REG(er0), PT_REG(orig_er0),
25 PT_REG(ccr), PT_REG(pc)
26};
27
28
29long h8300_get_reg(struct task_struct *task, int regno)
30{
31 switch (regno) {
32 case PT_USP:
33 return task->thread.usp + sizeof(long)*2;
34 case PT_CCR:
35 return *(unsigned short *)(task->thread.esp0 + h8300_register_offset[regno]);
36 default:
37 return *(unsigned long *)(task->thread.esp0 + h8300_register_offset[regno]);
38 }
39}
40
41
42int h8300_put_reg(struct task_struct *task, int regno, unsigned long data)
43{
44 unsigned short oldccr;
45 switch (regno) {
46 case PT_USP:
47 task->thread.usp = data - sizeof(long)*2;
48 case PT_CCR:
49 oldccr = *(unsigned short *)(task->thread.esp0 + h8300_register_offset[regno]);
50 oldccr &= ~CCR_MASK;
51 data &= CCR_MASK;
52 data |= oldccr;
53 *(unsigned short *)(task->thread.esp0 + h8300_register_offset[regno]) = data;
54 break;
55 default:
56 *(unsigned long *)(task->thread.esp0 + h8300_register_offset[regno]) = data;
57 break;
58 }
59 return 0;
60}
61
62
63void user_disable_single_step(struct task_struct *child)
64{
65 if((long)child->thread.breakinfo.addr != -1L) {
66 *child->thread.breakinfo.addr = child->thread.breakinfo.inst;
67 child->thread.breakinfo.addr = (unsigned short *)-1L;
68 }
69}
70
71
72enum jump_type {none,
73 jabs,
74 ind,
75 ret,
76 reg,
77 relb,
78 relw,
79 };
80
81
82
83
84
85
86struct optable {
87 unsigned char bitpattern;
88 unsigned char bitmask;
89 signed char length;
90 signed char type;
91} __attribute__((aligned(1),packed));
92
93#define OPTABLE(ptn,msk,len,jmp) \
94 { \
95 .bitpattern = ptn, \
96 .bitmask = msk, \
97 .length = len, \
98 .type = jmp, \
99 }
100
101static const struct optable optable_0[] = {
102 OPTABLE(0x00,0xff, 1,none),
103 OPTABLE(0x01,0xff,-1,none),
104 OPTABLE(0x02,0xfe, 1,none),
105 OPTABLE(0x04,0xee, 1,none),
106 OPTABLE(0x06,0xfe, 1,none),
107 OPTABLE(0x08,0xea, 1,none),
108 OPTABLE(0x0a,0xee, 1,none),
109 OPTABLE(0x0e,0xee, 1,none),
110 OPTABLE(0x10,0xfc, 1,none),
111 OPTABLE(0x16,0xfe, 1,none),
112 OPTABLE(0x20,0xe0, 1,none),
113 OPTABLE(0x40,0xf0, 1,relb),
114 OPTABLE(0x50,0xfc, 1,none),
115 OPTABLE(0x54,0xfd, 1,ret ),
116 OPTABLE(0x55,0xff, 1,relb),
117 OPTABLE(0x57,0xff, 1,none),
118 OPTABLE(0x58,0xfb, 2,relw),
119 OPTABLE(0x59,0xfb, 1,reg ),
120 OPTABLE(0x5a,0xfb, 2,jabs),
121 OPTABLE(0x5b,0xfb, 2,ind ),
122 OPTABLE(0x60,0xe8, 1,none),
123 OPTABLE(0x68,0xfa, 1,none),
124 OPTABLE(0x6a,0xfe,-2,none),
125 OPTABLE(0x6e,0xfe, 2,none),
126 OPTABLE(0x78,0xff, 4,none),
127 OPTABLE(0x79,0xff, 2,none),
128 OPTABLE(0x7a,0xff, 3,none),
129 OPTABLE(0x7b,0xff, 2,none),
130 OPTABLE(0x7c,0xfc, 2,none),
131 OPTABLE(0x80,0x80, 1,none),
132};
133
134static const struct optable optable_1[] = {
135 OPTABLE(0x00,0xff,-3,none),
136 OPTABLE(0x40,0xf0,-3,none),
137 OPTABLE(0x80,0xf0, 1,none),
138 OPTABLE(0xc0,0xc0, 2,none),
139};
140
141static const struct optable optable_2[] = {
142 OPTABLE(0x00,0x20, 2,none),
143 OPTABLE(0x20,0x20, 3,none),
144};
145
146static const struct optable optable_3[] = {
147 OPTABLE(0x69,0xfb, 2,none),
148 OPTABLE(0x6b,0xff,-4,none),
149 OPTABLE(0x6f,0xff, 3,none),
150 OPTABLE(0x78,0xff, 5,none),
151};
152
153static const struct optable optable_4[] = {
154 OPTABLE(0x00,0x78, 3,none),
155 OPTABLE(0x20,0x78, 4,none),
156};
157
158static const struct optables_list {
159 const struct optable *ptr;
160 int size;
161} optables[] = {
162#define OPTABLES(no) \
163 { \
164 .ptr = optable_##no, \
165 .size = sizeof(optable_##no) / sizeof(struct optable), \
166 }
167 OPTABLES(0),
168 OPTABLES(1),
169 OPTABLES(2),
170 OPTABLES(3),
171 OPTABLES(4),
172
173};
174
175const unsigned char condmask[] = {
176 0x00,0x40,0x01,0x04,0x02,0x08,0x10,0x20
177};
178
179static int isbranch(struct task_struct *task,int reson)
180{
181 unsigned char cond = h8300_get_reg(task, PT_CCR);
182
183
184
185
186 __asm__("bld #3,%w0\n\t"
187 "bxor #1,%w0\n\t"
188 "bst #4,%w0\n\t"
189 "bor #2,%w0\n\t"
190 "bst #5,%w0\n\t"
191 "bld #2,%w0\n\t"
192 "bor #0,%w0\n\t"
193 "bst #6,%w0\n\t"
194 :"=&r"(cond)::"cc");
195 cond &= condmask[reson >> 1];
196 if (!(reson & 1))
197 return cond == 0;
198 else
199 return cond != 0;
200}
201
202static unsigned short *getnextpc(struct task_struct *child, unsigned short *pc)
203{
204 const struct optable *op;
205 unsigned char *fetch_p;
206 unsigned char inst;
207 unsigned long addr;
208 unsigned long *sp;
209 int op_len,regno;
210 op = optables[0].ptr;
211 op_len = optables[0].size;
212 fetch_p = (unsigned char *)pc;
213 inst = *fetch_p++;
214 do {
215 if ((inst & op->bitmask) == op->bitpattern) {
216 if (op->length < 0) {
217 op = optables[-op->length].ptr;
218 op_len = optables[-op->length].size + 1;
219 inst = *fetch_p++;
220 } else {
221 switch (op->type) {
222 case none:
223 return pc + op->length;
224 case jabs:
225 addr = *(unsigned long *)pc;
226 return (unsigned short *)(addr & 0x00ffffff);
227 case ind:
228 addr = *pc & 0xff;
229 return (unsigned short *)(*(unsigned long *)addr);
230 case ret:
231 sp = (unsigned long *)h8300_get_reg(child, PT_USP);
232
233
234
235
236
237
238
239 return (unsigned short *)(*(sp+2) & 0x00ffffff);
240 case reg:
241 regno = (*pc >> 4) & 0x07;
242 if (regno == 0)
243 addr = h8300_get_reg(child, PT_ER0);
244 else
245 addr = h8300_get_reg(child, regno-1+PT_ER1);
246 return (unsigned short *)addr;
247 case relb:
248 if (inst == 0x55 || isbranch(child,inst & 0x0f))
249 pc = (unsigned short *)((unsigned long)pc +
250 ((signed char)(*fetch_p)));
251 return pc+1;
252 case relw:
253 if (inst == 0x5c || isbranch(child,(*fetch_p & 0xf0) >> 4))
254 pc = (unsigned short *)((unsigned long)pc +
255 ((signed short)(*(pc+1))));
256 return pc+2;
257 }
258 }
259 } else
260 op++;
261 } while(--op_len > 0);
262 return NULL;
263}
264
265
266
267void user_enable_single_step(struct task_struct *child)
268{
269 unsigned short *nextpc;
270 nextpc = getnextpc(child,(unsigned short *)h8300_get_reg(child, PT_PC));
271 child->thread.breakinfo.addr = nextpc;
272 child->thread.breakinfo.inst = *nextpc;
273 *nextpc = BREAKINST;
274}
275
276asmlinkage void trace_trap(unsigned long bp)
277{
278 if ((unsigned long)current->thread.breakinfo.addr == bp) {
279 user_disable_single_step(current);
280 force_sig(SIGTRAP,current);
281 } else
282 force_sig(SIGILL,current);
283}
284
285