Merge branch 'tizen_2.4' into tizen_2.4_dev 20/49920/2
authorAnatolii Nikulin <nikulin.a@samsung.com>
Wed, 21 Oct 2015 13:06:59 +0000 (16:06 +0300)
committerAnatolii Nikulin <nikulin.a@samsung.com>
Thu, 22 Oct 2015 09:52:43 +0000 (12:52 +0300)
Change-Id: I9ca9dd85e7c85433c9f4f121f2ef68952cc722ab
Signed-off-by: Anatolii Nikulin <nikulin.a@samsung.com>
23 files changed:
1  2 
fbiprobe/fbiprobe.c
preload/preload_control.c
preload/preload_module.c
preload/preload_probe.c
retprobe/retprobe.c
uprobe/arch/arm/swap-asm/swap_uprobes.c
uprobe/arch/arm/swap-asm/swap_uprobes.h
uprobe/arch/x86/swap-asm/swap_uprobes.c
uprobe/arch/x86/swap-asm/swap_uprobes.h
uprobe/swap_uprobes.c
uprobe/swap_uprobes.h
us_manager/helper.c
us_manager/img/img_file.c
us_manager/img/img_proc.c
us_manager/pf/pf_group.c
us_manager/pf/pf_group.h
us_manager/sspt/sspt.h
us_manager/sspt/sspt_file.c
us_manager/sspt/sspt_file.h
us_manager/sspt/sspt_page.c
us_manager/sspt/sspt_proc.c
us_manager/sspt/sspt_proc.h
wsp/wsp.c

