diff options
Diffstat (limited to 'arch/ia64/kernel/kprobes.c')
| -rw-r--r-- | arch/ia64/kernel/kprobes.c | 124 |
1 files changed, 97 insertions, 27 deletions
diff --git a/arch/ia64/kernel/kprobes.c b/arch/ia64/kernel/kprobes.c index 884f5cd27d8a..471086b808a4 100644 --- a/arch/ia64/kernel/kprobes.c +++ b/arch/ia64/kernel/kprobes.c | |||
| @@ -87,12 +87,25 @@ static enum instruction_type bundle_encoding[32][3] = { | |||
| 87 | * is IP relative instruction and update the kprobe | 87 | * is IP relative instruction and update the kprobe |
| 88 | * inst flag accordingly | 88 | * inst flag accordingly |
| 89 | */ | 89 | */ |
| 90 | static void update_kprobe_inst_flag(uint template, uint slot, uint major_opcode, | 90 | static void __kprobes update_kprobe_inst_flag(uint template, uint slot, |
| 91 | unsigned long kprobe_inst, struct kprobe *p) | 91 | uint major_opcode, |
| 92 | unsigned long kprobe_inst, | ||
| 93 | struct kprobe *p) | ||
| 92 | { | 94 | { |
| 93 | p->ainsn.inst_flag = 0; | 95 | p->ainsn.inst_flag = 0; |
| 94 | p->ainsn.target_br_reg = 0; | 96 | p->ainsn.target_br_reg = 0; |
| 95 | 97 | ||
| 98 | /* Check for Break instruction | ||
| 99 | * Bits 37:40 Major opcode to be zero | ||
| 100 | * Bits 27:32 X6 to be zero | ||
| 101 | * Bits 32:35 X3 to be zero | ||
| 102 | */ | ||
| 103 | if ((!major_opcode) && (!((kprobe_inst >> 27) & 0x1FF)) ) { | ||
| 104 | /* is a break instruction */ | ||
| 105 | p->ainsn.inst_flag |= INST_FLAG_BREAK_INST; | ||
| 106 | return; | ||
| 107 | } | ||
| 108 | |||
| 96 | if (bundle_encoding[template][slot] == B) { | 109 | if (bundle_encoding[template][slot] == B) { |
| 97 | switch (major_opcode) { | 110 | switch (major_opcode) { |
| 98 | case INDIRECT_CALL_OPCODE: | 111 | case INDIRECT_CALL_OPCODE: |
| @@ -126,8 +139,10 @@ static void update_kprobe_inst_flag(uint template, uint slot, uint major_opcode | |||
| 126 | * Returns 0 if supported | 139 | * Returns 0 if supported |
| 127 | * Returns -EINVAL if unsupported | 140 | * Returns -EINVAL if unsupported |
| 128 | */ | 141 | */ |
| 129 | static int unsupported_inst(uint template, uint slot, uint major_opcode, | 142 | static int __kprobes unsupported_inst(uint template, uint slot, |
| 130 | unsigned long kprobe_inst, struct kprobe *p) | 143 | uint major_opcode, |
| 144 | unsigned long kprobe_inst, | ||
| 145 | struct kprobe *p) | ||
| 131 | { | 146 | { |
| 132 | unsigned long addr = (unsigned long)p->addr; | 147 | unsigned long addr = (unsigned long)p->addr; |
| 133 | 148 | ||
| @@ -168,8 +183,9 @@ static int unsupported_inst(uint template, uint slot, uint major_opcode, | |||
| 168 | * on which we are inserting kprobe is cmp instruction | 183 | * on which we are inserting kprobe is cmp instruction |
| 169 | * with ctype as unc. | 184 | * with ctype as unc. |
| 170 | */ | 185 | */ |
| 171 | static uint is_cmp_ctype_unc_inst(uint template, uint slot, uint major_opcode, | 186 | static uint __kprobes is_cmp_ctype_unc_inst(uint template, uint slot, |
| 172 | unsigned long kprobe_inst) | 187 | uint major_opcode, |
| 188 | unsigned long kprobe_inst) | ||
| 173 | { | 189 | { |
| 174 | cmp_inst_t cmp_inst; | 190 | cmp_inst_t cmp_inst; |
| 175 | uint ctype_unc = 0; | 191 | uint ctype_unc = 0; |
| @@ -201,8 +217,10 @@ out: | |||
| 201 | * In this function we override the bundle with | 217 | * In this function we override the bundle with |
| 202 | * the break instruction at the given slot. | 218 | * the break instruction at the given slot. |
| 203 | */ | 219 | */ |
| 204 | static void prepare_break_inst(uint template, uint slot, uint major_opcode, | 220 | static void __kprobes prepare_break_inst(uint template, uint slot, |
| 205 | unsigned long kprobe_inst, struct kprobe *p) | 221 | uint major_opcode, |
| 222 | unsigned long kprobe_inst, | ||
| 223 | struct kprobe *p) | ||
| 206 | { | 224 | { |
| 207 | unsigned long break_inst = BREAK_INST; | 225 | unsigned long break_inst = BREAK_INST; |
| 208 | bundle_t *bundle = &p->ainsn.insn.bundle; | 226 | bundle_t *bundle = &p->ainsn.insn.bundle; |
| @@ -271,7 +289,8 @@ static inline int in_ivt_functions(unsigned long addr) | |||
| 271 | && addr < (unsigned long)__end_ivt_text); | 289 | && addr < (unsigned long)__end_ivt_text); |
| 272 | } | 290 | } |
| 273 | 291 | ||
| 274 | static int valid_kprobe_addr(int template, int slot, unsigned long addr) | 292 | static int __kprobes valid_kprobe_addr(int template, int slot, |
| 293 | unsigned long addr) | ||
| 275 | { | 294 | { |
| 276 | if ((slot > 2) || ((bundle_encoding[template][1] == L) && slot > 1)) { | 295 | if ((slot > 2) || ((bundle_encoding[template][1] == L) && slot > 1)) { |
| 277 | printk(KERN_WARNING "Attempting to insert unaligned kprobe " | 296 | printk(KERN_WARNING "Attempting to insert unaligned kprobe " |
| @@ -323,7 +342,7 @@ static void kretprobe_trampoline(void) | |||
| 323 | * - cleanup by marking the instance as unused | 342 | * - cleanup by marking the instance as unused |
| 324 | * - long jump back to the original return address | 343 | * - long jump back to the original return address |
| 325 | */ | 344 | */ |
| 326 | int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) | 345 | int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) |
| 327 | { | 346 | { |
| 328 | struct kretprobe_instance *ri = NULL; | 347 | struct kretprobe_instance *ri = NULL; |
| 329 | struct hlist_head *head; | 348 | struct hlist_head *head; |
| @@ -381,7 +400,8 @@ int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) | |||
| 381 | return 1; | 400 | return 1; |
| 382 | } | 401 | } |
| 383 | 402 | ||
| 384 | void arch_prepare_kretprobe(struct kretprobe *rp, struct pt_regs *regs) | 403 | void __kprobes arch_prepare_kretprobe(struct kretprobe *rp, |
| 404 | struct pt_regs *regs) | ||
| 385 | { | 405 | { |
| 386 | struct kretprobe_instance *ri; | 406 | struct kretprobe_instance *ri; |
| 387 | 407 | ||
| @@ -399,7 +419,7 @@ void arch_prepare_kretprobe(struct kretprobe *rp, struct pt_regs *regs) | |||
| 399 | } | 419 | } |
| 400 | } | 420 | } |
| 401 | 421 | ||
| 402 | int arch_prepare_kprobe(struct kprobe *p) | 422 | int __kprobes arch_prepare_kprobe(struct kprobe *p) |
| 403 | { | 423 | { |
| 404 | unsigned long addr = (unsigned long) p->addr; | 424 | unsigned long addr = (unsigned long) p->addr; |
| 405 | unsigned long *kprobe_addr = (unsigned long *)(addr & ~0xFULL); | 425 | unsigned long *kprobe_addr = (unsigned long *)(addr & ~0xFULL); |
| @@ -430,7 +450,7 @@ int arch_prepare_kprobe(struct kprobe *p) | |||
| 430 | return 0; | 450 | return 0; |
| 431 | } | 451 | } |
| 432 | 452 | ||
| 433 | void arch_arm_kprobe(struct kprobe *p) | 453 | void __kprobes arch_arm_kprobe(struct kprobe *p) |
| 434 | { | 454 | { |
| 435 | unsigned long addr = (unsigned long)p->addr; | 455 | unsigned long addr = (unsigned long)p->addr; |
| 436 | unsigned long arm_addr = addr & ~0xFULL; | 456 | unsigned long arm_addr = addr & ~0xFULL; |
| @@ -439,7 +459,7 @@ void arch_arm_kprobe(struct kprobe *p) | |||
| 439 | flush_icache_range(arm_addr, arm_addr + sizeof(bundle_t)); | 459 | flush_icache_range(arm_addr, arm_addr + sizeof(bundle_t)); |
| 440 | } | 460 | } |
| 441 | 461 | ||
| 442 | void arch_disarm_kprobe(struct kprobe *p) | 462 | void __kprobes arch_disarm_kprobe(struct kprobe *p) |
| 443 | { | 463 | { |
| 444 | unsigned long addr = (unsigned long)p->addr; | 464 | unsigned long addr = (unsigned long)p->addr; |
| 445 | unsigned long arm_addr = addr & ~0xFULL; | 465 | unsigned long arm_addr = addr & ~0xFULL; |
| @@ -449,7 +469,7 @@ void arch_disarm_kprobe(struct kprobe *p) | |||
| 449 | flush_icache_range(arm_addr, arm_addr + sizeof(bundle_t)); | 469 | flush_icache_range(arm_addr, arm_addr + sizeof(bundle_t)); |
| 450 | } | 470 | } |
| 451 | 471 | ||
| 452 | void arch_remove_kprobe(struct kprobe *p) | 472 | void __kprobes arch_remove_kprobe(struct kprobe *p) |
| 453 | { | 473 | { |
| 454 | } | 474 | } |
| 455 | 475 | ||
| @@ -461,7 +481,7 @@ void arch_remove_kprobe(struct kprobe *p) | |||
| 461 | * to original stack address, handle the case where we need to fixup the | 481 | * to original stack address, handle the case where we need to fixup the |
| 462 | * relative IP address and/or fixup branch register. | 482 | * relative IP address and/or fixup branch register. |
| 463 | */ | 483 | */ |
| 464 | static void resume_execution(struct kprobe *p, struct pt_regs *regs) | 484 | static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs) |
| 465 | { | 485 | { |
| 466 | unsigned long bundle_addr = ((unsigned long) (&p->opcode.bundle)) & ~0xFULL; | 486 | unsigned long bundle_addr = ((unsigned long) (&p->opcode.bundle)) & ~0xFULL; |
| 467 | unsigned long resume_addr = (unsigned long)p->addr & ~0xFULL; | 487 | unsigned long resume_addr = (unsigned long)p->addr & ~0xFULL; |
| @@ -528,13 +548,16 @@ turn_ss_off: | |||
| 528 | ia64_psr(regs)->ss = 0; | 548 | ia64_psr(regs)->ss = 0; |
| 529 | } | 549 | } |
| 530 | 550 | ||
| 531 | static void prepare_ss(struct kprobe *p, struct pt_regs *regs) | 551 | static void __kprobes prepare_ss(struct kprobe *p, struct pt_regs *regs) |
| 532 | { | 552 | { |
| 533 | unsigned long bundle_addr = (unsigned long) &p->opcode.bundle; | 553 | unsigned long bundle_addr = (unsigned long) &p->opcode.bundle; |
| 534 | unsigned long slot = (unsigned long)p->addr & 0xf; | 554 | unsigned long slot = (unsigned long)p->addr & 0xf; |
| 535 | 555 | ||
| 536 | /* Update instruction pointer (IIP) and slot number (IPSR.ri) */ | 556 | /* single step inline if break instruction */ |
| 537 | regs->cr_iip = bundle_addr & ~0xFULL; | 557 | if (p->ainsn.inst_flag == INST_FLAG_BREAK_INST) |
| 558 | regs->cr_iip = (unsigned long)p->addr & ~0xFULL; | ||
| 559 | else | ||
| 560 | regs->cr_iip = bundle_addr & ~0xFULL; | ||
| 538 | 561 | ||
| 539 | if (slot > 2) | 562 | if (slot > 2) |
| 540 | slot = 0; | 563 | slot = 0; |
| @@ -545,7 +568,39 @@ static void prepare_ss(struct kprobe *p, struct pt_regs *regs) | |||
| 545 | ia64_psr(regs)->ss = 1; | 568 | ia64_psr(regs)->ss = 1; |
| 546 | } | 569 | } |
| 547 | 570 | ||
| 548 | static int pre_kprobes_handler(struct die_args *args) | 571 | static int __kprobes is_ia64_break_inst(struct pt_regs *regs) |
| 572 | { | ||
| 573 | unsigned int slot = ia64_psr(regs)->ri; | ||
| 574 | unsigned int template, major_opcode; | ||
| 575 | unsigned long kprobe_inst; | ||
| 576 | unsigned long *kprobe_addr = (unsigned long *)regs->cr_iip; | ||
| 577 | bundle_t bundle; | ||
| 578 | |||
| 579 | memcpy(&bundle, kprobe_addr, sizeof(bundle_t)); | ||
| 580 | template = bundle.quad0.template; | ||
| 581 | |||
| 582 | /* Move to slot 2, if bundle is MLX type and kprobe slot is 1 */ | ||
| 583 | if (slot == 1 && bundle_encoding[template][1] == L) | ||
| 584 | slot++; | ||
| 585 | |||
| 586 | /* Get Kprobe probe instruction at given slot*/ | ||
| 587 | get_kprobe_inst(&bundle, slot, &kprobe_inst, &major_opcode); | ||
| 588 | |||
| 589 | /* For break instruction, | ||
| 590 | * Bits 37:40 Major opcode to be zero | ||
| 591 | * Bits 27:32 X6 to be zero | ||
| 592 | * Bits 32:35 X3 to be zero | ||
| 593 | */ | ||
| 594 | if (major_opcode || ((kprobe_inst >> 27) & 0x1FF) ) { | ||
| 595 | /* Not a break instruction */ | ||
| 596 | return 0; | ||
| 597 | } | ||
| 598 | |||
| 599 | /* Is a break instruction */ | ||
| 600 | return 1; | ||
| 601 | } | ||
| 602 | |||
| 603 | static int __kprobes pre_kprobes_handler(struct die_args *args) | ||
| 549 | { | 604 | { |
| 550 | struct kprobe *p; | 605 | struct kprobe *p; |
| 551 | int ret = 0; | 606 | int ret = 0; |
| @@ -558,7 +613,9 @@ static int pre_kprobes_handler(struct die_args *args) | |||
| 558 | if (kprobe_running()) { | 613 | if (kprobe_running()) { |
| 559 | p = get_kprobe(addr); | 614 | p = get_kprobe(addr); |
| 560 | if (p) { | 615 | if (p) { |
| 561 | if (kprobe_status == KPROBE_HIT_SS) { | 616 | if ( (kprobe_status == KPROBE_HIT_SS) && |
| 617 | (p->ainsn.inst_flag == INST_FLAG_BREAK_INST)) { | ||
| 618 | ia64_psr(regs)->ss = 0; | ||
| 562 | unlock_kprobes(); | 619 | unlock_kprobes(); |
| 563 | goto no_kprobe; | 620 | goto no_kprobe; |
| 564 | } | 621 | } |
| @@ -592,6 +649,19 @@ static int pre_kprobes_handler(struct die_args *args) | |||
| 592 | p = get_kprobe(addr); | 649 | p = get_kprobe(addr); |
| 593 | if (!p) { | 650 | if (!p) { |
| 594 | unlock_kprobes(); | 651 | unlock_kprobes(); |
| 652 | if (!is_ia64_break_inst(regs)) { | ||
| 653 | /* | ||
| 654 | * The breakpoint instruction was removed right | ||
| 655 | * after we hit it. Another cpu has removed | ||
| 656 | * either a probepoint or a debugger breakpoint | ||
| 657 | * at this address. In either case, no further | ||
| 658 | * handling of this interrupt is appropriate. | ||
| 659 | */ | ||
| 660 | ret = 1; | ||
| 661 | |||
| 662 | } | ||
| 663 | |||
| 664 | /* Not one of our break, let kernel handle it */ | ||
| 595 | goto no_kprobe; | 665 | goto no_kprobe; |
| 596 | } | 666 | } |
| 597 | 667 | ||
| @@ -616,7 +686,7 @@ no_kprobe: | |||
| 616 | return ret; | 686 | return ret; |
| 617 | } | 687 | } |
| 618 | 688 | ||
| 619 | static int post_kprobes_handler(struct pt_regs *regs) | 689 | static int __kprobes post_kprobes_handler(struct pt_regs *regs) |
| 620 | { | 690 | { |
| 621 | if (!kprobe_running()) | 691 | if (!kprobe_running()) |
| 622 | return 0; | 692 | return 0; |
| @@ -641,7 +711,7 @@ out: | |||
| 641 | return 1; | 711 | return 1; |
| 642 | } | 712 | } |
| 643 | 713 | ||
| 644 | static int kprobes_fault_handler(struct pt_regs *regs, int trapnr) | 714 | static int __kprobes kprobes_fault_handler(struct pt_regs *regs, int trapnr) |
| 645 | { | 715 | { |
| 646 | if (!kprobe_running()) | 716 | if (!kprobe_running()) |
| 647 | return 0; | 717 | return 0; |
| @@ -659,8 +729,8 @@ static int kprobes_fault_handler(struct pt_regs *regs, int trapnr) | |||
| 659 | return 0; | 729 | return 0; |
| 660 | } | 730 | } |
| 661 | 731 | ||
| 662 | int kprobe_exceptions_notify(struct notifier_block *self, unsigned long val, | 732 | int __kprobes kprobe_exceptions_notify(struct notifier_block *self, |
| 663 | void *data) | 733 | unsigned long val, void *data) |
| 664 | { | 734 | { |
| 665 | struct die_args *args = (struct die_args *)data; | 735 | struct die_args *args = (struct die_args *)data; |
| 666 | switch(val) { | 736 | switch(val) { |
| @@ -681,7 +751,7 @@ int kprobe_exceptions_notify(struct notifier_block *self, unsigned long val, | |||
| 681 | return NOTIFY_DONE; | 751 | return NOTIFY_DONE; |
| 682 | } | 752 | } |
| 683 | 753 | ||
| 684 | int setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) | 754 | int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) |
| 685 | { | 755 | { |
| 686 | struct jprobe *jp = container_of(p, struct jprobe, kp); | 756 | struct jprobe *jp = container_of(p, struct jprobe, kp); |
| 687 | unsigned long addr = ((struct fnptr *)(jp->entry))->ip; | 757 | unsigned long addr = ((struct fnptr *)(jp->entry))->ip; |
| @@ -703,7 +773,7 @@ int setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) | |||
| 703 | return 1; | 773 | return 1; |
| 704 | } | 774 | } |
| 705 | 775 | ||
| 706 | int longjmp_break_handler(struct kprobe *p, struct pt_regs *regs) | 776 | int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs) |
| 707 | { | 777 | { |
| 708 | *regs = jprobe_saved_regs; | 778 | *regs = jprobe_saved_regs; |
| 709 | return 1; | 779 | return 1; |
