diff options
Diffstat (limited to 'arch/ia64/kernel/kprobes.c')
-rw-r--r-- | arch/ia64/kernel/kprobes.c | 61 |
1 files changed, 35 insertions, 26 deletions
diff --git a/arch/ia64/kernel/kprobes.c b/arch/ia64/kernel/kprobes.c index 781960f80b6f..169ec3a7156c 100644 --- a/arch/ia64/kernel/kprobes.c +++ b/arch/ia64/kernel/kprobes.c | |||
@@ -136,10 +136,8 @@ static void __kprobes update_kprobe_inst_flag(uint template, uint slot, | |||
136 | static int __kprobes unsupported_inst(uint template, uint slot, | 136 | static int __kprobes unsupported_inst(uint template, uint slot, |
137 | uint major_opcode, | 137 | uint major_opcode, |
138 | unsigned long kprobe_inst, | 138 | unsigned long kprobe_inst, |
139 | struct kprobe *p) | 139 | unsigned long addr) |
140 | { | 140 | { |
141 | unsigned long addr = (unsigned long)p->addr; | ||
142 | |||
143 | if (bundle_encoding[template][slot] == I) { | 141 | if (bundle_encoding[template][slot] == I) { |
144 | switch (major_opcode) { | 142 | switch (major_opcode) { |
145 | case 0x0: //I_UNIT_MISC_OPCODE: | 143 | case 0x0: //I_UNIT_MISC_OPCODE: |
@@ -217,7 +215,7 @@ static void __kprobes prepare_break_inst(uint template, uint slot, | |||
217 | struct kprobe *p) | 215 | struct kprobe *p) |
218 | { | 216 | { |
219 | unsigned long break_inst = BREAK_INST; | 217 | unsigned long break_inst = BREAK_INST; |
220 | bundle_t *bundle = &p->ainsn.insn.bundle; | 218 | bundle_t *bundle = &p->opcode.bundle; |
221 | 219 | ||
222 | /* | 220 | /* |
223 | * Copy the original kprobe_inst qualifying predicate(qp) | 221 | * Copy the original kprobe_inst qualifying predicate(qp) |
@@ -423,11 +421,9 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) | |||
423 | unsigned long *kprobe_addr = (unsigned long *)(addr & ~0xFULL); | 421 | unsigned long *kprobe_addr = (unsigned long *)(addr & ~0xFULL); |
424 | unsigned long kprobe_inst=0; | 422 | unsigned long kprobe_inst=0; |
425 | unsigned int slot = addr & 0xf, template, major_opcode = 0; | 423 | unsigned int slot = addr & 0xf, template, major_opcode = 0; |
426 | bundle_t *bundle = &p->ainsn.insn.bundle; | 424 | bundle_t *bundle; |
427 | |||
428 | memcpy(&p->opcode.bundle, kprobe_addr, sizeof(bundle_t)); | ||
429 | memcpy(&p->ainsn.insn.bundle, kprobe_addr, sizeof(bundle_t)); | ||
430 | 425 | ||
426 | bundle = &((kprobe_opcode_t *)kprobe_addr)->bundle; | ||
431 | template = bundle->quad0.template; | 427 | template = bundle->quad0.template; |
432 | 428 | ||
433 | if(valid_kprobe_addr(template, slot, addr)) | 429 | if(valid_kprobe_addr(template, slot, addr)) |
@@ -440,20 +436,19 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) | |||
440 | /* Get kprobe_inst and major_opcode from the bundle */ | 436 | /* Get kprobe_inst and major_opcode from the bundle */ |
441 | get_kprobe_inst(bundle, slot, &kprobe_inst, &major_opcode); | 437 | get_kprobe_inst(bundle, slot, &kprobe_inst, &major_opcode); |
442 | 438 | ||
443 | if (unsupported_inst(template, slot, major_opcode, kprobe_inst, p)) | 439 | if (unsupported_inst(template, slot, major_opcode, kprobe_inst, addr)) |
444 | return -EINVAL; | 440 | return -EINVAL; |
445 | 441 | ||
446 | prepare_break_inst(template, slot, major_opcode, kprobe_inst, p); | ||
447 | 442 | ||
448 | return 0; | 443 | p->ainsn.insn = get_insn_slot(); |
449 | } | 444 | if (!p->ainsn.insn) |
445 | return -ENOMEM; | ||
446 | memcpy(&p->opcode, kprobe_addr, sizeof(kprobe_opcode_t)); | ||
447 | memcpy(p->ainsn.insn, kprobe_addr, sizeof(kprobe_opcode_t)); | ||
450 | 448 | ||
451 | void __kprobes flush_insn_slot(struct kprobe *p) | 449 | prepare_break_inst(template, slot, major_opcode, kprobe_inst, p); |
452 | { | ||
453 | unsigned long arm_addr; | ||
454 | 450 | ||
455 | arm_addr = ((unsigned long)&p->opcode.bundle) & ~0xFULL; | 451 | return 0; |
456 | flush_icache_range(arm_addr, arm_addr + sizeof(bundle_t)); | ||
457 | } | 452 | } |
458 | 453 | ||
459 | void __kprobes arch_arm_kprobe(struct kprobe *p) | 454 | void __kprobes arch_arm_kprobe(struct kprobe *p) |
@@ -461,9 +456,10 @@ void __kprobes arch_arm_kprobe(struct kprobe *p) | |||
461 | unsigned long addr = (unsigned long)p->addr; | 456 | unsigned long addr = (unsigned long)p->addr; |
462 | unsigned long arm_addr = addr & ~0xFULL; | 457 | unsigned long arm_addr = addr & ~0xFULL; |
463 | 458 | ||
464 | flush_insn_slot(p); | 459 | flush_icache_range((unsigned long)p->ainsn.insn, |
465 | memcpy((char *)arm_addr, &p->ainsn.insn.bundle, sizeof(bundle_t)); | 460 | (unsigned long)p->ainsn.insn + sizeof(kprobe_opcode_t)); |
466 | flush_icache_range(arm_addr, arm_addr + sizeof(bundle_t)); | 461 | memcpy((char *)arm_addr, &p->opcode, sizeof(kprobe_opcode_t)); |
462 | flush_icache_range(arm_addr, arm_addr + sizeof(kprobe_opcode_t)); | ||
467 | } | 463 | } |
468 | 464 | ||
469 | void __kprobes arch_disarm_kprobe(struct kprobe *p) | 465 | void __kprobes arch_disarm_kprobe(struct kprobe *p) |
@@ -471,11 +467,18 @@ void __kprobes arch_disarm_kprobe(struct kprobe *p) | |||
471 | unsigned long addr = (unsigned long)p->addr; | 467 | unsigned long addr = (unsigned long)p->addr; |
472 | unsigned long arm_addr = addr & ~0xFULL; | 468 | unsigned long arm_addr = addr & ~0xFULL; |
473 | 469 | ||
474 | /* p->opcode contains the original unaltered bundle */ | 470 | /* p->ainsn.insn contains the original unaltered kprobe_opcode_t */ |
475 | memcpy((char *) arm_addr, (char *) &p->opcode.bundle, sizeof(bundle_t)); | 471 | memcpy((char *) arm_addr, (char *) p->ainsn.insn, |
476 | flush_icache_range(arm_addr, arm_addr + sizeof(bundle_t)); | 472 | sizeof(kprobe_opcode_t)); |
473 | flush_icache_range(arm_addr, arm_addr + sizeof(kprobe_opcode_t)); | ||
477 | } | 474 | } |
478 | 475 | ||
476 | void __kprobes arch_remove_kprobe(struct kprobe *p) | ||
477 | { | ||
478 | mutex_lock(&kprobe_mutex); | ||
479 | free_insn_slot(p->ainsn.insn); | ||
480 | mutex_unlock(&kprobe_mutex); | ||
481 | } | ||
479 | /* | 482 | /* |
480 | * We are resuming execution after a single step fault, so the pt_regs | 483 | * We are resuming execution after a single step fault, so the pt_regs |
481 | * structure reflects the register state after we executed the instruction | 484 | * structure reflects the register state after we executed the instruction |
@@ -486,12 +489,12 @@ void __kprobes arch_disarm_kprobe(struct kprobe *p) | |||
486 | */ | 489 | */ |
487 | static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs) | 490 | static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs) |
488 | { | 491 | { |
489 | unsigned long bundle_addr = ((unsigned long) (&p->opcode.bundle)) & ~0xFULL; | 492 | unsigned long bundle_addr = (unsigned long) (&p->ainsn.insn->bundle); |
490 | unsigned long resume_addr = (unsigned long)p->addr & ~0xFULL; | 493 | unsigned long resume_addr = (unsigned long)p->addr & ~0xFULL; |
491 | unsigned long template; | 494 | unsigned long template; |
492 | int slot = ((unsigned long)p->addr & 0xf); | 495 | int slot = ((unsigned long)p->addr & 0xf); |
493 | 496 | ||
494 | template = p->opcode.bundle.quad0.template; | 497 | template = p->ainsn.insn->bundle.quad0.template; |
495 | 498 | ||
496 | if (slot == 1 && bundle_encoding[template][1] == L) | 499 | if (slot == 1 && bundle_encoding[template][1] == L) |
497 | slot = 2; | 500 | slot = 2; |
@@ -553,7 +556,7 @@ turn_ss_off: | |||
553 | 556 | ||
554 | static void __kprobes prepare_ss(struct kprobe *p, struct pt_regs *regs) | 557 | static void __kprobes prepare_ss(struct kprobe *p, struct pt_regs *regs) |
555 | { | 558 | { |
556 | unsigned long bundle_addr = (unsigned long) &p->opcode.bundle; | 559 | unsigned long bundle_addr = (unsigned long) &p->ainsn.insn->bundle; |
557 | unsigned long slot = (unsigned long)p->addr & 0xf; | 560 | unsigned long slot = (unsigned long)p->addr & 0xf; |
558 | 561 | ||
559 | /* single step inline if break instruction */ | 562 | /* single step inline if break instruction */ |
@@ -768,6 +771,12 @@ static int __kprobes kprobes_fault_handler(struct pt_regs *regs, int trapnr) | |||
768 | */ | 771 | */ |
769 | if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr)) | 772 | if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr)) |
770 | return 1; | 773 | return 1; |
774 | /* | ||
775 | * In case the user-specified fault handler returned | ||
776 | * zero, try to fix up. | ||
777 | */ | ||
778 | if (ia64_done_with_exception(regs)) | ||
779 | return 1; | ||
771 | 780 | ||
772 | /* | 781 | /* |
773 | * Let ia64_do_page_fault() fix it. | 782 | * Let ia64_do_page_fault() fix it. |