From: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
To: Peter Zijlstra <peterz@infradead.org>,
Linus Torvalds <torvalds@linux-foundation.org>
Cc: Oleg Nesterov <oleg@redhat.com>,
Andrew Morton <akpm@linux-foundation.org>,
LKML <linux-kernel@vger.kernel.org>,
Linux-mm <linux-mm@kvack.org>, Ingo Molnar <mingo@elte.hu>,
Andi Kleen <andi@firstfloor.org>,
Christoph Hellwig <hch@infradead.org>,
Steven Rostedt <rostedt@goodmis.org>,
Roland McGrath <roland@hack.frob.com>,
Thomas Gleixner <tglx@linutronix.de>,
Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>,
Arnaldo Carvalho de Melo <acme@infradead.org>,
Anton Arapov <anton@redhat.com>,
Ananth N Mavinakayanahalli <ananth@in.ibm.com>,
Jim Keniston <jkenisto@linux.vnet.ibm.com>,
Stephen Wilson <wilsons@start.ca>
Subject: [PATCH v6 3.2-rc1 5/28] Uprobes: copy of the original instruction.
Date: Fri, 11 Nov 2011 00:08:26 +0530 [thread overview]
Message-ID: <20111110183826.11361.17633.sendpatchset@srdronam.in.ibm.com> (raw)
In-Reply-To: <20111110183725.11361.57827.sendpatchset@srdronam.in.ibm.com>
When inserting the first probepoint, save a copy of the original
instruction. This copy is later used for fixup analysis, copied to the slot
on probe-hit and for restoring the original instruction.
Signed-off-by: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
---
Changelog: (Since v5)
- Uprobes no more depends on MM_OWNER; No reference to task_structs
while inserting/removing a probe.
- Uses read_mapping_page instead of grab_cache_page so that the pages
have valid content.
include/linux/uprobes.h | 12 +++++
kernel/uprobes.c | 111 +++++++++++++++++++++++++++++++++++++++++++----
2 files changed, 113 insertions(+), 10 deletions(-)
diff --git a/include/linux/uprobes.h b/include/linux/uprobes.h
index b4de058..fa2b663 100644
--- a/include/linux/uprobes.h
+++ b/include/linux/uprobes.h
@@ -26,6 +26,12 @@
#include <linux/rbtree.h>
struct vm_area_struct;
+#ifdef CONFIG_ARCH_SUPPORTS_UPROBES
+#include <asm/uprobes.h>
+#else
+
+#define MAX_UINSN_BYTES 4
+#endif
struct uprobe_consumer {
int (*handler)(struct uprobe_consumer *self, struct pt_regs *regs);
@@ -46,9 +52,15 @@ struct uprobe {
struct uprobe_consumer *consumers;
struct inode *inode; /* Also hold a ref to inode */
loff_t offset;
+ int copy;
+ u8 insn[MAX_UINSN_BYTES];
};
#ifdef CONFIG_UPROBES
+extern int __weak set_bkpt(struct mm_struct *mm, struct uprobe *uprobe,
+ unsigned long vaddr);
+extern int __weak set_orig_insn(struct mm_struct *mm, struct uprobe *uprobe,
+ unsigned long vaddr, bool verify);
extern int register_uprobe(struct inode *inode, loff_t offset,
struct uprobe_consumer *consumer);
extern void unregister_uprobe(struct inode *inode, loff_t offset,
diff --git a/kernel/uprobes.c b/kernel/uprobes.c
index 1baae40..f4574fd 100644
--- a/kernel/uprobes.c
+++ b/kernel/uprobes.c
@@ -23,6 +23,7 @@
#include <linux/kernel.h>
#include <linux/highmem.h>
+#include <linux/pagemap.h> /* read_mapping_page */
#include <linux/slab.h>
#include <linux/sched.h>
#include <linux/uprobes.h>
@@ -82,6 +83,20 @@ static bool valid_vma(struct vm_area_struct *vma, bool is_reg)
return false;
}
+int __weak set_bkpt(struct mm_struct *mm, struct uprobe *uprobe,
+ unsigned long vaddr)
+{
+ /* placeholder: yet to be implemented */
+ return 0;
+}
+
+int __weak set_orig_insn(struct mm_struct *mm, struct uprobe *uprobe,
+ unsigned long vaddr, bool verify)
+{
+ /* placeholder: yet to be implemented */
+ return 0;
+}
+
static int match_uprobe(struct uprobe *l, struct uprobe *r)
{
if (l->inode < r->inode)
@@ -251,8 +266,71 @@ static bool del_consumer(struct uprobe *uprobe,
return ret;
}
-static int install_breakpoint(struct mm_struct *mm, struct uprobe *uprobe)
+static int __copy_insn(struct address_space *mapping,
+ struct vm_area_struct *vma, char *insn,
+ unsigned long nbytes, unsigned long offset)
+{
+ struct file *filp = vma->vm_file;
+ struct page *page;
+ void *vaddr;
+ unsigned long off1;
+ unsigned long idx;
+
+ if (!filp)
+ return -EINVAL;
+
+ idx = (unsigned long)(offset >> PAGE_CACHE_SHIFT);
+ off1 = offset &= ~PAGE_MASK;
+
+ /*
+ * Ensure that the page that has the original instruction is
+ * populated and in page-cache.
+ */
+ page = read_mapping_page(mapping, idx, filp);
+ if (IS_ERR(page))
+ return -ENOMEM;
+
+ vaddr = kmap_atomic(page);
+ memcpy(insn, vaddr + off1, nbytes);
+ kunmap_atomic(vaddr);
+ page_cache_release(page);
+ return 0;
+}
+
+static int copy_insn(struct uprobe *uprobe, struct vm_area_struct *vma,
+ unsigned long addr)
+{
+ struct address_space *mapping;
+ int bytes;
+ unsigned long nbytes;
+
+ addr &= ~PAGE_MASK;
+ nbytes = PAGE_SIZE - addr;
+ mapping = uprobe->inode->i_mapping;
+
+ /* Instruction at end of binary; copy only available bytes */
+ if (uprobe->offset + MAX_UINSN_BYTES > uprobe->inode->i_size)
+ bytes = uprobe->inode->i_size - uprobe->offset;
+ else
+ bytes = MAX_UINSN_BYTES;
+
+ /* Instruction at the page-boundary; copy bytes in second page */
+ if (nbytes < bytes) {
+ if (__copy_insn(mapping, vma, uprobe->insn + nbytes,
+ bytes - nbytes, uprobe->offset + nbytes))
+ return -ENOMEM;
+
+ bytes = nbytes;
+ }
+ return __copy_insn(mapping, vma, uprobe->insn, bytes, uprobe->offset);
+}
+
+static int install_breakpoint(struct mm_struct *mm, struct uprobe *uprobe,
+ struct vm_area_struct *vma, loff_t vaddr)
{
+ unsigned long addr;
+ int ret = -EINVAL;
+
/*
* Probe is to be deleted;
* Dont know if somebody already inserted the probe;
@@ -261,15 +339,27 @@ static int install_breakpoint(struct mm_struct *mm, struct uprobe *uprobe)
if (!uprobe->consumers)
return -EEXIST;
- atomic_inc(&mm->mm_uprobes_count);
- return 0;
+ addr = (unsigned long)vaddr;
+ if (!uprobe->copy) {
+ ret = copy_insn(uprobe, vma, addr);
+ if (ret)
+ return ret;
+
+ /* TODO : Analysis and verification of instruction */
+ uprobe->copy = 1;
+ }
+ ret = set_bkpt(mm, uprobe, addr);
+ if (!ret)
+ atomic_inc(&mm->mm_uprobes_count);
+
+ return ret;
}
-static void remove_breakpoint(struct mm_struct *mm, struct uprobe *uprobe)
+static void remove_breakpoint(struct mm_struct *mm, struct uprobe *uprobe,
+ loff_t vaddr)
{
- /* Placeholder: Yet to be implemented */
- atomic_dec(&mm->mm_uprobes_count);
- return;
+ if (!set_orig_insn(mm, uprobe, (unsigned long)vaddr, true))
+ atomic_dec(&mm->mm_uprobes_count);
}
static void delete_uprobe(struct uprobe *uprobe)
@@ -385,7 +475,7 @@ static int __register_uprobe(struct inode *inode, loff_t offset,
mmput(mm);
continue;
}
- ret = install_breakpoint(mm, uprobe);
+ ret = install_breakpoint(mm, uprobe, vma, vi->vaddr);
up_read(&mm->mmap_sem);
mmput(mm);
if (ret && ret == -EEXIST)
@@ -436,7 +526,7 @@ static void __unregister_uprobe(struct inode *inode, loff_t offset,
mmput(mm);
continue;
}
- remove_breakpoint(mm, uprobe);
+ remove_breakpoint(mm, uprobe, vi->vaddr);
up_read(&mm->mmap_sem);
mmput(mm);
}
@@ -627,7 +717,8 @@ int mmap_uprobe(struct vm_area_struct *vma)
put_uprobe(uprobe);
continue;
}
- ret = install_breakpoint(vma->vm_mm, uprobe);
+ ret = install_breakpoint(vma->vm_mm, uprobe, vma,
+ vaddr);
if (ret == -EEXIST) {
atomic_inc(&vma->vm_mm->mm_uprobes_count);
ret = 0;
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
next prev parent reply other threads:[~2011-11-10 19:03 UTC|newest]
Thread overview: 31+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-11-10 18:37 [PATCH v6 3.2-rc1 0/28] Uprobes patchset with perf probe support Srikar Dronamraju
2011-11-10 18:37 ` [PATCH v6 3.2-rc1 1/28] uprobes: Auxillary routines to insert, find, delete uprobes Srikar Dronamraju
2011-11-10 18:37 ` [PATCH v6 3.2-rc1 2/28] Uprobes: Allow multiple consumers for an uprobe Srikar Dronamraju
2011-11-10 18:37 ` [PATCH v6 3.2-rc1 3/28] Uprobes: register/unregister probes Srikar Dronamraju
2011-11-10 18:38 ` [PATCH v6 3.2-rc1 4/28] uprobes: Define hooks for mmap/munmap Srikar Dronamraju
2011-11-10 18:38 ` Srikar Dronamraju [this message]
2011-11-10 18:38 ` [PATCH v6 3.2-rc1 6/28] Uprobes: define fixups Srikar Dronamraju
2011-11-10 18:38 ` [PATCH v6 3.2-rc1 7/28] Uprobes: uprobes arch info Srikar Dronamraju
2011-11-10 18:39 ` [PATCH v6 3.2-rc1 8/28] x86: analyze instruction and determine fixups Srikar Dronamraju
2011-11-10 18:39 ` [PATCH v6 3.2-rc1 9/28] Uprobes: Background page replacement Srikar Dronamraju
2011-11-10 18:39 ` [PATCH v6 3.2-rc1 10/28] x86: Set instruction pointer Srikar Dronamraju
2011-11-10 18:39 ` [PATCH v6 3.2-rc1 11/28] x86: Introduce TIF_UPROBE FLAG Srikar Dronamraju
2011-11-10 18:39 ` [PATCH v6 3.2-rc1 12/28] Uprobes: Handle breakpoint and Singlestep Srikar Dronamraju
2011-11-10 18:40 ` [PATCH v6 3.2-rc1 13/28] x86: define a x86 specific exception notifier Srikar Dronamraju
2011-11-10 18:40 ` [PATCH v6 3.2-rc1 14/28] uprobe: register " Srikar Dronamraju
2011-11-10 18:40 ` [PATCH v6 3.2-rc1 15/28] x86: Define x86_64 specific uprobe_task_arch_info structure Srikar Dronamraju
2011-11-10 18:40 ` [PATCH v6 3.2-rc1 16/28] uprobes: Introduce " Srikar Dronamraju
2011-11-10 18:40 ` [PATCH v6 3.2-rc1 17/28] x86: arch specific hooks for pre/post singlestep handling Srikar Dronamraju
2011-11-10 18:41 ` [PATCH v6 3.2-rc1 18/28] uprobes: slot allocation Srikar Dronamraju
2011-11-10 18:41 ` [PATCH v6 3.2-rc1 19/28] tracing: modify is_delete, is_return from ints to bool Srikar Dronamraju
2011-11-10 18:41 ` [PATCH v6 3.2-rc1 20/28] tracing: Extract out common code for kprobes/uprobes traceevents Srikar Dronamraju
2011-11-10 18:41 ` [PATCH v6 3.2-rc1 21/28] tracing: uprobes trace_event interface Srikar Dronamraju
2011-11-10 18:41 ` [PATCH v6 3.2-rc1 22/28] perf: rename target_module to target Srikar Dronamraju
2011-11-10 18:42 ` [PATCH v6 3.2-rc1 23/28] perf: perf interface for uprobes Srikar Dronamraju
2011-11-10 18:42 ` [PATCH v6 3.2-rc1 24/28] perf: show possible probes in a given executable file or library Srikar Dronamraju
2011-11-10 18:42 ` [PATCH v6 3.2-rc1 25/28] uprobes: call post_xol() unconditionally Srikar Dronamraju
2011-11-10 18:42 ` [PATCH v6 3.2-rc1 26/28] uprobes: introduce uprobe_deny_signal() Srikar Dronamraju
2011-11-10 18:42 ` [PATCH v6 3.2-rc1 27/28] uprobes: x86: introduce xol_was_trapped() Srikar Dronamraju
2011-11-10 18:43 ` [PATCH v6 3.2-rc1 28/28] uprobes: introduce UTASK_SSTEP_TRAPPED logic Srikar Dronamraju
2011-11-14 16:39 ` Oleg Nesterov
2011-11-15 7:44 ` Srikar Dronamraju
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20111110183826.11361.17633.sendpatchset@srdronam.in.ibm.com \
--to=srikar@linux.vnet.ibm.com \
--cc=acme@infradead.org \
--cc=akpm@linux-foundation.org \
--cc=ananth@in.ibm.com \
--cc=andi@firstfloor.org \
--cc=anton@redhat.com \
--cc=hch@infradead.org \
--cc=jkenisto@linux.vnet.ibm.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=masami.hiramatsu.pt@hitachi.com \
--cc=mingo@elte.hu \
--cc=oleg@redhat.com \
--cc=peterz@infradead.org \
--cc=roland@hack.frob.com \
--cc=rostedt@goodmis.org \
--cc=tglx@linutronix.de \
--cc=torvalds@linux-foundation.org \
--cc=wilsons@start.ca \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox