diff options
author | Tim Moore <timoore@redhat.com> | 2010-01-13 19:37:51 +0100 |
---|---|---|
committer | Tim Moore <timoore@redhat.com> | 2010-01-13 19:37:51 +0100 |
commit | 58b06a43d003a1e658b184d5ef577d44d824263e (patch) | |
tree | 513f1e61f0413a782747ccee02ee98ed7f6e8097 /runtime | |
parent | 275ea5e8ee085af6a7782fe3acbffe07645aa0a4 (diff) | |
download | systemtap-steved-58b06a43d003a1e658b184d5ef577d44d824263e.tar.gz systemtap-steved-58b06a43d003a1e658b184d5ef577d44d824263e.tar.xz systemtap-steved-58b06a43d003a1e658b184d5ef577d44d824263e.zip |
map through uretprobe trampoline in an arbitrary task
* runtime/uprobes2/uprobes.c (uprobe_get_pc_task): new function
(lookup_uretprobe): new helper function
(uprobe_get_pc): use it
* runtime/uprobes2/uprobes.h (uprobe_get_pc_task): declare
* runtime/uprobes/uprobes.c : ditto
* runtime/uprobes/uprobes.h : ditto
Diffstat (limited to 'runtime')
-rw-r--r-- | runtime/uprobes/uprobes.c | 68 | ||||
-rw-r--r-- | runtime/uprobes/uprobes.h | 6 | ||||
-rw-r--r-- | runtime/uprobes2/uprobes.c | 69 | ||||
-rw-r--r-- | runtime/uprobes2/uprobes.h | 6 |
4 files changed, 114 insertions, 35 deletions
diff --git a/runtime/uprobes/uprobes.c b/runtime/uprobes/uprobes.c index 5ccc7102..61050121 100644 --- a/runtime/uprobes/uprobes.c +++ b/runtime/uprobes/uprobes.c @@ -2596,6 +2596,33 @@ static void uretprobe_set_trampoline(struct uprobe_process *uproc, } } +static inline unsigned long lookup_uretprobe(struct hlist_node *r, + struct uprobe_process *uproc, + unsigned long pc, + unsigned long sp) +{ + struct uretprobe_instance *ret_inst; + unsigned long trampoline_addr; + + if (IS_ERR(uproc->uretprobe_trampoline_addr)) + return pc; + trampoline_addr = (unsigned long)uproc->uretprobe_trampoline_addr; + if (pc != trampoline_addr) + return pc; + hlist_for_each_entry_from(ret_inst, r, hlist) { + if (ret_inst->ret_addr == trampoline_addr) + continue; + /* First handler with a stack pointer lower than the + address (or equal) must be the one. */ + if (ret_inst->sp == sp || compare_stack_ptrs(ret_inst->sp, sp)) + return ret_inst->ret_addr; + } + printk(KERN_ERR "Original return address for trampoline not found at " + "0x%lx pid/tgid=%d/%d\n", sp, current->pid, current->tgid); + return 0; + +} + unsigned long uprobe_get_pc(struct uretprobe_instance *ri, unsigned long pc, unsigned long sp) { @@ -2603,9 +2630,7 @@ unsigned long uprobe_get_pc(struct uretprobe_instance *ri, unsigned long pc, struct uprobe_kimg *uk; struct uprobe_task *utask; struct uprobe_process *uproc; - unsigned long trampoline_addr; struct hlist_node *r; - struct uretprobe_instance *ret_inst; if (!ri) return 0; @@ -2623,25 +2648,34 @@ unsigned long uprobe_get_pc(struct uretprobe_instance *ri, unsigned long pc, uproc = uk->ppt->uproc; r = &ri->hlist; } - if (IS_ERR(uproc->uretprobe_trampoline_addr)) - return pc; - trampoline_addr = (unsigned long)uproc->uretprobe_trampoline_addr; - if (pc != trampoline_addr) + return lookup_uretprobe(r, uproc, pc, sp); +} + +EXPORT_SYMBOL_GPL(uprobe_get_pc); + +unsigned long uprobe_get_pc_task(struct task_struct *task, unsigned long pc, + unsigned long sp) +{ + struct uprobe_task *utask; + struct uprobe_process *uproc; + unsigned long result; + + utask = uprobe_find_utask(task); + if (!utask) { return pc; - hlist_for_each_entry_from(ret_inst, r, hlist) { - if (ret_inst->ret_addr == trampoline_addr) - continue; - /* First handler with a stack pointer lower than the - address (or equal) must be the one. */ - if (ret_inst->sp == sp || compare_stack_ptrs(ret_inst->sp, sp)) - return ret_inst->ret_addr; + } else if (current == task && utask->active_probe) { + /* everything's locked. */ + return uprobe_get_pc(GET_PC_URETPROBE_NONE, pc, sp); } - printk(KERN_ERR "Original return address for trampoline not found at " - "0x%lx pid/tgid=%d/%d\n", sp, current->pid, current->tgid); - return 0; + uproc = utask->uproc; + down_read(&uproc->rwsem); + result = lookup_uretprobe(utask->uretprobe_instances.first, uproc, pc, + sp); + up_read(&uproc->rwsem); + return result; } -EXPORT_SYMBOL_GPL(uprobe_get_pc); +EXPORT_SYMBOL_GPL(uprobe_get_pc_task); #else /* ! CONFIG_URETPROBES */ diff --git a/runtime/uprobes/uprobes.h b/runtime/uprobes/uprobes.h index 80725f23..2096ff20 100644 --- a/runtime/uprobes/uprobes.h +++ b/runtime/uprobes/uprobes.h @@ -107,6 +107,12 @@ extern void unmap_uretprobe(struct uretprobe *rp); extern unsigned long uprobe_get_pc(struct uretprobe_instance *ri, unsigned long pc, unsigned long sp); +/* + * This version will do the mapping for an arbitrary task. + */ +extern unsigned long uprobe_get_pc_task(struct task_struct *task, + unsigned long pc, + unsigned long sp); #ifdef UPROBES_IMPLEMENTATION diff --git a/runtime/uprobes2/uprobes.c b/runtime/uprobes2/uprobes.c index 623855ff..bf31b65d 100644 --- a/runtime/uprobes2/uprobes.c +++ b/runtime/uprobes2/uprobes.c @@ -2837,6 +2837,33 @@ static void uretprobe_set_trampoline(struct uprobe_process *uproc, } } +static inline unsigned long lookup_uretprobe(struct hlist_node *r, + struct uprobe_process *uproc, + unsigned long pc, + unsigned long sp) +{ + struct uretprobe_instance *ret_inst; + unsigned long trampoline_addr; + + if (IS_ERR(uproc->uretprobe_trampoline_addr)) + return pc; + trampoline_addr = (unsigned long)uproc->uretprobe_trampoline_addr; + if (pc != trampoline_addr) + return pc; + hlist_for_each_entry_from(ret_inst, r, hlist) { + if (ret_inst->ret_addr == trampoline_addr) + continue; + /* First handler with a stack pointer lower than the + address (or equal) must be the one. */ + if (ret_inst->sp == sp || compare_stack_ptrs(ret_inst->sp, sp)) + return ret_inst->ret_addr; + } + printk(KERN_ERR "Original return address for trampoline not found at " + "0x%lx pid/tgid=%d/%d\n", sp, current->pid, current->tgid); + return 0; + +} + unsigned long uprobe_get_pc(struct uretprobe_instance *ri, unsigned long pc, unsigned long sp) { @@ -2844,9 +2871,7 @@ unsigned long uprobe_get_pc(struct uretprobe_instance *ri, unsigned long pc, struct uprobe_kimg *uk; struct uprobe_task *utask; struct uprobe_process *uproc; - unsigned long trampoline_addr; struct hlist_node *r; - struct uretprobe_instance *ret_inst; if (!ri) return 0; @@ -2864,26 +2889,34 @@ unsigned long uprobe_get_pc(struct uretprobe_instance *ri, unsigned long pc, uproc = uk->ppt->uproc; r = &ri->hlist; } - if (IS_ERR(uproc->uretprobe_trampoline_addr)) - return pc; - trampoline_addr = (unsigned long)uproc->uretprobe_trampoline_addr; - if (pc != trampoline_addr) - return pc; - hlist_for_each_entry_from(ret_inst, r, hlist) { - if (ret_inst->ret_addr == trampoline_addr) - continue; - /* First handler with a stack pointer lower than the - address (or equal) must be the one. */ - if (ret_inst->sp == sp || compare_stack_ptrs(ret_inst->sp, sp)) - return ret_inst->ret_addr; - } - printk(KERN_ERR "Original return address for trampoline not found at " - "0x%lx pid/tgid=%d/%d\n", sp, current->pid, current->tgid); - return 0; + return lookup_uretprobe(r, uproc, pc, sp); } EXPORT_SYMBOL_GPL(uprobe_get_pc); +unsigned long uprobe_get_pc_task(struct task_struct *task, unsigned long pc, + unsigned long sp) +{ + struct uprobe_task *utask; + struct uprobe_process *uproc; + unsigned long result; + + utask = uprobe_find_utask(task); + if (!utask) { + return pc; + } else if (current == task && utask->active_probe) { + /* everything's locked. */ + return uprobe_get_pc(GET_PC_URETPROBE_NONE, pc, sp); + } + uproc = utask->uproc; + down_read(&uproc->rwsem); + result = lookup_uretprobe(utask->uretprobe_instances.first, uproc, pc, + sp); + up_read(&uproc->rwsem); + return result; +} + +EXPORT_SYMBOL_GPL(uprobe_get_pc_task); #else /* ! CONFIG_URETPROBES */ static void uretprobe_handle_entry(struct uprobe *u, struct pt_regs *regs, diff --git a/runtime/uprobes2/uprobes.h b/runtime/uprobes2/uprobes.h index c4e1f59c..b48a9832 100644 --- a/runtime/uprobes2/uprobes.h +++ b/runtime/uprobes2/uprobes.h @@ -100,6 +100,12 @@ extern void unmap_uretprobe(struct uretprobe *rp); extern unsigned long uprobe_get_pc(struct uretprobe_instance *ri, unsigned long pc, unsigned long sp); +/* + * This version will do the mapping for an arbitrary task. + */ +extern unsigned long uprobe_get_pc_task(struct task_struct *task, + unsigned long pc, + unsigned long sp); #ifdef UPROBES_IMPLEMENTATION |