diff options
Diffstat (limited to 'arch/x86')
-rw-r--r-- | arch/x86/kernel/uprobes.c | 27 |
1 files changed, 11 insertions, 16 deletions
diff --git a/arch/x86/kernel/uprobes.c b/arch/x86/kernel/uprobes.c index 5bcce852628a..d2792e884d54 100644 --- a/arch/x86/kernel/uprobes.c +++ b/arch/x86/kernel/uprobes.c | |||
@@ -424,10 +424,9 @@ static int default_post_xol_op(struct arch_uprobe *auprobe, struct pt_regs *regs | |||
424 | long correction = (long)(utask->vaddr - utask->xol_vaddr); | 424 | long correction = (long)(utask->vaddr - utask->xol_vaddr); |
425 | 425 | ||
426 | handle_riprel_post_xol(auprobe, regs, &correction); | 426 | handle_riprel_post_xol(auprobe, regs, &correction); |
427 | if (auprobe->def.fixups & UPROBE_FIX_IP) | 427 | if (auprobe->def.fixups & UPROBE_FIX_IP) { |
428 | regs->ip += correction; | 428 | regs->ip += correction; |
429 | 429 | } else if (auprobe->def.fixups & UPROBE_FIX_CALL) { | |
430 | if (auprobe->def.fixups & UPROBE_FIX_CALL) { | ||
431 | regs->sp += sizeof_long(); | 430 | regs->sp += sizeof_long(); |
432 | if (push_ret_address(regs, utask->vaddr + auprobe->def.ilen)) | 431 | if (push_ret_address(regs, utask->vaddr + auprobe->def.ilen)) |
433 | return -ERESTART; | 432 | return -ERESTART; |
@@ -623,7 +622,7 @@ static int branch_setup_xol_ops(struct arch_uprobe *auprobe, struct insn *insn) | |||
623 | int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe, struct mm_struct *mm, unsigned long addr) | 622 | int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe, struct mm_struct *mm, unsigned long addr) |
624 | { | 623 | { |
625 | struct insn insn; | 624 | struct insn insn; |
626 | bool fix_ip = true, fix_call = false; | 625 | u8 fix_ip_or_call = UPROBE_FIX_IP; |
627 | int ret; | 626 | int ret; |
628 | 627 | ||
629 | ret = uprobe_init_insn(auprobe, &insn, is_64bit_mm(mm)); | 628 | ret = uprobe_init_insn(auprobe, &insn, is_64bit_mm(mm)); |
@@ -647,21 +646,20 @@ int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe, struct mm_struct *mm, | |||
647 | case 0xcb: | 646 | case 0xcb: |
648 | case 0xc2: | 647 | case 0xc2: |
649 | case 0xca: | 648 | case 0xca: |
650 | fix_ip = false; | 649 | case 0xea: /* jmp absolute -- ip is correct */ |
650 | fix_ip_or_call = 0; | ||
651 | break; | 651 | break; |
652 | case 0x9a: /* call absolute - Fix return addr, not ip */ | 652 | case 0x9a: /* call absolute - Fix return addr, not ip */ |
653 | fix_call = true; | 653 | fix_ip_or_call = UPROBE_FIX_CALL; |
654 | fix_ip = false; | ||
655 | break; | ||
656 | case 0xea: /* jmp absolute -- ip is correct */ | ||
657 | fix_ip = false; | ||
658 | break; | 654 | break; |
659 | case 0xff: | 655 | case 0xff: |
660 | switch (MODRM_REG(&insn)) { | 656 | switch (MODRM_REG(&insn)) { |
661 | case 2: case 3: /* call or lcall, indirect */ | 657 | case 2: case 3: /* call or lcall, indirect */ |
662 | fix_call = true; | 658 | fix_ip_or_call = UPROBE_FIX_CALL; |
659 | break; | ||
663 | case 4: case 5: /* jmp or ljmp, indirect */ | 660 | case 4: case 5: /* jmp or ljmp, indirect */ |
664 | fix_ip = false; | 661 | fix_ip_or_call = 0; |
662 | break; | ||
665 | } | 663 | } |
666 | /* fall through */ | 664 | /* fall through */ |
667 | default: | 665 | default: |
@@ -669,10 +667,7 @@ int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe, struct mm_struct *mm, | |||
669 | } | 667 | } |
670 | 668 | ||
671 | auprobe->def.ilen = insn.length; | 669 | auprobe->def.ilen = insn.length; |
672 | if (fix_ip) | 670 | auprobe->def.fixups |= fix_ip_or_call; |
673 | auprobe->def.fixups |= UPROBE_FIX_IP; | ||
674 | if (fix_call) | ||
675 | auprobe->def.fixups |= UPROBE_FIX_CALL; | ||
676 | 671 | ||
677 | auprobe->ops = &default_xol_ops; | 672 | auprobe->ops = &default_xol_ops; |
678 | return 0; | 673 | return 0; |