From ba32f2a51c8f42da730987ff4a6c5915641fa2fd Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Wed, 10 Nov 2010 10:05:58 +0100 Subject: [PATCH] --- yaml --- r: 222159 b: refs/heads/master c: 89480801a17a3069f45169d40b828c8e511aa005 h: refs/heads/master i: 222157: 8fecdce847c773057e33fbf054e49193828fea73 222155: 46bd9492bce36aa35d0cbc71d9d21734d810b070 222151: a87918629b951e2878bd3a0c0dc496fe6c84a4ce 222143: 2aec1e2c6cb6ffe819c8c44309471c44b5cde50b v: v3 --- [refs] | 2 +- trunk/arch/s390/kernel/kprobes.c | 29 ++++++++++++++++++++++++++--- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/[refs] b/[refs] index dd560d490820..72c3112ec4ad 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: adb45839817392102e659c19e5c19aa39530021f +refs/heads/master: 89480801a17a3069f45169d40b828c8e511aa005 diff --git a/trunk/arch/s390/kernel/kprobes.c b/trunk/arch/s390/kernel/kprobes.c index 70cf73bdba25..2564793ec2b6 100644 --- a/trunk/arch/s390/kernel/kprobes.c +++ b/trunk/arch/s390/kernel/kprobes.c @@ -349,6 +349,7 @@ static int __kprobes trampoline_probe_handler(struct kprobe *p, struct hlist_node *node, *tmp; unsigned long flags, orig_ret_address = 0; unsigned long trampoline_address = (unsigned long)&kretprobe_trampoline; + kprobe_opcode_t *correct_ret_addr = NULL; INIT_HLIST_HEAD(&empty_rp); kretprobe_hash_lock(current, &head, &flags); @@ -371,10 +372,32 @@ static int __kprobes trampoline_probe_handler(struct kprobe *p, /* another task is sharing our hash bucket */ continue; - if (ri->rp && ri->rp->handler) - ri->rp->handler(ri, regs); + orig_ret_address = (unsigned long)ri->ret_addr; + + if (orig_ret_address != trampoline_address) + /* + * This is the real return address. Any other + * instances associated with this task are for + * other calls deeper on the call stack + */ + break; + } + + kretprobe_assert(ri, orig_ret_address, trampoline_address); + + correct_ret_addr = ri->ret_addr; + hlist_for_each_entry_safe(ri, node, tmp, head, hlist) { + if (ri->task != current) + /* another task is sharing our hash bucket */ + continue; orig_ret_address = (unsigned long)ri->ret_addr; + + if (ri->rp && ri->rp->handler) { + ri->ret_addr = correct_ret_addr; + ri->rp->handler(ri, regs); + } + recycle_rp_inst(ri, &empty_rp); if (orig_ret_address != trampoline_address) { @@ -386,7 +409,7 @@ static int __kprobes trampoline_probe_handler(struct kprobe *p, break; } } - kretprobe_assert(ri, orig_ret_address, trampoline_address); + regs->psw.addr = orig_ret_address | PSW_ADDR_AMODE; reset_current_kprobe();