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. |
