diff options
author | Oleg Nesterov <oleg@redhat.com> | 2014-04-25 12:06:19 -0400 |
---|---|---|
committer | Oleg Nesterov <oleg@redhat.com> | 2014-04-30 13:10:39 -0400 |
commit | 1dc76e6eacef271230d9ff6fd0f91824bda03f44 (patch) | |
tree | 2e8bcef731ebe89c98964646a6751a84fc5a0906 /arch/x86 | |
parent | 2b82cadffc4154a25c25d88a63c7fb3397cda9d6 (diff) |
uprobes/x86: Kill adjust_ret_addr(), simplify UPROBE_FIX_CALL logic
The only insn which could have both UPROBE_FIX_IP and UPROBE_FIX_CALL
was 0xe8 "call relative", and now it is handled by branch_xol_ops.
So we can change default_post_xol_op(UPROBE_FIX_CALL) to simply push
the address of next insn == utask->vaddr + insn.length, just we need
to record insn.length into the new auprobe->def.ilen member.
Note: if/when we teach branch_xol_ops to support jcxz/loopz we can
remove the "correction" logic, UPROBE_FIX_IP can use the same address.
Signed-off-by: Oleg Nesterov <oleg@redhat.com>
Diffstat (limited to 'arch/x86')
-rw-r--r-- | arch/x86/include/asm/uprobes.h | 1 | ||||
-rw-r--r-- | arch/x86/kernel/uprobes.c | 24 |
2 files changed, 4 insertions, 21 deletions
diff --git a/arch/x86/include/asm/uprobes.h b/arch/x86/include/asm/uprobes.h index 9ce25ce04fee..a040d493a4f9 100644 --- a/arch/x86/include/asm/uprobes.h +++ b/arch/x86/include/asm/uprobes.h | |||
@@ -54,6 +54,7 @@ struct arch_uprobe { | |||
54 | long riprel_target; | 54 | long riprel_target; |
55 | #endif | 55 | #endif |
56 | u8 fixups; | 56 | u8 fixups; |
57 | u8 ilen; | ||
57 | } def; | 58 | } def; |
58 | }; | 59 | }; |
59 | }; | 60 | }; |
diff --git a/arch/x86/kernel/uprobes.c b/arch/x86/kernel/uprobes.c index df75913acfc0..5bcce852628a 100644 --- a/arch/x86/kernel/uprobes.c +++ b/arch/x86/kernel/uprobes.c | |||
@@ -418,24 +418,6 @@ static int push_ret_address(struct pt_regs *regs, unsigned long ip) | |||
418 | return 0; | 418 | return 0; |
419 | } | 419 | } |
420 | 420 | ||
421 | /* | ||
422 | * Adjust the return address pushed by a call insn executed out of line. | ||
423 | */ | ||
424 | static int adjust_ret_addr(unsigned long sp, long correction) | ||
425 | { | ||
426 | int rasize = sizeof_long(); | ||
427 | long ra; | ||
428 | |||
429 | if (copy_from_user(&ra, (void __user *)sp, rasize)) | ||
430 | return -EFAULT; | ||
431 | |||
432 | ra += correction; | ||
433 | if (copy_to_user((void __user *)sp, &ra, rasize)) | ||
434 | return -EFAULT; | ||
435 | |||
436 | return 0; | ||
437 | } | ||
438 | |||
439 | static int default_post_xol_op(struct arch_uprobe *auprobe, struct pt_regs *regs) | 421 | static int default_post_xol_op(struct arch_uprobe *auprobe, struct pt_regs *regs) |
440 | { | 422 | { |
441 | struct uprobe_task *utask = current->utask; | 423 | struct uprobe_task *utask = current->utask; |
@@ -446,10 +428,9 @@ static int default_post_xol_op(struct arch_uprobe *auprobe, struct pt_regs *regs | |||
446 | regs->ip += correction; | 428 | regs->ip += correction; |
447 | 429 | ||
448 | if (auprobe->def.fixups & UPROBE_FIX_CALL) { | 430 | if (auprobe->def.fixups & UPROBE_FIX_CALL) { |
449 | if (adjust_ret_addr(regs->sp, correction)) { | 431 | regs->sp += sizeof_long(); |
450 | regs->sp += sizeof_long(); | 432 | if (push_ret_address(regs, utask->vaddr + auprobe->def.ilen)) |
451 | return -ERESTART; | 433 | return -ERESTART; |
452 | } | ||
453 | } | 434 | } |
454 | /* popf; tell the caller to not touch TF */ | 435 | /* popf; tell the caller to not touch TF */ |
455 | if (auprobe->def.fixups & UPROBE_FIX_SETF) | 436 | if (auprobe->def.fixups & UPROBE_FIX_SETF) |
@@ -687,6 +668,7 @@ int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe, struct mm_struct *mm, | |||
687 | handle_riprel_insn(auprobe, &insn); | 668 | handle_riprel_insn(auprobe, &insn); |
688 | } | 669 | } |
689 | 670 | ||
671 | auprobe->def.ilen = insn.length; | ||
690 | if (fix_ip) | 672 | if (fix_ip) |
691 | auprobe->def.fixups |= UPROBE_FIX_IP; | 673 | auprobe->def.fixups |= UPROBE_FIX_IP; |
692 | if (fix_call) | 674 | if (fix_call) |