aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/events/uprobes.c
diff options
context:
space:
mode:
authorOleg Nesterov <oleg@redhat.com>2012-09-30 14:11:45 -0400
committerOleg Nesterov <oleg@redhat.com>2012-10-07 15:19:42 -0400
commitcb9a19fe4aa51afa34786bd383e6614fa0083d58 (patch)
treee85fac9d3a69707cd9c3a98361f5cba845d5d260 /kernel/events/uprobes.c
parent142b18ddc81439acda4bc4231b291e99fe67d507 (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>
Diffstat (limited to 'kernel/events/uprobes.c')
-rw-r--r--kernel/events/uprobes.c60
1 files changed, 41 insertions, 19 deletions
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 */
79static atomic_t uprobe_events = ATOMIC_INIT(0); 79static 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
81struct uprobe { 88struct 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
573static 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
566static int 604static int
567install_breakpoint(struct uprobe *uprobe, struct mm_struct *mm, 605install_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(),