Simple merge
Simple merge
@@@ -566,8 -634,9 +634,9 @@@ static int preload_us_entry(struct uret
        struct us_ip *ip = container_of(ri->rp, struct us_ip, retprobe);
        struct us_priv *priv = (struct us_priv *)ri->data;
        unsigned long flags = get_preload_flags(current);
 -      unsigned long offset = ip->info->pl_i.handler;
 +      unsigned long offset = ip->desc->info.pl_i.handler;
        unsigned long vaddr = 0;
+       unsigned long base;
        char __user *path = NULL;
  
        if ((flags & HANDLER_RUNNING) ||
Simple merge
Simple merge
@@@ -608,44 -586,53 +586,52 @@@ static int arch_make_trampoline_thumb(u
   * @return 0 on success,\n
   * negative error code on error.
   */
 -int arch_prepare_uprobe(struct uprobe *up)
 +int arch_prepare_uprobe(struct uprobe *p)
  {
 -      struct kprobe *p = up2kp(up);
 -      struct task_struct *task = up->task;
+       int ret;
-       unsigned long vaddr = (unsigned long)p->addr;
 +      struct task_struct *task = p->task;
+       unsigned long vaddr = (unsigned long)p->addr & ~((unsigned long)1);
        unsigned long insn;
-       if (vaddr & 0x01) {
-               printk(KERN_INFO "Error in %s at %d: attempt "
-                      "to register uprobe at an unaligned address\n",
-                      __FILE__, __LINE__);
-               return -EINVAL;
-       }
+       int thumb_mode = (unsigned long)p->addr & 1;
+       unsigned long tramp[UPROBES_TRAMP_LEN];
+       unsigned long __user *utramp;
+       enum { tramp_len = sizeof(tramp) };
  
        if (!read_proc_vm_atomic(task, vaddr, &insn, sizeof(insn))) {
                printk(KERN_ERR "failed to read memory %lx!\n", vaddr);
                return -EINVAL;
        }
  
-       p->opcode = insn;
-       arch_copy_trampoline_arm_uprobe(p);
-       arch_copy_trampoline_thumb_uprobe(p);
-       if ((p->safe_arm) && (p->safe_thumb)) {
-               printk(KERN_INFO "Error in %s at %d: failed "
-                      "arch_copy_trampoline_*_uprobe() (both) "
-                      "[tgid=%u, addr=%lx, data=%lx]\n",
-                      __FILE__, __LINE__, task->tgid, vaddr, insn);
-               return -EFAULT;
+       ret = thumb_mode ?
+                       arch_make_trampoline_thumb(vaddr, insn,
+                                                  tramp, tramp_len) :
+                       arch_make_trampoline_arm(vaddr, insn, tramp);
+       if (ret) {
+               pr_err("failed to make tramp, addr=%p\n", p->addr);
+               return ret;
        }
  
-       p->atramp.utramp = swap_slot_alloc(p->sm);
-       if (p->atramp.utramp == NULL) {
 -      utramp = swap_slot_alloc(up->sm);
++      utramp = swap_slot_alloc(p->sm);
+       if (utramp == NULL) {
                printk(KERN_INFO "Error: swap_slot_alloc failed (%08lx)\n",
                       vaddr);
                return -ENOMEM;
        }
  
 -      if (!write_proc_vm_atomic(up->task, (unsigned long)utramp, tramp,
++      if (!write_proc_vm_atomic(p->task, (unsigned long)utramp, tramp,
+                                 tramp_len)) {
+               pr_err("failed to write memory tramp=%p!\n", utramp);
 -              swap_slot_free(up->sm, utramp);
++              swap_slot_free(p->sm, utramp);
+               return -EINVAL;
+       }
+       flush_insns(utramp, tramp_len);
+       p->ainsn.insn = utramp;
+       p->opcode = insn;
+       /* for uretprobe */
+       add_uprobe_table(p);
        return 0;
  }
  
@@@ -695,6 -682,15 +681,15 @@@ int arch_prepare_uretprobe(struct uretp
        return 0;
  }
  
 -                      ((unsigned long)ri->rp->up.kp.ainsn.insn + 0x1b) :
 -                      (unsigned long)(ri->rp->up.kp.ainsn.insn +
+ unsigned long arch_tramp_by_ri(struct uretprobe_instance *ri)
+ {
+       /* Understand function mode */
+       return ((unsigned long)ri->sp & 1) ?
++                      ((unsigned long)ri->rp->up.ainsn.insn + 0x1b) :
++                      (unsigned long)(ri->rp->up.ainsn.insn +
+                                       UPROBES_TRAMP_RET_BREAK_IDX);
+ }
  /**
   * @brief Disarms uretprobe instance.
   *
@@@ -713,15 -709,16 +708,16 @@@ int arch_disarm_urp_inst(struct uretpro
        unsigned long *stack = sp - RETPROBE_STACK_DEPTH + 1;
        unsigned long *found = NULL;
        unsigned long *buf[RETPROBE_STACK_DEPTH];
+       unsigned long vaddr;
        int i, retval;
  
-       /* Understand function mode */
-       if ((long)ri->sp & 1) {
-               tramp = (unsigned long *)
-                       ((unsigned long)ri->rp->up.ainsn.insn + 0x1b);
+       if (tr == 0) {
 -              vaddr = (unsigned long)ri->rp->up.kp.addr;
++              vaddr = (unsigned long)ri->rp->up.addr;
+               tramp = (unsigned long *)arch_tramp_by_ri(ri);
        } else {
-               tramp = (unsigned long *)(ri->rp->up.ainsn.insn +
-                                         UPROBES_TRAMP_RET_BREAK_IDX);
+               /* ri - invalid */
+               vaddr = 0;
+               tramp = (unsigned long *)tr;
        }
  
        /* check stack */
@@@ -854,131 -852,69 +850,87 @@@ void arch_set_orig_ret_addr(unsigned lo
   */
  void arch_remove_uprobe(struct uprobe *up)
  {
-       swap_slot_free(up->sm, up->atramp.utramp);
 -      swap_slot_free(up->sm, up->kp.ainsn.insn);
++      swap_slot_free(up->sm, up->ainsn.insn);
  }
  
static void restore_opcode_for_thumb(struct uprobe *p, struct pt_regs *regs)
int arch_arm_uprobe(struct uprobe *p)
  {
-       if (thumb_mode(regs) && !is_thumb2(p->opcode)) {
-               u16 tmp = p->opcode >> 16;
-               write_proc_vm_atomic(current,
-                               (unsigned long)((u16 *)p->addr + 1), &tmp, 2);
-               flush_insns(p->addr, 4);
+       int ret;
 -      unsigned long vaddr = (unsigned long)p->kp.addr & ~((unsigned long)1);
 -      int thumb_mode = (unsigned long)p->kp.addr & 1;
++      unsigned long vaddr = (unsigned long)p->addr & ~((unsigned long)1);
++      int thumb_mode = (unsigned long)p->addr & 1;
+       int len = 4 >> thumb_mode;      /* if thumb_mode then len = 2 */
+       unsigned long insn = thumb_mode ? UBP_THUMB : UBP_ARM;
+       ret = write_proc_vm_atomic(p->task, vaddr, &insn, len);
+       if (!ret) {
+               pr_err("arch_arm_uprobe: failed to write memory tgid=%u addr=%08lx len=%d\n",
+                      p->task->tgid, vaddr, len);
+               return -EACCES;
+       } else {
+               flush_insns(vaddr, len);
        }
+       return 0;
  }
  
- static int make_trampoline(struct uprobe *p, struct pt_regs *regs)
 -void arch_disarm_uprobe(struct kprobe *p, struct task_struct *task)
++void arch_disarm_uprobe(struct uprobe *p, struct task_struct *task)
  {
-       unsigned long *tramp, *utramp;
-       int sw;
+       int ret;
  
-       /*
-        * 0 bit - thumb mode           (0 - arm, 1 - thumb)
-        * 1 bit - arm mode support     (0 - off, 1  on)
-        * 2 bit - thumb mode support   (0 - off, 1  on)`
-        */
-       sw = (!!thumb_mode(regs)) |
-            (int)!p->safe_arm << 1 |
-            (int)!p->safe_thumb << 2;
-       switch (sw) {
-       /* ARM */
-       case 0b110:
-       case 0b010:
-               tramp = p->atramp.tramp_arm;
-               break;
-       /* THUMB */
-       case 0b111:
-       case 0b101:
-               restore_opcode_for_thumb(p, regs);
-               tramp = p->atramp.tramp_thumb;
-               break;
-       default:
-               printk(KERN_INFO "Error in %s at %d: we are in arm mode "
-                      "(!) and check instruction was fail "
-                      "(%0lX instruction at %p address)!\n",
-                      __FILE__, __LINE__, p->opcode, p->addr);
-               disarm_uprobe(p, p->task);
+       unsigned long vaddr = (unsigned long)p->addr & ~((unsigned long)1);
+       int thumb_mode = (unsigned long)p->addr & 1;
+       int len = 4 >> thumb_mode;      /* if thumb_mode then len = 2 */
  
-               return 1;
+       ret = write_proc_vm_atomic(task, vaddr, &p->opcode, len);
+       if (!ret) {
+               pr_err("arch_disarm_uprobe: failed to write memory tgid=%u addr=%08lx len=%d\n",
+                      task->tgid, vaddr, len);
+       } else {
+               flush_insns(vaddr, len);
        }
+ }
  
-       utramp = p->atramp.utramp;
+ static int urp_handler(struct pt_regs *regs, pid_t tgid)
+ {
 -      struct kprobe *p;
++      struct uprobe *p;
+       unsigned long vaddr = regs->ARM_pc;
+       unsigned long offset_bp = thumb_mode(regs) ?
+                                 0x1a :
+                                 4 * UPROBES_TRAMP_RET_BREAK_IDX;
+       unsigned long tramp_addr = vaddr - offset_bp;
  
-       if (!write_proc_vm_atomic(p->task, (unsigned long)utramp, tramp,
-                                 UPROBES_TRAMP_LEN * sizeof(*tramp))) {
-               printk(KERN_ERR "failed to write memory %p!\n", utramp);
-               return -EINVAL;
 -      p = get_ukprobe_by_insn_slot((void *)tramp_addr, tgid, regs);
++      p = get_uprobe_by_insn_slot((void *)tramp_addr, tgid, regs);
+       if (p == NULL) {
+               printk(KERN_INFO
+                      "no_uprobe: Not one of ours: let kernel handle it %lx\n",
+                      vaddr);
+               return 1;
        }
  
-       flush_insns(utramp, UPROBES_TRAMP_LEN * sizeof(*tramp));
-       p->ainsn.insn = utramp;
+       trampoline_uprobe_handler(p, regs);
  
        return 0;
  }
 +/**
 + * @brief Prepares singlestep for current CPU.
 + *
-  * @param p Pointer to uprobe.
++ * @param p Pointer to kprobe.
 + * @param regs Pointer to CPU registers data.
 + * @return Void.
 + */
- static void uprobe_prepare_singlestep(struct uprobe *p, struct pt_regs *regs)
++static void arch_prepare_singlestep(struct uprobe *p, struct pt_regs *regs)
 +{
 +      int cpu = smp_processor_id();
 +
 +      if (p->ss_addr[cpu]) {
 +              regs->ARM_pc = (unsigned long)p->ss_addr[cpu];
 +              p->ss_addr[cpu] = NULL;
 +      } else {
 +              regs->ARM_pc = (unsigned long)p->ainsn.insn;
 +      }
 +}
  
- static int uprobe_handler(struct pt_regs *regs)
- {
-       uprobe_opcode_t *addr = (uprobe_opcode_t *)(regs->ARM_pc);
-       struct task_struct *task = current;
-       pid_t tgid = task->tgid;
-       struct uprobe *p;
-       p = get_uprobe(addr, tgid);
-       if (p == NULL) {
-               unsigned long offset_bp = thumb_mode(regs) ?
-                                         0x1a :
-                                         4 * UPROBES_TRAMP_RET_BREAK_IDX;
-               void *tramp_addr = (void *)addr - offset_bp;
-               p = get_uprobe_by_insn_slot(tramp_addr, tgid, regs);
-               if (p == NULL) {
-                       printk(KERN_INFO "no_uprobe: Not one of ours: let "
-                              "kernel handle it %p\n", addr);
-                       return 1;
-               }
-               trampoline_uprobe_handler(p, regs);
-       } else {
-               if (p->ainsn.insn == NULL) {
-                       if (make_trampoline(p, regs)) {
-                               printk(KERN_INFO "no_uprobe live\n");
-                               return 0;
-                       }
-                       /* for uretprobe */
-                       add_uprobe_table(p);
-               }
-               if (!p->pre_handler || !p->pre_handler(p, regs))
-                       uprobe_prepare_singlestep(p, regs);
-       }
-       return 0;
- }
  /**
   * @brief Breakpoint instruction handler.
   *
   */
  int uprobe_trap_handler(struct pt_regs *regs, unsigned int instr)
  {
-       int ret;
+       int ret = 0;
 -      struct kprobe *p;
++      struct uprobe *p;
        unsigned long flags;
-       local_irq_save(flags);
+       unsigned long vaddr = regs->ARM_pc | !!thumb_mode(regs);
+       pid_t tgid = current->tgid;
  
+       local_irq_save(flags);
        preempt_disable();
-       ret = uprobe_handler(regs);
-       swap_preempt_enable_no_resched();
  
 -      p = get_ukprobe((kprobe_opcode_t *)vaddr, tgid);
++      p = get_uprobe((uprobe_opcode_t *)vaddr, tgid);
+       if (p) {
 -              struct uprobe *up = kp2up(p);
+               bool prepare = false;
 -              if (up->atomic_ctx) {
++              if (p->atomic_ctx) {
+                       if (!p->pre_handler || !p->pre_handler(p, regs))
+                               prepare = true;
+               } else {
+                       swap_preempt_enable_no_resched();
+                       local_irq_restore(flags);
+                       if (!p->pre_handler || !p->pre_handler(p, regs))
+                               prepare = true;
+                       local_irq_save(flags);
+                       preempt_disable();
+               }
+               if (prepare)
 -                      prepare_singlestep(p, regs);
++                      arch_prepare_singlestep(p, regs);
+       } else {
+               ret = urp_handler(regs, tgid);
+               /* check ARM/THUMB mode on correct */
+               if (ret) {
+                       vaddr ^= 1;
 -                      p = get_ukprobe((kprobe_opcode_t *)vaddr, tgid);
++                      p = get_uprobe((uprobe_opcode_t *)vaddr, tgid);
+                       if (p) {
+                               pr_err("invalid mode: thumb=%d addr=%p insn=%08lx\n",
+                                      !!thumb_mode(regs), p->addr, p->opcode);
+                               ret = 0;
+                               swap_preempt_enable_no_resched();
+                               local_irq_restore(flags);
+                               disarm_uprobe(p, current);
+                               local_irq_save(flags);
+                               preempt_disable();
+                       }
+               }
+       }
+       swap_preempt_enable_no_resched();
        local_irq_restore(flags);
        return ret;
  }
  
@@@ -44,26 -45,11 +44,26 @@@ struct uprobe
  struct uretprobe;
  struct uretprobe_instance;
  
 +typedef unsigned long uprobe_opcode_t;
 +
 +/**
 + * @struct arch_insn
 + * @brief Architecture depend copy of original instruction.
 + * @var arch_insn::insn
 + * Copy of the original instruction.
 + */
 +struct arch_insn {
 +      uprobe_opcode_t *insn;
 +};
 +
  /**
 - * @struct arch_specific_tramp
 + * @struct arch_tramp
   * @brief Stores arch-dependent trampolines.
   */
 -struct arch_specific_tramp {
 +struct arch_tramp {
 +      unsigned long tramp_arm[UPROBES_TRAMP_LEN];     /**< ARM trampoline */
 +      unsigned long tramp_thumb[UPROBES_TRAMP_LEN];   /**< Thumb trampoline */
-       void *utramp;                               /**< Pointer to trampoline */
++      void *utramp;                                   /**< Pointer to trampoline */
  };
  
  
@@@ -93,11 -79,14 +93,14 @@@ static inline int longjmp_break_uhandle
  void arch_opcode_analysis_uretprobe(struct uretprobe *rp);
  int arch_prepare_uretprobe(struct uretprobe_instance *ri, struct pt_regs *regs);
  int arch_disarm_urp_inst(struct uretprobe_instance *ri,
-                        struct task_struct *task);
+                        struct task_struct *task, unsigned long tr);
+ unsigned long arch_tramp_by_ri(struct uretprobe_instance *ri);
  
 -unsigned long arch_get_trampoline_addr(struct kprobe *p, struct pt_regs *regs);
 +unsigned long arch_get_trampoline_addr(struct uprobe *p, struct pt_regs *regs);
  void arch_set_orig_ret_addr(unsigned long orig_ret_addr, struct pt_regs *regs);
  void arch_remove_uprobe(struct uprobe *up);
 -void arch_disarm_uprobe(struct kprobe *p, struct task_struct *task);
+ int arch_arm_uprobe(struct uprobe *p);
++void arch_disarm_uprobe(struct uprobe *p, struct task_struct *task);
  
  static inline unsigned long swap_get_uarg(struct pt_regs *regs, unsigned long n)
  {
@@@ -182,12 -189,12 +187,12 @@@ int arch_prepare_uretprobe(struct uretp
  {
        /* Replace the return addr with trampoline addr */
        unsigned long ra = trampoline_addr(&ri->rp->up);
-       ri->sp = (uprobe_opcode_t *)regs->sp;
+       unsigned long ret_addr;
+       ri->sp = (kprobe_opcode_t *)regs->sp;
  
-       if (!read_proc_vm_atomic(current, regs->EREG(sp), &(ri->ret_addr),
-                                sizeof(ri->ret_addr))) {
-               printk(KERN_ERR "failed to read user space func ra %lx addr=%p!\n",
-                               regs->EREG(sp), ri->rp->up.addr);
+       if (get_user(ret_addr, (unsigned long *)regs->sp)) {
+               pr_err("failed to read user space func ra %lx addr=%p!\n",
 -                     regs->sp, ri->rp->up.kp.addr);
++                     regs->sp, ri->rp->up.addr);
                return -EINVAL;
        }
  
                return -EINVAL;
        }
  
 -      ri->ret_addr = (kprobe_opcode_t *)ret_addr;
++      ri->ret_addr = (uprobe_opcode_t *)ret_addr;
        return 0;
  }
  
@@@ -270,11 -294,42 +292,40 @@@ void arch_set_orig_ret_addr(unsigned lo
   * @param up Pointer to the target uprobe.
   * @return Void.
   */
 -void arch_remove_uprobe(struct uprobe *up)
 +void arch_remove_uprobe(struct uprobe *p)
  {
 -      struct kprobe *p = up2kp(up);
 -
 -      swap_slot_free(up->sm, p->ainsn.insn);
 +      swap_slot_free(p->sm, p->ainsn.insn);
  }
  
 -      kprobe_opcode_t insn = BREAKPOINT_INSTRUCTION;
 -      unsigned long vaddr = (unsigned long)p->kp.addr;
+ int arch_arm_uprobe(struct uprobe *p)
+ {
+       int ret;
 -void arch_disarm_uprobe(struct kprobe *p, struct task_struct *task)
++      uprobe_opcode_t insn = BREAKPOINT_INSTRUCTION;
++      unsigned long vaddr = (unsigned long)p->addr;
+       ret = write_proc_vm_atomic(p->task, vaddr, &insn, sizeof(insn));
+       if (!ret) {
+               pr_err("arch_arm_uprobe: failed to write memory tgid=%u vaddr=%08lx\n",
+                      p->task->tgid, vaddr);
+               return -EACCES;
+       }
+       return 0;
+ }
++void arch_disarm_uprobe(struct uprobe *p, struct task_struct *task)
+ {
+       int ret;
+       unsigned long vaddr = (unsigned long)p->addr;
+       ret = write_proc_vm_atomic(task, vaddr, &p->opcode, sizeof(p->opcode));
+       if (!ret) {
+               pr_err("arch_disarm_uprobe: failed to write memory tgid=%u, vaddr=%08lx\n",
+                      task->tgid, vaddr);
+       }
+ }
  static void set_user_jmp_op(void *from, void *to)
  {
        struct __arch_jmp_op {
        jop.raddr = (long)(to) - ((long)(from) + 5);
        jop.op = RELATIVEJUMP_INSTRUCTION;
  
-       if (!write_proc_vm_atomic(current, (unsigned long)from, &jop,
-                                 sizeof(jop)))
-               printk(KERN_WARNING
-                      "failed to write jump opcode to user space %p\n", from);
+       if (put_user(jop.op, (char *)from) ||
+           put_user(jop.raddr, (long *)(from + 1)))
+               pr_err("failed to write jump opcode to user space %p\n", from);
  }
  
 -static void resume_execution(struct kprobe *p,
 +static void resume_execution(struct uprobe *p,
                             struct pt_regs *regs,
                             unsigned long flags)
  {
@@@ -102,10 -86,13 +102,13 @@@ static inline int arch_opcode_analysis_
  
  int arch_prepare_uretprobe(struct uretprobe_instance *ri, struct pt_regs *regs);
  int arch_disarm_urp_inst(struct uretprobe_instance *ri,
-                        struct task_struct *task);
+                        struct task_struct *task, unsigned long tr);
+ unsigned long arch_tramp_by_ri(struct uretprobe_instance *ri);
 -unsigned long arch_get_trampoline_addr(struct kprobe *p, struct pt_regs *regs);
 +unsigned long arch_get_trampoline_addr(struct uprobe *p, struct pt_regs *regs);
  void arch_set_orig_ret_addr(unsigned long orig_ret_addr, struct pt_regs *regs);
  void arch_remove_uprobe(struct uprobe *up);
 -void arch_disarm_uprobe(struct kprobe *p, struct task_struct *task);
+ int arch_arm_uprobe(struct uprobe *p);
++void arch_disarm_uprobe(struct uprobe *p, struct task_struct *task);
  
  static inline unsigned long swap_get_uarg(struct pt_regs *regs, unsigned long n)
  {
@@@ -81,14 -117,10 +117,10 @@@ EXPORT_SYMBOL_GPL(uinst_info_disarm)
  /*
   * Keep all fields in the uprobe consistent
   */
 -static inline void copy_uprobe(struct kprobe *old_p, struct kprobe *p)
 +static inline void copy_uprobe(struct uprobe *old_p, struct uprobe *p)
  {
 -      memcpy(&p->opcode, &old_p->opcode, sizeof(kprobe_opcode_t));
 -      memcpy(&p->ainsn, &old_p->ainsn, sizeof(struct arch_specific_insn));
 +      memcpy(&p->opcode, &old_p->opcode, sizeof(uprobe_opcode_t));
 +      memcpy(&p->ainsn, &old_p->ainsn, sizeof(struct arch_insn));
- #ifdef CONFIG_ARM
-       p->safe_arm = old_p->safe_arm;
-       p->safe_thumb = old_p->safe_thumb;
- #endif
  }
  
  /*
@@@ -227,14 -251,9 +249,9 @@@ static int arm_uprobe(struct uprobe *p
   * @param task Pointer to the target task.
   * @return Void.
   */
 -void disarm_uprobe(struct kprobe *p, struct task_struct *task)
 +void disarm_uprobe(struct uprobe *p, struct task_struct *task)
  {
-       int ret = write_proc_vm_atomic(task, (unsigned long)p->addr,
-                                      &p->opcode, sizeof(p->opcode));
-       if (!ret) {
-               printk("disarm_uprobe: failed to write memory "
-                      "tgid=%u, addr=%p!\n", task->tgid, p->addr);
-       }
+       arch_disarm_uprobe(p, task);
  }
  EXPORT_SYMBOL_GPL(disarm_uprobe);
  
@@@ -484,15 -503,10 +501,7 @@@ int swap_register_uprobe(struct uprobe 
        if (!p->addr)
                return -EINVAL;
  
- /* thumb address = address-1; */
- #if defined(CONFIG_ARM)
-       /* TODO: must be corrected in 'bundle' */
-       if ((unsigned long) p->addr & 0x01)
-               p->addr = (uprobe_opcode_t *)((unsigned long)p->addr &
-                                             0xfffffffe);
- #endif
        p->ainsn.insn = NULL;
 -      p->mod_refcounted = 0;
 -      p->nmissed = 0;
        INIT_LIST_HEAD(&p->list);
  #ifdef KPROBES_PROFILE
        p->start_tm.tv_sec = p->start_tm.tv_usec = 0;
@@@ -933,7 -887,11 +884,11 @@@ void __swap_unregister_uretprobe(struc
                        printk(KERN_INFO "%s (%d/%d): "
                               "cannot disarm urp instance (%08lx)\n",
                               ri->task->comm, ri->task->tgid, ri->task->pid,
 -                             (unsigned long)rp->up.kp.addr);
 +                             (unsigned long)rp->up.addr);
+               if (is_current)
+                       spin_lock_irqsave(&uretprobe_lock, flags);
                recycle_urp_inst(ri);
        }
  
@@@ -64,45 -41,43 +64,73 @@@ typedef int (*uprobe_fault_handler_t) (
  
  /**
   * @struct uprobe
 - * @brief Stores uprobe data, based on kprobe.
 + * @brief Stores uprobe data.
   */
  struct uprobe {
 -      struct kprobe kp;                   /**< Kprobe for this uprobe */
 -      struct task_struct *task;           /**< Pointer to the task struct */
 -      struct slot_manager *sm;            /**< Pointer to slot manager */
 -      struct arch_specific_tramp atramp;  /**< Stores trampoline */
 +      struct hlist_node hlist; /**< Hash list.*/
 +      /** List of probes to search by instruction slot.*/
 +      struct hlist_node is_hlist;
 +      /** List of uprobes for multi-handler support.*/
 +      struct list_head list;
 +      /** Location of the probe point. */
 +      uprobe_opcode_t *addr;
 +      /** Called before addr is executed.*/
 +      uprobe_pre_handler_t pre_handler;
 +      /** Called after addr is executed, unless...*/
 +      uprobe_post_handler_t post_handler;
 +      /** ... called if executing addr causes a fault (eg. page fault).*/
 +      uprobe_fault_handler_t fault_handler;
 +      /** Return 1 if it handled fault, otherwise kernel will see it.*/
 +      uprobe_break_handler_t break_handler;
 +      /** Saved opcode (which has been replaced with breakpoint).*/
 +      uprobe_opcode_t opcode;
 +      /** Override single-step target address, may be used to redirect
 +       * control-flow to arbitrary address after probe point without
 +       * invocation of original instruction; useful for functions
 +       * replacement. If jprobe.entry should return address of function or
 +       * NULL if original function should be called.
 +       * Not supported for X86, not tested for MIPS. */
 +      uprobe_opcode_t *ss_addr[NR_CPUS];
 +#ifdef CONFIG_ARM
 +      /** Safe/unsafe to use probe on ARM.*/
 +      unsigned safe_arm:1;
 +      /** Safe/unsafe to use probe on Thumb.*/
 +      unsigned safe_thumb:1;
 +#endif
 +      struct arch_insn ainsn;              /**< Copy of the original instruction.*/
 +      struct arch_tramp atramp;            /**< Stores trampoline */
 +      struct task_struct *task;            /**< Pointer to the task struct */
 +      struct slot_manager *sm;             /**< Pointer to slot manager */
+       bool atomic_ctx;                    /**< Handler context */
  };
  
+ struct uinst_info {
+       struct hlist_node hlist;
+       unsigned long vaddr;
+       kprobe_opcode_t opcode;
+ };
+ struct urinst_info {
+       struct hlist_node hlist;
+       struct task_struct *task;
+       unsigned long sp;
+       unsigned long tramp;
+       unsigned long ret_addr;
+ };
+ struct uinst_info *uinst_info_create(unsigned long vaddr,
+                                    kprobe_opcode_t opcode);
+ void uinst_info_destroy(struct uinst_info *uinst);
+ void uinst_info_disarm(struct uinst_info *uinst, struct task_struct *task);
+ void urinst_info_get_current_hlist(struct hlist_head *head, bool recycle);
+ void urinst_info_put_current_hlist(struct hlist_head *head,
+                                 struct task_struct *task);
  /**
   * @brief Uprobe pre-entry handler.
   */
@@@ -193,11 -168,10 +221,10 @@@ void swap_unregister_uretprobe(struct u
  void __swap_unregister_uretprobe(struct uretprobe *rp, int disarm);
  
  void swap_unregister_all_uprobes(struct task_struct *task);
- void swap_discard_pending_uretprobes(struct task_struct *task);
  
  void swap_ujprobe_return(void);
 -struct kprobe *get_ukprobe(void *addr, pid_t tgid);
 -struct kprobe *get_ukprobe_by_insn_slot(void *addr,
 +struct uprobe *get_uprobe(void *addr, pid_t tgid);
 +struct uprobe *get_uprobe_by_insn_slot(void *addr,
                                        pid_t tgid,
                                        struct pt_regs *regs);
  
@@@ -178,32 -202,95 +202,95 @@@ static void unregister_ctx_task(void
   *                              copy_process()                                *
   ******************************************************************************
   */
- static atomic_t copy_process_cnt = ATOMIC_INIT(0);
+ static void func_uinst_creare(struct us_ip *ip, void *data)
+ {
+       struct hlist_head *head = (struct hlist_head *)data;
+       struct uprobe *up;
  
- static void recover_child(struct task_struct *child_task,
-                         struct sspt_proc *proc)
 -      up = probe_info_get_uprobe(ip->info, ip);
++      up = probe_info_get_uprobe(ip->desc->type, ip);
+       if (up) {
+               struct uinst_info *uinst;
 -              unsigned long vaddr = (unsigned long)up->kp.addr;
++              unsigned long vaddr = (unsigned long)up->addr;
 -              uinst = uinst_info_create(vaddr, up->kp.opcode);
++              uinst = uinst_info_create(vaddr, up->opcode);
+               if (uinst)
+                       hlist_add_head(&uinst->hlist, head);
+       }
+ }
+ static void disarm_for_task(struct task_struct *child, struct hlist_head *head)
  {
-       sspt_proc_uninstall(proc, child_task, US_DISARM);
-       swap_disarm_urp_inst_for_task(current, child_task);
+       struct uinst_info *uinst;
+       struct hlist_node *tmp;
+       DECLARE_NODE_PTR_FOR_HLIST(node);
+       swap_hlist_for_each_entry_safe(uinst, node, tmp, head, hlist) {
+               uinst_info_disarm(uinst, child);
+               hlist_del(&uinst->hlist);
+               uinst_info_destroy(uinst);
+       }
  }
  
- static void rm_uprobes_child(struct task_struct *task)
+ struct clean_data {
+       struct task_struct *task;
+       struct hlist_head head;
+       struct hlist_head rhead;
+ };
+ static atomic_t rm_uprobes_child_cnt = ATOMIC_INIT(0);
+ static unsigned long cb_clean_child(void *data)
+ {
+       struct clean_data *cdata = (struct clean_data *)data;
+       struct task_struct *child = cdata->task;
+       /* disarm up for child */
+       disarm_for_task(child, &cdata->head);
+       /* disarm urp for child */
+       urinst_info_put_current_hlist(&cdata->rhead, child);
+       atomic_dec(&rm_uprobes_child_cnt);
+       return 0;
+ }
+ static void rm_uprobes_child(struct kretprobe_instance *ri,
+                            struct pt_regs *regs, struct task_struct *child)
  {
        struct sspt_proc *proc;
+       struct clean_data cdata = {
+               .task = child,
+               .head = HLIST_HEAD_INIT,
+               .rhead = HLIST_HEAD_INIT
+       };
  
        sspt_proc_write_lock();
+       proc = sspt_proc_get_by_task_no_lock(current);
+       if (proc) {
+               sspt_proc_on_each_ip(proc, func_uinst_creare, (void *)&cdata.head);
+               urinst_info_get_current_hlist(&cdata.rhead, false);
+       }
+       sspt_proc_write_unlock();
  
-       proc = sspt_proc_get_by_task(current);
-       if (proc)
-               recover_child(task, proc);
+       if (proc) {
+               int ret;
  
-       sspt_proc_write_unlock();
+               /* set jumper */
+               ret = set_jump_cb((unsigned long)ri->ret_addr, regs,
+                                 cb_clean_child, &cdata, sizeof(cdata));
+               if (ret == 0) {
+                       atomic_inc(&rm_uprobes_child_cnt);
+                       ri->ret_addr = (unsigned long *)get_jump_addr();
+               }
+       }
  }
  
- static int entry_handler_cp(struct kretprobe_instance *ri, struct pt_regs *regs)
- {
-       atomic_inc(&copy_process_cnt);
  
+ static atomic_t pre_handler_cp_cnt = ATOMIC_INIT(0);
+ static unsigned long cp_cb(void *data)
+ {
        if (atomic_read(&stop_flag))
                call_mm_release(current);
  
@@@ -111,7 -114,10 +116,9 @@@ int img_file_add_ip(struct img_file *fi
                return 0;
        }
  
 -      ip = create_img_ip(addr, probe_i);
 +      ip = create_img_ip(addr, pd);
+       if (ip == NULL)
+               return -ENOMEM;
 -
        img_add_ip_by_list(file, ip);
  
        return 0;
@@@ -187,9 -185,13 +186,12 @@@ void img_proc_copy_to_sspt(struct img_p
        read_lock(&i_proc->rwlock);
        list_for_each_entry(i_file, &i_proc->file_list, list) {
                file = sspt_proc_find_file_or_new(proc, i_file->dentry);
 -
+               if (file) {
+                       struct img_ip *i_ip;
  
-               list_for_each_entry(i_ip, &i_file->ip_list, list)
-                       sspt_file_add_ip(file, i_ip);
+                       list_for_each_entry(i_ip, &i_file->ip_list, list)
 -                              sspt_file_add_ip(file, i_ip->addr, i_ip->info);
++                              sspt_file_add_ip(file, i_ip);
+               }
        }
        read_unlock(&i_proc->rwlock);
  }
Simple merge
Simple merge
@@@ -58,11 -58,12 +58,12 @@@ static inline int sspt_register_usprobe
                return -EINVAL;
        }
  
 -      up->kp.addr = (kprobe_opcode_t *)ip->orig_addr;
 +      up->addr = (kprobe_opcode_t *)ip->orig_addr;
        up->task = ip->page->file->proc->task;
        up->sm = ip->page->file->proc->sm;
+       up->atomic_ctx = true;
  
 -      ret = probe_info_register(ip->info, ip);
 +      ret = probe_info_register(ip->desc->type, ip);
        if (ret) {
                struct sspt_file *file = ip->page->file;
                char *name = file->dentry->d_iname;
@@@ -85,14 -86,15 +86,15 @@@ static inline int sspt_unregister_uspro
  
        switch (flag) {
        case US_UNREGS_PROBE:
 -              probe_info_unregister(ip->info, ip, 1);
 +              probe_info_unregister(ip->desc->type, ip, 1);
                break;
        case US_DISARM:
 -              up = probe_info_get_uprobe(ip->info, ip);
 +              up = probe_info_get_uprobe(ip->desc->type, ip);
-               disarm_uprobe(up, task);
+               if (up)
 -                      disarm_uprobe(&up->kp, task);
++                      disarm_uprobe(up, task);
                break;
        case US_UNINSTALL:
 -              probe_info_unregister(ip->info, ip, 0);
 +              probe_info_unregister(ip->desc->type, ip, 0);
                break;
        default:
                panic("incorrect value flag=%d", flag);
@@@ -178,24 -185,35 +187,40 @@@ struct sspt_page *sspt_find_page_mapped
   * @param ret_type Return type
   * @return Void
   */
 -void sspt_file_add_ip(struct sspt_file *file, unsigned long offset,
 -                    struct probe_info *probe_i)
 +void sspt_file_add_ip(struct sspt_file *file, struct img_ip *img_ip)
  {
 -      struct sspt_page *page =
 -              sspt_find_page_or_new(file, offset & PAGE_MASK);
 +      unsigned long offset = 0;
 +      struct sspt_page *page = NULL;
 +      struct us_ip *ip = NULL;
 +
 +      offset = img_ip->addr & PAGE_MASK;
 +      page = sspt_find_page_or_new(file, offset);
  
        /* FIXME: delete ip */
 -      struct us_ip *ip = create_ip(offset, probe_i, page);
 +      ip = create_ip(img_ip);
 +      if (!ip)
 +              return;
  
 -      if (page && ip)
 -              sspt_add_ip(page, ip);
 +      sspt_add_ip(page, ip);
 +      probe_info_init(ip->desc->type, ip);
  }
  
+ void sspt_file_on_each_ip(struct sspt_file *file,
+                         void (*func)(struct us_ip *, void *), void *data)
+ {
+       int i;
+       const int table_size = (1 << file->page_probes_hash_bits);
+       struct sspt_page *page;
+       struct hlist_head *head;
+       DECLARE_NODE_PTR_FOR_HLIST(node);
+       for (i = 0; i < table_size; ++i) {
+               head = &file->page_probes_table[i];
+               swap_hlist_for_each_entry(page, node, head, hlist)
+                       sspt_page_on_each_ip(page, func, data);
+       }
+ }
  /**
   * @brief Get sspt_page from sspt_file (look)
   *
@@@ -53,8 -53,12 +53,11 @@@ void sspt_file_free(struct sspt_file *f
  
  struct sspt_page *sspt_find_page_mapped(struct sspt_file *file,
                                        unsigned long page);
 -void sspt_file_add_ip(struct sspt_file *file, unsigned long offset,
 -                    struct probe_info *probe_i);
 +void sspt_file_add_ip(struct sspt_file *file, struct img_ip *img_ip);
  
+ void sspt_file_on_each_ip(struct sspt_file *file,
+                         void (*func)(struct us_ip *, void *), void *data);
  struct sspt_page *sspt_get_page(struct sspt_file *file,
                                unsigned long offset_addr);
  void sspt_put_page(struct sspt_page *page);
Simple merge
Simple merge
Simple merge
diff --cc wsp/wsp.c
Simple merge