diff options
Diffstat (limited to 'arch/ia64/kernel/kprobes.c')
-rw-r--r-- | arch/ia64/kernel/kprobes.c | 226 |
1 files changed, 159 insertions, 67 deletions
diff --git a/arch/ia64/kernel/kprobes.c b/arch/ia64/kernel/kprobes.c index 76e778951e20..6cb56dd4056d 100644 --- a/arch/ia64/kernel/kprobes.c +++ b/arch/ia64/kernel/kprobes.c | |||
@@ -88,6 +88,7 @@ static void __kprobes update_kprobe_inst_flag(uint template, uint slot, | |||
88 | { | 88 | { |
89 | p->ainsn.inst_flag = 0; | 89 | p->ainsn.inst_flag = 0; |
90 | p->ainsn.target_br_reg = 0; | 90 | p->ainsn.target_br_reg = 0; |
91 | p->ainsn.slot = slot; | ||
91 | 92 | ||
92 | /* Check for Break instruction | 93 | /* Check for Break instruction |
93 | * Bits 37:40 Major opcode to be zero | 94 | * Bits 37:40 Major opcode to be zero |
@@ -129,48 +130,6 @@ static void __kprobes update_kprobe_inst_flag(uint template, uint slot, | |||
129 | 130 | ||
130 | /* | 131 | /* |
131 | * In this function we check to see if the instruction | 132 | * In this function we check to see if the instruction |
132 | * on which we are inserting kprobe is supported. | ||
133 | * Returns 0 if supported | ||
134 | * Returns -EINVAL if unsupported | ||
135 | */ | ||
136 | static int __kprobes unsupported_inst(uint template, uint slot, | ||
137 | uint major_opcode, | ||
138 | unsigned long kprobe_inst, | ||
139 | unsigned long addr) | ||
140 | { | ||
141 | if (bundle_encoding[template][slot] == I) { | ||
142 | switch (major_opcode) { | ||
143 | case 0x0: //I_UNIT_MISC_OPCODE: | ||
144 | /* | ||
145 | * Check for Integer speculation instruction | ||
146 | * - Bit 33-35 to be equal to 0x1 | ||
147 | */ | ||
148 | if (((kprobe_inst >> 33) & 0x7) == 1) { | ||
149 | printk(KERN_WARNING | ||
150 | "Kprobes on speculation inst at <0x%lx> not supported\n", | ||
151 | addr); | ||
152 | return -EINVAL; | ||
153 | } | ||
154 | |||
155 | /* | ||
156 | * IP relative mov instruction | ||
157 | * - Bit 27-35 to be equal to 0x30 | ||
158 | */ | ||
159 | if (((kprobe_inst >> 27) & 0x1FF) == 0x30) { | ||
160 | printk(KERN_WARNING | ||
161 | "Kprobes on \"mov r1=ip\" at <0x%lx> not supported\n", | ||
162 | addr); | ||
163 | return -EINVAL; | ||
164 | |||
165 | } | ||
166 | } | ||
167 | } | ||
168 | return 0; | ||
169 | } | ||
170 | |||
171 | |||
172 | /* | ||
173 | * In this function we check to see if the instruction | ||
174 | * (qp) cmpx.crel.ctype p1,p2=r2,r3 | 133 | * (qp) cmpx.crel.ctype p1,p2=r2,r3 |
175 | * on which we are inserting kprobe is cmp instruction | 134 | * on which we are inserting kprobe is cmp instruction |
176 | * with ctype as unc. | 135 | * with ctype as unc. |
@@ -206,26 +165,136 @@ out: | |||
206 | } | 165 | } |
207 | 166 | ||
208 | /* | 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 | /* | ||
209 | * In this function we override the bundle with | 281 | * In this function we override the bundle with |
210 | * the break instruction at the given slot. | 282 | * the break instruction at the given slot. |
211 | */ | 283 | */ |
212 | static void __kprobes prepare_break_inst(uint template, uint slot, | 284 | static void __kprobes prepare_break_inst(uint template, uint slot, |
213 | uint major_opcode, | 285 | uint major_opcode, |
214 | unsigned long kprobe_inst, | 286 | unsigned long kprobe_inst, |
215 | struct kprobe *p) | 287 | struct kprobe *p, |
288 | int qp) | ||
216 | { | 289 | { |
217 | unsigned long break_inst = BREAK_INST; | 290 | unsigned long break_inst = BREAK_INST; |
218 | bundle_t *bundle = &p->opcode.bundle; | 291 | bundle_t *bundle = &p->opcode.bundle; |
219 | 292 | ||
220 | /* | 293 | /* |
221 | * Copy the original kprobe_inst qualifying predicate(qp) | 294 | * Copy the original kprobe_inst qualifying predicate(qp) |
222 | * to the break instruction iff !is_cmp_ctype_unc_inst | 295 | * to the break instruction |
223 | * because for cmp instruction with ctype equal to unc, | ||
224 | * which is a special instruction always needs to be | ||
225 | * executed regradless of qp | ||
226 | */ | 296 | */ |
227 | if (!is_cmp_ctype_unc_inst(template, slot, major_opcode, kprobe_inst)) | 297 | break_inst |= qp; |
228 | break_inst |= (0x3f & kprobe_inst); | ||
229 | 298 | ||
230 | switch (slot) { | 299 | switch (slot) { |
231 | case 0: | 300 | case 0: |
@@ -296,12 +365,6 @@ static int __kprobes valid_kprobe_addr(int template, int slot, | |||
296 | return -EINVAL; | 365 | return -EINVAL; |
297 | } | 366 | } |
298 | 367 | ||
299 | if (slot == 1 && bundle_encoding[template][1] != L) { | ||
300 | printk(KERN_WARNING "Inserting kprobes on slot #1 " | ||
301 | "is not supported\n"); | ||
302 | return -EINVAL; | ||
303 | } | ||
304 | |||
305 | return 0; | 368 | return 0; |
306 | } | 369 | } |
307 | 370 | ||
@@ -427,6 +490,7 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) | |||
427 | unsigned long kprobe_inst=0; | 490 | unsigned long kprobe_inst=0; |
428 | unsigned int slot = addr & 0xf, template, major_opcode = 0; | 491 | unsigned int slot = addr & 0xf, template, major_opcode = 0; |
429 | bundle_t *bundle; | 492 | bundle_t *bundle; |
493 | int qp; | ||
430 | 494 | ||
431 | bundle = &((kprobe_opcode_t *)kprobe_addr)->bundle; | 495 | bundle = &((kprobe_opcode_t *)kprobe_addr)->bundle; |
432 | template = bundle->quad0.template; | 496 | template = bundle->quad0.template; |
@@ -441,9 +505,9 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) | |||
441 | /* Get kprobe_inst and major_opcode from the bundle */ | 505 | /* Get kprobe_inst and major_opcode from the bundle */ |
442 | get_kprobe_inst(bundle, slot, &kprobe_inst, &major_opcode); | 506 | get_kprobe_inst(bundle, slot, &kprobe_inst, &major_opcode); |
443 | 507 | ||
444 | if (unsupported_inst(template, slot, major_opcode, kprobe_inst, addr)) | 508 | qp = unsupported_inst(template, slot, major_opcode, kprobe_inst, addr); |
445 | return -EINVAL; | 509 | if (qp < 0) |
446 | 510 | return -EINVAL; | |
447 | 511 | ||
448 | p->ainsn.insn = get_insn_slot(); | 512 | p->ainsn.insn = get_insn_slot(); |
449 | if (!p->ainsn.insn) | 513 | if (!p->ainsn.insn) |
@@ -451,30 +515,56 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) | |||
451 | memcpy(&p->opcode, kprobe_addr, sizeof(kprobe_opcode_t)); | 515 | memcpy(&p->opcode, kprobe_addr, sizeof(kprobe_opcode_t)); |
452 | memcpy(p->ainsn.insn, kprobe_addr, sizeof(kprobe_opcode_t)); | 516 | memcpy(p->ainsn.insn, kprobe_addr, sizeof(kprobe_opcode_t)); |
453 | 517 | ||
454 | prepare_break_inst(template, slot, major_opcode, kprobe_inst, p); | 518 | prepare_break_inst(template, slot, major_opcode, kprobe_inst, p, qp); |
455 | 519 | ||
456 | return 0; | 520 | return 0; |
457 | } | 521 | } |
458 | 522 | ||
459 | void __kprobes arch_arm_kprobe(struct kprobe *p) | 523 | void __kprobes arch_arm_kprobe(struct kprobe *p) |
460 | { | 524 | { |
461 | unsigned long addr = (unsigned long)p->addr; | 525 | unsigned long arm_addr; |
462 | unsigned long arm_addr = addr & ~0xFULL; | 526 | bundle_t *src, *dest; |
527 | |||
528 | arm_addr = ((unsigned long)p->addr) & ~0xFUL; | ||
529 | dest = &((kprobe_opcode_t *)arm_addr)->bundle; | ||
530 | src = &p->opcode.bundle; | ||
463 | 531 | ||
464 | flush_icache_range((unsigned long)p->ainsn.insn, | 532 | flush_icache_range((unsigned long)p->ainsn.insn, |
465 | (unsigned long)p->ainsn.insn + sizeof(kprobe_opcode_t)); | 533 | (unsigned long)p->ainsn.insn + sizeof(kprobe_opcode_t)); |
466 | memcpy((char *)arm_addr, &p->opcode, sizeof(kprobe_opcode_t)); | 534 | switch (p->ainsn.slot) { |
535 | case 0: | ||
536 | dest->quad0.slot0 = src->quad0.slot0; | ||
537 | break; | ||
538 | case 1: | ||
539 | dest->quad1.slot1_p1 = src->quad1.slot1_p1; | ||
540 | break; | ||
541 | case 2: | ||
542 | dest->quad1.slot2 = src->quad1.slot2; | ||
543 | break; | ||
544 | } | ||
467 | flush_icache_range(arm_addr, arm_addr + sizeof(kprobe_opcode_t)); | 545 | flush_icache_range(arm_addr, arm_addr + sizeof(kprobe_opcode_t)); |
468 | } | 546 | } |
469 | 547 | ||
470 | void __kprobes arch_disarm_kprobe(struct kprobe *p) | 548 | void __kprobes arch_disarm_kprobe(struct kprobe *p) |
471 | { | 549 | { |
472 | unsigned long addr = (unsigned long)p->addr; | 550 | unsigned long arm_addr; |
473 | unsigned long arm_addr = addr & ~0xFULL; | 551 | bundle_t *src, *dest; |
474 | 552 | ||
553 | arm_addr = ((unsigned long)p->addr) & ~0xFUL; | ||
554 | dest = &((kprobe_opcode_t *)arm_addr)->bundle; | ||
475 | /* p->ainsn.insn contains the original unaltered kprobe_opcode_t */ | 555 | /* p->ainsn.insn contains the original unaltered kprobe_opcode_t */ |
476 | memcpy((char *) arm_addr, (char *) p->ainsn.insn, | 556 | src = &p->ainsn.insn->bundle; |
477 | sizeof(kprobe_opcode_t)); | 557 | switch (p->ainsn.slot) { |
558 | case 0: | ||
559 | dest->quad0.slot0 = src->quad0.slot0; | ||
560 | break; | ||
561 | case 1: | ||
562 | dest->quad1.slot1_p1 = src->quad1.slot1_p1; | ||
563 | break; | ||
564 | case 2: | ||
565 | dest->quad1.slot2 = src->quad1.slot2; | ||
566 | break; | ||
567 | } | ||
478 | flush_icache_range(arm_addr, arm_addr + sizeof(kprobe_opcode_t)); | 568 | flush_icache_range(arm_addr, arm_addr + sizeof(kprobe_opcode_t)); |
479 | } | 569 | } |
480 | 570 | ||
@@ -807,7 +897,9 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self, | |||
807 | switch(val) { | 897 | switch(val) { |
808 | case DIE_BREAK: | 898 | case DIE_BREAK: |
809 | /* err is break number from ia64_bad_break() */ | 899 | /* err is break number from ia64_bad_break() */ |
810 | if (args->err == 0x80200 || args->err == 0x80300 || args->err == 0) | 900 | if ((args->err >> 12) == (__IA64_BREAK_KPROBE >> 12) |
901 | || args->err == __IA64_BREAK_JPROBE | ||
902 | || args->err == 0) | ||
811 | if (pre_kprobes_handler(args)) | 903 | if (pre_kprobes_handler(args)) |
812 | ret = NOTIFY_STOP; | 904 | ret = NOTIFY_STOP; |
813 | break; | 905 | break; |