uprobes patchset with perf probe support
Subsystems (10)
v7 cover uprobes patchset with perf probe support
This patchset implements Uprobes which enables you to dynamically probe any routine in a user space application and collect information non-disruptively.
This patchset resolves most of the comments on the previous posting
(https://lkml.org/lkml/2011/11/10/408) patchset applies on top of commit cfcfc9eca2b
This patchset depends on bulkref patch from Paul McKenney
https://lkml.org/lkml/2011/11/2/365 and enable interrupts before calling do_notify_resume on i686 patch
https://lkml.org/lkml/2011/10/25/265.
uprobes git is hosted at git://github.com/srikard/linux.git
with branch inode_uprobes_v32rc2.
(The previous patchset posted to lkml has been rebased to 3.2-rc2 is also available at branch inode_uprobes_v32rc2_prev. This is to help the reviewers of the previous patchsets to quickly identify the changes.)
Uprobes Patches
This patchset implements inode based uprobes which are specified as <file>:<offset> where offset is the offset from start of the map.
When a uprobe is registered, Uprobes makes a copy of the probed instruction, replaces the first byte(s) of the probed instruction with a breakpoint instruction. (Uprobes uses background page replacement mechanism and ensures that the breakpoint affects only that process.)
When a CPU hits the breakpoint instruction, Uprobes gets notified of trap and finds the associated uprobe. It then executes the associated handler. Uprobes single-steps its copy of the probed instruction and resumes execution of the probed process at the instruction following the probepoint. Instruction copies to be single-stepped are stored in a per-mm "execution out of line (XOL) area". Currently XOL area is allocated as one page vma.
For previous postings: please refer: https://lkml.org/lkml/2011/9/20/123
https://lkml.org/lkml/2011/6/7/232 https://lkml.org/lkml/2011/4/1/176
http://lkml.org/lkml/2011/3/14/171/ http://lkml.org/lkml/2010/12/16/65
http://lkml.org/lkml/2010/8/25/165 http://lkml.org/lkml/2010/7/27/121
http://lkml.org/lkml/2010/7/12/67 http://lkml.org/lkml/2010/7/8/239
http://lkml.org/lkml/2010/6/29/299 http://lkml.org/lkml/2010/6/14/41
http://lkml.org/lkml/2010/3/20/107 and http://lkml.org/lkml/2010/5/18/307
This patchset is a rework based on suggestions from discussions on lkml in September, March and January 2010 (http://lkml.org/lkml/2010/1/11/92,
http://lkml.org/lkml/2010/1/27/19, http://lkml.org/lkml/2010/3/20/107
and http://lkml.org/lkml/2010/3/31/199 ). This implementation of uprobes doesnt depend on utrace.
Advantages of uprobes over conventional debugging include:
1. Non-disruptive.
Unlike current ptrace based mechanisms, uprobes tracing wouldnt involve signals, stopping threads and context switching between the tracer and tracee.
2. Much better handling of multithreaded programs because of XOL. Current ptrace based mechanisms use single stepping inline, i.e they copy back the original instruction on hitting a breakpoint. In such mechanisms tracers have to stop all the threads on a breakpoint hit or tracers will not be able to handle all hits to the location of interest. Uprobes uses execution out of line, where the instruction to be traced is analysed at the time of breakpoint insertion and a copy of instruction is stored at a different location. On breakpoint hit, uprobes jumps to that copied location and singlesteps the same instruction and does the necessary fixups post singlestepping.
3. Multiple tracers for an application.
Multiple uprobes based tracer could work in unison to trace an application. There could one tracer that could be interested in generic events for a particular set of process. While there could be another tracer that is just interested in one specific event of a particular process thats part of the previous set of process.
4. Corelating events from kernels and userspace.
Uprobes could be used with other tools like kprobes, tracepoints or as part of higher level tools like perf to give a consolidated set of events from kernel and userspace. In future we could look at a single backtrace showing application, library and kernel calls.
Changes from last patchset:
- Rebased to Linus's 3.2-rc2 (cfcfc9eca2b)
- abort_xol does arch specific cleanups.
- added nop optimization.
Here is the list of TODO Items.
- Prefiltering (i.e filtering at the time of probe insertion)
- Return probes.
- Support for other architectures.
- Uprobes booster.
- replace macro W with bits in inat table.
Please refer "[PATCH 3.2-rc2 21/30] tracing: uprobes trace_event interface".
Please refer "[PATCH 3.2-rc2 23/30] perf: perf interface for uprobes".
Please do provide your valuable comments.
Thanks in advance.
Srikar
Srikar Dronamraju (30)
0: Uprobes patchset with perf probe support
1: uprobes: Auxillary routines to insert, find, delete uprobes 2: Uprobes: Allow multiple consumers for an uprobe.
3: Uprobes: register/unregister probes.
4: uprobes: Define hooks for mmap/munmap.
5: Uprobes: copy of the original instruction.
6: Uprobes: define fixups.
7: Uprobes: uprobes arch info
8: x86: analyze instruction and determine fixups.
9: Uprobes: Background page replacement.
10: x86: Set instruction pointer.
11: x86: Introduce TIF_UPROBE FLAG.
12: Uprobes: Handle breakpoint and Singlestep
13: x86: define a x86 specific exception notifier.
14: uprobe: register exception notifier
15: x86: Define x86_64 specific uprobe_task_arch_info structure 16: uprobes: Introduce uprobe_task_arch_info structure. 17: x86: arch specific hooks for pre/post singlestep handling. 18: uprobes: slot allocation.
19: tracing: modify is_delete, is_return from ints to bool. 20: tracing: Extract out common code for kprobes/uprobes traceevents. 21: tracing: uprobes trace_event interface
22: perf: rename target_module to target
23: perf: perf interface for uprobes
24: perf: show possible probes in a given executable file or library. 25: uprobes: call post_xol() unconditionally
26: uprobes: introduce uprobe_deny_signal()
27: uprobes: x86: introduce xol_was_trapped()
28: uprobes: introduce UTASK_SSTEP_TRAPPED logic
29: uprobes: Introduce uprobe flags
30: x86: skip singlestep where possible
Documentation/trace/uprobetracer.txt | 93 ++ arch/Kconfig | 3 + arch/x86/Kconfig | 5 +- arch/x86/include/asm/thread_info.h | 2 + arch/x86/include/asm/uprobes.h | 59 ++ arch/x86/kernel/Makefile | 1 + arch/x86/kernel/signal.c | 6 + arch/x86/kernel/uprobes.c | 648 +++++++++++++ include/linux/mm_types.h | 5 + include/linux/sched.h | 4 + include/linux/uprobes.h | 178 ++++ kernel/Makefile | 1 + kernel/fork.c | 15 + kernel/signal.c | 3 + kernel/trace/Kconfig | 20 + kernel/trace/Makefile | 2 + kernel/trace/trace.h | 5 + kernel/trace/trace_kprobe.c | 899 +------------------ kernel/trace/trace_probe.c | 785 ++++++++++++++++ kernel/trace/trace_probe.h | 161 ++++ kernel/trace/trace_uprobe.c | 768 ++++++++++++++++ kernel/uprobes.c | 1500 +++++++++++++++++++++++++++++++ mm/mmap.c | 33 +- tools/perf/Documentation/perf-probe.txt | 14 + tools/perf/builtin-probe.c | 49 +- tools/perf/util/probe-event.c | 411 +++++++-- tools/perf/util/probe-event.h | 12 +- tools/perf/util/symbol.c | 8 + tools/perf/util/symbol.h | 1 + 29 files changed, 4710 insertions(+), 981 deletions(-)
PATCH v7 1/30 uprobes: Auxillary routines to insert, find, delete uprobes
Uprobes are maintained in a rb-tree indexed by inode and offset (offset from the start of the map). For a unique inode, offset combination, there can be one unique uprobe in the rbtree. Provide routines that insert a given uprobe, find a uprobe given a inode and offset.
---
Changelog: (from v5)
1. drop reference to inode before dropping reference to uprobe.
include/linux/uprobes.h | 35 +++++++++ kernel/uprobes.c | 174 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 209 insertions(+), 0 deletions(-) create mode 100644 include/linux/uprobes.h create mode 100644 kernel/uprobes.c
include/linux/uprobes.h new file +35 -0
@@ -0,0 +1,35 @@ +#ifndef _LINUX_UPROBES_H +#define _LINUX_UPROBES_H +/* +* Userspace Probes (UProbes) +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +* +* Copyright (C) IBM Corporation, 2008-2011 +* Authors: +* Srikar Dronamraju +* Jim Keniston +*/ + +#include <linux/rbtree.h> + +struct uprobe { +struct rb_node rb_node;/* node in the rb tree */ +atomic_t ref; +struct inode *inode;/* Also hold a ref to inode */ +loff_t offset; +}; + +#endif /* _LINUX_UPROBES_H */
kernel/uprobes.c new file +174 -0
174 lines not on this page · raw message
Peter Zijlstra
maintainerRe: [PATCH v7 3.2-rc2 1/30] uprobes: Auxillary routines to insert, find, delete uprobes
Quoted 12 lines · Srikar Dronamraju
kernel/uprobes.c new file +12
-0+static struct uprobe *alloc_uprobe (struct inode *inode,loff_t offset) +{ +struct uprobe *uprobe, *cur_uprobe; + + uprobe =kzalloc (sizeof (struct uprobe ),GFP_KERNEL ); +if (!uprobe) +return NULL ; + + uprobe->inode =igrab (inode); + uprobe->offset = offset; + +/* add to uprobes_tree, sorted on inode:offset */
kernel/uprobes.c line 163
Quoted 10 lines
kernel/uprobes.c new file +10
-0+ cur_uprobe =insert_uprobe (uprobe); + +/* a uprobe exists for this inode:offset combination */ +if (cur_uprobe) { +kfree (uprobe); + uprobe = cur_uprobe; +iput (inode); + } +return uprobe; +}
A function called alloc that actually publishes the object is weird. Usually those things are separated. Alloc does the memory allocation and sometimes initialization like things, but it never publishes the thing.
This leads to slightly weird code later on. Its not wrong, just weird and makes reading this stuff slightly more challenging than needed.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. 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:"[email protected]"> [email protected] </a>
PATCH v7 2/30 uprobes: Allow multiple consumers for an uprobe.
In reply to Srikar DronamrajuSince there is a unique uprobe for a inode, offset combination, provide an ability for users to have more than one consumer for a uprobe.
Each consumer will define a handler and an optional filter. Handler specifies the routine to run on hitting a probepoint. Filter allows to selectively run the handler on hitting the probepoint. Handler/Filter will be relevant on probehit.
---
Changelog:(Since v5)
modified del_consumer as per comments from Peter.
include/linux/uprobes.h | 13 +++++++++++++ kernel/uprobes.c | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 0 deletions(-)
include/linux/uprobes.h +13 -0
@@ -25,9 +25,22 @@#include <linux/rbtree.h> +struct uprobe_consumer { +int (*handler)(struct uprobe_consumer *self,struct pt_regs *regs); +/* +* filter is optional; If a filter exists, handler is run +* if and only if filter returns true. +*/ +bool (*filter)(struct uprobe_consumer *self,struct task_struct *task); + +struct uprobe_consumer *next; +}; +struct uprobe {struct rb_node rb_node;/* node in the rb tree */ atomic_t ref; +struct rw_semaphore consumer_rwsem; +struct uprobe_consumer *consumers;struct inode *inode;/* Also hold a ref to inode */ loff_t offset; };
kernel/uprobes.c +35 -0
@@ -149,6 +149,7 @@ static struct uprobe *alloc_uprobe(struct inode *inode, loff_t offset) uprobe->inode =igrab (inode); uprobe->offset = offset; +init_rwsem (&uprobe->consumer_rwsem);/* add to uprobes_tree, sorted on inode:offset */ cur_uprobe =insert_uprobe (uprobe);
@@ -162,6 +163,40 @@ static struct uprobe *alloc_uprobe(struct inode *inode, loff_t offset)return uprobe; } +/* Returns the previous consumer */ +static struct uprobe_consumer *add_consumer (struct uprobe *uprobe, +struct uprobe_consumer *consumer) +{ +down_write (&uprobe->consumer_rwsem); + consumer->next = uprobe->consumers; + uprobe->consumers = consumer; +up_write (&uprobe->consumer_rwsem); +return consumer->next; +} + +/* +* For uprobe @uprobe, delete the consumer @consumer. +* Return true if the @consumer is deleted successfully +* or return false. +*/ +static bool del_consumer (struct uprobe *uprobe, +struct uprobe_consumer *consumer) +{ +struct uprobe_consumer **con; +bool ret = false; + +down_write (&uprobe->consumer_rwsem); +for (con = &uprobe->consumers; *con; con = &(*con)->next) { +if (*con == consumer) { + *con = consumer->next; + ret = true; +break ; + } + } +up_write (&uprobe->consumer_rwsem); +return ret; +} +static void delete_uprobe (struct uprobe *uprobe) {unsigned long flags;
PATCH v7 3/30 uprobes: register/unregister probes.
In reply to Srikar DronamrajuA probe is specified by a file:offset. Probe specifications are maintained in a rb tree. A uprobe can be shared by many consumers. While registering a probe, a breakpoint is inserted for the first consumer, On subsequent probes, the consumer gets appended to the existing list of consumers. While unregistering a probe, breakpoint is removed if and only if the consumer happens to be the only remaining consumer for the probe. All other unregisterations, the consumer is removed from the list of consumers.
Given a inode, we get a list of mm's that have mapped the inode. Do the actual registration if mm maps the page where a probe needs to be inserted/removed.
We use a temporary list to walk thro the vmas that map the inode.
- The number of maps that map the inode, is not known before we walk the rmap and keeps changing.
- extending vm_area_struct wasnt recommended.
- There can be more than one maps of the inode in the same mm.
---
Changelog: (Since v5)
1. Use i_size_read(inode) instead of inode->i_size.
2. Ensure uprobe->consumers is NULL, before __unregister_uprobe() is called.
3. remove restriction while unregistering.
4. Earlier code leaked inode references under some conditions while registering/unregistering.
5. continue the vma-rmap walk even if the intermediate vma doesnt meet the requirements.
6. validate the vma found by find_vma before inserting/removing the breakpoint
7. call del_consumer under mutex_lock.
arch/Kconfig | 9 + include/linux/uprobes.h | 16 ++ kernel/Makefile | 1 kernel/uprobes.c | 323 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 349 insertions(+), 0 deletions(-)
arch/Kconfig +9 -0
@@ -61,6 +61,15 @@ config OPTPROBES depends on KPROBES && HAVE_OPTPROBES depends on !PREEMPT +config UPROBES + bool "User-space probes (EXPERIMENTAL)" + help + Uprobes enables kernel subsystems to establish probepoints + in user applications and execute handler functions when + the probepoints are hit. + + If in doubt, say "N". + config HAVE_EFFICIENT_UNALIGNED_ACCESS bool help
include/linux/uprobes.h +16 -0
@@ -45,4 +45,20 @@ struct uprobe { loff_t offset; }; +#ifdef CONFIG_UPROBES +extern int register_uprobe (struct inode *inode,loff_t offset, +struct uprobe_consumer *consumer); +extern void unregister_uprobe (struct inode *inode,loff_t offset, +struct uprobe_consumer *consumer); +#else /* CONFIG_UPROBES is not defined */ +static inline int register_uprobe (struct inode *inode,loff_t offset, +struct uprobe_consumer *consumer) +{ +return -ENOSYS ; +} +static inline void unregister_uprobe (struct inode *inode,loff_t offset, +struct uprobe_consumer *consumer) +{ +} +#endif /* CONFIG_UPROBES */ #endif /* _LINUX_UPROBES_H */
kernel/Makefile +1 -0
@@ -109,6 +109,7 @@ obj-$(CONFIG_USER_RETURN_NOTIFIER) += user-return-notifier.o obj-$(CONFIG_PADATA) += padata.o obj-$(CONFIG_CRASH_DUMP) += crash_dump.o obj-$(CONFIG_JUMP_LABEL) += jump_label.o +obj-$(CONFIG_UPROBES) += uprobes.o ifneq ($(CONFIG_SCHED_OMIT_FRAME_POINTER),y) # According to Alan Modra <[email protected]>, the -fno-omit-frame-pointer is
kernel/uprobes.c +323 -0
343 lines not on this page · raw message
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. 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:"[email protected]"> [email protected] </a>
Peter Zijlstra
maintainerRe: [PATCH v7 3.2-rc2 3/30] uprobes: register/unregister probes.
Quoted 36 lines · Srikar Dronamraju
kernel/uprobes.c +36
-0+static int __register_uprobe (struct inode *inode,loff_t offset, +struct uprobe *uprobe) +{ +struct list_head try_list; +struct vm_area_struct *vma; +struct address_space *mapping; +struct vma_info *vi, *tmpvi; +struct mm_struct *mm; +loff_t vaddr; +int ret =0 ; + + mapping = inode->i_mapping; +INIT_LIST_HEAD (&try_list); +while ((vi =find_next_vma_info (&try_list, offset, + mapping, true)) !=NULL ) { +if (IS_ERR (vi)) { + ret = -ENOMEM ; +break ; + } + mm = vi->mm; +down_read (&mm->mmap_sem); + vma =find_vma (mm, (unsigned long )vi->vaddr); +if (!vma || !valid_vma (vma, true)) { +list_del (&vi->probe_list); +kfree (vi); +up_read (&mm->mmap_sem); +mmput (mm); +continue ; + } + vaddr = vma->vm_start + offset; + vaddr -= vma->vm_pgoff <<PAGE_SHIFT ; +if (vma->vm_file->f_mapping->host != inode || + vaddr != vi->vaddr) { +list_del (&vi->probe_list); +kfree (vi); +up_read (&mm->mmap_sem);
kernel/uprobes.c static void delete_uprobe(struct uprobe *uprobe) · line 371
Quoted 10 lines
kernel/uprobes.c +10
-0+mmput (mm); +continue ; + } + ret =install_breakpoint (mm); +up_read (&mm->mmap_sem); +mmput (mm); +if (ret && ret == -EEXIST ) + ret =0 ; +if (!ret) +break ;
Shouldn't that read:
if (ret) break;
So that we bail when there's a real error instead of no error?
kernel/uprobes.c static void delete_uprobe(struct uprobe *uprobe) · line 378
Quoted 7 lines
kernel/uprobes.c +7
-0+ } +list_for_each_entry_safe (vi, tmpvi, &try_list, probe_list) { +list_del (&vi->probe_list); +kfree (vi); + } +return ret; +}
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. 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:"[email protected]"> [email protected] </a>
Peter Zijlstra
maintainerRe: [PATCH v7 3.2-rc2 3/30] uprobes: register/unregister probes.
Quoted 4 lines · Peter Zijlstra
kernel/uprobes.c static void delete_uprobe(struct uprobe *uprobe) · line 344
Quoted 4 lines
kernel/uprobes.c +4
-0+if (IS_ERR (vi)) { + ret = -ENOMEM ; +break ; + }
Also, might as well use:
ret = PTR_ERR(vi);
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. 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:"[email protected]"> [email protected] </a>
Re: [PATCH v7 3.2-rc2 3/30] uprobes: register/unregister probes.
In reply to Peter ZijlstraQuoted 10 lines
kernel/uprobes.c static void delete_uprobe(struct uprobe *uprobe) · line 371
Quoted 3 lines
kernel/uprobes.c +3
-0+ ret =0 ; +if (!ret) +break ;Shouldn't that read:
if (ret) break;So that we bail when there's a real error instead of no error?
Right, will fix this and also do the PTR_ERR changes that you suggested.
Signature · 9 lines
thanks and regards Srikar -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. 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:"[email protected]"> [email protected] </a>
Peter Zijlstra
maintainerRe: [PATCH v7 3.2-rc2 3/30] uprobes: register/unregister probes.
In reply to Srikar Dronamrajukernel/uprobes.c static void delete_uprobe(struct uprobe *uprobe) · line 454
Quoted 10 lines · Srikar Dronamraju
kernel/uprobes.c +10
-0+int register_uprobe (struct inode *inode,loff_t offset, +struct uprobe_consumer *consumer) +{ +struct uprobe *uprobe; +int ret = -EINVAL ; + +if (!consumer || consumer->next) +return ret; + + inode =igrab (inode);
So why are you dealing with !consumer but not with !inode? and why does it make sense to allow !consumer at all?
Quoted 14 lines
kernel/uprobes.c +14
-0+if (!inode) +return ret; + +if (offset >i_size_read (inode)) + goto reg_out; + + ret =0 ; +mutex_lock (uprobes_hash (inode)); + uprobe =alloc_uprobe (inode, offset); +if (uprobe && !add_consumer (uprobe, consumer)) { + ret =__register_uprobe (inode, offset, uprobe); +if (ret) { + uprobe->consumers =NULL ; +__unregister_uprobe (inode, offset, uprobe);
kernel/uprobes.c static void delete_uprobe(struct uprobe *uprobe) · line 478
Quoted 10 lines
kernel/uprobes.c +10
-0+ } + } + +mutex_unlock (uprobes_hash (inode)); +put_uprobe (uprobe); + +reg_out: +iput (inode); +return ret; +}
So if this function returns an error the caller is responsible for cleaning up consumer, otherwise we take responsibility.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. 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:"[email protected]"> [email protected] </a>
Peter Zijlstra
maintainerRe: [PATCH v7 3.2-rc2 3/30] uprobes: register/unregister probes.
In reply to Srikar Dronamrajukernel/uprobes.c static void delete_uprobe(struct uprobe *uprobe) · line 493
Quoted 8 lines · Srikar Dronamraju
kernel/uprobes.c +8
-0+void unregister_uprobe (struct inode *inode,loff_t offset, +struct uprobe_consumer *consumer) +{ +struct uprobe *uprobe =NULL ; + + inode =igrab (inode); +if (!inode || !consumer) + goto unreg_out;
Why do you take a reference on the inode here? Surely inode is already made stable by whoever calls us?
Quoted 11 lines
kernel/uprobes.c +11
-0+ uprobe =find_uprobe (inode, offset); +if (!uprobe) + goto unreg_out; + +mutex_lock (uprobes_hash (inode)); +if (!del_consumer (uprobe, consumer)) { +mutex_unlock (uprobes_hash (inode)); + goto unreg_out; + } + +if (!uprobe->consumers)
kernel/uprobes.c static void delete_uprobe(struct uprobe *uprobe) · line 515
Quoted 10 lines
kernel/uprobes.c +10
-0+__unregister_uprobe (inode, offset, uprobe); + +mutex_unlock (uprobes_hash (inode)); + +unreg_out: +if (uprobe) +put_uprobe (uprobe); +if (inode) +iput (inode); +}
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. 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:"[email protected]"> [email protected] </a>
Peter Zijlstra
maintainerRe: [PATCH v7 3.2-rc2 3/30] uprobes: register/unregister probes.
In reply to Srikar Dronamrajukernel/uprobes.c line 37
Quoted 5 lines · Srikar Dronamraju
kernel/uprobes.c +5
-0+#define UPROBES_HASH_SZ 13 +/* serialize (un)register */ +static struct mutex uprobes_mutex[UPROBES_HASH_SZ ]; +#define uprobes_hash (v) (&uprobes_mutex[((unsigned long)(v)) %\ + UPROBES_HASH_SZ])
Was there any reason to for using this hasing scheme, say over hash.h?
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. 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:"[email protected]"> [email protected] </a>
Peter Zijlstra
maintainerRe: [PATCH v7 3.2-rc2 3/30] uprobes: register/unregister probes.
In reply to Srikar DronamrajuQuoted 6 lines · Srikar Dronamraju
kernel/uprobes.c +6
-0+static void __unregister_uprobe (struct inode *inode,loff_t offset, +struct uprobe *uprobe) +{ +struct list_head try_list; +struct address_space *mapping; +struct vma_info *vi, *tmpvi;
kernel/uprobes.c static void delete_uprobe(struct uprobe *uprobe) · line 395
Quoted 10 lines
kernel/uprobes.c +10
-0+struct vm_area_struct *vma; +struct mm_struct *mm; +loff_t vaddr; + + mapping = inode->i_mapping; +INIT_LIST_HEAD (&try_list); +while ((vi =find_next_vma_info (&try_list, offset, + mapping, false)) !=NULL ) { +if (IS_ERR (vi)) +break ;
So what kind of half-assed state are we left in if we try an unregister under memory pressure and how do we deal with that?
Quoted 21 lines
kernel/uprobes.c +21
-0+ mm = vi->mm; +down_read (&mm->mmap_sem); + vma =find_vma (mm, (unsigned long )vi->vaddr); +if (!vma || !valid_vma (vma, false)) { +list_del (&vi->probe_list); +kfree (vi); +up_read (&mm->mmap_sem); +mmput (mm); +continue ; + } + vaddr = vma->vm_start + offset; + vaddr -= vma->vm_pgoff <<PAGE_SHIFT ; +if (vma->vm_file->f_mapping->host != inode || + vaddr != vi->vaddr) { +list_del (&vi->probe_list); +kfree (vi); +up_read (&mm->mmap_sem); +mmput (mm); +continue ; + } +remove_breakpoint (mm);
kernel/uprobes.c static void delete_uprobe(struct uprobe *uprobe) · line 426
Quoted 10 lines
kernel/uprobes.c +10
-0+up_read (&mm->mmap_sem); +mmput (mm); + } + +list_for_each_entry_safe (vi, tmpvi, &try_list, probe_list) { +list_del (&vi->probe_list); +kfree (vi); + } +delete_uprobe (uprobe); +}
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. 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:"[email protected]"> [email protected] </a>
Re: [PATCH v7 3.2-rc2 3/30] uprobes: register/unregister probes.
Quoted 12 lines · Peter Zijlstra
Quoted 11 lines · Srikar Dronamraju
kernel/uprobes.c +11
-0+static void __unregister_uprobe (struct inode *inode,loff_t offset, +struct uprobe *uprobe) +{ +struct list_head try_list; +struct address_space *mapping; +struct vma_info *vi, *tmpvi; +struct vm_area_struct *vma; +struct mm_struct *mm; +loff_t vaddr; + + mapping = inode->i_mapping;
Quoted 9 lines
kernel/uprobes.c static void delete_uprobe(struct uprobe *uprobe) · line 395
Quoted 5 lines
kernel/uprobes.c +5
-0+INIT_LIST_HEAD (&try_list); +while ((vi =find_next_vma_info (&try_list, offset, + mapping, false)) !=NULL ) { +if (IS_ERR (vi)) +break ;So what kind of half-assed state are we left in if we try an unregister under memory pressure and how do we deal with that?
Agree, Even I had this concern and wanted to see if there are ways to deal with this.
- One approach would be pass extra GFG flags while we do allocations atleast in the unregister_uprobe.
Drawback of this approach: if the system is already under memory pressure we shouldnt exert more pressure by asking it to repeat.
- The other approach would be to cache these temporary objects while we insert probes. i.e keep these metadata around.
I am sure you wouldnt want to add additional metadata.
- Third approach would be to have a completion/worker routine kick in if unregister_uprobe fails due to memory allocations.
This looks better than the rest.
Do you have any other approaches that we could try?
Signature · 2 lines
thanks and regards Srikar
Peter Zijlstra
maintainerRe: [PATCH v7 3.2-rc2 3/30] uprobes: register/unregister probes.
Quoted 24 lines · Srikar Dronamraju
Quoted 12 lines · Peter Zijlstra
Quoted 11 lines · Srikar Dronamraju
kernel/uprobes.c +11
-0+static void __unregister_uprobe (struct inode *inode,loff_t offset, +struct uprobe *uprobe) +{ +struct list_head try_list; +struct address_space *mapping; +struct vma_info *vi, *tmpvi; +struct vm_area_struct *vma; +struct mm_struct *mm; +loff_t vaddr; + + mapping = inode->i_mapping;Quoted 9 lines
kernel/uprobes.c static void delete_uprobe(struct uprobe *uprobe) · line 395
Quoted 5 lines
kernel/uprobes.c +5
-0+INIT_LIST_HEAD (&try_list); +while ((vi =find_next_vma_info (&try_list, offset, + mapping, false)) !=NULL ) { +if (IS_ERR (vi)) +break ;So what kind of half-assed state are we left in if we try an unregister under memory pressure and how do we deal with that?
Quoted 2 lines
Agree, Even I had this concern and wanted to see if there are ways to deal with this.
If you do have this, please mention it in the Changelog and/or put /* XXX */ in the code or so to point it out that there's a problem here.
Quoted 1 line
Do you have any other approaches that we could try?
You could use the stuff from patch 29 to effectively disable the uprobe and return -ENOMEM to whoemever is unregistering. Basically failing the unreg.
That way you can leave the uprobe in existance and half installed but functionally fully disabled. Userspace (assuming we go back that far) can then either re-try the removal later, or even reinstate it by doing a register again or so.
Its still not pretty, but its better than pretending the unreg completed.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. 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:"[email protected]"> [email protected] </a>
Re: [PATCH v7 3.2-rc2 3/30] uprobes: register/unregister probes.
Quoted 5 lines
You could use the stuff from patch 29 to effectively disable the uprobe and return
-ENOMEMto whoemever is unregistering. Basically failing the unreg.
Quoted 8 lines
That way you can leave the uprobe in existance and half installed but functionally fully disabled. Userspace (assuming we go back that far) can then either re-try the removal later, or even reinstate it by doing a register again or so.
Its still not pretty, but its better than pretending the unreg completed.
This approach has its own disadvantages. perf record which does the unregister_uprobe() might be get stuck under low memory conditions while it tries to complete unregistration. Also the user would be confused if the tracer is still collecting information, once the unregister_uprobe has returned an error.
So I would still think using a kworker thread to complete unregistration on a low memory condition might be a better solution.
While I work on getting the kworker thread implementation ready, we could use delay deleting the probe, set the not_run_handler flag and also see if we can remove the breakpoint while the breakpoint is hit.
This way the only worse thing that can happen is the probed processes still take a hit.
If the kworker thread were to face a low memory situation, then it will try to schedule another kworker thread or itself again (at a later point in time). I still need to investigate some more on this.
Signature · 9 lines
Thanks and Regards Srikar -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. 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:"[email protected]"> [email protected] </a>
Peter Zijlstra
maintainerRe: [PATCH v7 3.2-rc2 3/30] uprobes: register/unregister probes.
In reply to Srikar DronamrajuQuoted 91 lines · Srikar Dronamraju
(quoted diff) +91
-0+static int __register_uprobe(struct inode *inode, loff_t offset, + struct uprobe *uprobe) +{ + struct list_head try_list; + struct vm_area_struct *vma; + struct address_space *mapping; + struct vma_info *vi, *tmpvi; + struct mm_struct *mm; + loff_t vaddr; + int ret = 0; + + mapping = inode->i_mapping; + INIT_LIST_HEAD(&try_list); + while ((vi = find_next_vma_info(&try_list, offset, + mapping, true)) != NULL) { + if (IS_ERR(vi)) { + ret = -ENOMEM; + break; + } + mm = vi->mm; + down_read(&mm->mmap_sem); + vma = find_vma(mm, (unsigned long)vi->vaddr); + if (!vma || !valid_vma(vma, true)) { + list_del(&vi->probe_list); + kfree(vi); + up_read(&mm->mmap_sem); + mmput(mm); + continue; + } + vaddr = vma->vm_start + offset; + vaddr -= vma->vm_pgoff << PAGE_SHIFT; + if (vma->vm_file->f_mapping->host != inode || + vaddr != vi->vaddr) { + list_del(&vi->probe_list); + kfree(vi); + up_read(&mm->mmap_sem); + mmput(mm); + continue; + } + ret = install_breakpoint(mm); + up_read(&mm->mmap_sem); + mmput(mm); + if (ret && ret == -EEXIST) + ret = 0; + if (!ret) + break; + } + list_for_each_entry_safe(vi, tmpvi, &try_list, probe_list) { + list_del(&vi->probe_list); + kfree(vi); + } + return ret; +} + +static void __unregister_uprobe(struct inode *inode, loff_t offset, + struct uprobe *uprobe) +{ + struct list_head try_list; + struct address_space *mapping; + struct vma_info *vi, *tmpvi; + struct vm_area_struct *vma; + struct mm_struct *mm; + loff_t vaddr; + + mapping = inode->i_mapping; + INIT_LIST_HEAD(&try_list); + while ((vi = find_next_vma_info(&try_list, offset, + mapping, false)) != NULL) { + if (IS_ERR(vi)) + break; + mm = vi->mm; + down_read(&mm->mmap_sem); + vma = find_vma(mm, (unsigned long)vi->vaddr); + if (!vma || !valid_vma(vma, false)) { + list_del(&vi->probe_list); + kfree(vi); + up_read(&mm->mmap_sem); + mmput(mm); + continue; + } + vaddr = vma->vm_start + offset; + vaddr -= vma->vm_pgoff << PAGE_SHIFT; + if (vma->vm_file->f_mapping->host != inode || + vaddr != vi->vaddr) { + list_del(&vi->probe_list); + kfree(vi); + up_read(&mm->mmap_sem); + mmput(mm); + continue; + } + remove_breakpoint(mm);
Review
Quoted 10 lines
(quoted diff) +10
-0+ up_read(&mm->mmap_sem); + mmput(mm); + } + + list_for_each_entry_safe(vi, tmpvi, &try_list, probe_list) { + list_del(&vi->probe_list); + kfree(vi); + } + delete_uprobe(uprobe); +}
I already mentioned on IRC that there's a lot of duplication here and how to 'solve that'...
Something like the below, it lost the delete_uprobe() bit, and it adds a few XXX marks where we have to deal with -ENOMEM. Also its not been near a compiler.
--- kernel/uprobes.c | 78 ++++++++++++++--------------------------------------- 1 files changed, 21 insertions(+), 57 deletions(-)
kernel/uprobes.c +21 -57
@@ -622,7 +622,7 @@ static int install_breakpoint(struct mm_struct *mm, struct uprobe *uprobe, }static void remove_breakpoint (struct mm_struct *mm,struct uprobe *uprobe, -loff_t vaddr) +struct vm_area_struct *vma,loff_t vaddr) {if (!set_orig_insn (mm, uprobe, (unsigned long )vaddr, true))atomic_dec (&mm->mm_uprobes_count);
@@ -713,8 +713,10 @@ static struct vma_info *find_next_vma_info(struct list_head *head,return retvi; } -static int __register_uprobe (struct inode *inode,loff_t offset, -struct uprobe *uprobe) +typedef int (*vma_func_t )(struct mm_struct *mm,struct uprobe *uprobe, +struct vm_area_struct *vma,unsigned long addr); + +static int __for_each_vma (struct uprobe *uprobe,vma_func_t func) {struct list_head try_list;struct vm_area_struct *vma;
@@ -724,12 +726,12 @@ static int __register_uprobe(struct inode *inode, loff_t offset,loff_t vaddr;int ret =0 ; - mapping = inode->i_mapping; + mapping = uprobe->inode->i_mapping;INIT_LIST_HEAD (&try_list); -while ((vi =find_next_vma_info (&try_list, offset, +while ((vi =find_next_vma_info (&try_list, uprobe->offset, mapping, true)) !=NULL ) {if (IS_ERR (vi)) { - ret = -ENOMEM ; + ret =PTR_ERR (vi);break ; } mm = vi->mm;
@@ -742,9 +744,9 @@ static int __register_uprobe(struct inode *inode, loff_t offset,mmput (mm);continue ; } - vaddr = vma->vm_start + offset; + vaddr = vma->vm_start + uprobe->offset; vaddr -= vma->vm_pgoff <<PAGE_SHIFT ; -if (vma->vm_file->f_mapping->host != inode || +if (vma->vm_file->f_mapping->host != uprobe->inode || vaddr != vi->vaddr) {list_del (&vi->probe_list);kfree (vi);
@@ -752,12 +754,12 @@ static int __register_uprobe(struct inode *inode, loff_t offset,mmput (mm);continue ; } - ret =install_breakpoint (mm, uprobe, vma, vi->vaddr); + ret =func (mm, uprobe, vma, vi->vaddr);up_read (&mm->mmap_sem);mmput (mm);if (ret && ret == -EEXIST ) ret =0 ; -if (!ret) +if (ret)break ; }list_for_each_entry_safe (vi, tmpvi, &try_list, probe_list) {
@@ -767,52 +769,14 @@ static int __register_uprobe(struct inode *inode, loff_t offset,return ret; } -static void __unregister_uprobe (struct inode *inode,loff_t offset, -struct uprobe *uprobe) +static int __register_uprobe (struct uprobe *uprobe) { -struct list_head try_list; -struct address_space *mapping; -struct vma_info *vi, *tmpvi; -struct vm_area_struct *vma; -struct mm_struct *mm; -loff_t vaddr; - - mapping = inode->i_mapping; -INIT_LIST_HEAD (&try_list); -while ((vi =find_next_vma_info (&try_list, offset, - mapping, false)) !=NULL ) { -if (IS_ERR (vi)) -break ; - mm = vi->mm; -down_read (&mm->mmap_sem); - vma =find_vma (mm, (unsigned long )vi->vaddr); -if (!vma || !valid_vma (vma, false)) { -list_del (&vi->probe_list); -kfree (vi); -up_read (&mm->mmap_sem); -mmput (mm); -continue ; - } - vaddr = vma->vm_start + offset; - vaddr -= vma->vm_pgoff <<PAGE_SHIFT ; -if (vma->vm_file->f_mapping->host != inode || - vaddr != vi->vaddr) { -list_del (&vi->probe_list); -kfree (vi); -up_read (&mm->mmap_sem); -mmput (mm); -continue ; - } -remove_breakpoint (mm, uprobe, vi->vaddr); -up_read (&mm->mmap_sem); -mmput (mm); - } +return __for_each_vma (uprobe, install_breakpoint); +} -list_for_each_entry_safe (vi, tmpvi, &try_list, probe_list) { -list_del (&vi->probe_list); -kfree (vi); - } -delete_uprobe (uprobe); +static int __unregister_uprobe (struct uprobe *uprobe) +{ +return __for_each_vma (uprobe, remove_breakpoint); }/*
@@ -852,10 +816,10 @@ int register_uprobe(struct inode *inode, loff_t offset,mutex_lock (uprobes_hash (inode)); uprobe =alloc_uprobe (inode, offset);if (uprobe && !add_consumer (uprobe, consumer)) { - ret =__register_uprobe (inode, offset, uprobe); + ret =__register_uprobe (uprobe);if (ret) { uprobe->consumers =NULL ; -__unregister_uprobe (inode, offset, uprobe); +__unregister_uprobe (uprobe);// -ENOMEM }else uprobe->flags |=UPROBES_RUN_HANDLER ; }
@@ -894,7 +858,7 @@ void unregister_uprobe(struct inode *inode, loff_t offset, }if (!uprobe->consumers) { -__unregister_uprobe (inode, offset, uprobe); +__unregister_uprobe (uprobe);// XXX -ENOMEM uprobe->flags &= ~UPROBES_RUN_HANDLER ; }mutex_unlock (uprobes_hash (inode));
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. 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:"[email protected]"> [email protected] </a>
PATCH v7 4/30 uprobes: Define hooks for mmap/munmap.
In reply to Srikar DronamrajuIf an executable vma is getting mapped, search and insert corresponding probes. On unmap, make sure the probes count is decremented by appropriate amount.
On process creation, make sure the probes count in the child is set correctly.
---
Changelog: (Since v5)
- use hash locks.
- Handle mremap.
- while forking, handle vma's that have VM_DONTCOPY.
- while forking, handle race of new breakpoints being inserted / removed in the parent process.
- Introduce find_least_offset_node() instead of close match logic in find_uprobe
- munmap now reuses build_probe_list instead of dec_mm_uprobes_count.
include/linux/mm_types.h | 3 + include/linux/uprobes.h | 12 +++ kernel/fork.c | 7 ++ kernel/uprobes.c | 188 ++++++++++++++++++++++++++++++++++++++++++++-- mm/mmap.c | 33 ++++++++ 5 files changed, 233 insertions(+), 10 deletions(-)
include/linux/mm_types.h +3 -0
@@ -389,6 +389,9 @@ struct mm_struct {#ifdef CONFIG_CPUMASK_OFFSTACK struct cpumask cpumask_allocation;#endif +#ifdef CONFIG_UPROBES +atomic_t mm_uprobes_count; +#endif };static inline void mm_init_cpumask (struct mm_struct *mm)
include/linux/uprobes.h +12 -0
@@ -25,6 +25,8 @@#include <linux/rbtree.h> +struct vm_area_struct ; +struct uprobe_consumer {int (*handler)(struct uprobe_consumer *self,struct pt_regs *regs);/*
@@ -40,6 +42,7 @@ struct uprobe {struct rb_node rb_node;/* node in the rb tree */ atomic_t ref;struct rw_semaphore consumer_rwsem; +struct list_head pending_list;struct uprobe_consumer *consumers;struct inode *inode;/* Also hold a ref to inode */ loff_t offset;
@@ -50,6 +53,8 @@ extern int register_uprobe(struct inode *inode, loff_t offset, struct uprobe_consumer *consumer);extern void unregister_uprobe (struct inode *inode,loff_t offset,struct uprobe_consumer *consumer); +extern int mmap_uprobe (struct vm_area_struct *vma); +extern void munmap_uprobe (struct vm_area_struct *vma);#else /* CONFIG_UPROBES is not defined */ static inline int register_uprobe (struct inode *inode,loff_t offset,struct uprobe_consumer *consumer)
@@ -60,5 +65,12 @@ static inline void unregister_uprobe(struct inode *inode, loff_t offset, struct uprobe_consumer *consumer) { } +static inline int mmap_uprobe (struct vm_area_struct *vma) +{ +return 0 ; +} +static inline void munmap_uprobe (struct vm_area_struct *vma) +{ +}#endif /* CONFIG_UPROBES */ #endif /* _LINUX_UPROBES_H */
kernel/fork.c +7 -0
@@ -66,6 +66,7 @@#include <linux/user-return-notifier.h> #include <linux/oom.h> #include <linux/khugepaged.h> +#include <linux/uprobes.h> #include <asm/pgtable.h> #include <asm/pgalloc.h>
@@ -421,6 +422,9 @@ static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm)if (retval) goto out; + +if (file &&mmap_uprobe (tmp)) + goto out; }/* a new mm has just been created */ arch_dup_mmap (oldmm, mm);
@@ -738,6 +742,9 @@ struct mm_struct *dup_mm(struct task_struct *tsk)#ifdef CONFIG_TRANSPARENT_HUGEPAGE mm->pmd_huge_pte =NULL ;#endif +#ifdef CONFIG_UPROBES +atomic_set (&mm->mm_uprobes_count,0 ); +#endif if (!mm_init (mm, tsk)) goto fail_nomem;
kernel/uprobes.c +179 -9
253 lines not on this page · raw message
mm/mmap.c +32 -1
@@ -30,6 +30,7 @@#include <linux/perf_event.h> #include <linux/audit.h> #include <linux/khugepaged.h> +#include <linux/uprobes.h> #include <asm/uaccess.h> #include <asm/cacheflush.h>
@@ -217,6 +218,7 @@ void unlink_file_vma(struct vm_area_struct *vma)mutex_lock (&mapping->i_mmap_mutex);__remove_shared_vm_struct (vma, file, mapping);mutex_unlock (&mapping->i_mmap_mutex); +munmap_uprobe (vma); } }
@@ -545,8 +547,14 @@ again: remove_next = 1 + (end > next->vm_end);if (file) { mapping = file->f_mapping; -if (!(vma->vm_flags &VM_NONLINEAR )) +if (!(vma->vm_flags &VM_NONLINEAR )) { root = &mapping->i_mmap; +munmap_uprobe (vma); + +if (adjust_next) +munmap_uprobe (next); + } +mutex_lock (&mapping->i_mmap_mutex);if (insert) {/*
@@ -616,8 +624,16 @@ again: remove_next = 1 + (end > next->vm_end);if (mapping)mutex_unlock (&mapping->i_mmap_mutex); +if (root) { +mmap_uprobe (vma); + +if (adjust_next) +mmap_uprobe (next); + } +if (remove_next) {if (file) { +munmap_uprobe (next);fput (file);if (next->vm_flags &VM_EXECUTABLE )removed_exe_file_vma (mm);
@@ -637,6 +653,8 @@ again: remove_next = 1 + (end > next->vm_end); goto again; } } +if (insert && file) +mmap_uprobe (insert);validate_mm (mm);
@@ -1329,6 +1347,11 @@ unsigned long mmap_region(struct file *file, unsigned long addr, mm->locked_vm += (len >>PAGE_SHIFT ); }else if ((flags &MAP_POPULATE ) && !(flags &MAP_NONBLOCK ))make_pages_present (addr, addr + len); + +if (file &&mmap_uprobe (vma)) +/* matching probes but cannot insert */ + goto unmap_and_free_vma; +return addr; unmap_and_free_vma:
@@ -2305,6 +2328,10 @@ int insert_vm_struct(struct mm_struct * mm, struct vm_area_struct * vma)if ((vma->vm_flags &VM_ACCOUNT ) &&security_vm_enough_memory_mm (mm,vma_pages (vma)))return -ENOMEM ; + +if (vma->vm_file &&mmap_uprobe (vma)) +return -EINVAL ; +vma_link (mm, vma, prev, rb_link, rb_parent);return 0 ; }
@@ -2356,6 +2383,10 @@ struct vm_area_struct *copy_vma(struct vm_area_struct **vmap, new_vma->vm_pgoff = pgoff;if (new_vma->vm_file) {get_file (new_vma->vm_file); + +if (mmap_uprobe (new_vma)) + goto out_free_mempol; +if (vma->vm_flags &VM_EXECUTABLE )added_exe_file_vma (mm); }
Peter Zijlstra
maintainerRe: [PATCH v7 3.2-rc2 4/30] uprobes: Define hooks for mmap/munmap.
kernel/uprobes.c void unregister_uprobe(struct inode *inode, loff_t offset, · line 614
Quoted 13 lines · Srikar Dronamraju
kernel/uprobes.c +13
-0+int mmap_uprobe (struct vm_area_struct *vma) +{ +struct list_head tmp_list; +struct uprobe *uprobe, *u; +struct inode *inode; +int ret =0 , count =0 ; + +if (!atomic_read (&uprobe_events) || !valid_vma (vma, true)) +return ret;/* Bail-out */ + + inode =igrab (vma->vm_file->f_mapping->host); +if (!inode) +return ret;
Since we hold mmap_sem, vma is pinned, which should pin the inode, why take out another ref?
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. 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:"[email protected]"> [email protected] </a>
Peter Zijlstra
maintainerRe: [PATCH v7 3.2-rc2 4/30] uprobes: Define hooks for mmap/munmap.
In reply to Srikar Dronamrajukernel/uprobes.c void unregister_uprobe(struct inode *inode, loff_t offset, · line 634
Quoted 5 lines · Srikar Dronamraju
kernel/uprobes.c +5
-0+ ret =install_breakpoint (vma->vm_mm, uprobe); +if (ret == -EEXIST ) { +atomic_inc (&vma->vm_mm->mm_uprobes_count); + ret =0 ; + }
Aren't you double counting that probe position here? The one that raced you to inserting it will also have incremented that counter, no?
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. 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:"[email protected]"> [email protected] </a>
Re: [PATCH v7 3.2-rc2 4/30] uprobes: Define hooks for mmap/munmap.
Quoted 10 lines · Peter Zijlstra
kernel/uprobes.c void unregister_uprobe(struct inode *inode, loff_t offset, · line 634
Quoted 5 lines · Srikar Dronamraju
kernel/uprobes.c +5
-0+ ret =install_breakpoint (vma->vm_mm, uprobe); +if (ret == -EEXIST ) { +atomic_inc (&vma->vm_mm->mm_uprobes_count); + ret =0 ; + }Aren't you double counting that probe position here? The one that raced you to inserting it will also have incremented that counter, no?
No we arent.
Because register_uprobe can never race with mmap_uprobe and register before mmap_uprobe registers .(Once we start mmap_region, register_uprobe waits for the read_lock of mmap_sem.)
And we badly need this for mmap_uprobe case. Because when we do mremap, or vma_adjust(), we do a munmap_uprobe() followed by mmap_uprobe() which would have decremented the count but not removed it. So when we do a mmap_uprobe, we need to increment the count.
Signature · 9 lines
Thanks and regards Srikar -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. 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:"[email protected]"> [email protected] </a>
Peter Zijlstra
maintainerRe: [PATCH v7 3.2-rc2 4/30] uprobes: Define hooks for mmap/munmap.
Quoted 9 lines · Srikar Dronamraju
Quoted 7 lines · Peter Zijlstra
Quoted 5 lines · Srikar Dronamraju
kernel/uprobes.c +5
-0+ ret =install_breakpoint (vma->vm_mm, uprobe); +if (ret == -EEXIST ) { +atomic_inc (&vma->vm_mm->mm_uprobes_count); + ret =0 ; + }
Quoted 8 lines
Quoted 3 lines
Aren't you double counting that probe position here? The one that raced you to inserting it will also have incremented that counter, no?
No we arent.
Becauseregister_uprobecan never race withmmap_uprobeand register beforemmap_uproberegisters .(Once we startmmap_region,register_uprobewaits for theread_lockofmmap_sem.)
Still doesn't make any sense. Since you don't increment on success, one has to assume install_breakpoint() will cause an increment. Therefore, when we encounter -EEXIST we'll already have accounted for this mm,inode,offset combination.
But I'll have another look at it, maybe I'm missing something obvious :-)
Quoted 4 lines
And we badly need this for
mmap_uprobecase. Because when we do mremap, orvma_adjust(), we do amunmap_uprobe()followed bymmap_uprobe()which would have decremented the count but not removed it. So when we do ammap_uprobe, we need to increment the count.
Well I see why the count needs to be correct, that's not the issue.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. 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:"[email protected]"> [email protected] </a>
Re: [PATCH v7 3.2-rc2 4/30] uprobes: Define hooks for mmap/munmap.
Quoted 19 lines · Peter Zijlstra
Quoted 9 lines · Srikar Dronamraju
Quoted 7 lines · Peter Zijlstra
Quoted 5 lines · Srikar Dronamraju
kernel/uprobes.c +5
-0+ ret =install_breakpoint (vma->vm_mm, uprobe); +if (ret == -EEXIST ) { +atomic_inc (&vma->vm_mm->mm_uprobes_count); + ret =0 ; + }Quoted 8 lines
Quoted 3 lines
Aren't you double counting that probe position here? The one that raced you to inserting it will also have incremented that counter, no?
No we arent.
Becauseregister_uprobecan never race withmmap_uprobeand register beforemmap_uproberegisters .(Once we startmmap_region,register_uprobewaits for theread_lockofmmap_sem.)
Quoted 5 lines
Still doesn't make any sense. Since you don't increment on success, one has to assume
install_breakpoint()will cause an increment. Therefore, when we encounter-EEXISTwe'll already have accounted for this mm,inode,offset combination.
In the success case, install_breakpoint itself does the increment. We cant allow install_breakpoint to increment in EEXIST case always because doing that in register_uprobe context would increment which is wrong.
Quoted 9 lines
But I'll have another look at it, maybe I'm missing something obvious :-)
Quoted 4 lines
And we badly need this for
mmap_uprobecase. Because when we do mremap, orvma_adjust(), we do amunmap_uprobe()followed bymmap_uprobe()which would have decremented the count but not removed it. So when we do ammap_uprobe, we need to increment the count.Well I see why the count needs to be correct, that's not the issue.
Okay ..
Signature · 9 lines
Thanks and Regards Srikar -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. 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:"[email protected]"> [email protected] </a>
Peter Zijlstra
maintainerRe: [PATCH v7 3.2-rc2 4/30] uprobes: Define hooks for mmap/munmap.
In reply to Srikar DronamrajuQuoted 18 lines · Srikar Dronamraju
Quoted 10 lines · Peter Zijlstra
kernel/uprobes.c void unregister_uprobe(struct inode *inode, loff_t offset, · line 634
Quoted 5 lines · Srikar Dronamraju
kernel/uprobes.c +5
-0+ ret =install_breakpoint (vma->vm_mm, uprobe); +if (ret == -EEXIST ) { +atomic_inc (&vma->vm_mm->mm_uprobes_count); + ret =0 ; + }Aren't you double counting that probe position here? The one that raced you to inserting it will also have incremented that counter, no?
No we arent.
Becauseregister_uprobecan never race withmmap_uprobeand register beforemmap_uproberegisters .(Once we startmmap_region,register_uprobewaits for theread_lockofmmap_sem.)
Quoted 4 lines
And we badly need this for
mmap_uprobecase. Because when we do mremap, orvma_adjust(), we do amunmap_uprobe()followed bymmap_uprobe()which would have decremented the count but not removed it. So when we do ammap_uprobe, we need to increment the count.
Ok, so I didn't parse that properly last time around.. but it still doesn't make sense, why would munmap_uprobe() decrement the count but not uninstall the probe?
install_breakpoint() returning -EEXIST on two different conditions doesn't help either.
So what I think you're doing is that you're optimizing the unmap case since the memory is going to be thrown out fixing up the instruction is a waste of time, but this leads to the asymmetry observed above. But you fail to mention this in both the changelog or a comment near that -EEXIST branch in mmap_uprobe.
Worse, you don't explain how the other -EEXIST (!consumers) thing interacts here, and I just gave up trying to figure that out since it made my head hurt.
Also, your whole series of patches is still utter crap, the splitup doesn't work at all, I need to constantly search back and forth between patches in order to figure out wtf is happening, and your changelogs only seem to add confusion if anything at all.
Also, you seem to have stuck a whole bunch of random patches at the end that fix various things without folding them back in to make the series saner/smaller.
I've now reverted to simply applying all patches and reading the end result and using git-blame to figure out what patch something came from :-(
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. 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:"[email protected]"> [email protected] </a>
Re: [PATCH v7 3.2-rc2 4/30] uprobes: Define hooks for mmap/munmap.
Quoted 24 lines
Quoted 15 lines
Quoted 9 lines
kernel/uprobes.c void unregister_uprobe(struct inode *inode, loff_t offset, · line 634
Quoted 5 lines
kernel/uprobes.c +5
-0+ ret =install_breakpoint (vma->vm_mm, uprobe); +if (ret == -EEXIST ) { +atomic_inc (&vma->vm_mm->mm_uprobes_count); + ret =0 ; + }Aren't you double counting that probe position here? The one that raced you to inserting it will also have incremented that counter, no?
No we arent.
Becauseregister_uprobecan never race withmmap_uprobeand register beforemmap_uproberegisters .(Once we startmmap_region,register_uprobewaits for theread_lockofmmap_sem.)Quoted 4 lines
And we badly need this for
mmap_uprobecase. Because when we do mremap, orvma_adjust(), we do amunmap_uprobe()followed bymmap_uprobe()which would have decremented the count but not removed it. So when we do ammap_uprobe, we need to increment the count.Ok, so I didn't parse that properly last time around.. but it still doesn't make sense, why would
munmap_uprobe()decrement the count but not uninstall the probe?
Quoted 6 lines
install_breakpoint()returning-EEXISTon two different conditions doesn't help either.So what I think you're doing is that you're optimizing the unmap case since the memory is going to be thrown out fixing up the instruction is a waste of time, but this leads to the asymmetry observed above. But you
Yes, we are optimizing the unmap case, because we expect the memory to be thrown out.
Quoted 7 lines
fail to mention this in both the changelog or a comment near that
-EEXISTbranch inmmap_uprobe.Worse, you don't explain how the other
-EEXIST(!consumers) thing interacts here, and I just gave up trying to figure that out since it made my head hurt.
install_breakpoints cannot have !consumers to be true when called from register_uprobe. (Since unregister_uprobe() which does the removal of consumer cannot race with register_uprobe().)
Now lets consider mmap_uprobe() being called from vm_adjust(), the preceding unmap_uprobe() has already decremented the count but left the count intact.
if consumers is NULL, unregister_uprobes() has kicked already in, so there is no point in inserting the probe, Hence we return EEXIST. The following unregister_uprobe() (or the munmap_uprobe() which might race before unregister_uprobe) is also going to decrement the count. So we have a case where the same breakpoint is accounted as removed twice. To offset this, we pretend as if the breakpoint is around by incrementing the count.
Would it help if I add an extra check in mmap_uprobe?
int mmap_uprobe(...) {
....
ret = install_breakpoint(vma->vm_mm, uprobe);
if (ret == -EEXIST) {
if (!read_opcode(vma->vm_mm, vaddr, &opcode) &&
(opcode == UPROBES_BKPT_INSN))
atomic_inc(&vma->vm_mm->mm_uprobes_count);
ret = 0;
} ....
}
The extra read_opcode check will tell us if the breakpoint is still around and then only increment the count. (As in it will distinguish if the mmap_uprobe is from vm_adjust).
Signature · 9 lines
Thanks and Regards Srikar -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. 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:"[email protected]"> [email protected] </a>
Peter Zijlstra
maintainerRe: [PATCH v7 3.2-rc2 4/30] uprobes: Define hooks for mmap/munmap.
Quoted 3 lines · Srikar Dronamraju
install_breakpointscannot have !consumers to be true when called fromregister_uprobe. (Sinceunregister_uprobe()which does the removal of consumer cannot race withregister_uprobe().)
Right, that's the easy case ;-)
Quoted 11 lines
Now lets consider
mmap_uprobe()being called fromvm_adjust(), the precedingunmap_uprobe()has already decremented the count but left the count intact.if consumers is NULL,
unregister_uprobes()has kicked already in, so there is no point in inserting the probe, Hence we return EEXIST. The followingunregister_uprobe()(or themunmap_uprobe()which might race beforeunregister_uprobe) is also going to decrement the count. So we have a case where the same breakpoint is accounted as removed twice. To offset this, we pretend as if the breakpoint is around by incrementing the count.
There's 2 main cases,
A) vma_adjust() vs unregister_uprobe() and
B) mmap() vs unregister_uprobe().
The result of A should be -1 reference in total, since we're removing the one probe. The result of B should be 0 since we're removing the probe and we shouldn't be installing new ones.
A1)
vma_adjust()
munmap_uprobe()
unregister_uprobe()
mmap_uprobe()
delete_uprobe()
munmap will to -1, mmap will do +1, __unregister_uprobe() which is
serialized against vma_adjust() will do -1 on either the old or new vma, resulting in a grand total of: -1+1-1=-1, OK
A2) breakpoint is in old, not in new, again two cases:
A2a) __unregister_uprobe() sees old
munmap -1, __unregister_uprobe -1, mmap 0: -2 FAIL
A2b) __unregister_uprobe() sees new
munmap -1, __unregister_uprobe 0, mmap 0: -1 OK
A3) breakpoint is in new, not in old, again two cases:
A3a) __unregister_uprobe() sees old
munmap 0, __unregister_uprobe 0, mmap: 1: 1 FAIL
A3b) __unregister_uprobe() seed new
munmap 0, __unregister_uprobe -1, mmap: 1: 0 FAIL
B1)
unregister_uprobe() mmap() mmap_uprobe() __unregister_uprobe() delete_uprobe() mmap +1, __unregister_uprobe() -1: 0 OK
B2)
unregister_uprobe() mmap() __unregister_uprobe() mmap_uprobe() delete_uprobe() mmap +1, __unregister_uprobe() 0: +1 FAIL
Quoted 11 lines
Would it help if I add an extra check in
mmap_uprobe?int
mmap_uprobe(...){
....ret = install_breakpoint(vma->vm_mm, uprobe); if (ret == -EEXIST) { if (!read_opcode(vma->vm_mm, vaddr, &opcode) && (opcode == UPROBES_BKPT_INSN)) atomic_inc(&vma->vm_mm->mm_uprobes_count); ret = 0; }
Quoted 6 lines
....
}The extra
read_opcodecheck will tell us if the breakpoint is still around and then only increment the count. (As in it will distinguish if themmap_uprobeis fromvm_adjust).
No, I don't see that fixing A2a for example.
Could be I confused myself above, but like said, this stuff hurt brain.
It might just be easiest not to optimize munmap and leave fancy stuff for later.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. 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:"[email protected]"> [email protected] </a>
Peter Zijlstra
maintainerRe: [PATCH v7 3.2-rc2 4/30] uprobes: Define hooks for mmap/munmap.
Quoted 6 lines · Peter Zijlstra
There's 2 main cases,
A)vma_adjust()vsunregister_uprobe()and
B)mmap()vsunregister_uprobe().The result of A should be -1 reference in total, since we're removing the one probe.
This might not be correct for A[23], please double check.
Quoted 27 lines
The result of B should be 0 since we're removing the
probe and we shouldn't be installing new ones.A1)
vma_adjust()
munmap_uprobe()
unregister_uprobe()
mmap_uprobe()
delete_uprobe()munmap will to -1, mmap will do +1,
__unregister_uprobe()which is
serialized againstvma_adjust()will do -1 on either the old or new vma, resulting in a grand total of: -1+1-1=-1, OKA2) breakpoint is in old, not in new, again two cases:
A2a)
__unregister_uprobe()sees oldmunmap -1, __unregister_uprobe -1, mmap 0: -2 FAILA2b)
__unregister_uprobe()sees newmunmap -1, __unregister_uprobe 0, mmap 0: -1 OKA3) breakpoint is in new, not in old, again two cases:
Quoted 7 lines
A3a)
__unregister_uprobe()sees oldmunmap 0,
__unregister_uprobe0, mmap: 1: 1 FAILA3b)
__unregister_uprobe()seed newmunmap 0,
__unregister_uprobe-1, mmap: 1: 0 FAIL
There's more cases, I forgot the details of how the prio_tree stuff works, so please consider if its possible to also have:
__unregister_uprobe() will observe neither old nor new
This could happen if we first munmap, __unregister_uprobe() will iterate past where mmap() will insert the new vma, mmap will insert the new vma, and __unregister_uprobe() will now not observe it.
and
__unregister_uprobe() will observe both old _and_ new
This latter could happen by favourably interleaving the prio_tree iteration with the munmap and mmap operations, so that we first observe the old vma, do the munmap, do the mmap, and then have the find_next_vma_info() thing find the new vma.
Quoted 9 lines
B1)
unregister_uprobe() mmap() mmap_uprobe() __unregister_uprobe() delete_uprobe() mmap +1, __unregister_uprobe() -1: 0 OK
Quoted 8 lines
B2)
unregister_uprobe() mmap() __unregister_uprobe() mmap_uprobe() delete_uprobe() mmap +1, __unregister_uprobe() 0: +1 FAIL
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. 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:"[email protected]"> [email protected] </a>
Re: [PATCH v7 3.2-rc2 4/30] uprobes: Define hooks for mmap/munmap.
Quoted 10 lines
There's more cases, I forgot the details of how the
prio_treestuff works, so please consider if its possible to also have:
__unregister_uprobe()will observe neither old nor newThis could happen if we first munmap,
__unregister_uprobe()will iterate past wheremmap()will insert the new vma, mmap will insert the new vma, and__unregister_uprobe()will now not observe it.
- When we iterate thro __unregister_uprobe(), we always walk from the root of the prio tree and not depend on the last found node. So __unregister_uprobe able to iterate thro the rmap without finding the old or the new vma would mean that the exclusive mmap_sem was dropped for atleast a brief period and munmap/mmap are disjoint.
Here munmap_uprobe would have reduced the count followed by the pages being cleared.__unregister_uprobe maintains the status quo.mmap_uprobe would load a new set of pages without any breakpoint, since there are no consumers, and no underlying breakpoints, it also maintains the status quo.
Quoted 8 lines
and
__unregister_uprobe()will observe both old _and_ newThis latter could happen by favourably interleaving the
prio_treeiteration with the munmap and mmap operations, so that we first observe the old vma, do the munmap, do the mmap, and then have thefind_next_vma_info()thing find the new vma.
If __unregister_uprobe() can observe both old _and_ new, then it means mmap has occurred. So its correct that probes are removed from the old and new. The munmap_uprobe of the old vma wouldnt see the breakpoint (via read_opcode) so wont decrement the count. If the munmap_uprobe had seen the breakpoint before unregister_uprobe, then unregister_uprobe cant decrement the count.
Signature · 9 lines
Thanks and Regards Srikar -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. 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:"[email protected]"> [email protected] </a>
Re: [PATCH v7 3.2-rc2 4/30] uprobes: Define hooks for mmap/munmap.
In reply to Peter ZijlstraThe rules that I am using are:
mmap_uprobe() increments the count if
- it successfully adds a breakpoint.
- it not add a breakpoint, but sees that there is a underlying breakpoint (via a read_opcode call).
munmap_uprobe() decrements the count if
- it sees a underlying breakpoint, (via a read_opcode call)
- Subsequent unregister_uprobe wouldnt find the breakpoint unless a mmap_uprobe kicks in, since the old vma would be dropped just after munmap_uprobe.
register_uprobe increments the count if:
- it successfully adds a breakpoint.
unregister_uprobe decrements the count if:
- it sees a underlying breakpoint and removes successfully. (via a read_opcode call)
- Subsequent munmap_uprobe wouldnt find the breakpoint since there is no underlying breakpoint after the breakpoint removal.
Quoted 9 lines
Quoted 8 lines
if consumers is NULL,
unregister_uprobes()has kicked already in, so there is no point in inserting the probe, Hence we return EEXIST. The followingunregister_uprobe()(or themunmap_uprobe()which might race beforeunregister_uprobe) is also going to decrement the count. So we have a case where the same breakpoint is accounted as removed twice. To offset this, we pretend as if the breakpoint is around by incrementing the count.
Quoted 6 lines
There's 2 main cases,
A)vma_adjust()vsunregister_uprobe()and
B)mmap()vsunregister_uprobe().The result of A should be -1 reference in total, since we're removing the one probe.
If the breakpoint was never there, then a value of 0 should also be correct. See case A3a and A3b.
Quoted 11 lines
The result of B should be 0 since we're removing the probe and we shouldn't be installing new ones.
A1)
vma_adjust()
munmap_uprobe()
unregister_uprobe()
mmap_uprobe()
delete_uprobe()
Quoted 3 lines
munmap will to -1, mmap will do +1,
__unregister_uprobe()which is
serialized againstvma_adjust()will do -1 on either the old or new vma, resulting in a grand total of: -1+1-1=-1, OK
Right.
Quoted 4 lines
A2) breakpoint is in old, not in new, again two cases:
A2a)
__unregister_uprobe()sees old
So unregister_uprobe is called on the vma before vma_adjust.
Quoted 3 lines
munmap -1, __unregister_uprobe -1, mmap 0: -2 FAIL
So munmap wouldnt decrement because, munmap_uprobe checks to see if the breakpoint is still around before it increments.
unregister unlike munmap removes the breakpoint too.
Quoted 2 lines
A2b)
__unregister_uprobe()sees new
So the order would be munmap(), mmap() and unregister_uprobe()
Quoted 1 line
munmap -1, __unregister_uprobe 0, mmap 0: -1 OK
Right, Since the old vma is gone, the new vma doesnt have the breakpoint.
Quoted 6 lines
A3) breakpoint is in new, not in old, again two cases:
A3a)
__unregister_uprobe()sees old
So unregister_uprobe is called on the vma before vma_adjust.
Quoted 1 line
munmap 0,
__unregister_uprobe0, mmap: 1: 1 FAIL
If mmap_uprobe() increments it would mean that breakpoint was already there. (-EEXIST + read_opcode); since there was no breakpoint, it will not increment..
0 is the correct value here, Not -1. because there was no probe inserted or removed.
Quoted 2 lines
A3b)
__unregister_uprobe()seed new
So the order would be munmap(), mmap() and unregister_uprobe()
Quoted 3 lines
munmap 0,
__unregister_uprobe-1, mmap: 1: 0 FAIL
If mmap_uprobe() increments it would mean that breakpoint was already there. __unregister_uprobe will decrement. Since we added a new probe and deleted it, the value 0 is correct here.
Quoted 9 lines
B1)
unregister_uprobe() mmap() mmap_uprobe() __unregister_uprobe() delete_uprobe() mmap +1, __unregister_uprobe() -1: 0 OK
Quoted 8 lines
B2)
unregister_uprobe() mmap() __unregister_uprobe() mmap_uprobe() delete_uprobe() mmap +1, __unregister_uprobe() 0: +1 FAIL
I think you meant __unregister_uprobe happened before mmap_uprobe.
If mmap_uprobe() increments it would mean that breakpoint was already there. (-EEXIST + read_opcode); since there was no breakpoint, it will not increment..
Quoted 16 lines
Quoted 15 lines
Would it help if I add an extra check in
mmap_uprobe?int
mmap_uprobe(...){
....ret = install_breakpoint(vma->vm_mm, uprobe); if (ret == -EEXIST) { if (!read_opcode(vma->vm_mm, vaddr, &opcode) && (opcode == UPROBES_BKPT_INSN)) atomic_inc(&vma->vm_mm->mm_uprobes_count); ret = 0; }....
}
Quoted 5 lines
Quoted 3 lines
The extra
read_opcodecheck will tell us if the breakpoint is still around and then only increment the count. (As in it will distinguish if themmap_uprobeis fromvm_adjust).No, I don't see that fixing A2a for example.
This check should help A3a and B2 cases.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. 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:"[email protected]"> [email protected] </a>
Peter Zijlstra
maintainerRe: [PATCH v7 3.2-rc2 4/30] uprobes: Define hooks for mmap/munmap.
Quoted 16 lines · Srikar Dronamraju
The rules that I am using are:
mmap_uprobe()increments the count if
- it successfully adds a breakpoint.
- it not add a breakpoint, but sees that there is a underlying breakpoint (via aread_opcodecall).
munmap_uprobe()decrements the count if
- it sees a underlying breakpoint, (via aread_opcodecall)
- Subsequentunregister_uprobewouldnt find the breakpoint unless ammap_uprobekicks in, since the old vma would be dropped just aftermunmap_uprobe.
register_uprobeincrements the count if:
- it successfully adds a breakpoint.
Quoted 6 lines
unregister_uprobedecrements the count if:
- it sees a underlying breakpoint and removes successfully. (via aread_opcodecall)
- Subsequentmunmap_uprobewouldnt find the breakpoint since there is no underlying breakpoint after the breakpoint removal.
The problem I'm having is that such stuff isn't included in the patch set.
We've got both comments in the C language and Changelog in our patch system, yet you consistently fail to use either to convey useful information on non-trivial bits like this.
This leaves the reviewer wondering if you've actually considered stuff properly, then me actually finding bugs in there does of course undermine that even further.
What I really would like is for this patch set not to have such subtle stuff at all, esp. at first. Once its in and its been used a bit we can start optimizing and add subtle crap like this.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. 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:"[email protected]"> [email protected] </a>
Re: [PATCH v7 3.2-rc2 4/30] uprobes: Define hooks for mmap/munmap.
Quoted 23 lines
Quoted 16 lines
The rules that I am using are:
mmap_uprobe()increments the count if
- it successfully adds a breakpoint.
- it not add a breakpoint, but sees that there is a underlying breakpoint (via aread_opcodecall).
munmap_uprobe()decrements the count if
- it sees a underlying breakpoint, (via aread_opcodecall)
- Subsequentunregister_uprobewouldnt find the breakpoint unless ammap_uprobekicks in, since the old vma would be dropped just aftermunmap_uprobe.
register_uprobeincrements the count if:
- it successfully adds a breakpoint.Quoted 6 lines
unregister_uprobedecrements the count if:
- it sees a underlying breakpoint and removes successfully. (via aread_opcodecall)
- Subsequentmunmap_uprobewouldnt find the breakpoint since there is no underlying breakpoint after the breakpoint removal.
Quoted 7 lines
The problem I'm having is that such stuff isn't included in the patch set.
We've got both comments in the C language and Changelog in our patch system, yet you consistently fail to use either to convey useful information on non-trivial bits like this.
Agree, I will put this as part of comments.
Quoted 7 lines
This leaves the reviewer wondering if you've actually considered stuff properly, then me actually finding bugs in there does of course undermine that even further.
What I really would like is for this patch set not to have such subtle stuff at all, esp. at first. Once its in and its been used a bit we can start optimizing and add subtle crap like this.
We actually started the discussion of why we increment the count in mmap_uprobe() in EEXIST case (and read_opcode()). It exists for two reasons.
- To handle fork case (that I wrote in another mail).
- To handle mremap.(the case where we are discussing now)
I would contend that removing the breakpoint in munmap doesnt amount to optimization. Since the start of unmap(), there cannot be another remove_breakpoint called for the vma,vaddr tuple, until the vma is cleaned up, or the subsequent mmap() is done. So the case of accounting for an already decremented count should never occur.
I was following the general convention being used within the kernel to not bother about the area that we are going to unmap. For example: If a ptraced area were to be unmapped or remapped, I dont see the breakpoint being removed and added back. Also if a ptrace process is exitting, we dont go about removing the installed breakpoints.
Also we would still need the check for EEXIST and read_opcode for handling the fork() case. So even if we add extra line to remove the actual breakpoint in munmap, It doesnt make the code any more simpler.
Signature · 9 lines
Thanks and Regards Srikar -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. 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:"[email protected]"> [email protected] </a>
Peter Zijlstra
maintainerRe: [PATCH v7 3.2-rc2 4/30] uprobes: Define hooks for mmap/munmap.
Quoted 22 lines · Srikar Dronamraju
Quoted 3 lines
What I really would like is for this patch set not to have such subtle stuff at all, esp. at first. Once its in and its been used a bit we can start optimizing and add subtle crap like this.
We actually started the discussion of why we increment the count in
mmap_uprobe()in EEXIST case (andread_opcode()). It exists for two reasons.
- To handle fork case (that I wrote in another mail).
- To handle mremap.(the case where we are discussing now)I would contend that removing the breakpoint in munmap doesnt amount to optimization. Since the start of
unmap(), there cannot be anotherremove_breakpointcalled for the vma,vaddr tuple, until the vma is cleaned up, or the subsequentmmap()is done. So the case of accounting for an already decremented count should never occur.I was following the general convention being used within the kernel to not bother about the area that we are going to unmap. For example: If a ptraced area were to be unmapped or remapped, I dont see the breakpoint being removed and added back. Also if a ptrace process is exitting, we dont go about removing the installed breakpoints.
Quoted 3 lines
Also we would still need the check for EEXIST and
read_opcodefor handling thefork()case. So even if we add extra line to remove the actual breakpoint in munmap, It doesnt make the code any more simpler.
Not adding the counter now does though. The whole mm->mm_uprobes_count thing itself is basically an optimization.
Without it we'll get to uprobe_notify_resume() too often, but who cares. And not having to worry about it removes a lot of this complexity.
Then in the patch where you introduce this optimization you can list all the nitty gritty details of mremap/fork and counter balancing.
Another point, maybe add some comments on how the generic bits of uprobe_notify_resume()/uprobe_bkpt_notifier()/uprobe_post_notifier() etc hang together and what the arch stuff should do.
Currently I have to flip back and forth between those to figure out what happens.
Having that information also helps validate that x86 does indeed do what is expected and helps other arch maintainers write their code without having to grok wtf x86 does.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. 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:"[email protected]"> [email protected] </a>
Re: [PATCH v7 3.2-rc2 4/30] uprobes: Define hooks for mmap/munmap.
Quoted 10 lines
Quoted 9 lines
I was following the general convention being used within the kernel to not bother about the area that we are going to unmap. For example: If a ptraced area were to be unmapped or remapped, I dont see the breakpoint being removed and added back. Also if a ptrace process is exitting, we dont go about removing the installed breakpoints.
Also we would still need the check for EEXIST and
read_opcodefor handling thefork()case. So even if we add extra line to remove the actual breakpoint in munmap, It doesnt make the code any more simpler.
Quoted 9 lines
Not adding the counter now does though. The whole
mm->mm_uprobes_countthing itself is basically an optimization.Without it we'll get to
uprobe_notify_resume()too often, but who cares. And not having to worry about it removes a lot of this complexity.Then in the patch where you introduce this optimization you can list all the nitty gritty details of mremap/fork and counter balancing.
Okay, I will move the optimization parts into a separate patch and keep it at the end of the patchset.
Quoted 11 lines
Another point, maybe add some comments on how the generic bits of uprobe_notify_resume()/uprobe_bkpt_notifier()/uprobe_post_notifier() etc hang together and what the arch stuff should do.
Currently I have to flip back and forth between those to figure out what happens.
Having that information also helps validate that x86 does indeed do what is expected and helps other arch maintainers write their code without having to grok wtf x86 does.
Okay, will work towards this.
Signature · 9 lines
Thanks and Regards Srikar -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. 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:"[email protected]"> [email protected] </a>
Re: [PATCH v7 3.2-rc2 4/30] uprobes: Define hooks for mmap/munmap.
In reply to Srikar DronamrajuQuoted 10 lines
int
mmap_uprobe(...){
....ret = install_breakpoint(vma->vm_mm, uprobe); if (ret == -EEXIST) { if (!read_opcode(vma->vm_mm, vaddr, &opcode) && (opcode == UPROBES_BKPT_INSN)) atomic_inc(&vma->vm_mm->mm_uprobes_count); ret = 0; }
Quoted 3 lines
....
}
Infact the check for EEXIST and read_opcode in mmap_uprobe() is needed for another reason too.
Lets say while unregister_uprobe was around, a thread thats being probed, just forked a child and the child called mmap_uprobe.
Now mmap_uprobe might find that the breakpoint is already inserted since the pages are shared with the parent. But before unregister_uprobe can come around and cleanup, the child can run and hit the breakpoint. Since the breakpoint count is 0 for the child, we dont expect the child to have hit a breakpoint placed by uprobes, and the child gets a SIGTRAP.
With this check for read_opcode on EEXIST from install_breakpoint, we will know that there is a valid breakpoint underneath and increment the count. So on a breakpoint hit, the uprobes notifier does the right thing.
If the unregister_uprobe() had already cleanup the breakpoint in the parent, the child's copy would also be clean so read_opcode wont find the breakpoint and hence we wont increment the breakpoint.
Signature · 2 lines
Thanks and Regards Srikar
Peter Zijlstra
maintainerRe: [PATCH v7 3.2-rc2 4/30] uprobes: Define hooks for mmap/munmap.
In reply to Srikar DronamrajuReview again: remove_next = 1 + (end > next->vm_end);
Quoted 1 line · Srikar Dronamraju
(quoted diff) +0
-0@@ -545,8 +547,14 @@ again: remove_next = 1 + (end > next->vm_end);
I'm not sure if you use quilt or git to produce these patches but can you either add:
QUILT_DIFF_OPTS="-F ^[[:alpha:]\$_].*[^:]\$"
to your .quiltrc, or:
[diff "default"]
xfuncname = "^[[:alpha:]$_].*[^:]$"
to your .gitconfig ?
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. 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:"[email protected]"> [email protected] </a>
Steven Rostedt
maintainerRe: [PATCH v7 3.2-rc2 4/30] uprobes: Define hooks for mmap/munmap.
Quoted 6 lines · Peter Zijlstra
Review again: remove_next = 1 + (end > next->vm_end);
Quoted 1 line · Srikar Dronamraju
(quoted diff) +0
-0@@ -545,8 +547,14 @@ again: remove_next = 1 + (end > next->vm_end);I'm not sure if you use quilt or git to produce these patches but can you either add:
Quoted 9 lines
QUILT_DIFF_OPTS="-F ^[[:alpha:]\$_].*[^:]\$"
to your .quiltrc, or:
[diff "default"]
xfuncname = "^[[:alpha:]$_].*[^:]$"to your .gitconfig ?
or just place a space in front of "again:"
/me runs!
-- Steve
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. 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:"[email protected]"> [email protected] </a>
Re: [PATCH v7 3.2-rc2 4/30] uprobes: Define hooks for mmap/munmap.
In reply to Peter ZijlstraQuoted 6 lines · Peter Zijlstra
Review again: remove_next = 1 + (end > next->vm_end);
Quoted 1 line · Srikar Dronamraju
(quoted diff) +0
-0@@ -545,8 +547,14 @@ again: remove_next = 1 + (end > next->vm_end);I'm not sure if you use quilt or git to produce these patches but can you either add:
Quoted 6 lines
QUILT_DIFF_OPTS="-F ^[[:alpha:]\$_].*[^:]\$"
to your .quiltrc, or:
[diff "default"]
xfuncname = "^[[:alpha:]$_].*[^:]$"
I use stgit
You had suggested this to me earlier, and I have it my ~/.gitconfig
[diff "default"]
xfuncname = "^[[:alpha:]$_].*[^:]$"
stg version
Stacked GIT 0.15
git version 1.7.1
Python version 2.6.6 (r266:84292, Apr 11 2011, 15:50:32) [GCC 4.4.4 20100726 (Red Hat 4.4.4-13)]
One thing that I might be doing differently is
I do a "stg export" before using sendpatchset to mail the patches.
Signature · 9 lines
Thanks and Regards Srikar -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. 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:"[email protected]"> [email protected] </a>
Peter Zijlstra
maintainerRe: [PATCH v7 3.2-rc2 4/30] uprobes: Define hooks for mmap/munmap.
Quoted 1 line · Srikar Dronamraju
I do a "stg export" before using sendpatchset to mail the patches.
hrm, weird stuff. I've no idea what stg does, but it looks like its not working right. A well, something to figure out on a rainy afternoon or so.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. 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:"[email protected]"> [email protected] </a>
PATCH v7 5/30 uprobes: copy of the original instruction.
In reply to Srikar DronamrajuWhen 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.
---
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(-)
include/linux/uprobes.h +12 -0
@@ -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,
kernel/uprobes.c +101 -10
157 lines not on this page · raw message
Peter Zijlstra
maintainerRe: [PATCH v7 3.2-rc2 5/30] uprobes: copy of the original instruction.
Review
Quoted 2 lines · Srikar Dronamraju
(quoted diff) +2
-0+ if (IS_ERR(page)) + return -ENOMEM;
again, why not use PTR_ERR() if you're there already?
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. 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:"[email protected]"> [email protected] </a>
Peter Zijlstra
maintainerRe: [PATCH v7 3.2-rc2 5/30] uprobes: copy of the original instruction.
In reply to Srikar DronamrajuQuoted 1 line · Srikar Dronamraju
+ /* TODO : Analysis and verification of instruction */
As in refuse to set a breakpoint on an instruction we can't deal with?
Do we care? The worst case we'll crash the program, but if we're allowed setting uprobes we already have enough privileges to do that anyway, right?
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. 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:"[email protected]"> [email protected] </a>
Steven Rostedt
maintainerRe: [PATCH v7 3.2-rc2 5/30] uprobes: copy of the original instruction.
Quoted 8 lines · Peter Zijlstra
Quoted 1 line · Srikar Dronamraju
+ /* TODO : Analysis and verification of instruction */
As in refuse to set a breakpoint on an instruction we can't deal with?
Do we care? The worst case we'll crash the program, but if we're allowed setting uprobes we already have enough privileges to do that anyway, right?
Well, I wouldn't be happy if I was running a server, and needed to analyze something it was doing, and because I screwed up the location of my probe, I crash the server, made lots of people unhappy and lose my job over it.
I think we do care, but it can be a TODO item.
-- Steve
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. 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:"[email protected]"> [email protected] </a>
Peter Zijlstra
maintainerRe: [PATCH v7 3.2-rc2 5/30] uprobes: copy of the original instruction.
Quoted 10 lines · Steven Rostedt
Quoted 8 lines · Peter Zijlstra
Quoted 1 line · Srikar Dronamraju
+ /* TODO : Analysis and verification of instruction */
As in refuse to set a breakpoint on an instruction we can't deal with?
Do we care? The worst case we'll crash the program, but if we're allowed setting uprobes we already have enough privileges to do that anyway, right?
Quoted 6 lines
Well, I wouldn't be happy if I was running a server, and needed to analyze something it was doing, and because I screwed up the location of my probe, I crash the server, made lots of people unhappy and lose my job over it.
I think we do care, but it can be a TODO item.
But but but, why not let userspace sort it? And if you're going to provide the kernel with inode:offset data yourself, you're already well aware of wtf you're doing.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. 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:"[email protected]"> [email protected] </a>
Re: [PATCH v7 3.2-rc2 5/30] uprobes: copy of the original instruction.
In reply to Peter ZijlstraQuoted 10 lines · On Wed, 23 Nov 2011 19:40:16 +0100 Peter Zijlstra <[email protected]> wrote:
Quoted 2 lines · Srikar Dronamraju
+ /* TODO : Analysis and verification of instruction
*/As in refuse to set a breakpoint on an instruction we can't deal with?
Do we care? The worst case we'll crash the program, but if we're allowed setting uprobes we already have enough privileges to do that anyway, right?
I think we should and we do care.
That's already implemented in the subsequent patches too. For example: we don't a trace breakpoint instruction.
Signature · 2 lines
Thanks and Regards Srikar
Peter Zijlstra
maintainerRe: [PATCH v7 3.2-rc2 5/30] uprobes: copy of the original instruction.
In reply to Srikar DronamrajuQuoted 43 lines · Srikar Dronamraju
kernel/uprobes.c +43
-0+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 */
kernel/uprobes.c static bool del_consumer(struct uprobe *uprobe, · line 321
Quoted 10 lines
kernel/uprobes.c +10
-0+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 ;
You just lost your possible -EINVAL return value.
kernel/uprobes.c static bool del_consumer(struct uprobe *uprobe, · line 326
Quoted 5 lines
kernel/uprobes.c +5
-0+ + bytes = nbytes; + } +return __copy_insn (mapping, vma, uprobe->insn, bytes, uprobe->offset); +}
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. 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:"[email protected]"> [email protected] </a>
PATCH v7 6/30 uprobes: define fixups.
In reply to Srikar DronamrajuDuring the first insertion of a probepoint, instruction is analyzed for fixups and cached in the per-uprobe struct. On a probehit, the cached fixup is used. Fixup analysis and caching is done in arch-specific code.
--- include/linux/uprobes.h | 12 ++++++++++++ 1 files changed, 12 insertions(+), 0 deletions(-)
include/linux/uprobes.h +12 -0
@@ -33,6 +33,17 @@ struct vm_area_struct;#define MAX_UINSN_BYTES 4#endif +#define uprobe_opcode_sz sizeof(uprobe_opcode_t) + +/* Post-execution fixups. Some architectures may define others. */ + +/* No fixup needed */ +#define UPROBES_FIX_NONE 0x0 +/* Adjust IP back to vicinity of actual insn */ +#define UPROBES_FIX_IP 0x1 +/* Adjust the return address of a call insn */ +#define UPROBES_FIX_CALL 0x2 +struct uprobe_consumer {int (*handler)(struct uprobe_consumer *self,struct pt_regs *regs);/*
@@ -53,6 +64,7 @@ struct uprobe {struct inode *inode;/* Also hold a ref to inode */ loff_t offset;int copy; +u16 fixups;u8 insn[MAX_UINSN_BYTES ]; };
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. 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:"[email protected]"> [email protected] </a>
PATCH v7 7/30 uprobes: uprobes arch info
In reply to Srikar DronamrajuIntroduce per uprobe arch info structure.
Used to store arch specific details. For example: details to handle Rip relative instructions in X86_64.
--- include/linux/uprobes.h | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-)
include/linux/uprobes.h +2 -1
@@ -29,7 +29,7 @@ struct vm_area_struct;#ifdef CONFIG_ARCH_SUPPORTS_UPROBES #include <asm/uprobes.h> #else - +struct uprobe_arch_info {};#define MAX_UINSN_BYTES 4#endif
@@ -60,6 +60,7 @@ struct uprobe {atomic_t ref;struct rw_semaphore consumer_rwsem;struct list_head pending_list; +struct uprobe_arch_info arch_info;struct uprobe_consumer *consumers;struct inode *inode;/* Also hold a ref to inode */ loff_t offset;
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. 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:"[email protected]"> [email protected] </a>
PATCH v7 8/30 x86: analyze instruction and determine fixups.
In reply to Srikar DronamrajuThe instruction analysis is based on x86 instruction decoder and determines if an instruction can be probed and determines the necessary fixups after singlestep. Instruction analysis is done at probe insertion time so that we avoid having to repeat the same analysis every time a probe is hit.
---
Changelog (since v5)
- Include Instruction Decoder if Uprobes gets defined.
- Remove const attributes for instruction prefix arrays.
- Uses mm_context to know if the application is 32 bit.
arch/x86/Kconfig | 5 - arch/x86/include/asm/uprobes.h | 42 ++++ arch/x86/kernel/Makefile | 1 arch/x86/kernel/uprobes.c | 399 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 446 insertions(+), 1 deletions(-) create mode 100644 arch/x86/include/asm/uprobes.h create mode 100644 arch/x86/kernel/uprobes.c
arch/x86/Kconfig +4 -1
@@ -77,7 +77,7 @@ config X86 select ARCH_HAVE_NMI_SAFE_CMPXCHG config INSTRUCTION_DECODER - def_bool (KPROBES || PERF_EVENTS) + def_bool (KPROBES || PERF_EVENTS || UPROBES) config OUTPUT_FORMAT string
@@ -249,6 +249,9 @@ config ARCH_CPU_PROBE_RELEASE def_bool y depends on HOTPLUG_CPU +config ARCH_SUPPORTS_UPROBES + def_bool y + source "init/Kconfig" source "kernel/Kconfig.freezer"
arch/x86/include/asm/uprobes.h new file +42 -0
42 lines not on this page · raw message
arch/x86/kernel/Makefile +1 -0
@@ -98,6 +98,7 @@ obj-$(CONFIG_X86_CHECK_BIOS_CORRUPTION) += check.o obj-$(CONFIG_SWIOTLB) += pci-swiotlb.o obj-$(CONFIG_OF) += devicetree.o +obj-$(CONFIG_UPROBES) += uprobes.o ### # 64 bit specific files
arch/x86/kernel/uprobes.c new file +399 -0
399 lines not on this page · raw message
Oleg Nesterov
maintainerRe: [PATCH v7 3.2-rc2 8/30] x86: analyze instruction and determine fixups.
arch/x86/kernel/uprobes.c line 341
Quoted 12 lines · Srikar Dronamraju
arch/x86/kernel/uprobes.c new file +10
-0+static void handle_riprel_insn (struct mm_struct *mm,struct uprobe *uprobe, +struct insn *insn) +{ +if (insn->immediate.nbytes) { + cursor++; +memmove (cursor, cursor + insn->displacement.nbytes, + insn->immediate.nbytes); + } +return ; +}
Of course I don not understand this code. But it seems that it can rewrite uprobe->insn ?
If yes, don't we need to save the original insn for unregister_uprobe?
Oleg.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. 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:"[email protected]"> [email protected] </a>
Re: [PATCH v7 3.2-rc2 8/30] x86: analyze instruction and determine fixups.
Quoted 17 lines · Oleg Nesterov
arch/x86/kernel/uprobes.c line 341
Quoted 12 lines · Srikar Dronamraju
arch/x86/kernel/uprobes.c new file +10
-0+static void handle_riprel_insn (struct mm_struct *mm,struct uprobe *uprobe, +struct insn *insn) +{ +if (insn->immediate.nbytes) { + cursor++; +memmove (cursor, cursor + insn->displacement.nbytes, + insn->immediate.nbytes); + } +return ; +}Of course I don not understand this code. But it seems that it can rewrite
uprobe->insn?
Yes, we do rewrite the instruction for the RIP relative instructions. But the first byte is still intact.
Quoted 1 line
If yes, don't we need to save the original insn for
unregister_uprobe?
When we unregister, we just put back the least opcode size which happens to be the first byte for x86.
Signature · 9 lines
Thanks and Regards Srikar -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. 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:"[email protected]"> [email protected] </a>
PATCH v7 9/30 uprobes: Background page replacement.
In reply to Srikar DronamrajuProvides Background page replacement by
- cow the page that needs replacement.
- modify a copy of the cowed page.
- replace the cow page with the modified page
- flush the page tables.
Also provides additional routines to read an opcode from a given virtual address and for verifying if a instruction is a breakpoint instruction.
---
Changelog (since v5)
- pass NULL to get_user_pages for the task parameter.
- call SetPageUptodate on the new page allocated in write_opcode.
- fix leaking a reference to the new page under certain conditions.
include/linux/uprobes.h | 2 kernel/uprobes.c | 264 ++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 258 insertions(+), 8 deletions(-)
include/linux/uprobes.h +2 -0
@@ -29,6 +29,7 @@ struct vm_area_struct;#ifdef CONFIG_ARCH_SUPPORTS_UPROBES #include <asm/uprobes.h> #else +typedef u8 uprobe_opcode_t ;struct uprobe_arch_info {};#define MAX_UINSN_BYTES 4#endif
@@ -74,6 +75,7 @@ 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 bool __weak is_bkpt_insn (u8 *insn);extern int register_uprobe (struct inode *inode,loff_t offset,struct uprobe_consumer *consumer); extern void unregister_uprobe(struct inode *inode, loff_t offset,
kernel/uprobes.c +256 -8
306 lines not on this page · raw message
Peter Zijlstra
maintainerRe: [PATCH v7 3.2-rc2 9/30] uprobes: Background page replacement.
kernel/uprobes.c static bool valid_vma(struct vm_area_struct *vma, bool is_reg) · line 225
Quoted 3 lines · Srikar Dronamraju
kernel/uprobes.c +3
-0+/* poke the new insn in, ASSUMES we don't cross page boundary */ + vaddr &= ~PAGE_MASK ; +memcpy (vaddr_new + vaddr, &opcode, uprobe_opcode_sz);
I still don't get why you don't simply write something like:
BUG_ON(vaddr + uprobe_opcode_size >= PAGE_SIZE);
That's as descriptive as the comment and actually does something if someone got it wrong, instead of silently corrupting crap.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. 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:"[email protected]"> [email protected] </a>
Peter Zijlstra
maintainerRe: [PATCH v7 3.2-rc2 9/30] uprobes: Background page replacement.
In reply to Srikar DronamrajuQuoted 4 lines · Srikar Dronamraju
kernel/uprobes.c +4
-0+static int read_opcode (struct mm_struct *mm,unsigned long vaddr, +uprobe_opcode_t *opcode) +{ +struct page *page;
kernel/uprobes.c static bool valid_vma(struct vm_area_struct *vma, bool is_reg) · line 272
Quoted 10 lines
kernel/uprobes.c +10
-0+void *vaddr_new; +int ret; + + ret =get_user_pages (NULL , mm, vaddr,1 ,0 ,0 , &page,NULL ); +if (ret <=0 ) +return ret; + +lock_page (page); + vaddr_new =kmap_atomic (page); + vaddr &= ~PAGE_MASK ;
BUG_ON(vaddr + uprobe_opcode_sz >= PAGE_SIZE);
Quoted 6 lines
kernel/uprobes.c +6
-0+memcpy (opcode, vaddr_new + vaddr, uprobe_opcode_sz); +kunmap_atomic (vaddr_new); +unlock_page (page); +put_page (page);/* we did a get_user_pages in the beginning */ +return 0 ; +}
Re: [PATCH v7 3.2-rc2 9/30] uprobes: Background page replacement.
Quoted 18 lines · Peter Zijlstra
Quoted 4 lines · Srikar Dronamraju
kernel/uprobes.c +4
-0+static int read_opcode (struct mm_struct *mm,unsigned long vaddr, +uprobe_opcode_t *opcode) +{ +struct page *page;kernel/uprobes.c static bool valid_vma(struct vm_area_struct *vma, bool is_reg) · line 272
Quoted 10 lines
kernel/uprobes.c +10
-0+void *vaddr_new; +int ret; + + ret =get_user_pages (NULL , mm, vaddr,1 ,0 ,0 , &page,NULL ); +if (ret <=0 ) +return ret; + +lock_page (page); + vaddr_new =kmap_atomic (page); + vaddr &= ~PAGE_MASK ;
BUG_ON(vaddr + uprobe_opcode_sz >= PAGE_SIZE);
Okay, will add BUG_ON.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. 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:"[email protected]"> [email protected] </a>
Peter Zijlstra
maintainerRe: [PATCH v7 3.2-rc2 9/30] uprobes: Background page replacement.
In reply to Srikar Dronamrajukernel/uprobes.c static bool valid_vma(struct vm_area_struct *vma, bool is_reg) · line 331
Quoted 10 lines · Srikar Dronamraju
kernel/uprobes.c +9
-0+/** +* is_bkpt_insn - check if instruction is breakpoint instruction. +* @insn: instruction to be checked. +* Default implementation of is_bkpt_insn +* Returns true if @insn is a breakpoint instruction. +*/ +bool __weak is_bkpt_insn (u8 *insn) +{ +return (insn[0 ] ==UPROBES_BKPT_INSN ); }
This seems wrong, UPROBES_BKPT_INSN basically defined to be of uprobe_opcode_t type, not u8.
So:
bool __weak is_bkpt_insn(uprobe_opcode_t *insn)
{
return *insn == UPROBE_BKPT_INSN;
}seems like the right way to write this.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. 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:"[email protected]"> [email protected] </a>
Re: [PATCH v7 3.2-rc2 9/30] uprobes: Background page replacement.
Quoted 15 lines · Peter Zijlstra
kernel/uprobes.c static bool valid_vma(struct vm_area_struct *vma, bool is_reg) · line 331
Quoted 10 lines · Srikar Dronamraju
kernel/uprobes.c +9
-0+/** +* is_bkpt_insn - check if instruction is breakpoint instruction. +* @insn: instruction to be checked. +* Default implementation of is_bkpt_insn +* Returns true if @insn is a breakpoint instruction. +*/ +bool __weak is_bkpt_insn (u8 *insn) +{ +return (insn[0 ] ==UPROBES_BKPT_INSN ); }This seems wrong,
UPROBES_BKPT_INSNbasically defined to be ofuprobe_opcode_ttype, not u8.
Quoted 9 lines
So:
bool
__weakis_bkpt_insn(uprobe_opcode_t *insn){ return *insn == UPROBE_BKPT_INSN; }seems like the right way to write this.
Agree, will fix this.
Thanks for bringing this up.
Signature · 9 lines
Thanks and Regards Srikar -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. 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:"[email protected]"> [email protected] </a>
Peter Zijlstra
maintainerRe: [PATCH v7 3.2-rc2 9/30] uprobes: Background page replacement.
In reply to Srikar DronamrajuQuoted 9 lines · Srikar Dronamraju
Provides Background page replacement by
- cow the page that needs replacement.
- modify a copy of the cowed page.
- replace the cow page with the modified page
- flush the page tables.Also provides additional routines to read an opcode from a given virtual address and for verifying if a instruction is a breakpoint instruction.
You again/still lost the reason why we duplicate bits of mm/ksm.c here.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. 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:"[email protected]"> [email protected] </a>
PATCH v7 10/30 x86: Set instruction pointer.
In reply to Srikar DronamrajuProvides x86 specific routine to set the instruction pointer to the given address.
--- arch/x86/include/asm/uprobes.h | 1 + arch/x86/kernel/uprobes.c | 10 ++++++++++ 2 files changed, 11 insertions(+), 0 deletions(-)
arch/x86/include/asm/uprobes.h +1 -0
@@ -39,4 +39,5 @@ struct uprobe_arch_info {};#endif struct uprobe ;extern int analyze_insn (struct mm_struct *mm,struct uprobe *uprobe); +extern void set_instruction_pointer (struct pt_regs *regs,unsigned long vaddr);#endif /* _ASM_UPROBES_H */
arch/x86/kernel/uprobes.c +10 -0
@@ -397,3 +397,13 @@ int analyze_insn(struct mm_struct *mm, struct uprobe *uprobe)prepare_fixups (uprobe, &insn);return 0 ; } + +/* +* @reg: reflects the saved state of the task +* @vaddr: the virtual address to jump to. +* Return 0 on success or a -ve number on error. +*/ +void set_instruction_pointer (struct pt_regs *regs,unsigned long vaddr) +{ + regs->ip = vaddr; +}
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. 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:"[email protected]"> [email protected] </a>
PATCH v7 11/30 x86: Introduce TIF_UPROBE FLAG.
In reply to Srikar DronamrajuOn a breakpoint or singlestep, the exception notifier will just set this thread_info FLAG so that do_notify_resume can be made aware that a breakpoint/singlestep has occurred.
--- arch/x86/include/asm/thread_info.h | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-)
arch/x86/include/asm/thread_info.h +2 -0
@@ -84,6 +84,7 @@ struct thread_info {#define TIF_SECCOMP 8/* secure computing */ #define TIF_MCE_NOTIFY 10/* notify userspace of an MCE */ #define TIF_USER_RETURN_NOTIFY 11/* notify kernel of userspace return */ +#define TIF_UPROBE 12/* breakpointed or singlestepping */ #define TIF_NOTSC 16/* TSC is not accessible in userland */ #define TIF_IA32 17/* 32bit process */ #define TIF_FORK 18/* ret_from_fork */
@@ -107,6 +108,7 @@ struct thread_info {#define _TIF_SECCOMP (1 << TIF_SECCOMP)#define _TIF_MCE_NOTIFY (1 << TIF_MCE_NOTIFY)#define _TIF_USER_RETURN_NOTIFY (1 << TIF_USER_RETURN_NOTIFY) +#define _TIF_UPROBE (1 << TIF_UPROBE)#define _TIF_NOTSC (1 << TIF_NOTSC)#define _TIF_IA32 (1 << TIF_IA32)#define _TIF_FORK (1 << TIF_FORK)
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. 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:"[email protected]"> [email protected] </a>
PATCH v7 12/30 uprobes: Handle breakpoint and Singlestep
In reply to Srikar DronamrajuProvides routines to create/manage and free the task specific information. Uses bulkref interface.
Adds a hook in uprobe_notify_resume to handle breakpoint and singlestep exception.
Uprobes needs to maintain some task specific information including if a task has hit a probepoint, uprobe corresponding to the probehit, the slot where the original instruction is copied to before single-stepping.
---
Changelog (since v5)
- Use bulkref instead of synchronize_sched
- Introduce per task bulkref_id to store the bulkref_id
- Modified comments.
include/linux/sched.h | 4 + include/linux/uprobes.h | 33 +++++++ kernel/fork.c | 6 + kernel/uprobes.c | 208 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 251 insertions(+), 0 deletions(-)
include/linux/sched.h +4 -0
@@ -1573,6 +1573,10 @@ struct task_struct {#ifdef CONFIG_HAVE_HW_BREAKPOINT atomic_t ptrace_bp_refcnt;#endif +#ifdef CONFIG_UPROBES +struct uprobe_task *utask; +int uprobes_bulkref_id; +#endif };/* Future-safe accessor for struct task_struct's cpus_allowed. */
include/linux/uprobes.h +33 -0
@@ -70,6 +70,24 @@ struct uprobe {u8 insn[MAX_UINSN_BYTES ]; }; +enum uprobe_task_state { +UTASK_RUNNING , +UTASK_BP_HIT , +UTASK_SSTEP +}; + +/* +* uprobe_task: Metadata of a task while it singlesteps. +*/ +struct uprobe_task { +unsigned long xol_vaddr; +unsigned long vaddr; + +enum uprobe_task_state state; + +struct uprobe *active_uprobe; +}; +#ifdef CONFIG_UPROBES extern int __weak set_bkpt (struct mm_struct *mm,struct uprobe *uprobe,unsigned long vaddr);
@@ -80,8 +98,13 @@ extern int register_uprobe(struct inode *inode, loff_t offset, struct uprobe_consumer *consumer);extern void unregister_uprobe (struct inode *inode,loff_t offset,struct uprobe_consumer *consumer); +extern void free_uprobe_utask (struct task_struct *tsk);extern int mmap_uprobe (struct vm_area_struct *vma);extern void munmap_uprobe (struct vm_area_struct *vma); +extern unsigned long __weak get_uprobe_bkpt_addr (struct pt_regs *regs); +extern int uprobe_post_notifier (struct pt_regs *regs); +extern int uprobe_bkpt_notifier (struct pt_regs *regs); +extern void uprobe_notify_resume (struct pt_regs *regs);#else /* CONFIG_UPROBES is not defined */ static inline int register_uprobe (struct inode *inode,loff_t offset,struct uprobe_consumer *consumer)
@@ -99,5 +122,15 @@ static inline int mmap_uprobe(struct vm_area_struct *vma)static inline void munmap_uprobe (struct vm_area_struct *vma) { } +static inline void uprobe_notify_resume (struct pt_regs *regs) +{ +} +static inline unsigned long get_uprobe_bkpt_addr (struct pt_regs *regs) +{ +return 0 ; +} +static inline void free_uprobe_utask (struct task_struct *tsk) +{ +}#endif /* CONFIG_UPROBES */ #endif /* _LINUX_UPROBES_H */
kernel/fork.c +6 -0
@@ -686,6 +686,8 @@ void mm_release(struct task_struct *tsk, struct mm_struct *mm)exit_pi_state_list (tsk);#endif +free_uprobe_utask (tsk); +/* Get rid of any cached register state */ deactivate_mm (tsk, mm);
@@ -1284,6 +1286,10 @@ static struct task_struct *copy_process(unsigned long clone_flags,INIT_LIST_HEAD (&p->pi_state_list); p->pi_state_cache =NULL ;#endif +#ifdef CONFIG_UPROBES + p->utask =NULL ; + p->uprobes_bulkref_id =-1 ; +#endif /* * sigaltstack should be cleared when sharing the same VM */
kernel/uprobes.c +208 -0
244 lines not on this page · raw message
Peter Zijlstra
maintainerRe: [PATCH v7 3.2-rc2 12/30] uprobes: Handle breakpoint and Singlestep
kernel/uprobes.c static struct uprobe *alloc_uprobe(struct inode *inode, loff_t offset) · line 477
Quoted 3 lines · Srikar Dronamraju
kernel/uprobes.c +3
-0+ consumer = uprobe->consumers; +for (consumer = uprobe->consumers; consumer; + consumer = consumer->next) {
that first expression seems redundant..
Re: [PATCH v7 3.2-rc2 12/30] uprobes: Handle breakpoint and Singlestep
Quoted 7 lines · Peter Zijlstra
kernel/uprobes.c static struct uprobe *alloc_uprobe(struct inode *inode, loff_t offset) · line 477
Quoted 3 lines · Srikar Dronamraju
kernel/uprobes.c +3
-0+ consumer = uprobe->consumers; +for (consumer = uprobe->consumers; consumer; + consumer = consumer->next) {that first expression seems redundant..
Yes, will remove.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. 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:"[email protected]"> [email protected] </a>
PATCH v7 13/30 x86: define a x86 specific exception notifier.
In reply to Srikar DronamrajuUprobes uses notifier mechanism to get in control when an application encounters a breakpoint or a singlestep exception.
---
Changelog (since v5)
- No more do a i386 specific enable interrupts. (Its now part of another patchset posted separately)
arch/x86/include/asm/uprobes.h | 4 ++++ arch/x86/kernel/signal.c | 6 ++++++ arch/x86/kernel/uprobes.c | 29 +++++++++++++++++++++++++++++ 3 files changed, 39 insertions(+), 0 deletions(-)
arch/x86/include/asm/uprobes.h +4 -0
@@ -23,6 +23,8 @@* Jim Keniston */ +#include <linux/notifier.h> +typedef u8 uprobe_opcode_t ;#define MAX_UINSN_BYTES 16#define UPROBES_XOL_SLOT_BYTES 128/* to keep it cache aligned */
@@ -40,4 +42,6 @@ struct uprobe_arch_info {};struct uprobe ;extern int analyze_insn (struct mm_struct *mm,struct uprobe *uprobe);extern void set_instruction_pointer (struct pt_regs *regs,unsigned long vaddr); +extern int uprobe_exception_notify (struct notifier_block *self, +unsigned long val,void *data);#endif /* _ASM_UPROBES_H */
arch/x86/kernel/signal.c +6 -0
@@ -20,6 +20,7 @@#include <linux/personality.h> #include <linux/uaccess.h> #include <linux/user-return-notifier.h> +#include <linux/uprobes.h> #include <asm/processor.h> #include <asm/ucontext.h>
@@ -820,6 +821,11 @@ do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags)mce_notify_process ();#endif /* CONFIG_X86_64 && CONFIG_X86_MCE */ +if (thread_info_flags & _TIF_UPROBE) { +clear_thread_flag (TIF_UPROBE ); +uprobe_notify_resume (regs); + } +/* deal with pending signal delivery */ if (thread_info_flags & _TIF_SIGPENDING)do_signal (regs);
arch/x86/kernel/uprobes.c +29 -0
@@ -407,3 +407,32 @@ void set_instruction_pointer(struct pt_regs *regs, unsigned long vaddr) { regs->ip = vaddr; } + +/* +* Wrapper routine for handling exceptions. +*/ +int uprobe_exception_notify (struct notifier_block *self, +unsigned long val,void *data) +{ +struct die_args *args = data; +struct pt_regs *regs = args->regs; +int ret =NOTIFY_DONE ; + +/* We are only interested in userspace traps */ +if (regs && !user_mode_vm (regs)) +return NOTIFY_DONE ; + +switch (val) { +case DIE_INT3 : +/* Run your handler here */ +if (uprobe_bkpt_notifier (regs)) + ret =NOTIFY_STOP ; +break ; +case DIE_DEBUG : +if (uprobe_post_notifier (regs)) + ret =NOTIFY_STOP ; +default : +break ; + } +return ret; +}
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. 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:"[email protected]"> [email protected] </a>
PATCH v7 14/30 uprobe: register exception notifier
In reply to Srikar DronamrajuUse the notifier mechanism to register uprobes exception notifier.
--- kernel/uprobes.c | 8 +++++++- 1 files changed, 7 insertions(+), 1 deletions(-)
kernel/uprobes.c +7 -1
@@ -30,6 +30,7 @@#include <linux/mmu_notifier.h> /* set_pte_at_notify */ #include <linux/swap.h> /* try_to_free_swap */ #include <linux/ptrace.h> /* user_enable_single_step */ +#include <linux/kdebug.h> /* notifier mechanism */ #include <linux/uprobes.h> static bulkref_t uprobes_srcu;
@@ -1229,6 +1230,11 @@ int uprobe_post_notifier(struct pt_regs *regs)return 1 ; } +struct notifier_block uprobe_exception_nb = { + .notifier_call = uprobe_exception_notify, + .priority =INT_MAX -1 ,/* notified after kprobes, kgdb */ +}; +static int __init init_uprobes (void ) {int i;
@@ -1238,7 +1244,7 @@ static int __init init_uprobes(void)mutex_init (&uprobes_mmap_mutex[i]); }init_bulkref (&uprobes_srcu); -return 0 ; +return register_die_notifier (&uprobe_exception_nb); } static void __exit exit_uprobes(void)
PATCH v7 15/30 x86: Define x86_64 specific uprobe_task_arch_info structure
In reply to Srikar DronamrajuOn x86_64, need to handle RIP relative instructions, which requires us to save and restore a register.
--- arch/x86/include/asm/uprobes.h | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-)
arch/x86/include/asm/uprobes.h +5 -0
@@ -36,8 +36,13 @@ typedef u8 uprobe_opcode_t;struct uprobe_arch_info {unsigned long rip_rela_target_address; }; + +struct uprobe_task_arch_info { +unsigned long saved_scratch_register; +};#else struct uprobe_arch_info {}; +struct uprobe_task_arch_info {};#endif struct uprobe ;extern int analyze_insn (struct mm_struct *mm,struct uprobe *uprobe);
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. 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:"[email protected]"> [email protected] </a>
PATCH v7 16/30 uprobes: Introduce uprobe_task_arch_info structure.
In reply to Srikar Dronamrajuuprobe_task_arch_info structure helps save and restore architecture specific artifacts at the probehit/singlestep/original instruction restore time.
--- include/linux/uprobes.h | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-)
include/linux/uprobes.h +2 -0
@@ -31,6 +31,7 @@ struct vm_area_struct;#else typedef u8 uprobe_opcode_t ;struct uprobe_arch_info {}; +struct uprobe_task_arch_info {};/* arch specific task info */ #define MAX_UINSN_BYTES 4#endif
@@ -84,6 +85,7 @@ struct uprobe_task {unsigned long vaddr;enum uprobe_task_state state; +struct uprobe_task_arch_info tskinfo;struct uprobe *active_uprobe; };
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. 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:"[email protected]"> [email protected] </a>
PATCH v7 17/30 x86: arch specific hooks for pre/post singlestep handling.
In reply to Srikar DronamrajuHooks for handling pre singlestepping and post singlestepping.
--- arch/x86/include/asm/uprobes.h | 2 + arch/x86/kernel/uprobes.c | 135 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 137 insertions(+), 0 deletions(-)
arch/x86/include/asm/uprobes.h +2 -0
@@ -47,6 +47,8 @@ struct uprobe_task_arch_info {};struct uprobe ;extern int analyze_insn (struct mm_struct *mm,struct uprobe *uprobe);extern void set_instruction_pointer (struct pt_regs *regs,unsigned long vaddr); +extern int pre_xol (struct uprobe *uprobe,struct pt_regs *regs); +extern int post_xol (struct uprobe *uprobe,struct pt_regs *regs);extern int uprobe_exception_notify (struct notifier_block *self,unsigned long val,void *data);#endif /* _ASM_UPROBES_H */
arch/x86/kernel/uprobes.c +135 -0
147 lines not on this page · raw message
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. 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:"[email protected]"> [email protected] </a>
PATCH v7 18/30 uprobes: slot allocation.
In reply to Srikar DronamrajuOne page of slots are allocated per mm.
On a probehit one free slot is acquired and released after singlestep operation completes.
---
Changelog (since v5)
- no more spin lock needed for slot allocation.
- use install_special_mapping to add a vma. (previous approach used init_creds)
- set uprobes_xol_area while holding map_sem exclusively.
include/linux/mm_types.h | 2 include/linux/uprobes.h | 24 +++++ kernel/fork.c | 2 kernel/uprobes.c | 215 +++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 240 insertions(+), 3 deletions(-)
include/linux/mm_types.h +2 -0
@@ -12,6 +12,7 @@#include <linux/completion.h> #include <linux/cpumask.h> #include <linux/page-debug-flags.h> +#include <linux/uprobes.h> #include <asm/page.h> #include <asm/mmu.h>
@@ -391,6 +392,7 @@ struct mm_struct {#endif #ifdef CONFIG_UPROBES atomic_t mm_uprobes_count; +struct uprobes_xol_area *uprobes_xol_area;#endif };
include/linux/uprobes.h +24 -0
@@ -90,6 +90,26 @@ struct uprobe_task {struct uprobe *active_uprobe; }; +/* +* On a breakpoint hit, thread contests for a slot. It free the +* slot after singlestep. Only definite number of slots are +* allocated. +*/ + +struct uprobes_xol_area { +wait_queue_head_t wq;/* if all slots are busy */ +atomic_t slot_count;/* currently in use slots */ +unsigned long *bitmap;/* 0 = free slot */ +struct page *page; + +/* +* We keep the vma's vm_start rather than a pointer to the vma +* itself. The probed process or a naughty kernel module could make +* the vma go away, and we must handle that reasonably gracefully. +*/ +unsigned long vaddr;/* Page(s) of instruction slots */ +}; +#ifdef CONFIG_UPROBES extern int __weak set_bkpt (struct mm_struct *mm,struct uprobe *uprobe,unsigned long vaddr);
@@ -101,6 +121,7 @@ extern int register_uprobe(struct inode *inode, loff_t offset,extern void unregister_uprobe (struct inode *inode,loff_t offset,struct uprobe_consumer *consumer);extern void free_uprobe_utask (struct task_struct *tsk); +extern void free_uprobes_xol_area (struct mm_struct *mm);extern int mmap_uprobe (struct vm_area_struct *vma);extern void munmap_uprobe (struct vm_area_struct *vma);extern unsigned long __weak get_uprobe_bkpt_addr (struct pt_regs *regs);
@@ -134,5 +155,8 @@ static inline unsigned long get_uprobe_bkpt_addr(struct pt_regs *regs)static inline void free_uprobe_utask (struct task_struct *tsk) { } +static inline void free_uprobes_xol_area (struct mm_struct *mm) +{ +}#endif /* CONFIG_UPROBES */ #endif /* _LINUX_UPROBES_H */
kernel/fork.c +2 -0
@@ -558,6 +558,7 @@ void mmput(struct mm_struct *mm)might_sleep ();if (atomic_dec_and_test (&mm->mm_users)) { +free_uprobes_xol_area (mm);exit_aio (mm);ksm_exit (mm);khugepaged_exit (mm);/* must run before exit_mmap */
@@ -746,6 +747,7 @@ struct mm_struct *dup_mm(struct task_struct *tsk)#endif #ifdef CONFIG_UPROBES atomic_set (&mm->mm_uprobes_count,0 ); + mm->uprobes_xol_area =NULL ;#endif if (!mm_init (mm, tsk))
kernel/uprobes.c +212 -3
251 lines not on this page · raw message
PATCH v7 19/30 tracing: modify is_delete, is_return from ints to bool.
In reply to Srikar Dronamrajuis_delete and is_return can take atmost 2 values and are better of being a boolean than a int.
---
Changelog (since v5):
- extracted from the next patch on Masami's suggestion.
kernel/trace/trace_kprobe.c | 16 ++++++++-------- 1 files changed, 8 insertions(+), 8 deletions(-)
kernel/trace/trace_kprobe.c +8 -8
@@ -651,7 +651,7 @@ static struct trace_probe *alloc_trace_probe(const char *group,void *addr, const char *symbol, unsigned long offs, - int nargs, int is_return) + int nargs, bool is_return) { struct trace_probe *tp;int ret = -ENOMEM ;
@@ -944,7 +944,7 @@ static int split_symbol_offset(char *symbol, unsigned long *offset)#define PARAM_MAX_STACK (THREAD_SIZE / sizeof(unsigned long))static int parse_probe_vars (char *arg,const struct fetch_type *t, -struct fetch_param *f,int is_return) +struct fetch_param *f,bool is_return) {int ret =0 ;unsigned long param;
@@ -977,7 +977,7 @@ static int parse_probe_vars(char *arg, const struct fetch_type *t,/* Recursive argument parser */ static int __parse_probe_arg (char *arg,const struct fetch_type *t, -struct fetch_param *f,int is_return) +struct fetch_param *f,bool is_return) {int ret =0 ;unsigned long param;
@@ -1089,7 +1089,7 @@ static int __parse_bitfield_probe_arg(const char *bf,/* String length checking wrapper */ static int parse_probe_arg (char *arg,struct trace_probe *tp, -struct probe_arg *parg,int is_return) +struct probe_arg *parg,bool is_return) {const char *t;int ret;
@@ -1162,7 +1162,7 @@ static int create_trace_probe(int argc, char **argv)*/ struct trace_probe *tp;int i, ret =0 ; -int is_return =0 , is_delete =0 ; +bool is_return = false, is_delete = false;char *symbol =NULL , *event =NULL , *group =NULL ;char *arg;unsigned long offset =0 ;
@@ -1171,11 +1171,11 @@ static int create_trace_probe(int argc, char **argv)/* argc must be >= 1 */ if (argv[0 ][0 ] =='p' ) - is_return =0 ; + is_return = false;else if (argv[0 ][0 ] =='r' ) - is_return =1 ; + is_return = true;else if (argv[0 ][0 ] =='-' ) - is_delete =1 ; + is_delete = true;else {pr_info ("Probe definition must be started with 'p', 'r' or" " '-'.\n" );
Re: [PATCH v7 3.2-rc2 19/30] tracing: modify is_delete, is_return from ints to bool.
Quoted 2 lines · Srikar Dronamraju
is_deleteandis_returncan take atmost 2 values and are better of being a boolean than a int.
I'm fine with this.
-- Steve
Quoted 3 lines
Signed-off-by Srikar Dronamraju <[email protected]>---
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. 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:"[email protected]"> [email protected] </a>
PATCH v7 20/30 tracing: Extract out common code for kprobes/uprobes traceevents.
In reply to Srikar DronamrajuMove parts of trace_kprobe.c that can be shared with upcoming trace_uprobe.c. Common code to kernel/trace/trace_probe.h and kernel/trace/trace_probe.c.
---
Changelog (since v5)
- Extracted out int to bool changes to a separate patch.
- Fix a bug in kprobe_trace_self_tests_init that was introduced in previous patchset.
kernel/trace/Kconfig | 4 kernel/trace/Makefile | 1 kernel/trace/trace_kprobe.c | 889 +------------------------------------------ kernel/trace/trace_probe.c | 779 ++++++++++++++++++++++++++++++++++++++ kernel/trace/trace_probe.h | 160 ++++++++ 5 files changed, 962 insertions(+), 871 deletions(-) create mode 100644 kernel/trace/trace_probe.c create mode 100644 kernel/trace/trace_probe.h
kernel/trace/Kconfig +4 -0
@@ -373,6 +373,7 @@ config KPROBE_EVENT depends on HAVE_REGS_AND_STACK_ACCESS_API bool "Enable kprobes-based dynamic events" select TRACING + select PROBE_EVENTS default y help This allows the user to add tracing events (similar to tracepoints)
@@ -385,6 +386,9 @@ config KPROBE_EVENT This option is also required by perf-probe subcommand of perf tools. If you want to use perf tools, this option is strongly recommended. +config PROBE_EVENTS + def_bool n + config DYNAMIC_FTRACE bool "enable/disable ftrace tracepoints dynamically" depends on FUNCTION_TRACER
kernel/trace/Makefile +1 -0
@@ -61,5 +61,6 @@ endif ifeq ($(CONFIG_TRACING),y) obj-$(CONFIG_KGDB_KDB) += trace_kdb.o endif +obj-$(CONFIG_PROBE_EVENTS) += trace_probe.o libftrace-y := ftrace.o
kernel/trace/trace_kprobe.c +18 -871
987 lines not on this page · raw message
kernel/trace/trace_probe.c new file +779 -0
779 lines not on this page · raw message
kernel/trace/trace_probe.h new file +160 -0
160 lines not on this page · raw message
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. 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:"[email protected]"> [email protected] </a>
Steven Rostedt
maintainerRe: [PATCH v7 3.2-rc2 20/30] tracing: Extract out common code for kprobes/uprobes traceevents.
Quoted 17 lines · Srikar Dronamraju
kernel/trace/trace_probe.h new file +4
-0@@ -0,0 +1,160 @@ +/* +* Common header file for probe-based Dynamic events. +* +* This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
Quoted 8 lines
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Copyright (C) IBM Corporation, 2010
+ * Author: Srikar Dronamraju
+ *
+ * Derived fromkernel/trace/trace_kprobe.cwritten by
Shouldn't the above be:
include/linux/trace_kprobe.h ?
Although, I would think both of these files are a bit more that derived from. I would have been a bit stronger on the wording and say: This code was copied from trace_kprobe.[ch] written by Masami ...
Then say,
Updates to make this generic:
* Copyright (C) IBM Corporation, 2010
* Author: Srikar Dronamraju
-- Steve
Quoted 3 lines
+ * Masami Hiramatsu <[email protected]>
+ */
+
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. 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:"[email protected]"> [email protected] </a>
Re: [PATCH v7 3.2-rc2 20/30] tracing: Extract out common code for kprobes/uprobes traceevents.
Quoted 14 lines
Quoted 5 lines
+ *
+ * Copyright (C) IBM Corporation, 2010
+ * Author: Srikar Dronamraju
+ *
+ * Derived fromkernel/trace/trace_kprobe.cwritten byShouldn't the above be:
include/linux/trace_kprobe.h?Although, I would think both of these files are a bit more that derived from. I would have been a bit stronger on the wording and say: This code was copied from trace_kprobe.[ch] written by Masami ...
Quoted 9 lines
Then say,
Updates to make this generic:
* Copyright (C) IBM Corporation, 2010
* Author: Srikar Dronamraju-- Steve
Okay, Will do as suggested.
Thanks for reporting/suggesting.
Signature · 2 lines
Thanks and Regards Srikar
PATCH v7 21/30 tracing: uprobes trace_event interface
In reply to Srikar DronamrajuImplements trace_event support for uprobes. In its current form it can be used to put probes at a specified offset in a file and dump the required registers when the code flow reaches the probed address.
The following example shows how to dump the instruction pointer and %ax a register at the probed text address. Here we are trying to probe zfree in /bin/zsh
# cd /sys/kernel/debug/tracing/
# cat /proc/`pgrep zsh`/maps | grep /bin/zsh | grep r-xp
00400000-0048a000 r-xp 00000000 08:03 130904 /bin/zsh
# objdump -T /bin/zsh | grep -w zfree
0000000000446420 g DF .text 0000000000000012 Base zfree
# echo 'p /bin/zsh:0x46420 %ip %ax' > uprobe_events
# cat uprobe_events
p:uprobes/p_zsh_0x46420 /bin/zsh:0x0000000000046420
# echo 1 > events/uprobes/enable
# sleep 20
# echo 0 > events/uprobes/enable
# cat trace
# tracer: nop
#
# TASK-PID CPU# TIMESTAMP FUNCTION
# | | | | |
zsh-24842 [006] 258544.995456: p_zsh_0x46420: (0x446420) arg1=446421 arg2=79
zsh-24842 [007] 258545.000270: p_zsh_0x46420: (0x446420) arg1=446421 arg2=79
zsh-24842 [002] 258545.043929: p_zsh_0x46420: (0x446420) arg1=446421 arg2=79
zsh-24842 [004] 258547.046129: p_zsh_0x46420: (0x446420) arg1=446421 arg2=79TODO: Connect a filter to a consumer.
---
Changelog (since v5)
- Added uprobe tracer documentation to this patch.
Documentation/trace/uprobetracer.txt | 93 ++++ arch/Kconfig | 8 kernel/trace/Kconfig | 16 + kernel/trace/Makefile | 1 kernel/trace/trace.h | 5 kernel/trace/trace_kprobe.c | 4 kernel/trace/trace_probe.c | 14 - kernel/trace/trace_probe.h | 3 kernel/trace/trace_uprobe.c | 768 ++++++++++++++++++++++++++++++++++ 9 files changed, 898 insertions(+), 14 deletions(-) create mode 100644 Documentation/trace/uprobetracer.txt create mode 100644 kernel/trace/trace_uprobe.c
Documentation/trace/uprobetracer.txt new file +93 -0
@@ -0,0 +1,93 @@ + Uprobe-tracer: Uprobe-based Event Tracing + ========================================= + Documentation is written by Srikar Dronamraju + +Overview +-------- +These events are similar to kprobe based events. +To enable this feature, build your kernel with CONFIG_UPROBE_EVENTS=y. + +Similar to the kprobe-event tracer, this doesn't need to be activated via +current_tracer. Instead of that, add probe points via +/sys/kernel/debug/tracing/uprobe_events, and enable it via +/sys/kernel/debug/tracing/events/uprobes/<EVENT>/enabled. + + +Synopsis of uprobe_tracer +------------------------- + p[:[GRP/]EVENT] PATH:SYMBOL[+offs] [FETCHARGS] : Set a probe + + GRP : Group name. If omitted, use "uprobes" for it. + EVENT : Event name. If omitted, the event name is generated + based on SYMBOL+offs. + PATH : path to an executable or a library. + SYMBOL[+offs] : Symbol+offset where the probe is inserted. + + FETCHARGS : Arguments. Each probe can have up to 128 args. + %REG : Fetch register REG + +Event Profiling +--------------- + You can check the total number of probe hits and probe miss-hits via +/sys/kernel/debug/tracing/uprobe_profile. + The first column is event name, the second is the number of probe hits, +the third is the number of probe miss-hits. + +Usage examples +-------------- +To add a probe as a new event, write a new definition to uprobe_events +as below. + + echo 'p: /bin/bash:0x4245c0' > /sys/kernel/debug/tracing/uprobe_events + + This sets a uprobe at an offset of 0x4245c0 in the executable /bin/bash + + + echo > /sys/kernel/debug/tracing/uprobe_events + + This clears all probe points. + +The following example shows how to dump the instruction pointer and %ax +a register at the probed text address. Here we are trying to probe +function zfree in /bin/zsh + + # cd /sys/kernel/debug/tracing/ + # cat /proc/`pgrep zsh`/maps | grep /bin/zsh | grep r-xp + 00400000-0048a000 r-xp 00000000 08:03 130904 /bin/zsh + # objdump -T /bin/zsh | grep -w zfree + 0000000000446420 g DF .text 0000000000000012 Base zfree + +0x46420 is the offset of zfree in object /bin/zsh that is loaded at +0x00400000. Hence the command to probe would be : + + # echo 'p /bin/zsh:0x46420 %ip %ax' > uprobe_events + +We can see the events that are registered by looking at the uprobe_events +file. + + # cat uprobe_events + p:uprobes/p_zsh_0x46420 /bin/zsh:0x0000000000046420 + +Right after definition, each event is disabled by default. For tracing these +events, you need to enable it by: + + # echo 1 > events/uprobes/enable + +Lets disable the event after sleeping for some time. + # sleep 20 + # echo 0 > events/uprobes/enable + +And you can see the traced information via /sys/kernel/debug/tracing/trace. + + # cat trace + # tracer: nop + # + # TASK-PID CPU# TIMESTAMP FUNCTION + # | | | | | + zsh-24842 [006] 258544.995456: p_zsh_0x46420: (0x446420) arg1=446421 arg2=79 + zsh-24842 [007] 258545.000270: p_zsh_0x46420: (0x446420) arg1=446421 arg2=79 + zsh-24842 [002] 258545.043929: p_zsh_0x46420: (0x446420) arg1=446421 arg2=79 + zsh-24842 [004] 258547.046129: p_zsh_0x46420: (0x446420) arg1=446421 arg2=79 + +Each line shows us probes were triggered for a pid 24842 with ip being +0x446421 and contents of ax register being 79.
arch/Kconfig +1 -7
@@ -62,13 +62,7 @@ config OPTPROBES depends on !PREEMPT config UPROBES - bool "User-space probes (EXPERIMENTAL)" - help - Uprobes enables kernel subsystems to establish probepoints - in user applications and execute handler functions when - the probepoints are hit. - - If in doubt, say "N". + def_bool n config HAVE_EFFICIENT_UNALIGNED_ACCESS bool
kernel/trace/Kconfig +16 -0
@@ -386,6 +386,22 @@ config KPROBE_EVENT This option is also required by perf-probe subcommand of perf tools. If you want to use perf tools, this option is strongly recommended. +config UPROBE_EVENT + bool "Enable uprobes-based dynamic events" + depends on ARCH_SUPPORTS_UPROBES + depends on MMU + select UPROBES + select PROBE_EVENTS + select TRACING + default n + help + This allows the user to add tracing events on top of userspace dynamic + events (similar to tracepoints) on the fly via the traceevents interface. + Those events can be inserted wherever uprobes can probe, and record + various registers. + This option is required if you plan to use perf-probe subcommand of perf + tools on user space applications. + config PROBE_EVENTS def_bool n
kernel/trace/Makefile +1 -0
@@ -62,5 +62,6 @@ ifeq ($(CONFIG_TRACING),y) obj-$(CONFIG_KGDB_KDB) += trace_kdb.o endif obj-$(CONFIG_PROBE_EVENTS) += trace_probe.o +obj-$(CONFIG_UPROBE_EVENT) += trace_uprobe.o libftrace-y := ftrace.o
kernel/trace/trace.h +5 -0
@@ -97,6 +97,11 @@ struct kretprobe_trace_entry_head {unsigned long ret_ip; }; +struct uprobe_trace_entry_head { +struct trace_entry ent; +unsigned long ip; +}; +/* * trace_flag_type is an enumeration that holds different * states when a trace occurs. These are:
kernel/trace/trace_kprobe.c +2 -2
@@ -524,8 +524,8 @@ static int create_trace_probe(int argc, char **argv) }/* Parse fetch argument */ - ret =traceprobe_parse_probe_arg (arg, &tp->size, &tp->args[i], - is_return); + ret =traceprobe_parse_probe_arg (arg, &tp->size, + &tp->args[i], is_return, true);if (ret) {pr_info ("Parse error at argument[%d]. (%d)\n" , i, ret); goto error;
kernel/trace/trace_probe.c +10 -4
@@ -528,13 +528,17 @@ static int parse_probe_vars(char *arg, const struct fetch_type *t,/* Recursive argument parser */ static int parse_probe_arg (char *arg,const struct fetch_type *t, -struct fetch_param *f,bool is_return) +struct fetch_param *f,bool is_return,bool is_kprobe) {int ret =0 ;unsigned long param;long offset;char *tmp; +/* Until uprobe_events supports only reg arguments */ +if (!is_kprobe && arg[0 ] !='%' ) +return -EINVAL ; +switch (arg[0 ]) {case '$' : ret =parse_probe_vars (arg +1 , t, f, is_return);
@@ -584,7 +588,8 @@ static int parse_probe_arg(char *arg, const struct fetch_type *t,if (!dprm)return -ENOMEM ; dprm->offset = offset; - ret =parse_probe_arg (arg, t2, &dprm->orig, is_return); + ret =parse_probe_arg (arg, t2, &dprm->orig, is_return, + is_kprobe);if (ret)kfree (dprm);else {
@@ -639,7 +644,7 @@ static int __parse_bitfield_probe_arg(const char *bf,/* String length checking wrapper */ int traceprobe_parse_probe_arg (char *arg,ssize_t *size, -struct probe_arg *parg,bool is_return) +struct probe_arg *parg,bool is_return,bool is_kprobe) {const char *t;int ret;
@@ -665,7 +670,8 @@ int traceprobe_parse_probe_arg(char *arg, ssize_t *size, } parg->offset = *size; *size += parg->type->size; - ret =parse_probe_arg (arg, parg->type, &parg->fetch, is_return); + ret =parse_probe_arg (arg, parg->type, &parg->fetch, is_return, + is_kprobe);if (ret >=0 && t !=NULL ) ret =__parse_bitfield_probe_arg (t, parg->type, &parg->fetch);if (ret >=0 ) {
kernel/trace/trace_probe.h +2 -1
@@ -65,6 +65,7 @@#define TP_FLAG_TRACE 1#define TP_FLAG_PROFILE 2#define TP_FLAG_REGISTERED 4 +#define TP_FLAG_UPROBE 8/* data_rloc: data relative location, compatible with u32 */
@@ -143,7 +144,7 @@ static inline int is_good_name(const char *name) }extern int traceprobe_parse_probe_arg (char *arg,ssize_t *size, -struct probe_arg *parg,bool is_return); +struct probe_arg *parg,bool is_return,bool is_kprobe);extern int traceprobe_conflict_field_name (const char *name,struct probe_arg *args,int narg);
kernel/trace/trace_uprobe.c new file +768 -0
768 lines not on this page · raw message
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. 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:"[email protected]"> [email protected] </a>
PATCH v7 22/30 perf: rename target_module to target
In reply to Srikar DronamrajuThis is a precursor patch that modifies names that refer to kernel/module to also refer to user space names.
--- tools/perf/builtin-probe.c | 12 ++++++------ tools/perf/util/probe-event.c | 26 +++++++++++++------------- 2 files changed, 19 insertions(+), 19 deletions(-)
tools/perf/builtin-probe.c +6 -6
@@ -61,7 +61,7 @@ static struct {struct perf_probe_event events[MAX_PROBES ];struct strlist *dellist;struct line_range line_range; -const char *target_module; +const char *target;int max_probe_points;struct strfilter *filter; } params;
@@ -249,7 +249,7 @@ static const struct option options[] = { "file", "vmlinux pathname"), OPT_STRING('s', "source", &symbol_conf.source_prefix, "directory", "path to kernel source"), - OPT_STRING('m', "module", ¶ms.target_module, + OPT_STRING('m', "module", ¶ms.target, "modname|path", "target module name (for online) or path (for offline)"),#endif
@@ -336,7 +336,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)if (!params.filter) params.filter =strfilter__new (DEFAULT_FUNC_FILTER ,NULL ); - ret =show_available_funcs (params.target_module, + ret =show_available_funcs (params.target, params.filter);strfilter__delete (params.filter);if (ret <0 )
@@ -357,7 +357,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)usage_with_options (probe_usage, options); } - ret =show_line_range (¶ms.line_range, params.target_module); + ret =show_line_range (¶ms.line_range, params.target);if (ret <0 )pr_err (" Error: Failed to show lines. (%d)\n" , ret);return ret;
@@ -374,7 +374,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used) ret =show_available_vars (params.events, params.nevents, params.max_probe_points, - params.target_module, + params.target, params.filter, params.show_ext_vars);strfilter__delete (params.filter);
@@ -396,7 +396,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)if (params.nevents) { ret =add_perf_probe_events (params.events, params.nevents, params.max_probe_points, - params.target_module, + params.target, params.force_add);if (ret <0 ) {pr_err (" Error: Failed to add events. (%d)\n" , ret);
tools/perf/util/probe-event.c +13 -13
@@ -275,10 +275,10 @@ static int add_module_to_probe_trace_events(struct probe_trace_event *tevs,/* Try to find perf_probe_event with debuginfo */ static int try_to_find_probe_trace_events (struct perf_probe_event *pev,struct probe_trace_event **tevs, -int max_tevs,const char *module) +int max_tevs,const char *target) {bool need_dwarf =perf_probe_event_need_dwarf (pev); -struct debuginfo *dinfo =open_debuginfo (module); +struct debuginfo *dinfo =open_debuginfo (target);int ntevs, ret =0 ;if (!dinfo) {
@@ -297,9 +297,9 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev,if (ntevs >0 ) {/* Succeeded to find trace events */ pr_debug ("find %d probe_trace_events.\n" , ntevs); -if (module) +if (target) ret =add_module_to_probe_trace_events (*tevs, ntevs, - module); + target);return ret <0 ? ret : ntevs; }
@@ -1798,14 +1798,14 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,static int convert_to_probe_trace_events (struct perf_probe_event *pev,struct probe_trace_event **tevs, -int max_tevs,const char *module) +int max_tevs,const char *target) {struct symbol *sym;int ret =0 , i;struct probe_trace_event *tev;/* Convert perf_probe_event with debuginfo */ - ret =try_to_find_probe_trace_events (pev, tevs, max_tevs, module); + ret =try_to_find_probe_trace_events (pev, tevs, max_tevs, target);if (ret !=0 )return ret;/* Found in debuginfo or got an error */
@@ -1821,8 +1821,8 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev, goto error; } -if (module) { - tev->point.module =strdup (module); +if (target) { + tev->point.module =strdup (target);if (tev->point.module ==NULL ) { ret = -ENOMEM ; goto error;
@@ -1886,7 +1886,7 @@ struct __event_package { };int add_perf_probe_events (struct perf_probe_event *pevs,int npevs, -int max_tevs,const char *module,bool force_add) +int max_tevs,const char *target,bool force_add) {int i, j, ret;struct __event_package *pkgs;
@@ -1909,7 +1909,7 @@ int add_perf_probe_events(struct perf_probe_event *pevs, int npevs, ret =convert_to_probe_trace_events (pkgs[i].pev, &pkgs[i].tevs, max_tevs, - module); + target);if (ret <0 ) goto end; pkgs[i].ntevs = ret;
@@ -2065,7 +2065,7 @@ static int filter_available_functions(struct map *map __unused,return 1 ; } -int show_available_funcs (const char *module,struct strfilter *_filter) +int show_available_funcs (const char *target,struct strfilter *_filter) {struct map *map;int ret;
@@ -2076,9 +2076,9 @@ int show_available_funcs(const char *module, struct strfilter *_filter)if (ret <0 )return ret; - map =kernel_get_module_map (module); + map =kernel_get_module_map (target);if (!map) { -pr_err ("Failed to find %s map.\n" , (module) ? :"kernel" ); +pr_err ("Failed to find %s map.\n" , (target) ? :"kernel" );return -EINVAL ; } available_func_filter = _filter;
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. 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:"[email protected]"> [email protected] </a>
PATCH v7 23/30 perf: perf interface for uprobes
In reply to Srikar DronamrajuEnhances perf probe to user space executables and libraries. Provides very basic support for uprobes.
[ Probing a function in the executable using function name ]
-------------------------------------------------------------
[root@localhost ~]# perf probe -x /bin/zsh zfree Add new event:
probe_zsh:zfree (on /bin/zsh:0x45400)
You can now use it on all perf tools, such as:
perf record -e probe_zsh:zfree -aR sleep 1
[root@localhost ~]# perf record -e probe_zsh:zfree -aR sleep 15 [ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.314 MB perf.data (~13715 samples) ] [root@localhost ~]# perf report --stdio
# Events: 3K probe_zsh:zfree
#
# Overhead Command Shared Object Symbol # ........ ....... ............. ......
#
100.00% zsh zsh [.] zfree
#
# (For a higher level overview, try: perf report --sort comm,dso) #
[root@localhost ~]
[ Probing a library function using function name ]
--------------------------------------------------
[root@localhost]#
[root@localhost]# perf probe -x /lib64/libc.so.6 malloc Add new event: probe_libc:malloc (on /lib64/libc-2.5.so:0x74dc0)
You can now use it on all perf tools, such as:
perf record -e probe_libc:malloc -aR sleep 1
[root@localhost]#
[root@localhost]# perf probe --list probe_libc:malloc (on /lib64/libc-2.5.so:0x0000000000074dc0)
---
(Changelog (since v5)
- Removed the separate documentation change patch and added the documentation changes as part of this patch.
tools/perf/Documentation/perf-probe.txt | 12 + tools/perf/builtin-probe.c | 37 +++ tools/perf/util/probe-event.c | 348 +++++++++++++++++++++++++------ tools/perf/util/probe-event.h | 8 - tools/perf/util/symbol.c | 8 + tools/perf/util/symbol.h | 1 6 files changed, 336 insertions(+), 78 deletions(-)
tools/perf/Documentation/perf-probe.txt +12 -0
@@ -98,6 +98,11 @@ OPTIONS --max-probes:: Set the maximum number of probe points for an event. Default is 128. +-x:: +--exec=PATH:: + Specify path to the executable or shared library file for user + space tracing. + PROBE SYNTAX ------------ Probe points are defined by following syntax.
@@ -182,6 +187,13 @@ Delete all probes on schedule(). ./perf probe --del='schedule*' +Add probes at zfree() function on /bin/zsh + + ./perf probe -x /bin/zsh zfree + +Add probes at malloc() function on libc + + ./perf probe -x /lib/libc.so.6 malloc SEE ALSO --------
tools/perf/builtin-probe.c +33 -4
@@ -57,6 +57,7 @@ static struct {bool show_ext_vars;bool show_funcs;bool mod_events; +bool uprobes;int nevents;struct perf_probe_event events[MAX_PROBES ];struct strlist *dellist;
@@ -78,6 +79,7 @@ static int parse_probe_event(const char *str)return -1 ; } + pev->uprobes = params.uprobes;/* Parse a perf-probe command into event */ ret =parse_perf_probe_command (str, pev);pr_debug ("%d arguments\n" , pev->nargs);
@@ -128,6 +130,27 @@ static int opt_del_probe_event(const struct option *opt __used,return 0 ; } +static int opt_set_target (const struct option *opt,const char *str, +int unset__used ) +{ +int ret = -ENOENT ; + +if (str && !params.target) { +if (!strcmp (opt->long_name,"exec" )) + params.uprobes = true; +#ifdef DWARF_SUPPORT + else if (!strcmp(opt->long_name, "module")) + params.uprobes = false; +#endif + else + return ret; + + params.target = str; + ret =0 ; + } +return ret; +} +#ifdef DWARF_SUPPORT static int opt_show_lines (const struct option *opt__used ,const char *str,int unset__used )
@@ -249,9 +272,9 @@ static const struct option options[] = { "file", "vmlinux pathname"),OPT_STRING ('s' ,"source" , &symbol_conf.source_prefix,"directory" ,"path to kernel source" ), -OPT_STRING ('m' ,"module" , ¶ms.target, -"modname|path" , -"target module name (for online) or path (for offline)" ), +OPT_CALLBACK ('m' ,"module" ,NULL ,"modname|path" , +"target module name (for online) or path (for offline)" , + opt_set_target), #endifOPT__DRY_RUN (&probe_event_dry_run), OPT_INTEGER('\0', "max-probes", ¶ms.max_probe_points,
@@ -263,6 +286,8 @@ static const struct option options[] = { "\t\t\t(default: \"" DEFAULT_VAR_FILTER "\" for --vars,\n" "\t\t\t \"" DEFAULT_FUNC_FILTER "\" for --funcs)", opt_set_filter), + OPT_CALLBACK('x', "exec", NULL, "executable|path", + "target executable name or path", opt_set_target), OPT_END() };
@@ -313,6 +338,10 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)pr_err (" Error: Don't use --list with --funcs.\n" );usage_with_options (probe_usage, options); } +if (params.uprobes) { +pr_warning (" Error: Don't use --list with --exec.\n" ); +usage_with_options (probe_usage, options); + } ret =show_perf_probe_events ();if (ret <0 ) pr_err(" Error: Failed to show event list. (%d)\n",
@@ -346,7 +375,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used) }#ifdef DWARF_SUPPORT -if (params.show_lines) { +if (params.show_lines && !params.uprobes) {if (params.mod_events) {pr_err (" Error: Don't use --line with" " --add/--del.\n" );
tools/perf/util/probe-event.c +277 -71
552 lines not on this page · raw message
tools/perf/util/probe-event.h +5 -3
@@ -7,7 +7,7 @@extern bool probe_event_dry_run; -/* kprobe-tracer tracing point */ +/* kprobe-tracer and uprobe-tracer tracing point */ struct probe_trace_point {char *symbol;/* Base symbol */ char *module;/* Module name */
@@ -21,7 +21,7 @@ struct probe_trace_arg_ref {long offset;/* Offset value */ }; -/* kprobe-tracer tracing argument */ +/* kprobe-tracer and uprobe-tracer tracing argument */ struct probe_trace_arg {char *name;/* Argument name */ char *value;/* Base value */
@@ -29,12 +29,13 @@ struct probe_trace_arg {struct probe_trace_arg_ref *ref;/* Referencing offset */ }; -/* kprobe-tracer tracing event (point + arg) */ +/* kprobe-tracer and uprobe-tracer tracing event (point + arg) */ struct probe_trace_event {char *event;/* Event name */ char *group;/* Group name */ struct probe_trace_point point;/* Trace point */ int nargs;/* Number of args */ +bool uprobes;/* uprobes only */ struct probe_trace_arg *args;/* Arguments */ };
@@ -70,6 +71,7 @@ struct perf_probe_event {char *group;/* Group name */ struct perf_probe_point point;/* Probe point */ int nargs;/* Number of arguments */ +bool uprobes;struct perf_probe_arg *args;/* Arguments */ };
tools/perf/util/symbol.c +8 -0
@@ -2767,3 +2767,11 @@ int machine__load_vmlinux_path(struct machine *machine, enum map_type type,return ret; } + +struct map *dso__new_map (const char *name) +{ +struct dso *dso =dso__new (name); +struct map *map =map__new2 (0 , dso,MAP__FUNCTION ); + +return map; +}
tools/perf/util/symbol.h +1 -0
@@ -217,6 +217,7 @@ void dso__set_long_name(struct dso *dso, char *name);void dso__set_build_id (struct dso *dso,void *build_id);void dso__read_running_kernel_build_id (struct dso *dso,struct machine *machine); +struct map *dso__new_map (const char *name);struct symbol *dso__find_symbol (struct dso *dso,enum map_type type,u64 addr); struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type,
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. 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:"[email protected]"> [email protected] </a>
PATCH v7 24/30 perf: show possible probes in a given executable file or library.
In reply to Srikar DronamrajuEnhances -F/--funcs option of "perf probe" to list possible probe points in an executable file or library.
Show last 10 functions in /bin/zsh.
# perf probe -F -x /bin/zsh | tail zstrtol ztrcmp ztrdup ztrduppfx ztrftime ztrlen ztrncpy ztrsub zwarn zwarnnam
Show first 10 functions in /lib/libc.so.6
# perf probe -F -x /lib/libc.so.6 | head _IO_adjust_column _IO_adjust_wcolumn _IO_default_doallocate _IO_default_finish _IO_default_pbackfail _IO_default_uflow _IO_default_xsgetn _IO_default_xsputn _IO_do_write@@GLIBC_2.2.5 _IO_doallocbuf
---
(Changelog (since v5)
- Removed the separate documentation change patch and added the documentation changes as part of this patch.
tools/perf/Documentation/perf-probe.txt | 4 ++ tools/perf/builtin-probe.c | 4 +- tools/perf/util/probe-event.c | 55 ++++++++++++++++++++++++------- tools/perf/util/probe-event.h | 4 +- 4 files changed, 49 insertions(+), 18 deletions(-)
tools/perf/Documentation/perf-probe.txt +3 -1
@@ -78,6 +78,8 @@ OPTIONS -F:: --funcs:: Show available functions in given module or kernel. + With -x/--exec, can also list functions in a user space executable + / shared library. --filter=FILTER:: (Only for --vars and --funcs) Set filter. FILTER is a combination of glob
@@ -101,7 +103,7 @@ OPTIONS -x:: --exec=PATH:: Specify path to the executable or shared library file for user - space tracing. + space tracing. Can also be used with --funcs option. PROBE SYNTAX ------------
tools/perf/builtin-probe.c +2 -2
@@ -365,8 +365,8 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)if (!params.filter) params.filter =strfilter__new (DEFAULT_FUNC_FILTER ,NULL ); - ret =show_available_funcs (params.target, - params.filter); + ret =show_available_funcs (params.target, params.filter, + params.uprobes);strfilter__delete (params.filter);if (ret <0 ) pr_err(" Error: Failed to show functions."
tools/perf/util/probe-event.c +42 -13
80 lines not on this page · raw message
tools/perf/util/probe-event.h +2 -2
@@ -131,8 +131,8 @@ extern int show_line_range(struct line_range *lr, const char *module);extern int show_available_vars (struct perf_probe_event *pevs,int npevs,int max_probe_points,const char *module,struct strfilter *filter,bool externs); -extern int show_available_funcs (const char *module,struct strfilter *filter); - +extern int show_available_funcs (const char *module,struct strfilter *filter, +bool user);/* Maximum index number of event-name postfix */ #define MAX_EVENT_INDEX 1024
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. 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:"[email protected]"> [email protected] </a>
PATCH v7 25/30 uprobes: call post_xol() unconditionally
In reply to Srikar DronamrajuKill sstep_complete(), change uprobe_notify_resume() to use post_xol() unconditionally.
It is wrong to assume that regs->ip always changes after the step. rep or jmp/call to self for example. We know that this task has already done the step, we can rely on DIE_DEBUG notification.
Original-patch-from: Oleg Nesterov <[email protected]>
--- include/linux/uprobes.h | 3 ++- kernel/uprobes.c | 38 ++++++++++++-------------------------- 2 files changed, 14 insertions(+), 27 deletions(-)
include/linux/uprobes.h +2 -1
@@ -74,7 +74,8 @@ struct uprobe {enum uprobe_task_state {UTASK_RUNNING ,UTASK_BP_HIT , -UTASK_SSTEP +UTASK_SSTEP , +UTASK_SSTEP_ACK , };/*
kernel/uprobes.c +12 -26
@@ -1313,24 +1313,6 @@ static int pre_ssout(struct uprobe *uprobe, struct pt_regs *regs, }/* -* Verify from Instruction Pointer if singlestep has indeed occurred. -* If Singlestep has occurred, then do post singlestep fix-ups. -*/ -static bool sstep_complete (struct uprobe *uprobe,struct pt_regs *regs) -{ -unsigned long vaddr =instruction_pointer (regs); - -/* -* If we have executed out of line, Instruction pointer -* cannot be same as virtual address of XOL slot. -*/ -if (vaddr == current->utask->xol_vaddr) -return false; -post_xol (uprobe, regs); -return true; -} - -/* * uprobe_notify_resume gets called in task context just before returning * to userspace. *
@@ -1377,15 +1359,18 @@ void uprobe_notify_resume(struct pt_regs *regs)else /* Cannot Singlestep; re-execute the instruction. */ goto cleanup_ret; - }else if (utask->state ==UTASK_SSTEP ) { + }else { u = utask->active_uprobe; -if (sstep_complete (u, regs)) { -put_uprobe (u); - utask->active_uprobe =NULL ; - utask->state =UTASK_RUNNING ; -user_disable_single_step (current); -xol_free_insn_slot (current); - } +if (utask->state ==UTASK_SSTEP_ACK ) +post_xol (u, regs); +else +WARN_ON_ONCE (1 ); + +put_uprobe (u); + utask->active_uprobe =NULL ; + utask->state =UTASK_RUNNING ; +user_disable_single_step (current); +xol_free_insn_slot (current); }return ;
@@ -1435,6 +1420,7 @@ int uprobe_post_notifier(struct pt_regs *regs)/* task is currently not uprobed */ return 0 ; + utask->state =UTASK_SSTEP_ACK ;set_thread_flag (TIF_UPROBE );return 1 ; }
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. 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:"[email protected]"> [email protected] </a>
PATCH v7 26/30 uprobes: introduce uprobe_deny_signal()
In reply to Srikar DronamrajuA not-UTASK_RUNNING task obviously can't handle the signals, neither it should stop/freeze/etc. It must not even exit if it was SIGKILL'ed
This patch adds the new hook, uprobe_deny_signal(), called by get_signal_to_deliver(). It simply clears TIF_SIGPENDING to ensure that this thread can do nothing connected to signals until it becomes UTASK_RUNNING.
We also change post_xol() path to do recalc_sigpending() before return to user-mode, this ensures the signal can't be lost.
Original-patch-from: Oleg Nesterov <[email protected]>
--- include/linux/uprobes.h | 5 +++++ kernel/signal.c | 3 +++ kernel/uprobes.c | 23 +++++++++++++++++++++++ 3 files changed, 31 insertions(+), 0 deletions(-)
include/linux/uprobes.h +5 -0
@@ -129,6 +129,7 @@ extern unsigned long __weak get_uprobe_bkpt_addr(struct pt_regs *regs);extern int uprobe_post_notifier (struct pt_regs *regs);extern int uprobe_bkpt_notifier (struct pt_regs *regs);extern void uprobe_notify_resume (struct pt_regs *regs); +extern bool uprobe_deny_signal (void );#else /* CONFIG_UPROBES is not defined */ static inline int register_uprobe (struct inode *inode,loff_t offset,struct uprobe_consumer *consumer)
@@ -149,6 +150,10 @@ static inline void munmap_uprobe(struct vm_area_struct *vma)static inline void uprobe_notify_resume (struct pt_regs *regs) { } +static inline bool uprobe_deny_signal (void ) +{ +return false; +}static inline unsigned long get_uprobe_bkpt_addr (struct pt_regs *regs) {return 0 ;
kernel/signal.c +3 -0
@@ -2149,6 +2149,9 @@ int get_signal_to_deliver(siginfo_t *info, struct k_sigaction *return_ka,struct signal_struct *signal = current->signal;int signr; +if (unlikely (uprobe_deny_signal ())) +return 0 ; + relock:/* * We'll jump back here after any time we were stopped in TASK_STOPPED.
kernel/uprobes.c +23 -0
@@ -1312,6 +1312,25 @@ static int pre_ssout(struct uprobe *uprobe, struct pt_regs *regs,return -EFAULT ; } +bool uprobe_deny_signal (void ) +{ +struct task_struct *tsk = current; +struct uprobe_task *utask = tsk->utask; + +if (likely (!utask || !utask->active_uprobe)) +return false; + +WARN_ON_ONCE (utask->state !=UTASK_SSTEP ); + +if (signal_pending (tsk)) { +spin_lock_irq (&tsk->sighand->siglock); +clear_tsk_thread_flag (tsk,TIF_SIGPENDING ); +spin_unlock_irq (&tsk->sighand->siglock); + } + +return true; +} +/* * uprobe_notify_resume gets called in task context just before returning * to userspace.
@@ -1371,6 +1390,10 @@ void uprobe_notify_resume(struct pt_regs *regs) utask->state =UTASK_RUNNING ;user_disable_single_step (current);xol_free_insn_slot (current); + +spin_lock_irq (¤t->sighand->siglock); +recalc_sigpending ();/* see uprobe_deny_signal() */ +spin_unlock_irq (¤t->sighand->siglock); }return ;
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. 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:"[email protected]"> [email protected] </a>
PATCH v7 27/30 uprobes: x86: introduce xol_was_trapped()
In reply to Srikar DronamrajuPostpone the signals until we execute the probed insn. This is simply wrong if xol insn traps and generates the signal itself. Say, SIGILL/SIGSEGV/etc.
Adds xol_was_trapped() to detect this case. It assumes that anything like do_page_fault/do_trap/etc sets thread.trap_no != -1.
We add uprobe_task_arch_info->saved_trap_no and change pre_xol/post_xol to save/restore thread.trap_no, xol_was_trapped() simply checks that ->trap_no is not equal to UPROBE_TRAP_NO == -1 set by pre_xol().
Original-patch-from: Oleg Nesterov <[email protected]>
---
Changelog (since v6)
- added x86 specific hook for aborting xol.
arch/x86/include/asm/uprobes.h | 7 ++++++- arch/x86/kernel/uprobes.c | 33 ++++++++++++++++++++++++++++++++- 2 files changed, 38 insertions(+), 2 deletions(-)
arch/x86/include/asm/uprobes.h +6 -1
@@ -39,16 +39,21 @@ struct uprobe_arch_info {struct uprobe_task_arch_info {unsigned long saved_scratch_register; +unsigned long saved_trap_no; };#else struct uprobe_arch_info {}; -struct uprobe_task_arch_info {}; +struct uprobe_task_arch_info { +unsigned long saved_trap_no; +};#endif struct uprobe ;extern int analyze_insn (struct mm_struct *mm,struct uprobe *uprobe);extern void set_instruction_pointer (struct pt_regs *regs,unsigned long vaddr);extern int pre_xol (struct uprobe *uprobe,struct pt_regs *regs);extern int post_xol (struct uprobe *uprobe,struct pt_regs *regs); +extern bool xol_was_trapped (struct task_struct *tsk);extern int uprobe_exception_notify (struct notifier_block *self,unsigned long val,void *data); +extern void abort_xol (struct pt_regs *regs,struct uprobe *uprobe);#endif /* _ASM_UPROBES_H */
arch/x86/kernel/uprobes.c +32 -1
@@ -409,6 +409,8 @@ void set_instruction_pointer(struct pt_regs *regs, unsigned long vaddr) regs->ip = vaddr; } +#define UPROBE_TRAP_NO -1ul +/* * pre_xol - prepare to execute out of line. * @uprobe: the probepoint information.
@@ -424,6 +426,9 @@ int pre_xol(struct uprobe *uprobe, struct pt_regs *regs) {struct uprobe_task_arch_info *tskinfo = ¤t->utask->tskinfo; + tskinfo->saved_trap_no = current->thread.trap_no; + current->thread.trap_no =UPROBE_TRAP_NO ; + regs->ip = current->utask->xol_vaddr;if (uprobe->fixups &UPROBES_FIX_RIP_AX ) { tskinfo->saved_scratch_register = regs->ax;
@@ -439,6 +444,11 @@ int pre_xol(struct uprobe *uprobe, struct pt_regs *regs)#else int pre_xol (struct uprobe *uprobe,struct pt_regs *regs) { +struct uprobe_task_arch_info *tskinfo = ¤t->utask->tskinfo; + + tskinfo->saved_trap_no = current->thread.trap_no; + current->thread.trap_no =UPROBE_TRAP_NO ; + regs->ip = current->utask->xol_vaddr;return 0 ; }
@@ -494,7 +504,8 @@ static void handle_riprel_post_xol(struct uprobe *uprobe,* Fall through to handle stuff like "jmpq *...(%rip)" and * "callq *...(%rip)". */ - *correction += 4; +if (correction) + *correction += 4; } }#else
@@ -504,6 +515,14 @@ static void handle_riprel_post_xol(struct uprobe *uprobe, }#endif +bool xol_was_trapped (struct task_struct *tsk) +{ +if (tsk->thread.trap_no !=UPROBE_TRAP_NO ) +return true; + +return false; +} +/* * Called after single-stepping. To avoid the SMP problems that can * occur when we temporarily put back the original opcode to
@@ -534,6 +553,9 @@ int post_xol(struct uprobe *uprobe, struct pt_regs *regs)int result =0 ;long correction; +WARN_ON_ONCE (current->thread.trap_no !=UPROBE_TRAP_NO ); + + current->thread.trap_no = utask->tskinfo.saved_trap_no; correction = (long )(utask->vaddr - utask->xol_vaddr);handle_riprel_post_xol (uprobe, regs, &correction);if (uprobe->fixups &UPROBES_FIX_IP )
@@ -571,3 +593,12 @@ int uprobe_exception_notify(struct notifier_block *self, }return ret; } + +void abort_xol (struct pt_regs *regs,struct uprobe *uprobe) +{ +struct uprobe_task *utask = current->utask; + + current->thread.trap_no = utask->tskinfo.saved_trap_no; +handle_riprel_post_xol (uprobe, regs,NULL ); +set_instruction_pointer (regs, utask->vaddr); +}
PATCH v7 28/30 uprobes: introduce UTASK_SSTEP_TRAPPED logic
In reply to Srikar DronamrajuAdd UTASK_SSTEP_TRAPPED state/code to handle the case when xol insn itself triggers the signal.
In this case we should restart the original insn even if the task is already SIGKILL'ed (say, the coredump should report the correct ip). This is even more important if the task has a handler for SIGSEGV/etc, The _same_ instruction should be repeated again after return from the signal handler, and SSTEP can never finish in this case.
Change uprobe_deny_signal() to set UTASK_SSTEP_TRAPPED and TIF_UPROBE. It also sets TIF_NOTIFY_RESUME.
When uprobe_notify_resume() sees UTASK_SSTEP_TRAPPED it does abort_xol() instead of post_xol().
Original-patch-from: Oleg Nesterov <[email protected]>
---
Changelog (since v6)
- abort_xol moved to previous patch.
include/linux/uprobes.h | 1 + kernel/uprobes.c | 13 ++++++++++--- 2 files changed, 11 insertions(+), 3 deletions(-)
include/linux/uprobes.h +1 -0
@@ -76,6 +76,7 @@ enum uprobe_task_state {UTASK_BP_HIT ,UTASK_SSTEP ,UTASK_SSTEP_ACK , + UTASK_SSTEP_TRAPPED, };/*
kernel/uprobes.c +10 -3
@@ -1326,6 +1326,12 @@ bool uprobe_deny_signal(void)spin_lock_irq (&tsk->sighand->siglock);clear_tsk_thread_flag (tsk,TIF_SIGPENDING );spin_unlock_irq (&tsk->sighand->siglock); + +if (__fatal_signal_pending (tsk) ||xol_was_trapped (tsk)) { + utask->state =UTASK_SSTEP_TRAPPED ; +set_tsk_thread_flag (tsk,TIF_UPROBE ); +set_tsk_thread_flag (tsk,TIF_NOTIFY_RESUME ); + } }return true;
@@ -1382,6 +1388,8 @@ void uprobe_notify_resume(struct pt_regs *regs) u = utask->active_uprobe;if (utask->state ==UTASK_SSTEP_ACK )post_xol (u, regs); +else if (utask->state ==UTASK_SSTEP_TRAPPED ) +abort_xol (regs, u);else WARN_ON_ONCE (1 );
@@ -1405,9 +1413,8 @@ void uprobe_notify_resume(struct pt_regs *regs)if (u) {put_uprobe (u);set_instruction_pointer (regs, probept); - }else { -/*TODO Return SIGTRAP signal */ - } + }else +send_sig (SIGTRAP , current,0 ); }/*
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. 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:"[email protected]"> [email protected] </a>
PATCH v7 29/30 uprobes: Introduce uprobe flags
In reply to Srikar DronamrajuWhile registering a probe, there is a timelag between the time the register request is given all probes are inserted in different processes. If the probe register fails after inserting a probe in couple of processes; the installed probes are reverted. However the probes could have hit and triggered handler before the probes are reverted.
Avoids running the handler until the register is complete or as soon as the last unregister kicks in.
Also this patch
- enables skipping singlestep where possible.
- uses a flag to denote if a copy of instruction is made.
--- include/linux/uprobes.h | 11 ++++++++++- kernel/uprobes.c | 32 ++++++++++++++++++++++++++------ 2 files changed, 36 insertions(+), 7 deletions(-)
include/linux/uprobes.h +10 -1
@@ -46,6 +46,14 @@ struct uprobe_task_arch_info {}; /* arch specific task info *//* Adjust the return address of a call insn */ #define UPROBES_FIX_CALL 0x2 +/* flags that denote/change uprobes behaviour */ +/* Have a copy of original instruction */ +#define UPROBES_COPY_INSN 0x1 +/* Dont run handlers when first register/ last unregister in progress*/ +#define UPROBES_RUN_HANDLER 0x2 +/* Can skip singlestep */ +#define UPROBES_SKIP_SSTEP 0x4 +struct uprobe_consumer {int (*handler)(struct uprobe_consumer *self,struct pt_regs *regs);/*
@@ -66,7 +74,7 @@ struct uprobe {struct uprobe_consumer *consumers;struct inode *inode;/* Also hold a ref to inode */ loff_t offset; -int copy; +int flags;u16 fixups;u8 insn[MAX_UINSN_BYTES ]; };
@@ -131,6 +139,7 @@ extern int uprobe_post_notifier(struct pt_regs *regs);extern int uprobe_bkpt_notifier (struct pt_regs *regs);extern void uprobe_notify_resume (struct pt_regs *regs);extern bool uprobe_deny_signal (void ); +extern bool __weak can_skip_xol (struct pt_regs *regs,struct uprobe *u);#else /* CONFIG_UPROBES is not defined */ static inline int register_uprobe (struct inode *inode,loff_t offset,struct uprobe_consumer *consumer)
kernel/uprobes.c +26 -6
@@ -436,6 +436,9 @@ static struct uprobe *insert_uprobe(struct uprobe *uprobe)spin_lock_irqsave (&uprobes_treelock, flags); u =__insert_uprobe (uprobe);spin_unlock_irqrestore (&uprobes_treelock, flags); + +/* For now assume that the instruction need not be single-stepped */ + uprobe->flags |=UPROBES_SKIP_SSTEP ;return u; }
@@ -475,6 +478,9 @@ static void handler_chain(struct uprobe *uprobe, struct pt_regs *regs) {struct uprobe_consumer *consumer; +if (!(uprobe->flags &UPROBES_RUN_HANDLER )) +return ; +down_read (&uprobe->consumer_rwsem); consumer = uprobe->consumers; for (consumer = uprobe->consumers; consumer;
@@ -594,7 +600,7 @@ static int install_breakpoint(struct mm_struct *mm, struct uprobe *uprobe,return -EEXIST ; addr = (unsigned long )vaddr; -if (!uprobe->copy) { +if (!(uprobe->flags &UPROBES_COPY_INSN )) { ret =copy_insn (uprobe, vma, addr);if (ret)return ret;
@@ -606,7 +612,7 @@ static int install_breakpoint(struct mm_struct *mm, struct uprobe *uprobe,if (ret)return ret; - uprobe->copy =1 ; + uprobe->flags |=UPROBES_COPY_INSN ; } ret =set_bkpt (mm, uprobe, addr);if (!ret)
@@ -850,7 +856,8 @@ int register_uprobe(struct inode *inode, loff_t offset,if (ret) { uprobe->consumers =NULL ;__unregister_uprobe (inode, offset, uprobe); - } + }else + uprobe->flags |=UPROBES_RUN_HANDLER ; }mutex_unlock (uprobes_hash (inode));
@@ -886,9 +893,10 @@ void unregister_uprobe(struct inode *inode, loff_t offset, goto unreg_out; } -if (!uprobe->consumers) +if (!uprobe->consumers) {__unregister_uprobe (inode, offset, uprobe); - + uprobe->flags &= ~UPROBES_RUN_HANDLER ; + }mutex_unlock (uprobes_hash (inode)); unreg_out:
@@ -1337,6 +1345,12 @@ bool uprobe_deny_signal(void)return true; } +bool __weak can_skip_xol (struct pt_regs *regs,struct uprobe *u) +{ + u->flags &= ~UPROBES_SKIP_SSTEP ; +return false; +} +/* * uprobe_notify_resume gets called in task context just before returning * to userspace.
@@ -1378,6 +1392,10 @@ void uprobe_notify_resume(struct pt_regs *regs) } utask->active_uprobe = u;handler_chain (u, regs); + +if (u->flags &UPROBES_SKIP_SSTEP &&can_skip_xol (regs, u)) + goto cleanup_ret; + utask->state =UTASK_SSTEP ;if (!pre_ssout (u, regs, probept))user_enable_single_step (current);
@@ -1411,8 +1429,10 @@ void uprobe_notify_resume(struct pt_regs *regs) utask->state =UTASK_RUNNING ; }if (u) { +if (!(u->flags &UPROBES_SKIP_SSTEP )) +set_instruction_pointer (regs, probept); +put_uprobe (u); -set_instruction_pointer (regs, probept); }else send_sig (SIGTRAP , current,0 ); }
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. 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:"[email protected]"> [email protected] </a>
PATCH v7 30/30 x86: skip singlestep where possible
In reply to Srikar DronamrajuCheck and skip singlestepping underlying instructions where possible.
For now handles single byte as well as few multibyte nop instructions. However can be extended to other instructions too.
--- arch/x86/kernel/uprobes.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 44 insertions(+), 0 deletions(-)
arch/x86/kernel/uprobes.c +44 -0
@@ -602,3 +602,47 @@ void abort_xol(struct pt_regs *regs, struct uprobe *uprobe)handle_riprel_post_xol (uprobe, regs,NULL );set_instruction_pointer (regs, utask->vaddr); } + +/* +* Skip these instructions: +* +* 0f 19 90 90 90 90 90 nopl -0x6f6f6f70(%rax) +* 0f 1f 00 nopl (%rax) +* 0f 1f 40 00 nopl 0x0(%rax) +* 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1) +* 0f 1f 80 00 00 00 00 nopl 0x0(%rax) +* 0f 1f 84 00 00 00 00 nopl 0x0(%rax,%rax,1) +* 66 0f 1f 44 00 00 00 nopw 0x0(%rax,%rax,1) +* 66 0f 1f 84 00 00 00 nopw 0x0(%rax,%rax,1) +* 66 87 c0 xchg %eax,%eax +* 66 90 nop +* 87 c0 xchg %eax,%eax +* 90 nop +*/ + +bool can_skip_xol (struct pt_regs *regs,struct uprobe *u) +{ +int i; + +for (i =0 ; i <MAX_UINSN_BYTES ; i++) { +if ((u->insn[i] ==0x66 )) +continue ; + +if (u->insn[i] ==0x90 ) +return true; + +if ((u->insn[i] ==0x0f ) && (u->insn[i+1 ] ==0x1f )) +return true; + +if ((u->insn[i] ==0x0f ) && (u->insn[i+1 ] ==0x19 )) +return true; + +if ((u->insn[i] ==0x87 ) && (u->insn[i+1 ] ==0xc0 )) +return true; + +break ; + } + + u->flags &= ~UPROBES_SKIP_SSTEP ; +return false; +}
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. 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:"[email protected]"> [email protected] </a>
Hi Ingo, Thomas, Linus, Stephen, Peter,
Quoted 15 lines
This patchset resolves most of the comments on the previous posting
(https://lkml.org/lkml/2011/11/10/408) patchset applies on top of commitcfcfc9eca2bThis patchset depends on bulkref patch from Paul McKenney
https://lkml.org/lkml/2011/11/2/365 and enable interrupts before callingdo_notify_resumeon i686 patch
https://lkml.org/lkml/2011/10/25/265.uprobes git is hosted at
git://github.com/srikard/linux.git
with branchinode_uprobes_v32rc2.
(The previous patchset posted to lkml has been rebased to 3.2-rc2 is also available at branchinode_uprobes_v32rc2_prev. This is to help the reviewers of the previous patchsets to quickly identify the changes.)
Quoted 3 lines
Uprobes Patches
This patchset implements inode based uprobes which are specified as <file>:<offset> where offset is the offset from start of the map.
Given that uprobes has been reviewed several times on LKML and all comments till now have been addressed, can we push uprobes into either -tip or -next. This will help people to test and give more feedback and also provide a way for it to be pushed into 3.3. This also helps in resolving and pushing fixes faster.
If you have concerns, can you please voice them?
Signature · 2 lines
Thanks and Regards Srikar
Hi Srikar,
Quoted 9 lines · On Tue, 22 Nov 2011 10:33:30 +0530 Srikar Dronamraju…
Quoted 3 lines
uprobes git is hosted at
git://github.com/srikard/linux.git
with branchinode_uprobes_v32rc2.Given that uprobes has been reviewed several times on LKML and all comments till now have been addressed, can we push uprobes into either -tip or -next. This will help people to test and give more feedback and also provide a way for it to be pushed into 3.3. This also helps in resolving and pushing fixes faster.
OK, I have added that to linux-next with you as the contact,
Quoted 1 line
If you have concerns, can you please voice them?
You should tidy up the commit messages (they almost all have really bad short descriptions) and make sure that the authorship is correct in all cases.
Also, I would prefer a less version specific branch name (like "for-next" or something) that way you won't have to keep asking me to change it over time. If there is any way you can host this on kernel.org, that will make the merging into Linus' tree a bit smoother.
Thanks for adding your subsystem tree as a participant of linux-next. As you may know, this is not a judgment of your code. The purpose of linux-next is for integration testing and to lower the impact of conflicts between subsystems in the next merge window.
You will need to ensure that the patches/commits in your tree/series have been:
* submitted under GPL v2 (or later) and include the Contributor's Signed-off-by,
* posted to the relevant mailing list,
* reviewed by you (or another maintainer of your subsystem tree),
* successfully unit tested, and
* destined for the current or next Linux merge window.
Basically, this should be just what you would send to Linus (or ask him to fetch). It is allowed to be rebased if you deem it necessary.
Signature · 15 lines
Cheers, Stephen Rothwell [email protected] Legal Stuff: By participating in linux-next, your subsystem tree contributions are public and will be included in the linux-next trees. You may be sent e-mail messages indicating errors or other issues when the patches/commits from your subsystem tree are merged and tested in linux-next. These messages may also be cross-posted to the linux-next mailing list, the linux-kernel mailing list, etc. The linux-next tree project and IBM (my employer) make no warranties regarding the linux-next project, the testing procedures, the results, the e-mails, etc. If you don't agree to these ground rules, let me know and I'll remove your tree from participation in linux-next.
Hi Stephen,
Quoted 10 lines
Quoted 8 lines
Quoted 2 lines
uprobes git is hosted at
git://github.com/srikard/linux.git
with branchinode_uprobes_v32rc2.Given that uprobes has been reviewed several times on LKML and all comments till now have been addressed, can we push uprobes into either -tip or -next. This will help people to test and give more feedback and also provide a way for it to be pushed into 3.3. This also helps in resolving and pushing fixes faster.
OK, I have added that to linux-next with you as the contact,
Thanks a lot for adding uprobes to linux-next.
I am already getting feedback on things to improve.
Quoted 7 lines
Quoted 2 lines
If you have concerns, can you please voice them?
You should tidy up the commit messages (they almost all have really bad short descriptions) and make sure that the authorship is correct in all cases.
I have relooked at the commit messages.
Have also resolve Dan Carpenter's comments on git log --oneline not showing properly.
Quoted 4 lines
Also, I would prefer a less version specific branch name (like "for-next" or something) that way you won't have to keep asking me to change it over time. If there is any way you can host this on kernel.org, that will make the merging into Linus' tree a bit smoother.
I have created a for-next branch at git://github.com/srikard/linux.git.
My kernel.org account isnt re-activated yet because I still need to complete key-signing. I will try to get that done at the earliest. Till then, I would have to host on github.
Please do let me know if there is anything that I have missed out.
Signature · 9 lines
Thanks and Regards Srikar -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. 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:"[email protected]"> [email protected] </a>
Hi Srikar,
Quoted 4 lines · On Wed, 23 Nov 2011 18:50:51 +0530 Srikar Dronamraju…
I have relooked at the commit messages.
Have also resolve Dan Carpenter's comments on git log --oneline not showing properly.
Looks better, thanks.
Quoted 1 line
I have created a for-next branch at
git://github.com/srikard/linux.git.
Thanks, I have switched to that.
Quoted 3 lines
My kernel.org account isnt re-activated yet because I still need to complete key-signing. I will try to get that done at the earliest. Till then, I would have to host on github.
That's ok.
Signature · 3 lines
Cheers, Stephen Rothwell [email protected] http://www.canb.auug.org.au/~sfr/
Oleg Nesterov
maintainercover uprobes: kill xol vma
In reply to Srikar DronamrajuHello.
On top of this series, not for inclusion yet, just to explain what I mean. May be someone can test it ;)
This series kills xol_vma. Instead we use the per_cpu-like xol slots.
This is much more simple and efficient. And this of course solves many problems we currently have with xol_vma.
For example, we simply can not trust it. We do not know what actually we are going to execute in UTASK_SSTEP mode. An application can unmap this area and then do mmap(PROT_EXEC|PROT_WRITE, MAP_FIXED) to fool uprobes.
The only disadvantage is that this adds a bit more arch-dependant code.
The main question, can this work? I know very little in this area. And I am not sure if this can be ported to other architectures.
Please comment.
Oleg.
arch/x86/include/asm/fixmap.h | 9 + arch/x86/include/asm/thread_info.h | 4 arch/x86/kernel/process.c | 6 arch/x86/kernel/uprobes.c | 26 +++- include/linux/mm_types.h | 1 include/linux/uprobes.h | 27 ---- kernel/fork.c | 2 kernel/uprobes.c | 239 +++---------------------------------- 8 files changed, 71 insertions(+), 243 deletions(-)
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. 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:"[email protected]"> [email protected] </a>
Oleg Nesterov
maintainerPATCH 1/5 uprobes: kill pre_ssout(), introduce set_xol_ip()
No functional changes, preparation.
- Do not change regs->ip in pre_xol().
- Kill pre_ssout(), move its code into the single caller.
- Add the new __weak helper, set_xol_ip(). Currently it simply does regs->ip = utask->xol_vaddr.
- Change uprobe_notify_resume() to do set_xol_ip() after pre_xol().
IOW, before this patch uprobe_notify_resume() does:
utask->state = UTASK_SSTEP; pre_ssout: xol_get_insn_slot(); pre_xol(); // <----- sets regs->ip user_enable_single_step(current);
after:
xol_get_insn_slot(); pre_xol(); // <------ doesn't change regs->ip user_enable_single_step(current); utask->state = UTASK_SSTEP; set_xol_ip(); // <----- sets regs->ip
--- arch/x86/kernel/uprobes.c | 2 -- include/linux/uprobes.h | 1 + kernel/uprobes.c | 27 +++++++++++++-------------- 3 files changed, 14 insertions(+), 16 deletions(-)
arch/x86/kernel/uprobes.c +0 -2
@@ -429,7 +429,6 @@ int pre_xol(struct uprobe *uprobe, struct pt_regs *regs) tskinfo->saved_trap_no = current->thread.trap_no; current->thread.trap_no =UPROBE_TRAP_NO ; - regs->ip = current->utask->xol_vaddr;if (uprobe->fixups &UPROBES_FIX_RIP_AX ) { tskinfo->saved_scratch_register = regs->ax; regs->ax = current->utask->vaddr;
@@ -449,7 +448,6 @@ int pre_xol(struct uprobe *uprobe, struct pt_regs *regs) tskinfo->saved_trap_no = current->thread.trap_no; current->thread.trap_no =UPROBE_TRAP_NO ; - regs->ip = current->utask->xol_vaddr; return 0; }#endif
include/linux/uprobes.h +1 -0
@@ -140,6 +140,7 @@ extern int uprobe_bkpt_notifier(struct pt_regs *regs);extern void uprobe_notify_resume (struct pt_regs *regs);extern bool uprobe_deny_signal (void );extern bool __weak can_skip_xol (struct pt_regs *regs,struct uprobe *u); +extern void __weak set_xol_ip (struct pt_regs *regs);#else /* CONFIG_UPROBES is not defined */ static inline int register_uprobe (struct inode *inode,loff_t offset,struct uprobe_consumer *consumer)
kernel/uprobes.c +13 -14
@@ -1311,15 +1311,6 @@ static struct uprobe_task *add_utask(void)return utask; } -/* Prepare to single-step probed instruction out of line. */ -static int pre_ssout (struct uprobe *uprobe,struct pt_regs *regs, -unsigned long vaddr) -{ -if (xol_get_insn_slot (uprobe, vaddr) && !pre_xol (uprobe, regs)) -return 0 ; -return -EFAULT ; -} -bool uprobe_deny_signal (void ) {struct task_struct *tsk = current;
@@ -1351,6 +1342,11 @@ bool __weak can_skip_xol(struct pt_regs *regs, struct uprobe *u)return false; } +void __weak set_xol_ip (struct pt_regs *regs) +{ +set_instruction_pointer (regs, current->utask->xol_vaddr); +} +/* * uprobe_notify_resume gets called in task context just before returning * to userspace.
@@ -1396,12 +1392,15 @@ void uprobe_notify_resume(struct pt_regs *regs)if (u->flags &UPROBES_SKIP_SSTEP &&can_skip_xol (regs, u)) goto cleanup_ret; - utask->state =UTASK_SSTEP ; -if (!pre_ssout (u, regs, probept)) -user_enable_single_step (current); -else -/* Cannot Singlestep; re-execute the instruction. */ +if (!xol_get_insn_slot (u, probept)) + goto cleanup_ret; + +if (pre_xol (u, regs)) goto cleanup_ret; + +user_enable_single_step (current); + utask->state =UTASK_SSTEP ; +set_xol_ip (regs); }else { u = utask->active_uprobe;if (utask->state ==UTASK_SSTEP_ACK )
Signature · 9 lines
1.5.5.1 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. 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:"[email protected]"> [email protected] </a>
Oleg Nesterov
maintainerPATCH 2/5 uprobes: introduce uprobe_switch_to()
In reply to Oleg NesterovIntroduce uprobe_switch_to(), it is called by switch_to() paths if the "next" task is going to execute the xol insn.
Currently we use TIF_SINGLESTEP (added to _TIF_WORK_CTXSW_NEXT) to detect this case in __switch_to_xtra() and call uprobe_switch_to(), may be we can add another flag.
uprobe_switch_to() verifies that this task is actually UTASK_SSTEP and X86_EFLAGS_TF is set.
Finally uprobe_switch_to() does set_xol_ip(). Currently this is not needed, but this means that set_xol_ip() is called every time the UTASK_SSTEP task migrates to another CPU.
To ensure set_xol_ip() can't race with itself we add preempt_disable() into another caller, uprobe_notify_resume().
Note! this patch assumes we can trust X86_EFLAGS_TF. I mean, afaiu even if the single-stepping insn races with irq/exception, this flag will be cleared if and only if this instruction was already executed.
--- arch/x86/include/asm/thread_info.h | 4 ++++ arch/x86/kernel/process.c | 6 ++++++ arch/x86/kernel/uprobes.c | 14 ++++++++++++++ include/linux/uprobes.h | 1 + kernel/uprobes.c | 2 ++ 5 files changed, 27 insertions(+), 0 deletions(-)
arch/x86/include/asm/thread_info.h +4 -0
@@ -150,7 +150,11 @@ struct thread_info { (_TIF_IO_BITMAP|_TIF_NOTSC|_TIF_BLOCKSTEP)#define _TIF_WORK_CTXSW_PREV (_TIF_WORK_CTXSW|_TIF_USER_RETURN_NOTIFY) +#ifdef CONFIG_UPROBES +#define _TIF_WORK_CTXSW_NEXT (_TIF_WORK_CTXSW|_TIF_DEBUG|_TIF_SINGLESTEP) +#else #define _TIF_WORK_CTXSW_NEXT (_TIF_WORK_CTXSW|_TIF_DEBUG) +#endif #define PREEMPT_ACTIVE 0x10000000
arch/x86/kernel/process.c +6 -0
@@ -229,6 +229,12 @@ void __switch_to_xtra(struct task_struct *prev_p, struct task_struct *next_p,*/ memset (tss->io_bitmap,0xff , prev->io_bitmap_max); } + +#ifdef CONFIG_UPROBES +if (test_tsk_thread_flag (next_p,TIF_SINGLESTEP )) +uprobe_switch_to (next_p); +#endif +propagate_user_return_notify (prev_p, next_p); }
arch/x86/kernel/uprobes.c +14 -0
@@ -452,6 +452,20 @@ int pre_xol(struct uprobe *uprobe, struct pt_regs *regs) }#endif +void uprobe_switch_to (struct task_struct *curr) +{ +struct uprobe_task *utask = curr->utask; +struct pt_regs *regs =task_pt_regs (curr); + +if (!utask || utask->state !=UTASK_SSTEP ) +return ; + +if (!(regs->flags &X86_EFLAGS_TF )) +return ; + +set_xol_ip (regs); +} +/* * Called by post_xol() to adjust the return address pushed by a call * instruction executed out of line.
include/linux/uprobes.h +1 -0
@@ -141,6 +141,7 @@ extern void uprobe_notify_resume(struct pt_regs *regs);extern bool uprobe_deny_signal (void );extern bool __weak can_skip_xol (struct pt_regs *regs,struct uprobe *u);extern void __weak set_xol_ip (struct pt_regs *regs); +extern void uprobe_switch_to (struct task_struct *);#else /* CONFIG_UPROBES is not defined */ static inline int register_uprobe (struct inode *inode,loff_t offset,struct uprobe_consumer *consumer)
kernel/uprobes.c +2 -0
@@ -1399,8 +1399,10 @@ void uprobe_notify_resume(struct pt_regs *regs) goto cleanup_ret;user_enable_single_step (current); +preempt_disable (); utask->state =UTASK_SSTEP ;set_xol_ip (regs); +preempt_enable (); }else { u = utask->active_uprobe;if (utask->state ==UTASK_SSTEP_ACK )
Signature · 9 lines
1.5.5.1 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. 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:"[email protected]"> [email protected] </a>
Peter Zijlstra
maintainerRe: [PATCH 2/5] uprobes: introduce uprobe_switch_to()
Quoted 16 lines · Oleg Nesterov
arch/x86/kernel/uprobes.c +13
-0+void uprobe_switch_to (struct task_struct *curr) +{ +struct uprobe_task *utask = curr->utask; +struct pt_regs *regs =task_pt_regs (curr); + +if (!utask || utask->state !=UTASK_SSTEP ) +return ; + +if (!(regs->flags &X86_EFLAGS_TF )) +return ; + +set_xol_ip (regs); +}void
__weakset_xol_ip(struct pt_regs *regs)
{
Review
Quoted 10 lines
(quoted diff) +9
-0+ int cpu = smp_processor_id(); + struct uprobe_task *utask = current->utask; + struct uprobe *uprobe = utask->active_uprobe; + + memcpy(uprobe_xol_slots[cpu], uprobe->insn, MAX_UINSN_BYTES); + + utask->xol_vaddr = fix_to_virt(UPROBE_XOL_FIRST_PAGE) + + UPROBES_XOL_SLOT_BYTES * cpu; + set_instruction_pointer(regs, utask->xol_vaddr); }
So uprobe_switch_to() will always reset the IP to the start of the slot? That sounds wrong, things like the RIP relative stuff needs multiple instructions.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. 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:"[email protected]"> [email protected] </a>
Oleg Nesterov
maintainerRe: [PATCH 2/5] uprobes: introduce uprobe_switch_to()
Quoted 16 lines · Peter Zijlstra
Quoted 13 lines · Oleg Nesterov
arch/x86/kernel/uprobes.c +13
-0+void uprobe_switch_to (struct task_struct *curr) +{ +struct uprobe_task *utask = curr->utask; +struct pt_regs *regs =task_pt_regs (curr); + +if (!utask || utask->state !=UTASK_SSTEP ) +return ; + +if (!(regs->flags &X86_EFLAGS_TF )) +return ; + +set_xol_ip (regs); +}
Quoted 16 lines
Review
Quoted 12 lines
void
__weakset_xol_ip(struct pt_regs *regs)
{(quoted diff) +9
-0+ int cpu = smp_processor_id(); + struct uprobe_task *utask = current->utask; + struct uprobe *uprobe = utask->active_uprobe; + + memcpy(uprobe_xol_slots[cpu], uprobe->insn, MAX_UINSN_BYTES); + + utask->xol_vaddr = fix_to_virt(UPROBE_XOL_FIRST_PAGE) + + UPROBES_XOL_SLOT_BYTES * cpu; + set_instruction_pointer(regs, utask->xol_vaddr); }So
uprobe_switch_to()will always reset the IP to the start of the slot? That sounds wrong, things like the RIP relative stuff needs multiple instructions.
Hmm. Could you explain? Especially the "multiple instructions" part.
In any case we should reset the IP to the start of the slot.
But yes, I'm afraid this is too simple. Before this patches pre_xol() is called when we already know ->xol_vaddr. But afaics x86 doesn't use this info (post_xol() does). So this looks equally correct or wrong.
But perhaps we need another arch-dependent hook which takes ->xol_vaddr into account instead of simple memcpy(), to handle the RIP relative case.
Or I misunderstood?
Peter, all, I apologize in advance, I can't be responsive today.
Oleg.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. 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:"[email protected]"> [email protected] </a>
Peter Zijlstra
maintainerRe: [PATCH 2/5] uprobes: introduce uprobe_switch_to()
Quoted 42 lines · Oleg Nesterov
Quoted 16 lines · Peter Zijlstra
Quoted 13 lines · Oleg Nesterov
arch/x86/kernel/uprobes.c +13
-0+void uprobe_switch_to (struct task_struct *curr) +{ +struct uprobe_task *utask = curr->utask; +struct pt_regs *regs =task_pt_regs (curr); + +if (!utask || utask->state !=UTASK_SSTEP ) +return ; + +if (!(regs->flags &X86_EFLAGS_TF )) +return ; + +set_xol_ip (regs); +}Quoted 16 lines
Review
Quoted 12 lines
void
__weakset_xol_ip(struct pt_regs *regs)
{(quoted diff) +9
-0+ int cpu = smp_processor_id(); + struct uprobe_task *utask = current->utask; + struct uprobe *uprobe = utask->active_uprobe; + + memcpy(uprobe_xol_slots[cpu], uprobe->insn, MAX_UINSN_BYTES); + + utask->xol_vaddr = fix_to_virt(UPROBE_XOL_FIRST_PAGE) + + UPROBES_XOL_SLOT_BYTES * cpu; + set_instruction_pointer(regs, utask->xol_vaddr); }So
uprobe_switch_to()will always reset the IP to the start of the slot? That sounds wrong, things like the RIP relative stuff needs multiple instructions.Hmm. Could you explain? Especially the "multiple instructions" part.
In any case we should reset the IP to the start of the slot.
But yes, I'm afraid this is too simple. Before this patches
pre_xol()is called when we already know ->xol_vaddr. But afaics x86 doesn't use this info (post_xol()does). So this looks equally correct or wrong.
Quoted 5 lines
But perhaps we need another arch-dependent hook which takes ->xol_vaddr into account instead of simple
memcpy(), to handle the RIP relative case.Or I misunderstood?
Suppose you need multiple instructions to replace the one you patched out, for example because the instruction was RIP relative (the effect relied on the IP the instruction is at, eg. short jumps instead of absolute jumps).
One way to translate these instructions is something like
push eax
mov eax, $previous_ip
$ins eax+offset
pop eax
Also, the thing Srikar mentioned is boosted probes, in that case you forgo the whole single step thing and rewrite the probe as:
$ins
jmp $next_insn
Now in the former case you still single step so the context switch hook can function as proposed (triggered off of TIF_SINGLESTEP). However if you get preempted after the mov you want to continue with the $ins, not restart at push. So uprobe_switch_to() will have to preserve the relative offset within the slot.
On the second example there's no singlestepping left, so we need to create a new TIF flag, when you first set up the probe you toggle that flag and on the first context switch where the IP is outside of the slot you clear it. But still you need to maintain relative offset within the slot when you move it around.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. 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:"[email protected]"> [email protected] </a>
Oleg Nesterov
maintainerRe: [PATCH 2/5] uprobes: introduce uprobe_switch_to()
Quoted 16 lines · Peter Zijlstra
Quoted 14 lines · Oleg Nesterov
Quoted 4 lines · Peter Zijlstra
So
uprobe_switch_to()will always reset the IP to the start of the slot? That sounds wrong, things like the RIP relative stuff needs multiple instructions.Hmm. Could you explain? Especially the "multiple instructions" part.
In any case we should reset the IP to the start of the slot.
But yes, I'm afraid this is too simple. Before this patches
pre_xol()is called when we already know ->xol_vaddr. But afaics x86 doesn't use this info (post_xol()does). So this looks equally correct or wrong.
Quoted 8 lines
Quoted 5 lines
But perhaps we need another arch-dependent hook which takes ->xol_vaddr into account instead of simple
memcpy(), to handle the RIP relative case.Or I misunderstood?
Suppose you need multiple instructions to replace the one you patched out,
Ah, I see, thanks...
Yes, in this case set_xol_ip() should add the offset, regs->ip % UPROBES_XOL_SLOT_BYTES.
But the current code doesn't use multiple instructions and it relies on the single-stepping, so I think currently this is correct.
Quoted 10 lines
for example because the instruction was RIP relative (the effect relied on the IP the instruction is at, eg. short jumps instead of absolute jumps).
One way to translate these instructions is something like
push eax
mov eax, $previous_ip
$ins eax+offset
pop eax
I can be easily wrong, but afaics this particular case is covered by pre_xol/post_xol. But I guess this doesn't matter.
Yes, I thought about multiple insns in xol slot too.
Quoted 5 lines
Also, the thing Srikar mentioned is boosted probes, in that case you forgo the whole single step thing and rewrite the probe as:
$ins
jmp $next_insn
Yes! it would be nice to avoid the stepping if possible. But so far I am not sure how/when this can work...
Quoted 4 lines
Now in the former case you still single step so the context switch hook can function as proposed (triggered off of
TIF_SINGLESTEP). However if you get preempted after the mov you want to continue with the $ins, not restart at push.
This is not clear to me. Single step with multiple insns?
Quoted 2 lines
So
uprobe_switch_to()will have to preserve the
relative offset within the slot.
Yes, agreed.
Quoted 5 lines
On the second example there's no singlestepping left, so we need to create a new TIF flag, when you first set up the probe you toggle that flag and on the first context switch where the IP is outside of the slot you clear it. But still you need to maintain relative offset within the slot when you move it around.
Yes. Currently uprobe_switch_to() checks X86_EFLAGS_TF() to verify that it is correct to change regs->ip. But if we know that, say, this insn can't jump/call/rep we can simply check regs->ip. And in this case we can avoid the stepping.
Thanks,
Oleg.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. 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:"[email protected]"> [email protected] </a>
Oleg Nesterov
maintainerPATCH 3/5 uprobes: introduce uprobe_xol_slots[NR_CPUS]
In reply to Oleg NesterovThis patch adds uprobe_xol_slots[UPROBES_XOL_SLOT_BYTES][NR_CPUS] array. Each CPU has its own slot for xol (used in the next patch).
We "export" this data to the user-space via set_fixmap(PAGE_KERNEL_VSYSCALL).
--- arch/x86/include/asm/fixmap.h | 9 +++++++++ arch/x86/kernel/uprobes.c | 10 ++++++++++ include/linux/uprobes.h | 1 + kernel/uprobes.c | 4 ++++ 4 files changed, 24 insertions(+), 0 deletions(-)
arch/x86/include/asm/fixmap.h +9 -0
@@ -81,6 +81,15 @@ enum fixed_addresses { VVAR_PAGE, VSYSCALL_HPET,#endif + +#ifdef CONFIG_UPROBES +#define UPROBES_XOL_SLOT_BYTES 128 + +UPROBE_XOL_LAST_PAGE , +UPROBE_XOL_FIRST_PAGE =UPROBE_XOL_LAST_PAGE + +NR_CPUS *UPROBES_XOL_SLOT_BYTES /PAGE_SIZE , +#endif +FIX_DBGP_BASE ,FIX_EARLYCON_MEM_BASE , #ifdef CONFIG_PROVIDE_OHCI1394_DMA_INIT
arch/x86/kernel/uprobes.c +10 -0
@@ -664,3 +664,13 @@ bool can_skip_xol(struct pt_regs *regs, struct uprobe *u) u->flags &= ~UPROBES_SKIP_SSTEP ;return false; } + +void __init map_uprobe_xol_slots (void *pages) +{ +int idx =UPROBE_XOL_FIRST_PAGE ; + +do { +__set_fixmap (idx,__pa (pages),PAGE_KERNEL_VSYSCALL ); + pages +=PAGE_SIZE ; + }while (idx-- !=UPROBE_XOL_LAST_PAGE ); +}
include/linux/uprobes.h +1 -0
@@ -142,6 +142,7 @@ extern bool uprobe_deny_signal(void);extern bool __weak can_skip_xol (struct pt_regs *regs,struct uprobe *u);extern void __weak set_xol_ip (struct pt_regs *regs);extern void uprobe_switch_to (struct task_struct *); +extern void map_uprobe_xol_slots (void *);#else /* CONFIG_UPROBES is not defined */ static inline int register_uprobe (struct inode *inode,loff_t offset,struct uprobe_consumer *consumer)
kernel/uprobes.c +4 -0
@@ -1342,6 +1342,9 @@ bool __weak can_skip_xol(struct pt_regs *regs, struct uprobe *u)return false; } +static unsigned char +uprobe_xol_slots[UPROBES_XOL_SLOT_BYTES][NR_CPUS] __page_aligned_bss; +void __weak set_xol_ip (struct pt_regs *regs) {set_instruction_pointer (regs, current->utask->xol_vaddr);
@@ -1490,6 +1493,7 @@ static int __init init_uprobes(void)mutex_init (&uprobes_mmap_mutex[i]); }init_bulkref (&uprobes_srcu); +map_uprobe_xol_slots (uprobe_xol_slots);return register_die_notifier (&uprobe_exception_nb); }
Signature · 9 lines
1.5.5.1 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. 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:"[email protected]"> [email protected] </a>
Peter Zijlstra
maintainerRe: [PATCH 3/5] uprobes: introduce uprobe_xol_slots[NR_CPUS]
arch/x86/include/asm/fixmap.h enum fixed_addresses { · line 90
Quoted 2 lines · Oleg Nesterov
arch/x86/include/asm/fixmap.h +2
-0+UPROBE_XOL_FIRST_PAGE =UPROBE_XOL_LAST_PAGE + + NR_CPUS * UPROBES_XOL_SLOT_BYTES / PAGE_SIZE,
I think that wants to be:
+ DIV_ROUND_UP(NR_CPUS * UPROBES_XOL_SLOT_BYTES, PAGE_SIZE);
otherwise you'll end up with 0 pages for UP and the sort.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. 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:"[email protected]"> [email protected] </a>
Peter Zijlstra
maintainerRe: [PATCH 3/5] uprobes: introduce uprobe_xol_slots[NR_CPUS]
Quoted 8 lines · Peter Zijlstra
arch/x86/include/asm/fixmap.h enum fixed_addresses { · line 90
Quoted 2 lines · Oleg Nesterov
arch/x86/include/asm/fixmap.h +2
-0+UPROBE_XOL_FIRST_PAGE =UPROBE_XOL_LAST_PAGE + + NR_CPUS * UPROBES_XOL_SLOT_BYTES / PAGE_SIZE,I think that wants to be:
+DIV_ROUND_UP(NR_CPUS * UPROBES_XOL_SLOT_BYTES, PAGE_SIZE);otherwise you'll end up with 0 pages for UP and the sort.
Ah, no I see, you'll already have the one LAST_PAGE thing.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. 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:"[email protected]"> [email protected] </a>
Oleg Nesterov
maintainerRe: [PATCH 3/5] uprobes: introduce uprobe_xol_slots[NR_CPUS]
In reply to Oleg NesterovQuoted 2 lines · Oleg Nesterov
This patch adds uprobe_xol_slots[UPROBES_XOL_SLOT_BYTES][NR_CPUS] array.
Typo, it should be uprobe_xol_slots[NR_CPUS][UPROBES_XOL_SLOT_BYTES].
-------------------------------------------------------------------------
[PATCH 3/5] uprobes: introduce uprobe_xol_slots[NR_CPUS]
This patch adds uprobe_xol_slots[UPROBES_XOL_SLOT_BYTES][NR_CPUS] array. Each CPU has its own slot for xol (used in the next patch).
We "export" this data to the user-space via set_fixmap(PAGE_KERNEL_VSYSCALL).
--- arch/x86/include/asm/fixmap.h | 9 +++++++++ arch/x86/kernel/uprobes.c | 10 ++++++++++ include/linux/uprobes.h | 1 + kernel/uprobes.c | 4 ++++ 4 files changed, 24 insertions(+), 0 deletions(-)
arch/x86/include/asm/fixmap.h +9 -0
@@ -81,6 +81,15 @@ enum fixed_addresses { VVAR_PAGE, VSYSCALL_HPET,#endif + +#ifdef CONFIG_UPROBES +#define UPROBES_XOL_SLOT_BYTES 128 + +UPROBE_XOL_LAST_PAGE , +UPROBE_XOL_FIRST_PAGE =UPROBE_XOL_LAST_PAGE + +NR_CPUS *UPROBES_XOL_SLOT_BYTES /PAGE_SIZE , +#endif +FIX_DBGP_BASE ,FIX_EARLYCON_MEM_BASE , #ifdef CONFIG_PROVIDE_OHCI1394_DMA_INIT
arch/x86/kernel/uprobes.c +10 -0
@@ -664,3 +664,13 @@ bool can_skip_xol(struct pt_regs *regs, struct uprobe *u) u->flags &= ~UPROBES_SKIP_SSTEP ;return false; } + +void __init map_uprobe_xol_slots (void *pages) +{ +int idx =UPROBE_XOL_FIRST_PAGE ; + +do { +__set_fixmap (idx,__pa (pages),PAGE_KERNEL_VSYSCALL ); + pages +=PAGE_SIZE ; + }while (idx-- !=UPROBE_XOL_LAST_PAGE ); +}
include/linux/uprobes.h +1 -0
@@ -142,6 +142,7 @@ extern bool uprobe_deny_signal(void);extern bool __weak can_skip_xol (struct pt_regs *regs,struct uprobe *u);extern void __weak set_xol_ip (struct pt_regs *regs);extern void uprobe_switch_to (struct task_struct *); +extern void map_uprobe_xol_slots (void *);#else /* CONFIG_UPROBES is not defined */ static inline int register_uprobe (struct inode *inode,loff_t offset,struct uprobe_consumer *consumer)
kernel/uprobes.c +4 -0
@@ -1342,6 +1342,9 @@ bool __weak can_skip_xol(struct pt_regs *regs, struct uprobe *u)return false; } +static unsigned char +uprobe_xol_slots[NR_CPUS][UPROBES_XOL_SLOT_BYTES] __page_aligned_bss; +void __weak set_xol_ip (struct pt_regs *regs) {set_instruction_pointer (regs, current->utask->xol_vaddr);
@@ -1490,6 +1493,7 @@ static int __init init_uprobes(void)mutex_init (&uprobes_mmap_mutex[i]); }init_bulkref (&uprobes_srcu); +map_uprobe_xol_slots (uprobe_xol_slots);return register_die_notifier (&uprobe_exception_nb); }
Signature · 9 lines
1.5.5.1 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. 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:"[email protected]"> [email protected] </a>
Oleg Nesterov
maintainerPATCH 4/5 uprobes: teach set_xol_ip() to use uprobe_xol_slots[]
In reply to Oleg NesterovChange set_xol_ip() to use uprobe_xol_slots[] per-cpu array to "allocate" the insn slot. We do not care if the task migrates to another CPU before executing xol insn, set_xol_ip() will be called again by uprobe_switch_to(). Likewise, we do not care if the task is simply preempted or sleeps.
IOW, uprobe_xol_slots[CPU] is "owned" by cpu_curr(CPU).
This makes xol_get_insn_slot/xol_free_insn_slot unnecessary, but uprobe_notify_resume() should set utask->vaddr. The patch updates the callers but doesn't remove this code to simplify the review.
--- kernel/uprobes.c | 16 ++++++++++------ 1 files changed, 10 insertions(+), 6 deletions(-)
kernel/uprobes.c +10 -6
@@ -1285,7 +1285,6 @@ void free_uprobe_utask(struct task_struct *tsk)if (utask->active_uprobe)put_uprobe (utask->active_uprobe); -xol_free_insn_slot (tsk);kfree (utask); tsk->utask =NULL ; }
@@ -1347,7 +1346,15 @@ uprobe_xol_slots[UPROBES_XOL_SLOT_BYTES][NR_CPUS] __page_aligned_bss;void __weak set_xol_ip (struct pt_regs *regs) { -set_instruction_pointer (regs, current->utask->xol_vaddr); +int cpu =smp_processor_id (); +struct uprobe_task *utask = current->utask; +struct uprobe *uprobe = utask->active_uprobe; + +memcpy (uprobe_xol_slots[cpu], uprobe->insn,MAX_UINSN_BYTES ); + + utask->xol_vaddr =fix_to_virt (UPROBE_XOL_FIRST_PAGE ) + +UPROBES_XOL_SLOT_BYTES * cpu; +set_instruction_pointer (regs, utask->xol_vaddr); }/*
@@ -1390,14 +1397,12 @@ void uprobe_notify_resume(struct pt_regs *regs) goto cleanup_ret; } utask->active_uprobe = u; + utask->vaddr = probept;handler_chain (u, regs);if (u->flags &UPROBES_SKIP_SSTEP &&can_skip_xol (regs, u)) goto cleanup_ret; -if (!xol_get_insn_slot (u, probept)) - goto cleanup_ret; -if (pre_xol (u, regs)) goto cleanup_ret;
@@ -1419,7 +1424,6 @@ void uprobe_notify_resume(struct pt_regs *regs) utask->active_uprobe =NULL ; utask->state =UTASK_RUNNING ;user_disable_single_step (current); -xol_free_insn_slot (current);spin_lock_irq (¤t->sighand->siglock);recalc_sigpending ();/* see uprobe_deny_signal() */
Signature · 9 lines
1.5.5.1 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. 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:"[email protected]"> [email protected] </a>
Oleg Nesterov
maintainerPATCH 5/5 uprobes: remove the uprobes_xol_area code
In reply to Oleg NesterovRemove the no longer needed uprobes_xol_area code.
--- include/linux/mm_types.h | 1 - include/linux/uprobes.h | 24 ------ kernel/fork.c | 2 - kernel/uprobes.c | 198 ---------------------------------------------- 4 files changed, 0 insertions(+), 225 deletions(-)
include/linux/mm_types.h +0 -1
@@ -392,7 +392,6 @@ struct mm_struct {#endif #ifdef CONFIG_UPROBES atomic_t mm_uprobes_count; -struct uprobes_xol_area *uprobes_xol_area;#endif };
include/linux/uprobes.h +0 -24
@@ -100,26 +100,6 @@ struct uprobe_task {struct uprobe *active_uprobe; }; -/* -* On a breakpoint hit, thread contests for a slot. It free the -* slot after singlestep. Only definite number of slots are -* allocated. -*/ - -struct uprobes_xol_area { -wait_queue_head_t wq;/* if all slots are busy */ -atomic_t slot_count;/* currently in use slots */ -unsigned long *bitmap;/* 0 = free slot */ -struct page *page; - -/* -* We keep the vma's vm_start rather than a pointer to the vma -* itself. The probed process or a naughty kernel module could make -* the vma go away, and we must handle that reasonably gracefully. -*/ -unsigned long vaddr;/* Page(s) of instruction slots */ -}; -#ifdef CONFIG_UPROBES extern int __weak set_bkpt (struct mm_struct *mm,struct uprobe *uprobe,unsigned long vaddr);
@@ -131,7 +111,6 @@ extern int register_uprobe(struct inode *inode, loff_t offset,extern void unregister_uprobe (struct inode *inode,loff_t offset,struct uprobe_consumer *consumer);extern void free_uprobe_utask (struct task_struct *tsk); -extern void free_uprobes_xol_area (struct mm_struct *mm);extern int mmap_uprobe (struct vm_area_struct *vma);extern void munmap_uprobe (struct vm_area_struct *vma);extern unsigned long __weak get_uprobe_bkpt_addr (struct pt_regs *regs);
@@ -174,8 +153,5 @@ static inline unsigned long get_uprobe_bkpt_addr(struct pt_regs *regs)static inline void free_uprobe_utask (struct task_struct *tsk) { } -static inline void free_uprobes_xol_area (struct mm_struct *mm) -{ -}#endif /* CONFIG_UPROBES */ #endif /* _LINUX_UPROBES_H */
kernel/fork.c +0 -2
@@ -553,7 +553,6 @@ void mmput(struct mm_struct *mm)might_sleep ();if (atomic_dec_and_test (&mm->mm_users)) { -free_uprobes_xol_area (mm);exit_aio (mm);ksm_exit (mm);khugepaged_exit (mm);/* must run before exit_mmap */
@@ -742,7 +741,6 @@ struct mm_struct *dup_mm(struct task_struct *tsk)#endif #ifdef CONFIG_UPROBES atomic_set (&mm->mm_uprobes_count,0 ); - mm->uprobes_xol_area =NULL ;#endif if (!mm_init (mm, tsk))
kernel/uprobes.c +0 -198
210 lines not on this page · raw message
Signature · 9 lines
1.5.5.1 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. 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:"[email protected]"> [email protected] </a>
Peter Zijlstra
maintainerRe: [PATCH RFC 0/5] uprobes: kill xol vma
In reply to Oleg NesterovQuoted 14 lines · Oleg Nesterov
On top of this series, not for inclusion yet, just to explain what I mean. May be someone can test it ;)
This series kills
xol_vma. Instead we use the per_cpu-like xol slots.This is much more simple and efficient. And this of course solves many problems we currently have with
xol_vma.For example, we simply can not trust it. We do not know what actually we are going to execute in
UTASK_SSTEPmode. An application can unmap this area and then dommap(PROT_EXEC|PROT_WRITE, MAP_FIXED)to fool uprobes.
Quoted 5 lines
The only disadvantage is that this adds a bit more arch-dependant code.
The main question, can this work? I know very little in this area. And I am not sure if this can be ported to other architectures.
I very much like this approach! I think the provided implementation might have some issues, but yeah, using fixmaps and a __switch_to_xtra hook to provide per task slots seems very nice indeed!
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. 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:"[email protected]"> [email protected] </a>
Re: [PATCH RFC 0/5] uprobes: kill xol vma
In reply to Oleg NesterovQuoted 14 lines
On top of this series, not for inclusion yet, just to explain what I mean. May be someone can test it ;)
This series kills
xol_vma. Instead we use the per_cpu-like xol slots.This is much more simple and efficient. And this of course solves many problems we currently have with
xol_vma.For example, we simply can not trust it. We do not know what actually we are going to execute in
UTASK_SSTEPmode. An application can unmap this area and then dommap(PROT_EXEC|PROT_WRITE, MAP_FIXED)to fool uprobes.
Quoted 5 lines
The only disadvantage is that this adds a bit more arch-dependant code.
The main question, can this work? I know very little in this area. And I am not sure if this can be ported to other architectures.
Nice idea. I think this will help us in implementing boosted uprobes if tweak a bit. (i.e having a jump after the actual instruction that gets us back to the actual instruction stream). The current method of using a first cum-first-serve slot reservation doesnt work for booster because we have had to clear the slot in the post processing.
I will apply your patches and test and let you know how it goes. (in a day or two).
Signature · 9 lines
Thanks and Regards Srikar -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. 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:"[email protected]"> [email protected] </a>
Oleg Nesterov
maintainerRe: [PATCH RFC 0/5] uprobes: kill xol vma
Quoted 3 lines · Srikar Dronamraju
I will apply your patches and test and let you know how it goes. (in a day or two).
Thanks! please note that 3/5 is wrong, I sent the updated version. Or you can add the fix below.
Oleg.
kernel/uprobes.c +1 -1
@@ -1144,7 +1144,7 @@ bool __weak can_skip_xol(struct pt_regs *regs, struct uprobe *u) }static unsigned char -uprobe_xol_slots[UPROBES_XOL_SLOT_BYTES][NR_CPUS] __page_aligned_bss; +uprobe_xol_slots[NR_CPUS][UPROBES_XOL_SLOT_BYTES] __page_aligned_bss;void __weak set_xol_ip (struct pt_regs *regs) {
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. 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:"[email protected]"> [email protected] </a>
Re: [PATCH RFC 0/5] uprobes: kill xol vma
kernel/uprobes.c bool __weak can_skip_xol(struct pt_regs *regs, struct uprobe *u) · line 1147
Quoted 4 lines
static unsigned char
kernel/uprobes.c +1
-1-uprobe_xol_slots[UPROBES_XOL_SLOT_BYTES][NR_CPUS] __page_aligned_bss; +uprobe_xol_slots[NR_CPUS][UPROBES_XOL_SLOT_BYTES] __page_aligned_bss;
NR_CPUS arrays are basically always wrong.
Use per cpu data.
-Andi
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. 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:"[email protected]"> [email protected] </a>
Peter Zijlstra
maintainerRe: [PATCH RFC 0/5] uprobes: kill xol vma
Quoted 7 lines · Andi Kleen
kernel/uprobes.c bool __weak can_skip_xol(struct pt_regs *regs, struct uprobe *u) · line 1147
Quoted 3 lines
static unsigned char
kernel/uprobes.c +1
-1-uprobe_xol_slots[UPROBES_XOL_SLOT_BYTES][NR_CPUS] __page_aligned_bss; +uprobe_xol_slots[NR_CPUS][UPROBES_XOL_SLOT_BYTES] __page_aligned_bss;
NR_CPUSarrays are basically always wrong.Use per cpu data.
Doesn't really work here, you'd know if you'd read the patches. What we could do though is do a UPROBES_XOL_SLOT_BYTES * nr_cpu_ids bootmem allocation or so.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. 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:"[email protected]"> [email protected] </a>
Oleg Nesterov
maintainerRe: [PATCH RFC 0/5] uprobes: kill xol vma
Quoted 4 lines · Peter Zijlstra
What we
could do though is do aUPROBES_XOL_SLOT_BYTES*nr_cpu_idsbootmem allocation or so.
Agreed, this looks much better.
I'd prefer to do this in a separate patch to keep this change as simple as possible.
Oleg.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. 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:"[email protected]"> [email protected] </a>
Oleg Nesterov
maintainerRe: [PATCH RFC 0/5] uprobes: kill xol vma
In reply to Oleg NesterovQuoted 14 lines · Oleg Nesterov
On top of this series, not for inclusion yet, just to explain what I mean. May be someone can test it ;)
This series kills
xol_vma. Instead we use the per_cpu-like xol slots.This is much more simple and efficient. And this of course solves many problems we currently have with
xol_vma.For example, we simply can not trust it. We do not know what actually we are going to execute in
UTASK_SSTEPmode. An application can unmap this area and then dommap(PROT_EXEC|PROT_WRITE, MAP_FIXED)to fool uprobes.
Quoted 4 lines
The only disadvantage is that this adds a bit more arch-dependant code.
The main question, can this work?
OK, it almost works.
But, this way we can't probe the compat tasks. A __USER32_CS task can't access the fix_to_virt() area, so it can't use uprobe_xol_slots[].
Many thanks to Josh who noticed this.
I'll try to think more, but so far I do not see any simple solution.
Oleg.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. 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:"[email protected]"> [email protected] </a>