Merge branch 'dev' into kernel
authorVyacheslav Cherkashin <v.cherkashin@samsung.com>
Fri, 12 Apr 2013 07:49:41 +0000 (11:49 +0400)
committerVyacheslav Cherkashin <v.cherkashin@samsung.com>
Fri, 12 Apr 2013 08:01:02 +0000 (12:01 +0400)
Conflicts:
src/modules/driver/probes_manager.c
src/modules/kprobe/arch/asm-arm/dbi_kprobes.c
src/modules/kprobe/dbi_insn_slots.c
src/modules/kprobe/dbi_kprobes.c
src/modules/kprobe/dbi_uprobes.c

1  2 
driver/probes_manager.c
driver/sspt/sspt_debug.h
driver/sspt/sspt_file.c
driver/storage.c
driver/us_proc_inst.c
kprobe/arch/asm-arm/dbi_kprobes.c
kprobe/dbi_insn_slots.c
kprobe/dbi_kprobes.c
kprobe/dbi_kprobes_deps.c
kprobe/dbi_kprobes_deps.h
uprobe/swap_uprobes.c

@@@ -17,6 -17,6 +17,7 @@@
  
  #include <linux/percpu.h>
  #include <ksyms.h>
++#include <dbi_kprobes_deps.h>
  #include "module.h"
  #include "probes_manager.h"
  
