diff options
-rw-r--r-- | arch/ia64/kernel/kprobes.c | 175 |
1 files changed, 122 insertions, 53 deletions
diff --git a/arch/ia64/kernel/kprobes.c b/arch/ia64/kernel/kprobes.c index 8406d24d516b..6cb56dd4056d 100644 --- a/arch/ia64/kernel/kprobes.c +++ b/arch/ia64/kernel/kprobes.c | |||
@@ -130,48 +130,6 @@ static void __kprobes update_kprobe_inst_flag(uint template, uint slot, | |||
130 | 130 | ||
131 | /* | 131 | /* |
132 | * In this function we check to see if the instruction | 132 | * In this function we check to see if the instruction |
133 | * on which we are inserting kprobe is supported. | ||
134 | * Returns 0 if supported | ||
135 | * Returns -EINVAL if unsupported | ||
136 | */ | ||
137 | static int __kprobes unsupported_inst(uint template, uint slot, | ||
138 | uint major_opcode, | ||
139 | unsigned long kprobe_inst, | ||
140 | unsigned long addr) | ||
141 | { | ||
142 | if (bundle_encoding[template][slot] == I) { | ||
143 | switch (major_opcode) { | ||
144 | case 0x0: //I_UNIT_MISC_OPCODE: | ||
145 | /* | ||
146 | * Check for Integer speculation instruction | ||
147 | * - Bit 33-35 to be equal to 0x1 | ||
148 | */ | ||
149 | if (((kprobe_inst >> 33) & 0x7) == 1) { | ||
150 | printk(KERN_WARNING | ||
151 | "Kprobes on speculation inst at <0x%lx> not supported\n", | ||
152 | addr); | ||
153 | return -EINVAL; | ||
154 | } | ||
155 | |||
156 | /* | ||
157 | * IP relative mov instruction | ||
158 | * - Bit 27-35 to be equal to 0x30 | ||
159 | */ | ||
160 | if (((kprobe_inst >> 27) & 0x1FF) == 0x30) { | ||
161 | printk(KERN_WARNING | ||
162 | "Kprobes on \"mov r1=ip\" at <0x%lx> not supported\n", | ||
163 | addr); | ||
164 | return -EINVAL; | ||
165 | |||
166 | } | ||
167 | } | ||
168 | } | ||
169 | return 0; | ||
170 | } | ||
171 | |||
172 | |||
173 | /* | ||
174 | * In this function we check to see if the instruction | ||
175 | * (qp) cmpx.crel.ctype p1,p2=r2,r3 | 133 | * (qp) cmpx.crel.ctype p1,p2=r2,r3 |
176 | * on which we are inserting kprobe is cmp instruction | 134 | * on which we are inserting kprobe is cmp instruction |
177 | * with ctype as unc. | 135 | * with ctype as unc. |
@@ -207,26 +165,136 @@ out: | |||
207 | } | 165 | } |
208 | 166 | ||
209 | /* | 167 | /* |
168 | * In this function we check to see if the instruction | ||
169 | * on which we are inserting kprobe is supported. | ||
170 | * Returns qp value if supported | ||
171 | * Returns -EINVAL if unsupported | ||
172 | */ | ||
173 | static int __kprobes unsupported_inst(uint template, uint slot, | ||
174 | uint major_opcode, | ||
175 | unsigned long kprobe_inst, | ||
176 | unsigned long addr) | ||
177 | { | ||
178 | int qp; | ||
179 | |||
180 | qp = kprobe_inst & 0x3f; | ||
181 | if (is_cmp_ctype_unc_inst(template, slot, major_opcode, kprobe_inst)) { | ||
182 | if (slot == 1 && qp) { | ||
183 | printk(KERN_WARNING "Kprobes on cmp unc" | ||
184 | "instruction on slot 1 at <0x%lx>" | ||
185 | "is not supported\n", addr); | ||
186 | return -EINVAL; | ||
187 | |||
188 | } | ||
189 | qp = 0; | ||
190 | } | ||
191 | else if (bundle_encoding[template][slot] == I) { | ||
192 | if (major_opcode == 0) { | ||
193 | /* | ||
194 | * Check for Integer speculation instruction | ||
195 | * - Bit 33-35 to be equal to 0x1 | ||
196 | */ | ||
197 | if (((kprobe_inst >> 33) & 0x7) == 1) { | ||
198 | printk(KERN_WARNING | ||
199 | "Kprobes on speculation inst at <0x%lx> not supported\n", | ||
200 | addr); | ||
201 | return -EINVAL; | ||
202 | } | ||
203 | /* | ||
204 | * IP relative mov instruction | ||
205 | * - Bit 27-35 to be equal to 0x30 | ||
206 | */ | ||
207 | if (((kprobe_inst >> 27) & 0x1FF) == 0x30) { | ||
208 | printk(KERN_WARNING | ||
209 | "Kprobes on \"mov r1=ip\" at <0x%lx> not supported\n", | ||
210 | addr); | ||
211 | return -EINVAL; | ||
212 | |||
213 | } | ||
214 | } | ||
215 | else if ((major_opcode == 5) && !(kprobe_inst & (0xFUl << 33)) && | ||
216 | (kprobe_inst & (0x1UL << 12))) { | ||
217 | /* test bit instructions, tbit,tnat,tf | ||
218 | * bit 33-36 to be equal to 0 | ||
219 | * bit 12 to be equal to 1 | ||
220 | */ | ||
221 | if (slot == 1 && qp) { | ||
222 | printk(KERN_WARNING "Kprobes on test bit" | ||
223 | "instruction on slot at <0x%lx>" | ||
224 | "is not supported\n", addr); | ||
225 | return -EINVAL; | ||
226 | } | ||
227 | qp = 0; | ||
228 | } | ||
229 | } | ||
230 | else if (bundle_encoding[template][slot] == B) { | ||
231 | if (major_opcode == 7) { | ||
232 | /* IP-Relative Predict major code is 7 */ | ||
233 | printk(KERN_WARNING "Kprobes on IP-Relative" | ||
234 | "Predict is not supported\n"); | ||
235 | return -EINVAL; | ||
236 | } | ||
237 | else if (major_opcode == 2) { | ||
238 | /* Indirect Predict, major code is 2 | ||
239 | * bit 27-32 to be equal to 10 or 11 | ||
240 | */ | ||
241 | int x6=(kprobe_inst >> 27) & 0x3F; | ||
242 | if ((x6 == 0x10) || (x6 == 0x11)) { | ||
243 | printk(KERN_WARNING "Kprobes on" | ||
244 | "Indirect Predict is not supported\n"); | ||
245 | return -EINVAL; | ||
246 | } | ||
247 | } | ||
248 | } | ||
249 | /* kernel does not use float instruction, here for safety kprobe | ||
250 | * will judge whether it is fcmp/flass/float approximation instruction | ||
251 | */ | ||
252 | else if (unlikely(bundle_encoding[template][slot] == F)) { | ||
253 | if ((major_opcode == 4 || major_opcode == 5) && | ||
254 | (kprobe_inst & (0x1 << 12))) { | ||
255 | /* fcmp/fclass unc instruction */ | ||
256 | if (slot == 1 && qp) { | ||
257 | printk(KERN_WARNING "Kprobes on fcmp/fclass " | ||
258 | "instruction on slot at <0x%lx> " | ||
259 | "is not supported\n", addr); | ||
260 | return -EINVAL; | ||
261 | |||
262 | } | ||
263 | qp = 0; | ||
264 | } | ||
265 | if ((major_opcode == 0 || major_opcode == 1) && | ||
266 | (kprobe_inst & (0x1UL << 33))) { | ||
267 | /* float Approximation instruction */ | ||
268 | if (slot == 1 && qp) { | ||
269 | printk(KERN_WARNING "Kprobes on float Approx " | ||
270 | "instr at <0x%lx> is not supported\n", | ||
271 | addr); | ||
272 | return -EINVAL; | ||
273 | } | ||
274 | qp = 0; | ||
275 | } | ||
276 | } | ||
277 | return qp; | ||
278 | } | ||
279 | |||
280 | /* | ||
210 | * In this function we override the bundle with | 281 | * In this function we override the bundle with |
211 | * the break instruction at the given slot. | 282 | * the break instruction at the given slot. |
212 | */ | 283 | */ |
213 | static void __kprobes prepare_break_inst(uint template, uint slot, | 284 | static void __kprobes prepare_break_inst(uint template, uint slot, |
214 | uint major_opcode, | 285 | uint major_opcode, |
215 | unsigned long kprobe_inst, | 286 | unsigned long kprobe_inst, |
216 | struct kprobe *p) | 287 | struct kprobe *p, |
288 | int qp) | ||
217 | { | 289 | { |
218 | unsigned long break_inst = BREAK_INST; | 290 | unsigned long break_inst = BREAK_INST; |
219 | bundle_t *bundle = &p->opcode.bundle; | 291 | bundle_t *bundle = &p->opcode.bundle; |
220 | 292 | ||
221 | /* | 293 | /* |
222 | * Copy the original kprobe_inst qualifying predicate(qp) | 294 | * Copy the original kprobe_inst qualifying predicate(qp) |
223 | * to the break instruction iff !is_cmp_ctype_unc_inst | 295 | * to the break instruction |
224 | * because for cmp instruction with ctype equal to unc, | ||
225 | * which is a special instruction always needs to be | ||
226 | * executed regradless of qp | ||
227 | */ | 296 | */ |
228 | if (!is_cmp_ctype_unc_inst(template, slot, major_opcode, kprobe_inst)) | 297 | break_inst |= qp; |
229 | break_inst |= (0x3f & kprobe_inst); | ||
230 | 298 | ||
231 | switch (slot) { | 299 | switch (slot) { |
232 | case 0: | 300 | case 0: |
@@ -422,6 +490,7 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) | |||
422 | unsigned long kprobe_inst=0; | 490 | unsigned long kprobe_inst=0; |
423 | unsigned int slot = addr & 0xf, template, major_opcode = 0; | 491 | unsigned int slot = addr & 0xf, template, major_opcode = 0; |
424 | bundle_t *bundle; | 492 | bundle_t *bundle; |
493 | int qp; | ||
425 | 494 | ||
426 | bundle = &((kprobe_opcode_t *)kprobe_addr)->bundle; | 495 | bundle = &((kprobe_opcode_t *)kprobe_addr)->bundle; |
427 | template = bundle->quad0.template; | 496 | template = bundle->quad0.template; |
@@ -436,9 +505,9 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) | |||
436 | /* Get kprobe_inst and major_opcode from the bundle */ | 505 | /* Get kprobe_inst and major_opcode from the bundle */ |
437 | get_kprobe_inst(bundle, slot, &kprobe_inst, &major_opcode); | 506 | get_kprobe_inst(bundle, slot, &kprobe_inst, &major_opcode); |
438 | 507 | ||
439 | if (unsupported_inst(template, slot, major_opcode, kprobe_inst, addr)) | 508 | qp = unsupported_inst(template, slot, major_opcode, kprobe_inst, addr); |
440 | return -EINVAL; | 509 | if (qp < 0) |
441 | 510 | return -EINVAL; | |
442 | 511 | ||
443 | p->ainsn.insn = get_insn_slot(); | 512 | p->ainsn.insn = get_insn_slot(); |
444 | if (!p->ainsn.insn) | 513 | if (!p->ainsn.insn) |
@@ -446,7 +515,7 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) | |||
446 | memcpy(&p->opcode, kprobe_addr, sizeof(kprobe_opcode_t)); | 515 | memcpy(&p->opcode, kprobe_addr, sizeof(kprobe_opcode_t)); |
447 | memcpy(p->ainsn.insn, kprobe_addr, sizeof(kprobe_opcode_t)); | 516 | memcpy(p->ainsn.insn, kprobe_addr, sizeof(kprobe_opcode_t)); |
448 | 517 | ||
449 | prepare_break_inst(template, slot, major_opcode, kprobe_inst, p); | 518 | prepare_break_inst(template, slot, major_opcode, kprobe_inst, p, qp); |
450 | 519 | ||
451 | return 0; | 520 | return 0; |
452 | } | 521 | } |