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