@@@ -136,12 -293,44 +137,12 @@@ int reset_probes(void
        struct hlist_node *node, *tnode;
        kernel_probe_t *p;
  
-       hlist_for_each_entry_safe (p, node, tnode, &kernel_probes, hlist) {
+       swap_hlist_for_each_entry_safe (p, node, tnode, &kernel_probes, hlist) {
 -              if (p->addr == pf_addr) {
 -                      probes_flags &= ~PROBE_FLAG_PF_INSTLD;
 -                      pf_probe = NULL;
 -              } else if (p->addr == cp_addr) {
 -                      probes_flags &= ~PROBE_FLAG_CP_INSTLD;
 -                      cp_probe = NULL;
 -              } else if (p->addr == exit_addr) {
 -                      probes_flags &= ~PROBE_FLAG_EXIT_INSTLD;
 -                      exit_probe = NULL;
 -              } else if (p->addr == mr_addr) {
 -                      probes_flags &= ~PROBE_FLAG_MR_INSTLD;
 -                      mr_probe = NULL;
 -              } else if (p->addr == unmap_addr) {
 -                      probes_flags &= ~PROBE_FLAG_UNMAP_INSTLD;
 -                      unmap_probe = NULL;
 -              }
                hlist_del(node);
                kfree(p);
        }
  
-       hlist_for_each_entry_safe (p, node, tnode, &otg_kernel_probes, hlist) {
+       swap_hlist_for_each_entry_safe (p, node, tnode, &otg_kernel_probes, hlist) {
 -              if (p->addr == pf_addr) {
 -                      probes_flags &= ~PROBE_FLAG_PF_INSTLD;
 -                      pf_probe = NULL;
 -              } else if (p->addr == cp_addr) {
 -                      probes_flags &= ~PROBE_FLAG_CP_INSTLD;
 -                      cp_probe = NULL;
 -              } else if (p->addr == exit_addr) {
 -                      probes_flags &= ~PROBE_FLAG_EXIT_INSTLD;
 -                      exit_probe = NULL;
 -              } else if (p->addr == mr_addr) {
 -                      probes_flags &= ~PROBE_FLAG_MR_INSTLD;
 -                      mr_probe = NULL;
 -              } else if (p->addr == unmap_addr) {
 -                      probes_flags &= ~PROBE_FLAG_UNMAP_INSTLD;
 -                      unmap_probe = NULL;
 -              }
                hlist_del(node);
                kfree(p);
        }
Simple merge
@@@ -27,6 -27,6 +27,7 @@@
  #include <linux/slab.h>
  #include <linux/list.h>
  #include <linux/hash.h>
++#include <dbi_kprobes_deps.h>
  
  static int calculation_hash_bits(int cnt)
  {
@@@ -22,7 -22,6 +22,8 @@@
  #include <linux/spinlock.h>
  #include <linux/kernel.h>
  #include <linux/time.h>
 +#include <ksyms.h>
++#include <dbi_kprobes_deps.h>
  #include "module.h"
  #include "storage.h"
  #include "handlers_core.h"
Simple merge
@@@ -438,7 -1396,8 +438,7 @@@ int trampoline_probe_handler(struct kpr
         *       real return address, and all the rest will point to
         *       kretprobe_trampoline
         */
-       hlist_for_each_entry_safe(ri, node, tmp, head, hlist) {
 -      swap_hlist_for_each_entry_safe (ri, node, tmp, head, hlist)
 -      {
++      swap_hlist_for_each_entry_safe(ri, node, tmp, head, hlist) {
                if (ri->task != current)
                        /* another task is sharing our hash bucket */
                        continue;
   */
  
  #include "dbi_insn_slots.h"
 -#include "dbi_uprobes.h"
 -#include "dbi_kdebug.h"
 -
 -#include <linux/hash.h>
 -#include <linux/mman.h>
 -#include <linux/hugetlb.h>
 -
 +#include <linux/module.h>
 +#include <linux/rculist.h>
  #include <linux/slab.h>
  #include <linux/spinlock.h>
 -
 -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
 -extern unsigned long do_mmap_pgoff(struct file *file, unsigned long addr,
 -                        unsigned long len, unsigned long prot,
 -                        unsigned long flags, unsigned long pgoff, unsigned long *populate);
 -#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) */
 -extern unsigned long do_mmap_pgoff(struct file *file, unsigned long addr,
 -                        unsigned long len, unsigned long prot,
 -                        unsigned long flags, unsigned long pgoff);
 -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) */
 -
 -struct hlist_head kprobe_insn_pages;
 -struct hlist_head uprobe_insn_pages;
++#include <dbi_kprobes_deps.h>
  
  struct chunk {
        unsigned long *data;
@@@ -150,56 -251,68 +151,56 @@@ static struct fixed_alloc *create_fixed
                return NULL;
        }
  
 -      chunk_init(&kip->chunk, data, PAGE_SIZE/sizeof(unsigned long), slot_size(task));
 -      kip->task = task;
 +      chunk_init(&fa->chunk, data, PAGE_SIZE/sizeof(unsigned long), sm->slot_size);
  
 -      return kip;
 +      return fa;
  }
  
 -static void kip_free(struct kprobe_insn_page * kip)
 +static void free_fixed_alloc(struct slot_manager *sm, struct fixed_alloc *fa)
  {
 -      chunk_uninit(&kip->chunk);
 -      page_free(kip->chunk.data, kip->task);
 -      kfree(kip);
 +      chunk_uninit(&fa->chunk);
 +      sm->free(sm, fa->chunk.data);
 +      kfree(fa);
  }
  
 -/**
 - * get_us_insn_slot() - Find a slot on an executable page for an instruction.
 - * We allocate an executable page if there's no room on existing ones.
 - */
 -kprobe_opcode_t *get_insn_slot(struct task_struct *task, int atomic)
 +
 +void *alloc_insn_slot(struct slot_manager *sm)
  {
 -      kprobe_opcode_t * free_slot;
 -      struct kprobe_insn_page *kip;
 +      void *free_slot;
 +      struct fixed_alloc *fa;
        struct hlist_node *pos;
 -      struct hlist_head *page_list = task ? &uprobe_insn_pages : &kprobe_insn_pages;
 -
 -      swap_hlist_for_each_entry_rcu(kip, pos, page_list, hlist) {
 -              if (!task || (kip->task->tgid == task->tgid)) {
 -                      free_slot = chunk_allocate(&kip->chunk, slot_size(task));
 -                      if (free_slot == NULL) {
 -                              break;
 -                      }
  
-       hlist_for_each_entry_rcu(fa, pos, &sm->page_list, hlist) {
++      swap_hlist_for_each_entry_rcu(fa, pos, &sm->page_list, hlist) {
 +              free_slot = chunk_allocate(&fa->chunk, sm->slot_size);
 +              if (free_slot)
                        return free_slot;
 -              }
        }
  
 -      kip = kip_new(task, atomic);
 -      if(kip == NULL)
 +      fa = create_fixed_alloc(sm);
 +      if(fa == NULL)
                return NULL;
  
 -      INIT_HLIST_NODE (&kip->hlist);
 -      hlist_add_head_rcu(&kip->hlist, page_list);
 +      INIT_HLIST_NODE(&fa->hlist);
 +      hlist_add_head_rcu(&fa->hlist, &sm->page_list);
  
 -      return chunk_allocate(&kip->chunk, slot_size(task));
 +      return chunk_allocate(&fa->chunk, sm->slot_size);
  }
 +EXPORT_SYMBOL_GPL(alloc_insn_slot);
  
 -void free_insn_slot(struct hlist_head *page_list, struct task_struct *task, kprobe_opcode_t *slot)
 +void free_insn_slot(struct slot_manager *sm, void *slot)
  {
 -      struct kprobe_insn_page *kip;
 +      struct fixed_alloc *fa;
        struct hlist_node *pos;
  
-       hlist_for_each_entry_rcu(fa, pos, &sm->page_list, hlist) {
 -      swap_hlist_for_each_entry_rcu(kip, pos, page_list, hlist) {
 -              if (!(!task || (kip->task->tgid == task->tgid)))
 -                      continue;
 -
 -              if (!chunk_check_ptr(&kip->chunk, slot, PAGE_SIZE))
++      swap_hlist_for_each_entry_rcu(fa, pos, &sm->page_list, hlist) {
 +              if (!chunk_check_ptr(&fa->chunk, slot, PAGE_SIZE))
                        continue;
  
 -              chunk_deallocate(&kip->chunk, slot, slot_size(task));
 +              chunk_deallocate(&fa->chunk, slot, sm->slot_size);
  
 -              if (chunk_free(&kip->chunk)) {
 -                      hlist_del_rcu(&kip->hlist);
 -                      kip_free(kip);
 +              if (chunk_free(&fa->chunk)) {
 +                      hlist_del_rcu(&fa->hlist);
 +                      free_fixed_alloc(sm, fa);
                }
  
                return;
@@@ -162,12 -144,13 +162,12 @@@ struct kprobe *get_kprobe(void *addr
  {
        struct hlist_head *head;
        struct hlist_node *node;
 -      struct kprobe *p, *retVal = NULL;
 +      struct kprobe *p;
  
        head = &kprobe_table[hash_ptr (addr, KPROBE_HASH_BITS)];
-       hlist_for_each_entry_rcu(p, node, head, hlist) {
+       swap_hlist_for_each_entry_rcu(p, node, head, hlist) {
 -              if (p->addr == addr && p->tgid == tgid) {
 -                      retVal = p;
 -                      break;
 +              if (p->addr == addr) {
 +                      return p;
                }
        }
  
@@@ -260,31 -253,22 +260,31 @@@ struct kretprobe_instance *get_free_rp_
  {
        struct hlist_node *node;
        struct kretprobe_instance *ri;
 -      swap_hlist_for_each_entry (ri, node, &rp->free_instances, uflist)
 +
-       hlist_for_each_entry(ri, node, &rp->free_instances, uflist) {
++      swap_hlist_for_each_entry(ri, node, &rp->free_instances, uflist) {
                return ri;
 -      if(!alloc_nodes_kretprobe(rp)){
 -           swap_hlist_for_each_entry (ri, node, &rp->free_instances, uflist)
 -                return ri;
        }
-               hlist_for_each_entry(ri, node, &rp->free_instances, uflist) {
 +
 +      if (!alloc_nodes_kretprobe(rp)) {
++              swap_hlist_for_each_entry(ri, node, &rp->free_instances, uflist) {
 +                      return ri;
 +              }
 +      }
 +
        return NULL;
  }
 +EXPORT_SYMBOL_GPL(get_free_rp_inst);
  
  /* Called with kretprobe_lock held */
 -struct kretprobe_instance *get_free_rp_inst_no_alloc (struct kretprobe *rp)
 +struct kretprobe_instance *get_free_rp_inst_no_alloc(struct kretprobe *rp)
  {
        struct hlist_node *node;
        struct kretprobe_instance *ri;
 -      swap_hlist_for_each_entry (ri, node, &rp->free_instances, uflist)
 +
-       hlist_for_each_entry(ri, node, &rp->free_instances, uflist) {
++      swap_hlist_for_each_entry(ri, node, &rp->free_instances, uflist) {
                return ri;
 +      }
 +
        return NULL;
  }
  
@@@ -293,14 -277,9 +293,14 @@@ struct kretprobe_instance *get_used_rp_
  {
        struct hlist_node *node;
        struct kretprobe_instance *ri;
 -      swap_hlist_for_each_entry (ri, node, &rp->used_instances, uflist) return ri;
 +
-       hlist_for_each_entry(ri, node, &rp->used_instances, uflist) {
++      swap_hlist_for_each_entry(ri, node, &rp->used_instances, uflist) {
 +              return ri;
 +      }
 +
        return NULL;
  }
 +EXPORT_SYMBOL_GPL(get_used_rp_inst);
  
  /* Called with kretprobe_lock held */
  void add_rp_inst (struct kretprobe_instance *ri)
Simple merge
Simple merge
index 0ef88ce,0000000..c4ab6f7
mode 100644,000000..100644
--- /dev/null
@@@ -1,983 -1,0 +1,983 @@@
-               hlist_for_each_entry_rcu (p, node, head, is_hlist_arm) {
 +/*
 + *  Dynamic Binary Instrumentation Module based on KProbes
 + *  modules/kprobe/dbi_uprobes.h
 + *
 + * 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) Samsung Electronics, 2006-2010
 + *
 + * 2008-2009    Alexey Gerenkov <a.gerenkov@samsung.com> User-Space
 + *              Probes initial implementation; Support x86/ARM/MIPS for both user and kernel spaces.
 + * 2010         Ekaterina Gorelkina <e.gorelkina@samsung.com>: redesign module for separating core and arch parts
 + *
 + */
 +
 +
 +#include "swap_uprobes.h"
 +#include "dbi_kdebug.h"
 +
 +#include <asm/swap_uprobes.h>
 +
 +#include <linux/hash.h>
 +#include <linux/mempolicy.h>
 +#include <linux/module.h>
 +#include <dbi_insn_slots.h>
 +#include <dbi_kprobes_deps.h>
 +
 +enum {
 +      UPROBE_HASH_BITS  = 10,
 +      UPROBE_TABLE_SIZE = (1 << UPROBE_HASH_BITS)
 +};
 +
 +struct hlist_head uprobe_insn_slot_table[UPROBE_TABLE_SIZE];
 +struct hlist_head uprobe_table[UPROBE_TABLE_SIZE];
 +struct hlist_head uprobe_insn_pages;
 +
 +DEFINE_SPINLOCK(uretprobe_lock);      /* Protects uretprobe_inst_table */
 +static struct hlist_head uretprobe_inst_table[UPROBE_TABLE_SIZE];
 +
 +#define DEBUG_PRINT_HASH_TABLE 0
 +
 +#if DEBUG_PRINT_HASH_TABLE
 +void print_kprobe_hash_table(void)
 +{
 +      int i;
 +      struct hlist_head *head;
 +      struct hlist_node *node;
 +      struct kprobe *p;
 +
 +      // print uprobe table
 +      for (i = 0; i < KPROBE_TABLE_SIZE; ++i) {
 +              head = &kprobe_table[i];
-               hlist_for_each_entry_rcu (p, node, head, is_hlist_arm) {
++              swap_hlist_for_each_entry_rcu(p, node, head, is_hlist_arm) {
 +                      printk("####### find K tgid=%u, addr=%x\n",
 +                                      p->tgid, p->addr);
 +              }
 +      }
 +}
 +
 +void print_kretprobe_hash_table(void)
 +{
 +      int i;
 +      struct hlist_head *head;
 +      struct hlist_node *node;
 +      struct kprobe *p;
 +
 +      // print uprobe table
 +      for (i = 0; i < KPROBE_TABLE_SIZE; ++i) {
 +              head = &kretprobe_inst_table[i];
-               hlist_for_each_entry_rcu (p, node, head, is_hlist_arm) {
++              swap_hlist_for_each_entry_rcu(p, node, head, is_hlist_arm) {
 +                      printk("####### find KR tgid=%u, addr=%x\n",
 +                                      p->tgid, p->addr);
 +              }
 +      }
 +}
 +
 +void print_uprobe_hash_table(void)
 +{
 +      int i;
 +      struct hlist_head *head;
 +      struct hlist_node *node;
 +      struct kprobe *p;
 +
 +      // print uprobe table
 +      for (i = 0; i < UPROBE_TABLE_SIZE; ++i) {
 +              head = &uprobe_insn_slot_table[i];
-       hlist_for_each_entry_rcu(p, node, head, hlist) {
++              swap_hlist_for_each_entry_rcu(p, node, head, is_hlist_arm) {
 +                      printk("####### find U tgid=%u, addr=%x\n",
 +                                      p->tgid, p->addr);
 +              }
 +      }
 +}
 +#endif
 +
 +/*
 + * Keep all fields in the uprobe consistent
 + */
 +static inline void copy_uprobe(struct kprobe *old_p, struct kprobe *p)
 +{
 +      memcpy(&p->opcode, &old_p->opcode, sizeof(kprobe_opcode_t));
 +      memcpy(&p->ainsn, &old_p->ainsn, sizeof(struct arch_specific_insn));
 +      p->ss_addr = old_p->ss_addr;
 +#ifdef CONFIG_ARM
 +      p->safe_arm = old_p->safe_arm;
 +      p->safe_thumb = old_p->safe_thumb;
 +#endif
 +}
 +
 +/*
 + * Aggregate handlers for multiple uprobes support - these handlers
 + * take care of invoking the individual uprobe handlers on p->list
 + */
 +static int aggr_pre_uhandler(struct kprobe *p, struct pt_regs *regs)
 +{
 +      struct kprobe *kp;
 +      int ret;
 +
 +      list_for_each_entry_rcu(kp, &p->list, list) {
 +              if (kp->pre_handler) {
 +                      ret = kp->pre_handler(kp, regs);
 +                      if (ret) {
 +                              return ret;
 +                      }
 +              }
 +      }
 +
 +      return 0;
 +}
 +
 +static void aggr_post_uhandler(struct kprobe *p, struct pt_regs *regs, unsigned long flags)
 +{
 +      struct kprobe *kp;
 +
 +      list_for_each_entry_rcu(kp, &p->list, list) {
 +              if (kp->post_handler) {
 +                      kp->post_handler(kp, regs, flags);
 +              }
 +      }
 +}
 +
 +static int aggr_fault_uhandler(struct kprobe *p, struct pt_regs *regs, int trapnr)
 +{
 +      return 0;
 +}
 +
 +static int aggr_break_uhandler(struct kprobe *p, struct pt_regs *regs)
 +{
 +      return 0;
 +}
 +
 +/*
 + * Add the new probe to old_p->list. Fail if this is the
 + * second ujprobe at the address - two ujprobes can't coexist
 + */
 +static int add_new_uprobe(struct kprobe *old_p, struct kprobe *p)
 +{
 +      if (p->break_handler) {
 +              if (old_p->break_handler) {
 +                      return -EEXIST;
 +              }
 +
 +              list_add_tail_rcu(&p->list, &old_p->list);
 +              old_p->break_handler = aggr_break_uhandler;
 +      } else {
 +              list_add_rcu (&p->list, &old_p->list);
 +      }
 +
 +      if (p->post_handler && !old_p->post_handler) {
 +              old_p->post_handler = aggr_post_uhandler;
 +      }
 +
 +      return 0;
 +}
 +
 +/*
 + * Fill in the required fields of the "manager uprobe". Replace the
 + * earlier uprobe in the hlist with the manager uprobe
 + */
 +static inline void add_aggr_uprobe(struct kprobe *ap, struct kprobe *p)
 +{
 +      copy_uprobe(p, ap);
 +
 +      ap->addr = p->addr;
 +      ap->pre_handler = aggr_pre_uhandler;
 +      ap->fault_handler = aggr_fault_uhandler;
 +
 +      if (p->post_handler) {
 +              ap->post_handler = aggr_post_uhandler;
 +      }
 +
 +      if (p->break_handler) {
 +              ap->break_handler = aggr_break_uhandler;
 +      }
 +
 +      INIT_LIST_HEAD(&ap->list);
 +      list_add_rcu(&p->list, &ap->list);
 +
 +      hlist_replace_rcu(&p->hlist, &ap->hlist);
 +}
 +
 +/*
 + * This is the second or subsequent uprobe at the address - handle
 + * the intricacies
 + */
 +static int register_aggr_uprobe(struct kprobe *old_p, struct kprobe *p)
 +{
 +      int ret = 0;
 +      struct kprobe *ap;
 +
 +      if (old_p->pre_handler == aggr_pre_uhandler) {
 +              copy_uprobe(old_p, p);
 +              ret = add_new_uprobe(old_p, p);
 +      } else {
 +              struct uprobe *uap = kzalloc(sizeof(*uap), GFP_KERNEL);
 +              if (!uap) {
 +                      return -ENOMEM;
 +              }
 +
 +              uap->task = kp2up(p)->task;
 +              ap = up2kp(uap);
 +              add_aggr_uprobe(ap, old_p);
 +              copy_uprobe(ap, p);
 +              ret = add_new_uprobe(ap, p);
 +      }
 +
 +      return ret;
 +}
 +
 +static void arm_uprobe(struct uprobe *p)
 +{
 +      kprobe_opcode_t insn = BREAKPOINT_INSTRUCTION;
 +      int ret = write_proc_vm_atomic(p->task, (unsigned long)p->kp.addr,
 +                                     &insn, sizeof(insn));
 +      if (!ret) {
 +              panic("arm_uprobe: failed to write memory "
 +                    "tgid=%u addr=%p!\n", p->task->tgid, p->kp.addr);
 +      }
 +}
 +
 +void disarm_uprobe(struct kprobe *p, struct task_struct *task)
 +{
 +      int ret = write_proc_vm_atomic(task, (unsigned long)p->addr,
 +                                     &p->opcode, sizeof(p->opcode));
 +      if (!ret) {
 +              panic("disarm_uprobe: failed to write memory "
 +                    "tgid=%u, addr=%p!\n", task->tgid, p->addr);
 +      }
 +}
 +EXPORT_SYMBOL_GPL(disarm_uprobe);
 +
 +static void init_uprobes_insn_slots(void)
 +{
 +      int i;
 +      for (i = 0; i < UPROBE_TABLE_SIZE; ++i) {
 +              INIT_HLIST_HEAD(&uprobe_insn_slot_table[i]);
 +      }
 +}
 +
 +static void init_uprobe_table(void)
 +{
 +      int i;
 +      for (i = 0; i < UPROBE_TABLE_SIZE; ++i) {
 +              INIT_HLIST_HEAD(&uprobe_table[i]);
 +      }
 +}
 +
 +static void init_uretprobe_inst_table(void)
 +{
 +      int i;
 +      for (i = 0; i < UPROBE_TABLE_SIZE; ++i) {
 +              INIT_HLIST_HEAD (&uretprobe_inst_table[i]);
 +      }
 +}
 +
 +struct kprobe *get_ukprobe(void *addr, pid_t tgid)
 +{
 +      struct hlist_head *head;
 +      struct hlist_node *node;
 +      struct kprobe *p;
 +
 +      head = &uprobe_table[hash_ptr(addr, UPROBE_HASH_BITS)];
-       hlist_for_each_entry_rcu(p, node, head, is_hlist_arm) {
++      swap_hlist_for_each_entry_rcu(p, node, head, hlist) {
 +              if (p->addr == addr && kp2up(p)->task->tgid == tgid) {
 +                      return p;
 +              }
 +      }
 +
 +      return NULL;
 +}
 +
 +static void add_uprobe_table(struct kprobe *p)
 +{
 +#ifdef CONFIG_ARM
 +      INIT_HLIST_NODE(&p->is_hlist_arm);
 +      hlist_add_head_rcu(&p->is_hlist_arm, &uprobe_insn_slot_table[hash_ptr(p->ainsn.insn_arm, UPROBE_HASH_BITS)]);
 +      INIT_HLIST_NODE(&p->is_hlist_thumb);
 +      hlist_add_head_rcu(&p->is_hlist_thumb, &uprobe_insn_slot_table[hash_ptr(p->ainsn.insn_thumb, UPROBE_HASH_BITS)]);
 +#else /* CONFIG_ARM */
 +      INIT_HLIST_NODE(&p->is_hlist);
 +      hlist_add_head_rcu(&p->is_hlist, &uprobe_insn_slot_table[hash_ptr(p->ainsn.insn, UPROBE_HASH_BITS)]);
 +#endif /* CONFIG_ARM */
 +}
 +
 +#ifdef CONFIG_ARM
 +static struct kprobe *get_ukprobe_bis_arm(void *addr, pid_t tgid)
 +{
 +      struct hlist_head *head;
 +      struct hlist_node *node;
 +      struct kprobe *p;
 +
 +      /* TODO: test - two processes invokes instrumented function */
 +      head = &uprobe_insn_slot_table[hash_ptr(addr, UPROBE_HASH_BITS)];
-       hlist_for_each_entry_rcu(p, node, head, is_hlist_thumb) {
++      swap_hlist_for_each_entry_rcu(p, node, head, is_hlist_arm) {
 +              if (p->ainsn.insn == addr && kp2up(p)->task->tgid == tgid) {
 +                      return p;
 +              }
 +      }
 +
 +      return NULL;
 +}
 +
 +static struct kprobe *get_ukprobe_bis_thumb(void *addr, pid_t tgid)
 +{
 +      struct hlist_head *head;
 +      struct hlist_node *node;
 +      struct kprobe *p;
 +
 +      /* TODO: test - two processes invokes instrumented function */
 +      head = &uprobe_insn_slot_table[hash_ptr(addr, UPROBE_HASH_BITS)];
-       hlist_for_each_entry_rcu(p, node, head, is_hlist) {
++      swap_hlist_for_each_entry_rcu(p, node, head, is_hlist_thumb) {
 +              if (p->ainsn.insn == addr && kp2up(p)->task->tgid == tgid) {
 +                      return p;
 +              }
 +      }
 +
 +      return NULL;
 +}
 +
 +struct kprobe *get_ukprobe_by_insn_slot(void *addr, pid_t tgid, struct pt_regs *regs)
 +{
 +      return thumb_mode(regs) ?
 +                      get_ukprobe_bis_thumb(addr - 0x1a, tgid) :
 +                      get_ukprobe_bis_arm(addr - 4 * UPROBES_TRAMP_RET_BREAK_IDX, tgid);
 +}
 +#else /* CONFIG_ARM */
 +struct kprobe *get_ukprobe_by_insn_slot(void *addr, pid_t tgid, struct pt_regs *regs)
 +{
 +      struct hlist_head *head;
 +      struct hlist_node *node;
 +      struct kprobe *p;
 +
 +      /* TODO: test - two processes invokes instrumented function */
 +      head = &uprobe_insn_slot_table[hash_ptr(addr, UPROBE_HASH_BITS)];
-       hlist_for_each_entry(ri, node, &rp->used_instances, uflist) {
++      swap_hlist_for_each_entry_rcu(p, node, head, is_hlist) {
 +              if (p->ainsn.insn == addr && kp2up(p)->task->tgid == tgid) {
 +                      return p;
 +              }
 +      }
 +
 +      return NULL;
 +}
 +#endif /* CONFIG_ARM */
 +
 +
 +static void remove_uprobe(struct uprobe *up)
 +{
 +      struct kprobe *p = &up->kp;
 +      struct task_struct *task = up->task;
 +
 +#ifdef CONFIG_ARM
 +      free_insn_slot(up->sm, p->ainsn.insn_arm);
 +      free_insn_slot(up->sm, p->ainsn.insn_thumb);
 +#else /* CONFIG_ARM */
 +      free_insn_slot(up->sm, p->ainsn.insn);
 +#endif /* CONFIG_ARM */
 +}
 +
 +static struct hlist_head *uretprobe_inst_table_head(void *hash_key)
 +{
 +      return &uretprobe_inst_table[hash_ptr (hash_key, UPROBE_HASH_BITS)];
 +}
 +
 +/* Called with uretprobe_lock held */
 +static void add_urp_inst(struct uretprobe_instance *ri)
 +{
 +      /*
 +       * Remove rp inst off the free list -
 +       * Add it back when probed function returns
 +       */
 +      hlist_del(&ri->uflist);
 +
 +      /* Add rp inst onto table */
 +      INIT_HLIST_NODE(&ri->hlist);
 +      hlist_add_head(&ri->hlist, uretprobe_inst_table_head(ri->task->mm));
 +
 +      /* Also add this rp inst to the used list. */
 +      INIT_HLIST_NODE(&ri->uflist);
 +      hlist_add_head(&ri->uflist, &ri->rp->used_instances);
 +}
 +
 +/* Called with uretprobe_lock held */
 +static void recycle_urp_inst(struct uretprobe_instance *ri)
 +{
 +      if (ri->rp) {
 +              hlist_del(&ri->hlist);
 +              /* remove rp inst off the used list */
 +              hlist_del(&ri->uflist);
 +              /* put rp inst back onto the free list */
 +              INIT_HLIST_NODE(&ri->uflist);
 +              hlist_add_head(&ri->uflist, &ri->rp->free_instances);
 +      }
 +}
 +
 +/* Called with uretprobe_lock held */
 +static struct uretprobe_instance *get_used_urp_inst(struct uretprobe *rp)
 +{
 +      struct hlist_node *node;
 +      struct uretprobe_instance *ri;
 +
-       hlist_for_each_entry (ri, node, &rp->free_instances, uflist) {
++      swap_hlist_for_each_entry(ri, node, &rp->used_instances, uflist) {
 +              return ri;
 +      }
 +
 +      return NULL;
 +}
 +
 +/* Called with uretprobe_lock held */
 +struct uretprobe_instance *get_free_urp_inst_no_alloc(struct uretprobe *rp)
 +{
 +      struct hlist_node *node;
 +      struct uretprobe_instance *ri;
 +
-       hlist_for_each_entry(ri, node, &rp->free_instances, uflist) {
++      swap_hlist_for_each_entry(ri, node, &rp->free_instances, uflist) {
 +              return ri;
 +      }
 +
 +      return NULL;
 +}
 +
 +/* Called with uretprobe_lock held */
 +static void free_urp_inst(struct uretprobe *rp)
 +{
 +      struct uretprobe_instance *ri;
 +      while ((ri = get_free_urp_inst_no_alloc(rp)) != NULL) {
 +              hlist_del(&ri->uflist);
 +              kfree(ri);
 +      }
 +}
 +
 +#define COMMON_URP_NR 10
 +
 +static int alloc_nodes_uretprobe(struct uretprobe *rp)
 +{
 +      int alloc_nodes;
 +      struct uretprobe_instance *inst;
 +      int i;
 +
 +#if 1//def CONFIG_PREEMPT
 +      rp->maxactive += max(COMMON_URP_NR, 2 * NR_CPUS);
 +#else
 +      rp->maxacpptive += NR_CPUS;
 +#endif
 +      alloc_nodes = COMMON_URP_NR;
 +
 +      for (i = 0; i < alloc_nodes; ++i) {
 +              inst = kmalloc(sizeof(*inst), GFP_ATOMIC);
 +              if (inst == NULL) {
 +                      free_urp_inst(rp);
 +                      return -ENOMEM;
 +              }
 +              INIT_HLIST_NODE(&inst->uflist);
 +              hlist_add_head(&inst->uflist, &rp->free_instances);
 +      }
 +
 +      return 0;
 +}
 +
 +/* Called with uretprobe_lock held */
 +static struct uretprobe_instance *get_free_urp_inst(struct uretprobe *rp)
 +{
 +      struct hlist_node *node;
 +      struct uretprobe_instance *ri;
 +
-               hlist_for_each_entry(ri, node, &rp->free_instances, uflist) {
++      swap_hlist_for_each_entry(ri, node, &rp->free_instances, uflist) {
 +              return ri;
 +      }
 +
 +      if (!alloc_nodes_uretprobe(rp)) {
-       hlist_for_each_entry_safe(ri, node, tmp, head, hlist) {
++              swap_hlist_for_each_entry(ri, node, &rp->free_instances, uflist) {
 +                      return ri;
 +              }
 +      }
 +
 +      return NULL;
 +}
 +// ===================================================================
 +
 +int dbi_register_uprobe(struct uprobe *up, int atomic)
 +{
 +      int ret = 0;
 +      struct kprobe *p, *old_p;
 +
 +      p = &up->kp;
 +      if (!p->addr) {
 +              return -EINVAL;
 +      }
 +
 +      DBPRINTF("p->addr = 0x%p p = 0x%p\n", p->addr, p);
 +
 +// thumb address = address-1;
 +#if defined(CONFIG_ARM)
 +      // TODO: must be corrected in 'bundle'
 +      if ((unsigned long) p->addr & 0x01) {
 +              p->addr = (kprobe_opcode_t *)((unsigned long)p->addr & 0xfffffffe);
 +      }
 +#endif
 +
 +      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;
 +      p->hnd_tm_sum.tv_sec = p->hnd_tm_sum.tv_usec = 0;
 +      p->count = 0;
 +#endif
 +
 +      // get the first item
 +      old_p = get_ukprobe(p->addr, kp2up(p)->task->tgid);
 +      if (old_p) {
 +#ifdef CONFIG_ARM
 +              p->safe_arm = old_p->safe_arm;
 +              p->safe_thumb = old_p->safe_thumb;
 +#endif
 +              ret = register_aggr_uprobe(old_p, p);
 +              if (!ret) {
 +//                    atomic_inc(&kprobe_count);
 +                      add_uprobe_table(p);
 +              }
 +              DBPRINTF("goto out\n", ret);
 +              goto out;
 +      }
 +
 +      ret = arch_prepare_uprobe(up, &uprobe_insn_pages, atomic);
 +      if (ret) {
 +              DBPRINTF("goto out\n", ret);
 +              goto out;
 +      }
 +
 +      DBPRINTF ("before out ret = 0x%x\n", ret);
 +
 +      // TODO: add uprobe (must be in function)
 +      INIT_HLIST_NODE(&p->hlist);
 +      hlist_add_head_rcu(&p->hlist, &uprobe_table[hash_ptr(p->addr, UPROBE_HASH_BITS)]);
 +      add_uprobe_table(p);
 +      arm_uprobe(up);
 +
 +out:
 +      DBPRINTF("out ret = 0x%x\n", ret);
 +      return ret;
 +}
 +
 +void dbi_unregister_uprobe(struct uprobe *up, int atomic)
 +{
 +      struct kprobe *p, *old_p, *list_p;
 +      int cleanup_p;
 +
 +      p = &up->kp;
 +      old_p = get_ukprobe(p->addr, kp2up(p)->task->tgid);
 +      if (unlikely(!old_p)) {
 +              return;
 +      }
 +
 +      if (p != old_p) {
 +              list_for_each_entry_rcu(list_p, &old_p->list, list) {
 +                      if (list_p == p) {
 +                              /* uprobe p is a valid probe */
 +                              goto valid_p;
 +                      }
 +              }
 +
 +              return;
 +      }
 +
 +valid_p:
 +      if ((old_p == p) || ((old_p->pre_handler == aggr_pre_uhandler) &&
 +          (p->list.next == &old_p->list) && (p->list.prev == &old_p->list))) {
 +              /* Only probe on the hash list */
 +              disarm_uprobe(&up->kp, up->task);
 +              hlist_del_rcu(&old_p->hlist);
 +              cleanup_p = 1;
 +      } else {
 +              list_del_rcu(&p->list);
 +              cleanup_p = 0;
 +      }
 +
 +      if (cleanup_p) {
 +              if (p != old_p) {
 +                      list_del_rcu(&p->list);
 +                      kfree(old_p);
 +              }
 +
 +              if (!in_atomic()) {
 +                      synchronize_sched();
 +              }
 +
 +              remove_uprobe(up);
 +      } else {
 +              if (p->break_handler) {
 +                      old_p->break_handler = NULL;
 +              }
 +
 +              if (p->post_handler) {
 +                      list_for_each_entry_rcu (list_p, &old_p->list, list) {
 +                              if (list_p->post_handler) {
 +                                      cleanup_p = 2;
 +                                      break;
 +                              }
 +                      }
 +
 +                      if (cleanup_p == 0) {
 +                              old_p->post_handler = NULL;
 +                      }
 +              }
 +      }
 +}
 +
 +int dbi_register_ujprobe(struct ujprobe *jp, int atomic)
 +{
 +      int ret = 0;
 +
 +      /* Todo: Verify probepoint is a function entry point */
 +      jp->up.kp.pre_handler = setjmp_upre_handler;
 +      jp->up.kp.break_handler = longjmp_break_uhandler;
 +
 +      ret = dbi_register_uprobe(&jp->up, atomic);
 +
 +      return ret;
 +}
 +
 +void dbi_unregister_ujprobe(struct ujprobe *jp, int atomic)
 +{
 +      dbi_unregister_uprobe(&jp->up, atomic);
 +      /*
 +       * Here is an attempt to unregister even those probes that have not been
 +       * installed (hence not added to the hlist).
 +       * So if we try to delete them from the hlist we will get NULL pointer
 +       * dereference error. That is why we check whether this node
 +       * really belongs to the hlist.
 +       */
 +#ifdef CONFIG_ARM
 +      if (!(hlist_unhashed(&jp->up.kp.is_hlist_arm))) {
 +              hlist_del_rcu(&jp->up.kp.is_hlist_arm);
 +      }
 +      if (!(hlist_unhashed(&jp->up.kp.is_hlist_thumb))) {
 +              hlist_del_rcu(&jp->up.kp.is_hlist_thumb);
 +      }
 +#else /* CONFIG_ARM */
 +      if (!(hlist_unhashed(&jp->up.kp.is_hlist))) {
 +              hlist_del_rcu(&jp->up.kp.is_hlist);
 +      }
 +#endif /* CONFIG_ARM */
 +}
 +
 +int trampoline_uprobe_handler(struct kprobe *p, struct pt_regs *regs)
 +{
 +      struct uretprobe_instance *ri = NULL;
 +      struct hlist_head *head;
 +      struct hlist_node *node, *tmp;
 +      unsigned long flags, tramp_addr, orig_ret_addr = 0;
 +
 +      tramp_addr = arch_get_trampoline_addr(p, regs);
 +      spin_lock_irqsave(&uretprobe_lock, flags);
 +
 +      head = uretprobe_inst_table_head(current->mm);
 +
 +      /*
 +       * It is possible to have multiple instances associated with a given
 +       * task either because an multiple functions in the call path
 +       * have a return probe installed on them, and/or more then one
 +       * return probe was registered for a target function.
 +       *
 +       * We can handle this because:
 +       *     - instances are always inserted at the head of the list
 +       *     - when multiple return probes are registered for the same
 +       *       function, the first instance's ret_addr will point to the
 +       *       real return address, and all the rest will point to
 +       *       uretprobe_trampoline
 +       */
-       hlist_for_each_entry_safe(ri, node, tmp, head, hlist) {
++      swap_hlist_for_each_entry_safe(ri, node, tmp, head, hlist) {
 +              if (ri->task != current) {
 +                      /* another task is sharing our hash bucket */
 +                      continue;
 +              }
 +
 +              if (ri->rp && ri->rp->handler) {
 +                      ri->rp->handler(ri, regs, ri->rp->priv_arg);
 +              }
 +
 +              orig_ret_addr = (unsigned long)ri->ret_addr;
 +              recycle_urp_inst(ri);
 +
 +              if (orig_ret_addr != tramp_addr) {
 +                      /*
 +                       * This is the real return address. Any other
 +                       * instances associated with this task are for
 +                       * other calls deeper on the call stack
 +                       */
 +                      break;
 +              }
 +      }
 +
 +      spin_unlock_irqrestore(&uretprobe_lock, flags);
 +      arch_set_orig_ret_addr(orig_ret_addr, regs);
 +
 +      return 1;
 +}
 +
 +static int pre_handler_uretprobe(struct kprobe *p, struct pt_regs *regs)
 +{
 +      struct uprobe *up = container_of(p, struct uprobe, kp);
 +      struct uretprobe *rp = container_of(up, struct uretprobe, up);
 +      struct uretprobe_instance *ri;
 +      unsigned long flags;
 +
 +      /* TODO: consider to only swap the RA after the last pre_handler fired */
 +      spin_lock_irqsave(&uretprobe_lock, flags);
 +
 +      /* TODO: test - remove retprobe after func entry but before its exit */
 +      if ((ri = get_free_urp_inst(rp)) != NULL) {
 +              ri->rp = rp;
 +              ri->task = current;
 +
 +              arch_prepare_uretprobe(ri, regs);
 +
 +              add_urp_inst(ri);
 +      } else {
 +              ++rp->nmissed;
 +      }
 +
 +      spin_unlock_irqrestore(&uretprobe_lock, flags);
 +
 +      return 0;
 +}
 +
 +int dbi_register_uretprobe(struct uretprobe *rp, int atomic)
 +{
 +      int i, ret = 0;
 +      struct uretprobe_instance *inst;
 +
 +      DBPRINTF ("START\n");
 +
 +      rp->up.kp.pre_handler = pre_handler_uretprobe;
 +      rp->up.kp.post_handler = NULL;
 +      rp->up.kp.fault_handler = NULL;
 +      rp->up.kp.break_handler = NULL;
 +
 +      /* Pre-allocate memory for max kretprobe instances */
 +      if (rp->maxactive <= 0) {
 +#if 1//def CONFIG_PREEMPT
 +              rp->maxactive = max(10, 2 * NR_CPUS);
 +#else
 +              rp->maxactive = NR_CPUS;
 +#endif
 +      }
 +
 +      INIT_HLIST_HEAD(&rp->used_instances);
 +      INIT_HLIST_HEAD(&rp->free_instances);
 +
 +      for (i = 0; i < rp->maxactive; i++) {
 +              inst = kmalloc(sizeof(*inst), GFP_KERNEL);
 +              if (inst == NULL) {
 +                      free_urp_inst(rp);
 +                      ret = -ENOMEM;
 +                      goto out;
 +              }
 +
 +              INIT_HLIST_NODE(&inst->uflist);
 +              hlist_add_head(&inst->uflist, &rp->free_instances);
 +      }
 +
 +      rp->nmissed = 0;
 +
 +      /* Establish function entry probe point */
 +      ret = dbi_register_uprobe(&rp->up, atomic);
 +      if (ret) {
 +              free_urp_inst(rp);
 +              goto out;
 +      }
 +
 +out:
 +      return ret;
 +}
 +
 +int dbi_disarm_urp_inst(struct uretprobe_instance *ri, struct task_struct *rm_task)
 +{
 +      struct task_struct *task = rm_task ? rm_task : ri->task;
 +      kprobe_opcode_t *tramp;
 +      kprobe_opcode_t *sp = (kprobe_opcode_t *)((long)ri->sp & ~1);
 +      kprobe_opcode_t *stack = sp - RETPROBE_STACK_DEPTH + 1;
 +      kprobe_opcode_t *found = NULL;
 +      kprobe_opcode_t *buf[RETPROBE_STACK_DEPTH];
 +      int i, retval;
 +
 +      /* Understand function mode */
 +      if ((long)ri->sp & 1) {
 +              tramp = (kprobe_opcode_t *)
 +                      ((unsigned long)ri->rp->up.kp.ainsn.insn + 0x1b);
 +      } else {
 +              tramp = (kprobe_opcode_t *)
 +                      (ri->rp->up.kp.ainsn.insn + UPROBES_TRAMP_RET_BREAK_IDX);
 +      }
 +
 +      retval = read_proc_vm_atomic(task, (unsigned long)stack, buf, sizeof(buf));
 +      if (retval != sizeof(buf)) {
 +              printk("---> %s (%d/%d): failed to read stack from %08lx",
 +                      task->comm, task->tgid, task->pid, (unsigned long)stack);
 +              retval = -EFAULT;
 +              goto out;
 +      }
 +
 +      /* search the stack from the bottom */
 +      for (i = RETPROBE_STACK_DEPTH - 1; i >= 0; i--) {
 +              if (buf[i] == tramp) {
 +                      found = stack + i;
 +                      break;
 +              }
 +      }
 +
 +      if (found) {
 +              printk("---> %s (%d/%d): trampoline found at %08lx (%08lx /%+d) - %p\n",
 +                              task->comm, task->tgid, task->pid,
 +                              (unsigned long)found, (unsigned long)sp,
 +                              found - sp, ri->rp->up.kp.addr);
 +              retval = write_proc_vm_atomic(task, (unsigned long)found, &ri->ret_addr,
 +                              sizeof(ri->ret_addr));
 +              if (retval != sizeof(ri->ret_addr)) {
 +                      printk("---> %s (%d/%d): failed to write value to %08lx",
 +                              task->comm, task->tgid, task->pid, (unsigned long)found);
 +                      retval = -EFAULT;
 +              } else {
 +                      retval = 0;
 +              }
 +      } else {
 +              struct pt_regs *uregs = task_pt_regs(ri->task);
 +              unsigned long ra = dbi_get_ret_addr(uregs);
 +              if (ra == (unsigned long)tramp) {
 +                      printk("---> %s (%d/%d): trampoline found at lr = %08lx - %p\n",
 +                                      task->comm, task->tgid, task->pid, ra, ri->rp->up.kp.addr);
 +                      dbi_set_ret_addr(uregs, (unsigned long)tramp);
 +                      retval = 0;
 +              } else {
 +                      printk("---> %s (%d/%d): trampoline NOT found at sp = %08lx, lr = %08lx - %p\n",
 +                                      task->comm, task->tgid, task->pid,
 +                                      (unsigned long)sp, ra, ri->rp->up.kp.addr);
 +                      retval = -ENOENT;
 +              }
 +      }
 +
 +out:
 +      return retval;
 +}
 +
 +/* Called with uretprobe_lock held */
 +int dbi_disarm_urp_inst_for_task(struct task_struct *parent, struct task_struct *task)
 +{
 +      struct uretprobe_instance *ri;
 +      struct hlist_node *node, *tmp;
 +      struct hlist_head *head = uretprobe_inst_table_head(parent->mm);
 +
-               hlist_for_each_entry_safe(p, node, tnode, head, hlist) {
++      swap_hlist_for_each_entry_safe(ri, node, tmp, head, hlist) {
 +              if (parent == ri->task) {
 +                      dbi_disarm_urp_inst(ri, task);
 +              }
 +      }
 +
 +      return 0;
 +}
 +EXPORT_SYMBOL_GPL(dbi_disarm_urp_inst_for_task);
 +
 +void dbi_unregister_uretprobe(struct uretprobe *rp, int atomic)
 +{
 +      unsigned long flags;
 +      struct uretprobe_instance *ri;
 +
 +      spin_lock_irqsave (&uretprobe_lock, flags);
 +
 +      while ((ri = get_used_urp_inst(rp)) != NULL) {
 +              if (dbi_disarm_urp_inst(ri, NULL) != 0)
 +                      /*panic*/printk("%s (%d/%d): cannot disarm urp instance (%08lx)\n",
 +                                      ri->task->comm, ri->task->tgid, ri->task->pid,
 +                                      (unsigned long)rp->up.kp.addr);
 +              recycle_urp_inst(ri);
 +      }
 +
 +      if (hlist_empty(&rp->used_instances)) {
 +              struct kprobe *p = &rp->up.kp;
 +#ifdef CONFIG_ARM
 +              if (!(hlist_unhashed(&p->is_hlist_arm))) {
 +                      hlist_del_rcu(&p->is_hlist_arm);
 +              }
 +
 +              if (!(hlist_unhashed(&p->is_hlist_thumb))) {
 +                      hlist_del_rcu(&p->is_hlist_thumb);
 +              }
 +#else /* CONFIG_ARM */
 +              if (!(hlist_unhashed(&p->is_hlist))) {
 +                      hlist_del_rcu(&p->is_hlist);
 +              }
 +#endif /* CONFIG_ARM */
 +      }
 +
 +      while ((ri = get_used_urp_inst(rp)) != NULL) {
 +              ri->rp = NULL;
 +              hlist_del(&ri->uflist);
 +      }
 +
 +      spin_unlock_irqrestore(&uretprobe_lock, flags);
 +      free_urp_inst(rp);
 +
 +      dbi_unregister_uprobe(&rp->up, atomic);
 +}
 +
 +void dbi_unregister_all_uprobes(struct task_struct *task, int atomic)
 +{
 +      struct hlist_head *head;
 +      struct hlist_node *node, *tnode;
 +      struct kprobe *p;
 +      int i;
 +
 +      for (i = 0; i < UPROBE_TABLE_SIZE; ++i) {
 +              head = &uprobe_table[i];
++              swap_hlist_for_each_entry_safe(p, node, tnode, head, hlist) {
 +                      if (kp2up(p)->task->tgid == task->tgid) {
 +                              struct uprobe *up = container_of(p, struct uprobe, kp);
 +                              printk("dbi_unregister_all_uprobes: delete uprobe at %p[%lx] for %s/%d\n",
 +                                              p->addr, (unsigned long)p->opcode, task->comm, task->pid);
 +                              dbi_unregister_uprobe(up, atomic);
 +                      }
 +              }
 +      }
 +}
 +
 +void dbi_uprobe_return(void)
 +{
 +      dbi_arch_uprobe_return();
 +}
 +
 +static int __init init_uprobes(void)
 +{
 +      init_uprobe_table();
 +      init_uprobes_insn_slots();
 +      init_uretprobe_inst_table();
 +
 +      return swap_arch_init_uprobes();
 +}
 +
 +static void __exit exit_uprobes(void)
 +{
 +      swap_arch_exit_uprobes();
 +}
 +
 +EXPORT_SYMBOL_GPL(dbi_uprobe_return);
 +EXPORT_SYMBOL_GPL(dbi_register_ujprobe);
 +EXPORT_SYMBOL_GPL(dbi_unregister_ujprobe);
 +EXPORT_SYMBOL_GPL(dbi_register_uretprobe);
 +EXPORT_SYMBOL_GPL(dbi_unregister_uretprobe);
 +EXPORT_SYMBOL_GPL(dbi_unregister_all_uprobes);
 +
 +module_init(init_uprobes);
 +module_exit(exit_uprobes);
 +
 +MODULE_LICENSE ("GPL");