diff options
| author | Oleg Nesterov <oleg@redhat.com> | 2012-09-30 14:11:45 -0400 |
|---|---|---|
| committer | Oleg Nesterov <oleg@redhat.com> | 2012-10-07 15:19:42 -0400 |
| commit | cb9a19fe4aa51afa34786bd383e6614fa0083d58 (patch) | |
| tree | e85fac9d3a69707cd9c3a98361f5cba845d5d260 | |
| parent | 142b18ddc81439acda4bc4231b291e99fe67d507 (diff) | |
uprobes: Introduce prepare_uprobe()
Preparation. Extract the copy_insn/arch_uprobe_analyze_insn code
from install_breakpoint() into the new helper, prepare_uprobe().
And move uprobe->flags defines from uprobes.h to uprobes.c, nobody
else can use them anyway.
Signed-off-by: Oleg Nesterov <oleg@redhat.com>
Acked-by: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
| -rw-r--r-- | include/linux/uprobes.h | 10 | ||||
| -rw-r--r-- | kernel/events/uprobes.c | 60 |
2 files changed, 41 insertions, 29 deletions
diff --git a/include/linux/uprobes.h b/include/linux/uprobes.h index 18d839da6517..24594571c5a3 100644 --- a/include/linux/uprobes.h +++ b/include/linux/uprobes.h | |||
| @@ -35,16 +35,6 @@ struct inode; | |||
| 35 | # include <asm/uprobes.h> | 35 | # include <asm/uprobes.h> |
| 36 | #endif | 36 | #endif |
| 37 | 37 | ||
| 38 | /* flags that denote/change uprobes behaviour */ | ||
| 39 | |||
| 40 | /* Have a copy of original instruction */ | ||
| 41 | #define UPROBE_COPY_INSN 0x1 | ||
| 42 | |||
| 43 | /* Dont run handlers when first register/ last unregister in progress*/ | ||
| 44 | #define UPROBE_RUN_HANDLER 0x2 | ||
| 45 | /* Can skip singlestep */ | ||
| 46 | #define UPROBE_SKIP_SSTEP 0x4 | ||
| 47 | |||
| 48 | struct uprobe_consumer { | 38 | struct uprobe_consumer { |
| 49 | int (*handler)(struct uprobe_consumer *self, struct pt_regs *regs); | 39 | int (*handler)(struct uprobe_consumer *self, struct pt_regs *regs); |
| 50 | /* | 40 | /* |
diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c index c718fef28617..4f315fa94c52 100644 --- a/kernel/events/uprobes.c +++ b/kernel/events/uprobes.c | |||
| @@ -78,6 +78,13 @@ static struct mutex uprobes_mmap_mutex[UPROBES_HASH_SZ]; | |||
| 78 | */ | 78 | */ |
| 79 | static atomic_t uprobe_events = ATOMIC_INIT(0); | 79 | static atomic_t uprobe_events = ATOMIC_INIT(0); |
| 80 | 80 | ||
| 81 | /* Have a copy of original instruction */ | ||
| 82 | #define UPROBE_COPY_INSN 0x1 | ||
| 83 | /* Dont run handlers when first register/ last unregister in progress*/ | ||
| 84 | #define UPROBE_RUN_HANDLER 0x2 | ||
| 85 | /* Can skip singlestep */ | ||
| 86 | #define UPROBE_SKIP_SSTEP 0x4 | ||
| 87 | |||
| 81 | struct uprobe { | 88 | struct uprobe { |
| 82 | struct rb_node rb_node; /* node in the rb tree */ | 89 | struct rb_node rb_node; /* node in the rb tree */ |
| 83 | atomic_t ref; | 90 | atomic_t ref; |
| @@ -563,6 +570,37 @@ static int copy_insn(struct uprobe *uprobe, struct file *filp) | |||
| 563 | return __copy_insn(mapping, filp, uprobe->arch.insn, bytes, uprobe->offset); | 570 | return __copy_insn(mapping, filp, uprobe->arch.insn, bytes, uprobe->offset); |
| 564 | } | 571 | } |
| 565 | 572 | ||
| 573 | static int prepare_uprobe(struct uprobe *uprobe, struct file *file, | ||
| 574 | struct mm_struct *mm, unsigned long vaddr) | ||
| 575 | { | ||
| 576 | int ret = 0; | ||
| 577 | |||
| 578 | if (uprobe->flags & UPROBE_COPY_INSN) | ||
| 579 | return ret; | ||
| 580 | |||
| 581 | ret = copy_insn(uprobe, file); | ||
| 582 | if (ret) | ||
| 583 | goto out; | ||
| 584 | |||
| 585 | ret = -ENOTSUPP; | ||
| 586 | if (is_swbp_insn((uprobe_opcode_t *)uprobe->arch.insn)) | ||
| 587 | goto out; | ||
| 588 | |||
| 589 | ret = arch_uprobe_analyze_insn(&uprobe->arch, mm, vaddr); | ||
| 590 | if (ret) | ||
| 591 | goto out; | ||
| 592 | |||
| 593 | /* write_opcode() assumes we don't cross page boundary */ | ||
| 594 | BUG_ON((uprobe->offset & ~PAGE_MASK) + | ||
| 595 | UPROBE_SWBP_INSN_SIZE > PAGE_SIZE); | ||
| 596 | |||
| 597 | smp_wmb(); /* pairs with rmb() in find_active_uprobe() */ | ||
| 598 | uprobe->flags |= UPROBE_COPY_INSN; | ||
| 599 | |||
| 600 | out: | ||
| 601 | return ret; | ||
| 602 | } | ||
| 603 | |||
| 566 | static int | 604 | static int |
| 567 | install_breakpoint(struct uprobe *uprobe, struct mm_struct *mm, | 605 | install_breakpoint(struct uprobe *uprobe, struct mm_struct *mm, |
| 568 | struct vm_area_struct *vma, unsigned long vaddr) | 606 | struct vm_area_struct *vma, unsigned long vaddr) |
| @@ -580,25 +618,9 @@ install_breakpoint(struct uprobe *uprobe, struct mm_struct *mm, | |||
| 580 | if (!uprobe->consumers) | 618 | if (!uprobe->consumers) |
| 581 | return 0; | 619 | return 0; |
| 582 | 620 | ||
| 583 | if (!(uprobe->flags & UPROBE_COPY_INSN)) { | 621 | ret = prepare_uprobe(uprobe, vma->vm_file, mm, vaddr); |
| 584 | ret = copy_insn(uprobe, vma->vm_file); | 622 | if (ret) |
| 585 | if (ret) | 623 | return ret; |
| 586 | return ret; | ||
| 587 | |||
| 588 | if (is_swbp_insn((uprobe_opcode_t *)uprobe->arch.insn)) | ||
| 589 | return -ENOTSUPP; | ||
| 590 | |||
| 591 | ret = arch_uprobe_analyze_insn(&uprobe->arch, mm, vaddr); | ||
| 592 | if (ret) | ||
| 593 | return ret; | ||
| 594 | |||
| 595 | /* write_opcode() assumes we don't cross page boundary */ | ||
| 596 | BUG_ON((uprobe->offset & ~PAGE_MASK) + | ||
| 597 | UPROBE_SWBP_INSN_SIZE > PAGE_SIZE); | ||
| 598 | |||
| 599 | smp_wmb(); /* pairs with rmb() in find_active_uprobe() */ | ||
| 600 | uprobe->flags |= UPROBE_COPY_INSN; | ||
| 601 | } | ||
| 602 | 624 | ||
| 603 | /* | 625 | /* |
| 604 | * set MMF_HAS_UPROBES in advance for uprobe_pre_sstep_notifier(), | 626 | * set MMF_HAS_UPROBES in advance for uprobe_pre_sstep_notifier(), |
