}
 #endif /* !CONFIG_OPTPROBES */
 
+#ifdef CONFIG_KRETPROBES
+static nokprobe_inline bool is_kretprobe_trampoline(unsigned long addr)
+{
+       return (void *)addr == kretprobe_trampoline_addr();
+}
+
+unsigned long kretprobe_find_ret_addr(struct task_struct *tsk, void *fp,
+                                     struct llist_node **cur);
+#else
+static nokprobe_inline bool is_kretprobe_trampoline(unsigned long addr)
+{
+       return false;
+}
+
+static nokprobe_inline
+unsigned long kretprobe_find_ret_addr(struct task_struct *tsk, void *fp,
+                                     struct llist_node **cur)
+{
+       return 0;
+}
+#endif
+
 /* Returns true if kprobes handled the fault */
 static nokprobe_inline bool kprobe_page_fault(struct pt_regs *regs,
                                              unsigned int trap)
 
 
 #ifdef CONFIG_KRETPROBES
 
-unsigned long __kretprobe_trampoline_handler(struct pt_regs *regs,
-                                            void *frame_pointer)
+/* This assumes the 'tsk' is the current task or the is not running. */
+static kprobe_opcode_t *__kretprobe_find_ret_addr(struct task_struct *tsk,
+                                                 struct llist_node **cur)
 {
-       kprobe_opcode_t *correct_ret_addr = NULL;
        struct kretprobe_instance *ri = NULL;
-       struct llist_node *first, *node;
-       struct kretprobe *rp;
+       struct llist_node *node = *cur;
+
+       if (!node)
+               node = tsk->kretprobe_instances.first;
+       else
+               node = node->next;
 
-       /* Find all nodes for this frame. */
-       first = node = current->kretprobe_instances.first;
        while (node) {
                ri = container_of(node, struct kretprobe_instance, llist);
-
-               BUG_ON(ri->fp != frame_pointer);
-
                if (ri->ret_addr != kretprobe_trampoline_addr()) {
-                       correct_ret_addr = ri->ret_addr;
-                       /*
-                        * This is the real return address. Any other
-                        * instances associated with this task are for
-                        * other calls deeper on the call stack
-                        */
-                       goto found;
+                       *cur = node;
+                       return ri->ret_addr;
                }
-
                node = node->next;
        }
-       pr_err("kretprobe: Return address not found, not execute handler. Maybe there is a bug in the kernel.\n");
-       BUG_ON(1);
+       return NULL;
+}
+NOKPROBE_SYMBOL(__kretprobe_find_ret_addr);
 
-found:
-       /* Unlink all nodes for this frame. */
-       current->kretprobe_instances.first = node->next;
-       node->next = NULL;
+/**
+ * kretprobe_find_ret_addr -- Find correct return address modified by kretprobe
+ * @tsk: Target task
+ * @fp: A frame pointer
+ * @cur: a storage of the loop cursor llist_node pointer for next call
+ *
+ * Find the correct return address modified by a kretprobe on @tsk in unsigned
+ * long type. If it finds the return address, this returns that address value,
+ * or this returns 0.
+ * The @tsk must be 'current' or a task which is not running. @fp is a hint
+ * to get the currect return address - which is compared with the
+ * kretprobe_instance::fp field. The @cur is a loop cursor for searching the
+ * kretprobe return addresses on the @tsk. The '*@cur' should be NULL at the
+ * first call, but '@cur' itself must NOT NULL.
+ */
+unsigned long kretprobe_find_ret_addr(struct task_struct *tsk, void *fp,
+                                     struct llist_node **cur)
+{
+       struct kretprobe_instance *ri = NULL;
+       kprobe_opcode_t *ret;
+
+       if (WARN_ON_ONCE(!cur))
+               return 0;
+
+       do {
+               ret = __kretprobe_find_ret_addr(tsk, cur);
+               if (!ret)
+                       break;
+               ri = container_of(*cur, struct kretprobe_instance, llist);
+       } while (ri->fp != fp);
 
-       /* Run them..  */
+       return (unsigned long)ret;
+}
+NOKPROBE_SYMBOL(kretprobe_find_ret_addr);
+
+unsigned long __kretprobe_trampoline_handler(struct pt_regs *regs,
+                                            void *frame_pointer)
+{
+       kprobe_opcode_t *correct_ret_addr = NULL;
+       struct kretprobe_instance *ri = NULL;
+       struct llist_node *first, *node = NULL;
+       struct kretprobe *rp;
+
+       /* Find correct address and all nodes for this frame. */
+       correct_ret_addr = __kretprobe_find_ret_addr(current, &node);
+       if (!correct_ret_addr) {
+               pr_err("kretprobe: Return address not found, not execute handler. Maybe there is a bug in the kernel.\n");
+               BUG_ON(1);
+       }
+
+       /* Run the user handler of the nodes. */
+       first = current->kretprobe_instances.first;
        while (first) {
                ri = container_of(first, struct kretprobe_instance, llist);
-               first = first->next;
+
+               if (WARN_ON_ONCE(ri->fp != frame_pointer))
+                       break;
 
                rp = get_kretprobe(ri);
                if (rp && rp->handler) {
                        rp->handler(ri, regs);
                        __this_cpu_write(current_kprobe, prev);
                }
+               if (first == node)
+                       break;
+
+               first = first->next;
+       }
+
+       /* Unlink all nodes for this frame. */
+       first = current->kretprobe_instances.first;
+       current->kretprobe_instances.first = node->next;
+       node->next = NULL;
+
+       /* Recycle free instances. */
+       while (first) {
+               ri = container_of(first, struct kretprobe_instance, llist);
+               first = first->next;
 
                recycle_rp_inst(ri);
        }