[IMPROVE] remove atomic context from kprobe handler 23/69323/4
authorVyacheslav Cherkashin <v.cherkashin@samsung.com>
Tue, 10 May 2016 12:41:00 +0000 (15:41 +0300)
committerDmitry Kovalenko <d.kovalenko@samsung.com>
Wed, 18 May 2016 10:46:16 +0000 (03:46 -0700)
Changes:
1. Kprobe redesign.
2. Current kprobe state saved in stack (thread context) or
in per_cpu_kpc_data (interrupt context).

for ARM:
In kprobe handler irq is turned on, if kprobe was fired in
non-irq context.

for x86:
Breakpoint is processed in several stages:
1. Save regs and change ip on exec_trampoline().
2. Call handlers in original context.
3. Restore regs and changed instruction processing.

Change-Id: I0b8d007eafddaabffd3a030a7a9aaa7ebf1642f3
Signed-off-by: Vyacheslav Cherkashin <v.cherkashin@samsung.com>
12 files changed:
energy/energy.c
kprobe/arch/arm/swap-asm/swap_kprobes.c
kprobe/arch/arm/swap-asm/swap_kprobes.h
kprobe/arch/x86/swap-asm/swap_kprobes.c
kprobe/arch/x86/swap-asm/swap_kprobes.h
kprobe/swap_kprobes.c
kprobe/swap_kprobes.h
ks_features/ks_features.c
ks_manager/ks_manager.c
task_ctx/task_ctx.c
uprobe/arch/x86/swap-asm/swap_uprobes.c
us_manager/helper.c

index 5a44dae..74a7d50 100644 (file)
@@ -65,8 +65,8 @@ static int energy_xxx_once(struct kern_probe p[], int size)
                struct kretprobe *rp = p[i].rp;
 
                sym = p[i].name;
-               rp->kp.addr = (kprobe_opcode_t *)swap_ksyms(sym);
-               if (rp->kp.addr == NULL)
+               rp->kp.addr = swap_ksyms(sym);
+               if (rp->kp.addr == 0)
                        goto not_found;
        }
 
@@ -1135,18 +1135,18 @@ int energy_once(void)
        const char *sym;
 
        sym = "__switch_to";
-       switch_to_krp.kp.addr = (kprobe_opcode_t *)swap_ksyms(sym);
-       if (switch_to_krp.kp.addr == NULL)
+       switch_to_krp.kp.addr = swap_ksyms(sym);
+       if (switch_to_krp.kp.addr == 0)
                goto not_found;
 
        sym = "sys_read";
-       sys_read_krp.kp.addr = (kprobe_opcode_t *)swap_ksyms(sym);
-       if (sys_read_krp.kp.addr == NULL)
+       sys_read_krp.kp.addr = swap_ksyms(sym);
+       if (sys_read_krp.kp.addr == 0)
                goto not_found;
 
        sym = "sys_write";
-       sys_write_krp.kp.addr = (kprobe_opcode_t *)swap_ksyms(sym);
-       if (sys_write_krp.kp.addr == NULL)
+       sys_write_krp.kp.addr = swap_ksyms(sym);
+       if (sys_write_krp.kp.addr == 0)
                goto not_found;
 
        energy_xxx_once(bt_probes, bt_probes_cnt);
index 2a689b2..9a8eee4 100644 (file)
@@ -307,14 +307,12 @@ EXPORT_SYMBOL_GPL(arch_make_trampoline_arm);
 /**
  * @brief Creates trampoline for kprobe.
  *
- * @param p Pointer to kprobe.
+ * @param p Pointer to kp_core.
  * @param sm Pointer to slot manager
  * @return 0 on success, error code on error.
  */
-int swap_arch_prepare_kprobe(struct kprobe *p, struct slot_manager *sm)
+int arch_kp_core_prepare(struct kp_core *p, struct slot_manager *sm)
 {
-       unsigned long addr = (unsigned long)p->addr;
-       unsigned long insn = p->opcode = *p->addr;
        unsigned long *tramp;
        int ret;
 
@@ -322,7 +320,8 @@ int swap_arch_prepare_kprobe(struct kprobe *p, struct slot_manager *sm)
        if (tramp == NULL)
                return -ENOMEM;
 
-       ret = arch_make_trampoline_arm(addr, insn, tramp);
+       p->opcode = *(unsigned long *)p->addr;
+       ret = arch_make_trampoline_arm(p->addr, p->opcode, tramp);
        if (ret) {
                swap_slot_free(sm, tramp);
                return ret;
@@ -343,95 +342,81 @@ int swap_arch_prepare_kprobe(struct kprobe *p, struct slot_manager *sm)
  * @param regs Pointer to CPU registers data.
  * @return Void.
  */
-static void prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
+static void prepare_singlestep(struct kp_core *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;
+               regs->ARM_pc = p->ss_addr[cpu];
+               p->ss_addr[cpu] = 0;
        } else {
                regs->ARM_pc = (unsigned long)p->ainsn.insn;
        }
 }
 
-/**
- * @brief Saves previous kprobe.
- *
- * @param kcb Pointer to kprobe_ctlblk struct whereto save current kprobe.
- * @param p_run Pointer to kprobe.
- * @return Void.
- */
-void save_previous_kprobe(struct kprobe_ctlblk *kcb, struct kprobe *p_run)
-{
-       kcb->prev_kprobe.kp = swap_kprobe_running();
-       kcb->prev_kprobe.status = kcb->kprobe_status;
-}
-
-/**
- * @brief Restores previous kprobe.
- *
- * @param kcb Pointer to kprobe_ctlblk which contains previous kprobe.
- * @return Void.
- */
-void restore_previous_kprobe(struct kprobe_ctlblk *kcb)
+static void save_previous_kp_core(struct kp_core_ctlblk *kcb)
 {
-       swap_kprobe_running_set(kcb->prev_kprobe.kp);
-       kcb->kprobe_status = kcb->prev_kprobe.status;
+       kcb->prev_kp_core.p = kp_core_running();
+       kcb->prev_kp_core.status = kcb->kp_core_status;
 }
 
 /**
- * @brief Sets currently running kprobe.
+ * @brief Restores previous kp_core.
  *
- * @param p Pointer to currently running kprobe.
- * @param regs Pointer to CPU registers data.
- * @param kcb Pointer to kprobe_ctlblk.
+ * @param kcb Pointer to kp_core_ctlblk which contains previous kp_core.
  * @return Void.
  */
-void set_current_kprobe(struct kprobe *p,
-                       struct pt_regs *regs,
-                       struct kprobe_ctlblk *kcb)
+void restore_previous_kp_core(struct kp_core_ctlblk *kcb)
 {
-       swap_kprobe_running_set(p);
+       kp_core_running_set(kcb->prev_kp_core.p);
+       kcb->kp_core_status = kcb->prev_kp_core.status;
 }
 
 static int kprobe_handler(struct pt_regs *regs)
 {
-       struct kprobe *p, *cur;
-       struct kprobe_ctlblk *kcb;
+       struct kp_core *p, *cur;
+       struct kp_core_ctlblk *kcb;
 
-       kcb = swap_get_kprobe_ctlblk();
-       cur = swap_kprobe_running();
-       p = swap_get_kprobe((void *)regs->ARM_pc);
+       kcb = kp_core_ctlblk();
+       cur = kp_core_running();
+
+       rcu_read_lock();
+       p = kp_core_by_addr(regs->ARM_pc);
+       if (p)
+               kp_core_get(p);
+       rcu_read_unlock();
 
        if (p) {
                if (cur) {
                        /* Kprobe is pending, so we're recursing. */
-                       switch (kcb->kprobe_status) {
+                       switch (kcb->kp_core_status) {
                        case KPROBE_HIT_ACTIVE:
                        case KPROBE_HIT_SSDONE:
                                /* A pre- or post-handler probe got us here. */
-                               swap_kprobes_inc_nmissed_count(p);
-                               save_previous_kprobe(kcb, NULL);
-                               set_current_kprobe(p, 0, 0);
-                               kcb->kprobe_status = KPROBE_REENTER;
+                               save_previous_kp_core(kcb);
+                               kp_core_running_set(p);
+                               kcb->kp_core_status = KPROBE_REENTER;
                                prepare_singlestep(p, regs);
-                               restore_previous_kprobe(kcb);
+                               restore_previous_kp_core(kcb);
                                break;
                        default:
                                /* impossible cases */
                                BUG();
                        }
                } else {
-                       set_current_kprobe(p, 0, 0);
-                       kcb->kprobe_status = KPROBE_HIT_ACTIVE;
+                       kp_core_running_set(p);
+                       kcb->kp_core_status = KPROBE_HIT_ACTIVE;
+
+                       if (!(regs->ARM_cpsr & PSR_I_BIT))
+                               local_irq_enable();
 
-                       if (!p->pre_handler || !p->pre_handler(p, regs)) {
-                               kcb->kprobe_status = KPROBE_HIT_SS;
+                       if (!p->handlers.pre(p, regs)) {
+                               kcb->kp_core_status = KPROBE_HIT_SS;
                                prepare_singlestep(p, regs);
-                               swap_kprobe_running_set(NULL);
+                               kp_core_running_set(NULL);
                        }
                }
+               kp_core_put(p);
        } else {
                goto no_kprobe;
        }
@@ -454,21 +439,20 @@ no_kprobe:
 int kprobe_trap_handler(struct pt_regs *regs, unsigned int instr)
 {
        int ret;
-       unsigned long flags;
-
-       local_irq_save(flags);
 
        if (likely(instr == BREAKPOINT_INSTRUCTION)) {
                ret = kprobe_handler(regs);
        } else {
-               struct kprobe *p = swap_get_kprobe((void *)regs->ARM_pc);
+               struct kp_core *p;
+
+               rcu_read_lock();
+               p = kp_core_by_addr(regs->ARM_pc);
 
                /* skip false exeption */
                ret = p && (p->opcode == instr) ? 0 : 1;
+               rcu_read_unlock();
        }
 
-       local_irq_restore(flags);
-
        return ret;
 }
 
@@ -482,15 +466,7 @@ int kprobe_trap_handler(struct pt_regs *regs, unsigned int instr)
 int swap_setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
 {
        struct jprobe *jp = container_of(p, struct jprobe, kp);
-       kprobe_pre_entry_handler_t pre_entry =
-               (kprobe_pre_entry_handler_t)jp->pre_entry;
        entry_point_t entry = (entry_point_t)jp->entry;
-       pre_entry = (kprobe_pre_entry_handler_t)jp->pre_entry;
-
-       if (pre_entry) {
-               p->ss_addr[smp_processor_id()] = (void *)
-                                                pre_entry(jp->priv_arg, regs);
-       }
 
        if (entry) {
                entry(regs->ARM_r0, regs->ARM_r1, regs->ARM_r2,
@@ -546,9 +522,9 @@ static void write_u32(unsigned long addr, unsigned long val)
  * @param p Pointer to target kprobe.
  * @return Void.
  */
-void swap_arch_arm_kprobe(struct kprobe *p)
+void arch_kp_core_arm(struct kp_core *core)
 {
-       write_u32((long)p->addr, BREAKPOINT_INSTRUCTION);
+       write_u32(core->addr, BREAKPOINT_INSTRUCTION);
 }
 
 /**
@@ -557,9 +533,9 @@ void swap_arch_arm_kprobe(struct kprobe *p)
  * @param p Pointer to target kprobe.
  * @return Void.
  */
-void swap_arch_disarm_kprobe(struct kprobe *p)
+void arch_kp_core_disarm(struct kp_core *core)
 {
-       write_u32((long)p->addr, p->opcode);
+       write_u32(core->addr, core->opcode);
 }
 
 /**
@@ -663,7 +639,7 @@ __asm(
  */
 int set_kjump_cb(struct pt_regs *regs, jumper_cb_t cb, void *data, size_t size)
 {
-       struct kprobe *p;
+       struct kp_core *p;
        struct kj_cb_data *cb_data;
 
        cb_data = kmalloc(sizeof(*cb_data) + size, GFP_ATOMIC);
@@ -674,8 +650,8 @@ int set_kjump_cb(struct pt_regs *regs, jumper_cb_t cb, void *data, size_t size)
        if (size)
                memcpy(cb_data->data, data, size);
 
-       p = swap_kprobe_running();
-       p->ss_addr[smp_processor_id()] = (kprobe_opcode_t *)&kjump_trampoline;
+       p = kp_core_running();
+       p->ss_addr[smp_processor_id()] = (unsigned long)&kjump_trampoline;
 
        cb_data->ret_addr = (unsigned long)p->ainsn.insn;
        cb_data->cb = cb;
@@ -696,7 +672,7 @@ static int kjump_pre_handler(struct kprobe *p, struct pt_regs *regs)
 
        /* restore regs */
        memcpy(regs, &data->regs, sizeof(*regs));
-       p->ss_addr[smp_processor_id()] = (void *)data->ret_addr;
+       /* p->ss_addr[smp_processor_id()] = (unsigned long)data->ret_addr; */
 
        /* FIXME: potential memory leak, when process kill */
        kfree(data);
@@ -706,7 +682,7 @@ static int kjump_pre_handler(struct kprobe *p, struct pt_regs *regs)
 
 static struct kprobe kjump_kprobe = {
        .pre_handler = kjump_pre_handler,
-       .addr = (unsigned long *)&kjump_trampoline + 2, /* nop */
+       .addr = (unsigned long)&kjump_trampoline + 2 * 4,       /* nop */
 };
 
 static int kjump_init(void)
index b961a0c..fff80d1 100644 (file)
@@ -89,15 +89,15 @@ typedef unsigned long kprobe_opcode_t;
 #define UREGS_OFFSET 8
 
 /**
- * @struct prev_kprobe
- * @brief Stores previous kprobe.
- * @var prev_kprobe::kp
- * Pointer to kprobe struct.
- * @var prev_kprobe::status
+ * @struct prev_kp_core
+ * @brief Stores previous kp_core.
+ * @var prev_kp_core::p
+ * Pointer to kp_core struct.
+ * @var prev_kp_core::status
  * Kprobe status.
  */
-struct prev_kprobe {
-       struct kprobe *kp;
+struct prev_kp_core {
+       struct kp_core *p;
        unsigned long status;
 };
 
@@ -609,16 +609,16 @@ static inline void swap_set_arg(struct pt_regs *regs, int num,
 
 
 /**
- * @struct kprobe_ctlblk
- * @brief Per-cpu kprobe control block.
- * @var kprobe_ctlblk::kprobe_status
+ * @struct kp_core_ctlblk
+ * @brief Per-cpu kp_core control block.
+ * @var kp_core_ctlblk::kp_core_status
  * Kprobe status.
- * @var kprobe_ctlblk::prev_kprobe
- * Previous kprobe.
+ * @var kp_core_ctlblk::prev_kp_core
+ * Previous kp_core.
  */
-struct kprobe_ctlblk {
-       unsigned long kprobe_status;
-       struct prev_kprobe prev_kprobe;
+struct kp_core_ctlblk {
+       unsigned long kp_core_status;
+       struct prev_kp_core prev_kp_core;
 };
 
 /**
@@ -648,21 +648,20 @@ int arch_make_trampoline_arm(unsigned long addr, unsigned long insn,
 struct slot_manager;
 struct kretprobe;
 struct kretprobe_instance;
-int swap_arch_prepare_kprobe(struct kprobe *p, struct slot_manager *sm);
+struct kp_core;
+struct kprobe;
+
+int arch_kp_core_prepare(struct kp_core *p, struct slot_manager *sm);
 void swap_arch_prepare_kretprobe(struct kretprobe_instance *ri,
                                 struct pt_regs *regs);
 
-void swap_arch_arm_kprobe(struct kprobe *p);
-void swap_arch_disarm_kprobe(struct kprobe *p);
+void arch_kp_core_arm(struct kp_core *p);
+void arch_kp_core_disarm(struct kp_core *p);
 
 int swap_setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs);
 int swap_longjmp_break_handler(struct kprobe *p, struct pt_regs *regs);
 
-void save_previous_kprobe(struct kprobe_ctlblk *kcb, struct kprobe *cur_p);
-void restore_previous_kprobe(struct kprobe_ctlblk *kcb);
-void set_current_kprobe(struct kprobe *p,
-                       struct pt_regs *regs,
-                       struct kprobe_ctlblk *kcb);
+void restore_previous_kp_core(struct kp_core_ctlblk *kcb);
 
 void __naked swap_kretprobe_trampoline(void);
 
index 0f9cc49..37a74c7 100644 (file)
@@ -217,17 +217,17 @@ static int is_IF_modifier(kprobe_opcode_t opcode)
  * @param sm Pointer to slot manager
  * @return 0 on success, error code on error.
  */
-int swap_arch_prepare_kprobe(struct kprobe *p, struct slot_manager *sm)
+int arch_kp_core_prepare(struct kp_core *p, struct slot_manager *sm)
 {
        /* insn: must be on special executable page on i386. */
        p->ainsn.insn = swap_slot_alloc(sm);
        if (p->ainsn.insn == NULL)
                return -ENOMEM;
 
-       memcpy(p->ainsn.insn, p->addr, MAX_INSN_SIZE);
+       memcpy(p->ainsn.insn, (void *)p->addr, MAX_INSN_SIZE);
 
-       p->opcode = *p->addr;
-       p->ainsn.boostable = swap_can_boost(p->addr) ? 0 : -1;
+       p->opcode = *(char *)p->addr;
+       p->ainsn.boostable = swap_can_boost((void *)p->addr) ? 0 : -1;
 
        return 0;
 }
@@ -239,7 +239,7 @@ int swap_arch_prepare_kprobe(struct kprobe *p, struct slot_manager *sm)
  * @param regs Pointer to CPU registers data.
  * @return Void.
  */
-static void prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
+static void prepare_singlestep(struct kp_core *p, struct pt_regs *regs)
 {
        regs->flags |= TF_MASK;
        regs->flags &= ~IF_MASK;
@@ -254,65 +254,55 @@ static void prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
 /**
  * @brief Saves previous kprobe.
  *
- * @param kcb Pointer to kprobe_ctlblk struct whereto save current kprobe.
+ * @param kcb Pointer to kp_core_ctlblk struct whereto save current kprobe.
  * @param p_run Pointer to kprobe.
  * @return Void.
  */
-void save_previous_kprobe(struct kprobe_ctlblk *kcb, struct kprobe *cur_p)
+static void save_previous_kp_core(struct kp_core_ctlblk *kcb, struct kp_core *cur)
 {
-       if (kcb->prev_kprobe.kp != NULL) {
+       if (kcb->prev_kp_core.p != NULL) {
                panic("no space to save new probe[]: "
-                     "task = %d/%s, prev %p, current %p, new %p,",
-                     current->pid, current->comm, kcb->prev_kprobe.kp->addr,
-                     swap_kprobe_running()->addr, cur_p->addr);
+                     "task = %d/%s, prev %08lx, current %08lx, new %08lx,",
+                     current->pid, current->comm, kcb->prev_kp_core.p->addr,
+                     kp_core_running()->addr, cur->addr);
        }
 
 
-       kcb->prev_kprobe.kp = swap_kprobe_running();
-       kcb->prev_kprobe.status = kcb->kprobe_status;
-
+       kcb->prev_kp_core.p = kp_core_running();
+       kcb->prev_kp_core.status = kcb->kp_core_status;
 }
 
 /**
- * @brief Restores previous kprobe.
+ * @brief Restores previous kp_core.
  *
- * @param kcb Pointer to kprobe_ctlblk which contains previous kprobe.
+ * @param kcb Pointer to kp_core_ctlblk which contains previous kp_core.
  * @return Void.
  */
-void restore_previous_kprobe(struct kprobe_ctlblk *kcb)
+void restore_previous_kp_core(struct kp_core_ctlblk *kcb)
 {
-       swap_kprobe_running_set(kcb->prev_kprobe.kp);
-       kcb->kprobe_status = kcb->prev_kprobe.status;
-       kcb->prev_kprobe.kp = NULL;
-       kcb->prev_kprobe.status = 0;
+       kp_core_running_set(kcb->prev_kp_core.p);
+       kcb->kp_core_status = kcb->prev_kp_core.status;
+       kcb->prev_kp_core.p = NULL;
+       kcb->prev_kp_core.status = 0;
 }
 
-/**
- * @brief Sets currently running kprobe.
- *
- * @param p Pointer to currently running kprobe.
- * @param regs Pointer to CPU registers data.
- * @param kcb Pointer to kprobe_ctlblk.
- * @return Void.
- */
-void set_current_kprobe(struct kprobe *p,
-                       struct pt_regs *regs,
-                       struct kprobe_ctlblk *kcb)
+static void set_current_kp_core(struct kp_core *p, struct pt_regs *regs,
+                               struct kp_core_ctlblk *kcb)
 {
-       swap_kprobe_running_set(p);
-       kcb->kprobe_saved_eflags = kcb->kprobe_old_eflags =
+       kp_core_running_set(p);
+       kcb->kp_core_saved_eflags = kcb->kp_core_old_eflags =
                (regs->EREG(flags) & (TF_MASK | IF_MASK));
        if (is_IF_modifier(p->opcode))
-               kcb->kprobe_saved_eflags &= ~IF_MASK;
+               kcb->kp_core_saved_eflags &= ~IF_MASK;
 }
 
-static int setup_singlestep(struct kprobe *p, struct pt_regs *regs,
-                           struct kprobe_ctlblk *kcb)
+static int setup_singlestep(struct kp_core *p, struct pt_regs *regs,
+                           struct kp_core_ctlblk *kcb)
 {
 #if !defined(CONFIG_PREEMPT) || defined(CONFIG_PM)
-       if (p->ainsn.boostable == 1 && !p->post_handler) {
+       if (p->ainsn.boostable == 1) {
                /* Boost up -- we can execute copied instructions directly */
-               swap_kprobe_running_set(NULL);
+               kp_core_running_set(NULL);
                regs->ip = (unsigned long)p->ainsn.insn;
 
                return 1;
@@ -320,7 +310,7 @@ static int setup_singlestep(struct kprobe *p, struct pt_regs *regs,
 #endif /* !CONFIG_PREEMPT */
 
        prepare_singlestep(p, regs);
-       kcb->kprobe_status = KPROBE_HIT_SS;
+       kcb->kp_core_status = KPROBE_HIT_SS;
 
        return 1;
 }
@@ -334,31 +324,65 @@ static struct pt_regs *current_regs(void)
 }
 
 
-void restore_int3(void);
+void exec_trampoline(void);
+void exec_trampoline_int3(void);
 __asm(
-       "restore_int3:\n"
+       "exec_trampoline:\n"
+       "call   exec_handler\n"
+       "exec_trampoline_int3:\n"
        "int3\n"
 );
 
+static int __used exec_handler(void)
+{
+       struct kp_core *p = kp_core_running();
+       struct pt_regs *regs = current_regs();
+
+       return p->handlers.pre(p, regs);
+}
+
+static int befor_exec_trampoline(struct pt_regs *regs)
+{
+       int ret = (int)regs->ax;
+       struct kp_core *p = kp_core_running();
+       struct kp_core_ctlblk *kcb = kp_core_ctlblk();
+
+       /* restore regs from stack */
+       *regs = *current_regs();
+
+       if (ret) {
+               kp_core_put(p);
+               return ret;
+       }
+
+       setup_singlestep(p, regs, kcb);
+       if (!(regs->flags & TF_MASK))
+               kp_core_put(p);
+
+       return 1;
+}
+
 static int __kprobe_handler(struct pt_regs *regs)
 {
-       struct kprobe *p = 0;
+       struct kp_core *p;
        int ret = 0;
-       kprobe_opcode_t *addr = NULL;
-       struct kprobe_ctlblk *kcb;
+       unsigned long addr = regs->ip - 1;
+       struct kp_core_ctlblk *kcb;
 
-       addr = (kprobe_opcode_t *) (regs->EREG(ip) - sizeof(kprobe_opcode_t));
+       kcb = kp_core_ctlblk();
 
-       kcb = swap_get_kprobe_ctlblk();
-       p = swap_get_kprobe(addr);
+       rcu_read_lock();
+       p = kp_core_by_addr(addr);
+       kp_core_get(p);
+       rcu_read_unlock();
 
        /* Check we're not actually recursing */
-       if (swap_kprobe_running()) {
+       if (kp_core_running()) {
                if (p) {
-                       if (kcb->kprobe_status == KPROBE_HIT_SS &&
+                       if (kcb->kp_core_status == KPROBE_HIT_SS &&
                            *p->ainsn.insn == BREAKPOINT_INSTRUCTION) {
-                               regs->EREG(flags) &= ~TF_MASK;
-                               regs->EREG(flags) |= kcb->kprobe_saved_eflags;
+                               regs->flags &= ~TF_MASK;
+                               regs->flags |= kcb->kp_core_saved_eflags;
                                goto no_kprobe;
                        }
 
@@ -369,15 +393,14 @@ static int __kprobe_handler(struct pt_regs *regs)
                         * just single step on the instruction of the new probe
                         * without calling any user handlers.
                         */
-                       save_previous_kprobe(kcb, p);
-                       set_current_kprobe(p, regs, kcb);
-                       swap_kprobes_inc_nmissed_count(p);
+                       save_previous_kp_core(kcb, p);
+                       set_current_kp_core(p, regs, kcb);
                        prepare_singlestep(p, regs);
-                       kcb->kprobe_status = KPROBE_REENTER;
+                       kcb->kp_core_status = KPROBE_REENTER;
 
                        goto out_get_kp_if_TF;
                } else {
-                       if (*addr != BREAKPOINT_INSTRUCTION) {
+                       if (*(char *)addr != BREAKPOINT_INSTRUCTION) {
                                /* The breakpoint instruction was removed by
                                 * another cpu right after we hit, no further
                                 * handling of this interrupt is appropriate
@@ -387,16 +410,12 @@ static int __kprobe_handler(struct pt_regs *regs)
                                goto no_kprobe;
                        }
 
-                       p = swap_kprobe_running();
-                       if (p->break_handler && p->break_handler(p, regs))
-                               goto ss_probe;
-
                        goto no_kprobe;
                }
        }
 
        if (!p) {
-               if (*addr != BREAKPOINT_INSTRUCTION) {
+               if (*(char *)addr != BREAKPOINT_INSTRUCTION) {
                        /*
                         * The breakpoint instruction was removed right
                         * after we hit it.  Another cpu has removed
@@ -410,30 +429,21 @@ static int __kprobe_handler(struct pt_regs *regs)
                        ret = 1;
                }
 
-               if (!p) {
-                       /* Not one of ours: let kernel handle it */
-                       DBPRINTF("no_kprobe");
-                       goto no_kprobe;
-               }
+               goto no_kprobe;
        }
 
-       set_current_kprobe(p, regs, kcb);
-       kcb->kprobe_status = KPROBE_HIT_ACTIVE;
+       set_current_kp_core(p, regs, kcb);
+       kcb->kp_core_status = KPROBE_HIT_ACTIVE;
 
        /* save regs to stack */
        *current_regs() = *regs;
 
-       regs->ip = (unsigned long)restore_int3;
-       get_kp(p);
-
+       regs->ip = (unsigned long)exec_trampoline;
        return 1;
 
-ss_probe:
-       setup_singlestep(p, regs, kcb);
-
 out_get_kp_if_TF:
-       if ((regs->flags & TF_MASK))
-               get_kp(p);
+       if (!(regs->flags & TF_MASK))
+               kp_core_put(p);
 
        return 1;
 
@@ -441,37 +451,12 @@ no_kprobe:
        return ret;
 }
 
-static int restore_handler(struct pt_regs *regs)
-{
-       struct kprobe *p = swap_kprobe_running();
-       struct kprobe_ctlblk *kcb = swap_get_kprobe_ctlblk();
-
-       /* restore regs from stack */
-       *regs = *current_regs();
-
-       if (p->pre_handler) {
-               int ret;
-
-               ret = p->pre_handler(p, regs);
-               if (ret) {
-                       put_kp(p);
-                       return ret;
-               }
-       }
-
-       setup_singlestep(p, regs, kcb);
-       if (!(regs->flags & TF_MASK))
-               put_kp(p);
-
-       return 1;
-}
-
 static int kprobe_handler(struct pt_regs *regs)
 {
        int ret;
 
-       if (regs->ip == (unsigned long)restore_int3 + 1)
-               ret = restore_handler(regs);
+       if (regs->ip == (unsigned long)exec_trampoline_int3 + 1)
+               ret = befor_exec_trampoline(regs);
        else
                ret = __kprobe_handler(regs);
 
@@ -489,13 +474,11 @@ int swap_setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
 {
        struct jprobe *jp = container_of(p, struct jprobe, kp);
        kprobe_pre_entry_handler_t pre_entry;
-       entry_point_t entry;
 
        unsigned long addr;
-       struct kprobe_ctlblk *kcb = swap_get_kprobe_ctlblk();
+       struct kp_core_ctlblk *kcb = kp_core_ctlblk();
 
        pre_entry = (kprobe_pre_entry_handler_t) jp->pre_entry;
-       entry = (entry_point_t) jp->entry;
 
        kcb->jprobe_saved_regs = *regs;
        kcb->jprobe_saved_esp = stack_addr(regs);
@@ -512,9 +495,6 @@ int swap_setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18)
        trace_hardirqs_off();
 #endif
-       if (pre_entry)
-               p->ss_addr[smp_processor_id()] = (kprobe_opcode_t *)
-                                                pre_entry(jp->priv_arg, regs);
 
        regs->EREG(ip) = (unsigned long)(jp->entry);
 
@@ -535,7 +515,7 @@ void swap_jprobe_return_end(void);
  */
 void swap_jprobe_return(void)
 {
-       struct kprobe_ctlblk *kcb = swap_get_kprobe_ctlblk();
+       struct kp_core_ctlblk *kcb = kp_core_ctlblk();
 
        asm volatile("       xchgl   %%ebx,%%esp\n"
                     "       int3\n"
@@ -574,9 +554,9 @@ void arch_ujprobe_return(void)
  *
  * This function also checks instruction size for preparing direct execution.
  */
-static void resume_execution(struct kprobe *p,
+static void resume_execution(struct kp_core *p,
                             struct pt_regs *regs,
-                            struct kprobe_ctlblk *kcb)
+                            struct kp_core_ctlblk *kcb)
 {
        unsigned long *tos;
        unsigned long copy_eip = (unsigned long) p->ainsn.insn;
@@ -592,7 +572,7 @@ static void resume_execution(struct kprobe *p,
        switch (insns[0]) {
        case 0x9c: /* pushfl */
                *tos &= ~(TF_MASK | IF_MASK);
-               *tos |= kcb->kprobe_old_eflags;
+               *tos |= kcb->kp_core_old_eflags;
                break;
        case 0xc2: /* iret/ret/lret */
        case 0xc3:
@@ -658,30 +638,25 @@ no_change:
  */
 static int post_kprobe_handler(struct pt_regs *regs)
 {
-       struct kprobe *cur = swap_kprobe_running();
-       struct kprobe_ctlblk *kcb = swap_get_kprobe_ctlblk();
+       struct kp_core *cur = kp_core_running();
+       struct kp_core_ctlblk *kcb = kp_core_ctlblk();
 
        if (!cur)
                return 0;
 
-       put_kp(cur);
-
-       if ((kcb->kprobe_status != KPROBE_REENTER) && cur->post_handler) {
-               kcb->kprobe_status = KPROBE_HIT_SSDONE;
-               cur->post_handler(cur, regs, 0);
-       }
+       kp_core_put(cur);
 
        resume_execution(cur, regs, kcb);
-       regs->EREG(flags) |= kcb->kprobe_saved_eflags;
+       regs->flags |= kcb->kp_core_saved_eflags;
 #ifndef CONFIG_X86
        trace_hardirqs_fixup_flags(regs->EREG(flags));
 #endif /* CONFIG_X86 */
        /* Restore back the original saved kprobes variables and continue. */
-       if (kcb->kprobe_status == KPROBE_REENTER) {
-               restore_previous_kprobe(kcb);
+       if (kcb->kp_core_status == KPROBE_REENTER) {
+               restore_previous_kp_core(kcb);
                goto out;
        }
-       swap_kprobe_running_set(NULL);
+       kp_core_running_set(NULL);
 out:
        /*
         * if somebody else is singlestepping across a probe point, eflags
@@ -696,10 +671,10 @@ out:
 
 static int kprobe_fault_handler(struct pt_regs *regs, int trapnr)
 {
-       struct kprobe *cur = swap_kprobe_running();
-       struct kprobe_ctlblk *kcb = swap_get_kprobe_ctlblk();
+       struct kp_core *cur = kp_core_running();
+       struct kp_core_ctlblk *kcb = kp_core_ctlblk();
 
-       switch (kcb->kprobe_status) {
+       switch (kcb->kp_core_status) {
        case KPROBE_HIT_SS:
        case KPROBE_REENTER:
                /*
@@ -709,33 +684,16 @@ static int kprobe_fault_handler(struct pt_regs *regs, int trapnr)
                 * and allow the page fault handler to continue as a
                 * normal page fault.
                 */
-               regs->EREG(ip) = (unsigned long) cur->addr;
-               regs->EREG(flags) |= kcb->kprobe_old_eflags;
-               if (kcb->kprobe_status == KPROBE_REENTER)
-                       restore_previous_kprobe(kcb);
+               regs->ip = cur->addr;
+               regs->flags |= kcb->kp_core_old_eflags;
+               if (kcb->kp_core_status == KPROBE_REENTER)
+                       restore_previous_kp_core(kcb);
                else
-                       swap_kprobe_running_set(NULL);
+                       kp_core_running_set(NULL);
                break;
        case KPROBE_HIT_ACTIVE:
        case KPROBE_HIT_SSDONE:
                /*
-                * We increment the nmissed count for accounting,
-                * we can also use npre/npostfault count for accouting
-                * these specific fault cases.
-                */
-               swap_kprobes_inc_nmissed_count(cur);
-
-               /*
-                * We come here because instructions in the pre/post
-                * handler caused the page_fault, this could happen
-                * if handler tries to access user space by
-                * copy_from_user(), get_user() etc. Let the
-                * user-specified handler try to fix it first.
-                */
-               if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr))
-                       return 1;
-
-               /*
                 * In case the user-specified fault handler returned
                 * zero, try to fix up.
                 */
@@ -783,7 +741,7 @@ static int kprobe_exceptions_notify(struct notifier_block *self,
                        ret = NOTIFY_STOP;
                break;
        case DIE_GPF:
-               if (swap_kprobe_running() &&
+               if (kp_core_running() &&
                    kprobe_fault_handler(args->regs, args->trapnr))
                        ret = NOTIFY_STOP;
                break;
@@ -803,64 +761,26 @@ static struct notifier_block kprobe_exceptions_nb = {
 };
 
 /**
- * @brief Longjump break handler.
+ * @brief Arms kp_core.
  *
- * @param p Pointer to fired kprobe.
- * @param regs Pointer to CPU registers data.
- * @return 0 on success.
- */
-int swap_longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
-{
-       struct kprobe_ctlblk *kcb = swap_get_kprobe_ctlblk();
-       u8 *addr = (u8 *) (regs->EREG(ip) - 1);
-       unsigned long stack_addr = (unsigned long) (kcb->jprobe_saved_esp);
-       struct jprobe *jp = container_of(p, struct jprobe, kp);
-
-       DBPRINTF("p = %p\n", p);
-
-       if ((addr > (u8 *)swap_jprobe_return) &&
-           (addr < (u8 *)swap_jprobe_return_end)) {
-               if (stack_addr(regs) != kcb->jprobe_saved_esp) {
-                       struct pt_regs *saved_regs = &kcb->jprobe_saved_regs;
-                       printk(KERN_INFO "current esp %p does not match saved esp %p\n",
-                              stack_addr(regs), kcb->jprobe_saved_esp);
-                       printk(KERN_INFO "Saved registers for jprobe %p\n", jp);
-                       swap_show_registers(saved_regs);
-                       printk(KERN_INFO "Current registers\n");
-                       swap_show_registers(regs);
-                       panic("BUG");
-                       /* BUG(); */
-               }
-               *regs = kcb->jprobe_saved_regs;
-               memcpy((kprobe_opcode_t *) stack_addr, kcb->jprobes_stack,
-                      MIN_STACK_SIZE(stack_addr));
-               return 1;
-       }
-
-       return 0;
-}
-
-/**
- * @brief Arms kprobe.
- *
- * @param p Pointer to target kprobe.
+ * @param core Pointer to target kp_core.
  * @return Void.
  */
-void swap_arch_arm_kprobe(struct kprobe *p)
+void arch_kp_core_arm(struct kp_core *p)
 {
-       swap_text_poke(p->addr,
+       swap_text_poke((void *)p->addr,
                       ((unsigned char[]){BREAKPOINT_INSTRUCTION}), 1);
 }
 
 /**
- * @brief Disarms kprobe.
+ * @brief Disarms kp_core.
  *
- * @param p Pointer to target kprobe.
+ * @param core Pointer to target kp_core.
  * @return Void.
  */
-void swap_arch_disarm_kprobe(struct kprobe *p)
+void arch_kp_core_disarm(struct kp_core *p)
 {
-       swap_text_poke(p->addr, &p->opcode, 1);
+       swap_text_poke((void *)p->addr, &p->opcode, 1);
 }
 
 static __used void *trampoline_probe_handler_x86(struct pt_regs *regs)
@@ -907,7 +827,7 @@ void swap_arch_prepare_kretprobe(struct kretprobe_instance *ri,
  */
 struct kj_cb_data {
        struct pt_regs regs;
-       struct kprobe *p;
+       struct kp_core *p;
 
        jumper_cb_t cb;
        char data[0];
@@ -941,7 +861,7 @@ int set_kjump_cb(struct pt_regs *regs, jumper_cb_t cb, void *data, size_t size)
        /* save regs */
        cb_data->regs = *regs;
 
-       cb_data->p = swap_kprobe_running();
+       cb_data->p = kp_core_running();
        cb_data->cb = cb;
 
        /* save data */
@@ -954,17 +874,17 @@ int set_kjump_cb(struct pt_regs *regs, jumper_cb_t cb, void *data, size_t size)
        /* jump to kjump_trampoline */
        regs->ip = (unsigned long)&kjump_trampoline;
 
-       swap_kprobe_running_set(NULL);
+       kp_core_running_set(NULL);
 
        return 1;
 }
 EXPORT_SYMBOL_GPL(set_kjump_cb);
 
-static int restore_regs_pre_handler(struct kprobe *p, struct pt_regs *regs)
+static int restore_regs_pre_handler(struct kprobe *kp, struct pt_regs *regs)
 {
        struct kj_cb_data *data = (struct kj_cb_data *)regs->ax;
-       struct kprobe *kp = data->p;
-       struct kprobe_ctlblk *kcb = swap_get_kprobe_ctlblk();
+       struct kp_core *p = data->p;
+       struct kp_core_ctlblk *kcb = kp_core_ctlblk();
 
        /* restore regs */
        *regs = data->regs;
@@ -972,17 +892,17 @@ static int restore_regs_pre_handler(struct kprobe *p, struct pt_regs *regs)
        /* FIXME: potential memory leak, when process kill */
        kfree(data);
 
-       kcb = swap_get_kprobe_ctlblk();
+       kcb = kp_core_ctlblk();
 
-       set_current_kprobe(kp, regs, kcb);
-       setup_singlestep(kp, regs, kcb);
+       set_current_kp_core(p, regs, kcb);
+       setup_singlestep(p, regs, kcb);
 
        return 1;
 }
 
 static struct kprobe restore_regs_kp = {
        .pre_handler = restore_regs_pre_handler,
-       .addr = (kprobe_opcode_t *)&kjump_trampoline_int3,      /* nop */
+       .addr = (unsigned long)&kjump_trampoline_int3,  /* nop */
 };
 
 static int kjump_init(void)
index bb361a0..533d195 100644 (file)
@@ -171,32 +171,32 @@ static inline int swap_fp_backtrace(struct task_struct *task,
 }
 
 /**
- * @struct prev_kprobe
- * @brief Stores previous kprobe.
- * @var prev_kprobe::kp
- * Pointer to kprobe struct.
- * @var prev_kprobe::status
- * Kprobe status.
+ * @struct prev_kp_core
+ * @brief Stores previous kp_core.
+ * @var prev_kp_core::kp
+ * Pointer to kp_core struct.
+ * @var prev_kp_core::status
+ * kp_core status.
  */
-struct prev_kprobe {
-       struct kprobe *kp;
+struct prev_kp_core {
+       struct kp_core *p;
        unsigned long status;
 };
 
 /**
- * @struct kprobe_ctlblk
- * @brief Per-cpu kprobe control block.
- * @var kprobe_ctlblk::kprobe_status
- * Kprobe status.
- * @var kprobe_ctlblk::prev_kprobe
- * Previous kprobe.
+ * @struct kp_core_ctlblk
+ * @brief Per-cpu kp_core control block.
+ * @var kp_core_ctlblk::kp_core_status
+ * kp_core status.
+ * @var kp_core_ctlblk::prev_kp_core
+ * Previous kp_core.
  */
-struct kprobe_ctlblk {
-       unsigned long kprobe_status;
-       struct prev_kprobe prev_kprobe;
+struct kp_core_ctlblk {
+       unsigned long kp_core_status;
+       struct prev_kp_core prev_kp_core;
        struct pt_regs jprobe_saved_regs;
-       unsigned long kprobe_old_eflags;
-       unsigned long kprobe_saved_eflags;
+       unsigned long kp_core_old_eflags;
+       unsigned long kp_core_saved_eflags;
        unsigned long *jprobe_saved_esp;
        kprobe_opcode_t jprobes_stack[MAX_STACK_SIZE];
 };
@@ -208,7 +208,7 @@ struct kprobe_ctlblk {
  * @var arch_specific_insn::insn
  * Copy of the original instruction.
  * @var arch_specific_insn::boostable
- * If this flag is not 0, this kprobe can be boost when its
+ * If this flag is not 0, this kp_core can be boost when its
  * post_handler and break_handler is not set.
  */
 struct arch_specific_insn {
@@ -225,17 +225,20 @@ typedef kprobe_opcode_t (*entry_point_t) (unsigned long, unsigned long,
 
 int arch_init_module_deps(void);
 
+struct kprobe;
+struct kp_core;
 struct slot_manager;
 struct kretprobe_instance;
 
-int swap_arch_prepare_kprobe(struct kprobe *p, struct slot_manager *sm);
-void swap_arch_arm_kprobe(struct kprobe *p);
-void swap_arch_disarm_kprobe(struct kprobe *p);
+int arch_kp_core_prepare(struct kp_core *p, struct slot_manager *sm);
+void arch_kp_core_arm(struct kp_core *core);
+void arch_kp_core_disarm(struct kp_core *core);
+int swap_setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs);
 void swap_arch_prepare_kretprobe(struct kretprobe_instance *ri,
                                 struct pt_regs *regs);
 void swap_kretprobe_trampoline(void);
 
-void restore_previous_kprobe(struct kprobe_ctlblk *kcb);
+void restore_previous_kp_core(struct kp_core_ctlblk *kcb);
 int swap_can_boost(kprobe_opcode_t *opcodes);
 static inline int arch_check_insn(struct arch_specific_insn *ainsn)
 {
index ff6c163..2a2bce6 100644 (file)
@@ -41,7 +41,7 @@
 #include <linux/mm.h>
 #include <linux/pagemap.h>
 #include <linux/stop_machine.h>
-
+#include <linux/delay.h>
 #include <ksyms/ksyms.h>
 #include <master/swap_initializer.h>
 #include <swap-asm/swap_kprobes.h>
@@ -72,7 +72,7 @@ struct slot_manager sm;
 
 static DEFINE_SPINLOCK(kretprobe_lock);        /* Protects kretprobe_inst_table */
 
-struct hlist_head kprobe_table[KPROBE_TABLE_SIZE];
+static struct hlist_head kprobe_table[KPROBE_TABLE_SIZE];
 static struct hlist_head kretprobe_inst_table[KPROBE_TABLE_SIZE];
 
 /**
@@ -119,6 +119,11 @@ static void exit_sm(void)
        /* FIXME: free */
 }
 
+static struct hlist_head *kpt_head_by_addr(unsigned long addr)
+{
+       return &kprobe_table[hash_ptr((void *)addr, KPROBE_HASH_BITS)];
+}
+
 static void kretprobe_assert(struct kretprobe_instance *ri,
                             unsigned long orig_ret_address,
                             unsigned long trampoline_address)
@@ -137,42 +142,46 @@ static void kretprobe_assert(struct kretprobe_instance *ri,
                        panic("kretprobe BUG!: ri->rp = NULL\n");
 
                panic("kretprobe BUG!: "
-                     "Processing kretprobe %p @ %p (%d/%d - %s)\n",
+                     "Processing kretprobe %p @ %08lx (%d/%d - %s)\n",
                      ri->rp, ri->rp->kp.addr, ri->task->tgid,
                      ri->task->pid, ri->task->comm);
        }
 }
 
-struct kp_data {
-       struct kprobe *running;
-       struct kprobe *instance;
-       struct kprobe_ctlblk ctlblk;
+struct kpc_data {
+       struct kp_core *running;
+       struct kp_core_ctlblk ctlblk;
 };
 
 static void ktd_cur_init(struct task_struct *task, void *data)
 {
-       struct kp_data *d = (struct kp_data *)data;
+       struct kpc_data *d = (struct kpc_data *)data;
 
        memset(d, 0, sizeof(*d));
 }
 
 static void ktd_cur_exit(struct task_struct *task, void *data)
 {
-       struct kp_data *d = (struct kp_data *)data;
+       struct kpc_data *d = (struct kpc_data *)data;
 
        WARN(d->running, "running probe is not NULL");
-       WARN(d->instance, "instance probe is not NULL");
 }
 
 struct ktask_data ktd_cur = {
        .init = ktd_cur_init,
        .exit = ktd_cur_exit,
-       .size = sizeof(struct kp_data),
+       .size = sizeof(struct kpc_data),
 };
 
-static struct kp_data *kprobe_data(void)
+static DEFINE_PER_CPU(struct kpc_data, per_cpu_kpc_data);
+
+static struct kpc_data *kp_core_data(void)
 {
-       return (struct kp_data *)swap_ktd(&ktd_cur, current);
+       if (in_interrupt()) {
+               return &__get_cpu_var(per_cpu_kpc_data);
+       } else {
+               return (struct kpc_data *)swap_ktd(&ktd_cur, current);
+       }
 }
 
 static int kprobe_cur_reg(void)
@@ -185,46 +194,24 @@ static void kprobe_cur_unreg(void)
        swap_ktd_unreg(&ktd_cur);
 }
 
-
-static struct kprobe *kprobe_instance(void)
-{
-       return kprobe_data()->instance;
-}
-
-static void kprobe_instance_set(struct kprobe *p)
+struct kp_core *kp_core_running(void)
 {
-       kprobe_data()->instance = p;
+       return kp_core_data()->running;
 }
 
-
-struct kprobe *swap_kprobe_running(void)
+void kp_core_running_set(struct kp_core *p)
 {
-       return kprobe_data()->running;
-}
-
-void swap_kprobe_running_set(struct kprobe *p)
-{
-       kprobe_data()->running = p;
+       kp_core_data()->running = p;
 }
 
 /**
- * @brief Sets the current kprobe to NULL.
+ * @brief Gets kp_core_ctlblk for the current CPU.
  *
- * @return Void.
+ * @return Current CPU struct kp_core_ctlblk.
  */
-void swap_reset_current_kprobe(void)
+struct kp_core_ctlblk *kp_core_ctlblk(void)
 {
-       swap_kprobe_running_set(NULL);
-}
-
-/**
- * @brief Gets kprobe_ctlblk for the current CPU.
- *
- * @return Current CPU struct kprobe_ctlblk.
- */
-struct kprobe_ctlblk *swap_get_kprobe_ctlblk(void)
-{
-       return &kprobe_data()->ctlblk;
+       return &kp_core_data()->ctlblk;
 }
 
 /*
@@ -235,116 +222,26 @@ struct kprobe_ctlblk *swap_get_kprobe_ctlblk(void)
  */
 
 /**
- * @brief Gets kprobe.
+ * @brief Gets kp_core.
  *
  * @param addr Probe address.
- * @return Kprobe for addr.
+ * @return kprobe_core for addr.
  */
-struct kprobe *swap_get_kprobe(void *addr)
+struct kp_core *kp_core_by_addr(unsigned long addr)
 {
        struct hlist_head *head;
-       struct kprobe *p;
+       struct kp_core *core;
        DECLARE_NODE_PTR_FOR_HLIST(node);
 
-       head = &kprobe_table[hash_ptr(addr, KPROBE_HASH_BITS)];
-       swap_hlist_for_each_entry_rcu(p, node, head, hlist) {
-               if (p->addr == addr)
-                       return p;
+       head = kpt_head_by_addr(addr);
+       swap_hlist_for_each_entry_rcu(core, node, head, hlist) {
+               if (core->addr == addr)
+                       return core;
        }
 
        return NULL;
 }
 
-/*
- * Aggregate handlers for multiple kprobes support - these handlers
- * take care of invoking the individual kprobe handlers on p->list
- */
-static int aggr_pre_handler(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) {
-                       kprobe_instance_set(kp);
-                       ret = kp->pre_handler(kp, regs);
-                       if (ret)
-                               return ret;
-               }
-               kprobe_instance_set(NULL);
-       }
-
-       return 0;
-}
-
-static void aggr_post_handler(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) {
-                       kprobe_instance_set(kp);
-                       kp->post_handler(kp, regs, flags);
-                       kprobe_instance_set(NULL);
-               }
-       }
-}
-
-static int aggr_fault_handler(struct kprobe *p,
-                             struct pt_regs *regs,
-                             int trapnr)
-{
-       struct kprobe *cur = kprobe_instance();
-
-       /*
-        * if we faulted "during" the execution of a user specified
-        * probe handler, invoke just that probe's fault handler
-        */
-       if (cur && cur->fault_handler) {
-               if (cur->fault_handler(cur, regs, trapnr))
-                       return 1;
-       }
-
-       return 0;
-}
-
-static int aggr_break_handler(struct kprobe *p, struct pt_regs *regs)
-{
-       struct kprobe *cur = kprobe_instance();
-       int ret = 0;
-       DBPRINTF("cur = 0x%p\n", cur);
-       if (cur)
-               DBPRINTF("cur = 0x%p cur->break_handler = 0x%p\n",
-                        cur, cur->break_handler);
-
-       if (cur && cur->break_handler) {
-               if (cur->break_handler(cur, regs))
-                       ret = 1;
-       }
-       kprobe_instance_set(NULL);
-
-       return ret;
-}
-
-/**
- * @brief Walks the list and increments nmissed count for multiprobe case.
- *
- * @param p Pointer to the missed kprobe.
- * @return Void.
- */
-void swap_kprobes_inc_nmissed_count(struct kprobe *p)
-{
-       struct kprobe *kp;
-       if (p->pre_handler != aggr_pre_handler) {
-               p->nmissed++;
-       } else {
-               list_for_each_entry_rcu(kp, &p->list, list) {
-                       ++kp->nmissed;
-               }
-       }
-}
 
 static int alloc_nodes_kretprobe(struct kretprobe *rp);
 
@@ -443,130 +340,130 @@ static void free_rp_inst(struct kretprobe *rp)
        }
 }
 
-/*
- * Keep all fields in the kprobe consistent
- */
-static inline void copy_kprobe(struct kprobe *old_p, struct kprobe *p)
+static void kp_core_remove(struct kp_core *core)
 {
-       memcpy(&p->opcode, &old_p->opcode, sizeof(kprobe_opcode_t));
-       memcpy(&p->ainsn, &old_p->ainsn, sizeof(struct arch_specific_insn));
+       /* TODO: check boostable for x86 and MIPS */
+       swap_slot_free(&sm, core->ainsn.insn);
 }
 
-/*
- * Add the new probe to old_p->list. Fail if this is the
- * second jprobe at the address - two jprobes can't coexist
- */
-static int add_new_kprobe(struct kprobe *old_p, struct kprobe *p)
+static void kp_core_wait(struct kp_core *p)
 {
-       if (p->break_handler) {
-               if (old_p->break_handler)
-                       return -EEXIST;
+       int ms = 1;
 
-               list_add_tail_rcu(&p->list, &old_p->list);
-               old_p->break_handler = aggr_break_handler;
-       } else {
-               list_add_rcu(&p->list, &old_p->list);
+       while (atomic_read(&p->usage)) {
+               msleep(ms);
+               ms += ms < 7 ? 1 : 0;
        }
-
-       if (p->post_handler && !old_p->post_handler)
-               old_p->post_handler = aggr_post_handler;
-
-       return 0;
 }
 
-/**
- * hlist_replace_rcu - replace old entry by new one
- * @old : the element to be replaced
- * @new : the new element to insert
- *
- * The @old entry will be replaced with the @new entry atomically.
- */
-inline void swap_hlist_replace_rcu(struct hlist_node *old,
-                                  struct hlist_node *new)
+static struct kp_core *kp_core_create(unsigned long addr)
 {
-       struct hlist_node *next = old->next;
-
-       new->next = next;
-       new->pprev = old->pprev;
-       smp_wmb();
-       if (next)
-               new->next->pprev = &new->next;
-       if (new->pprev)
-               *new->pprev = new;
-       old->pprev = LIST_POISON2;
+       struct kp_core *core;
+
+       core = kzalloc(sizeof(*core), GFP_KERNEL);
+       if (core) {
+               INIT_HLIST_NODE(&core->hlist);
+               core->addr = addr;
+               atomic_set(&core->usage, 0);
+               rwlock_init(&core->handlers.lock);
+       }
+
+       return core;
 }
 
-/*
- * Fill in the required fields of the "manager kprobe". Replace the
- * earlier kprobe in the hlist with the manager kprobe
- */
-static inline void add_aggr_kprobe(struct kprobe *ap, struct kprobe *p)
+static void kp_core_free(struct kp_core *core)
 {
-       copy_kprobe(p, ap);
-       ap->addr = p->addr;
-       ap->pre_handler = aggr_pre_handler;
-       ap->fault_handler = aggr_fault_handler;
-       if (p->post_handler)
-               ap->post_handler = aggr_post_handler;
-       if (p->break_handler)
-               ap->break_handler = aggr_break_handler;
-
-       INIT_LIST_HEAD(&ap->list);
-       list_add_rcu(&p->list, &ap->list);
-
-       swap_hlist_replace_rcu(&p->hlist, &ap->hlist);
+       WARN_ON(atomic_read(&core->usage));
+       kfree(core);
 }
 
-/*
- * This is the second or subsequent kprobe at the address - handle
- * the intricacies
- */
-static int register_aggr_kprobe(struct kprobe *old_p, struct kprobe *p)
+static int pre_handler_one(struct kp_core *core, struct pt_regs *regs)
 {
        int ret = 0;
-       struct kprobe *ap;
-       DBPRINTF("start\n");
+       struct kprobe *p = core->handlers.kps[0];
 
-       DBPRINTF("p = %p old_p = %p\n", p, old_p);
-       if (old_p->pre_handler == aggr_pre_handler) {
-               DBPRINTF("aggr_pre_handler\n");
+       if (p->pre_handler)
+               ret = p->pre_handler(p, regs);
 
-               copy_kprobe(old_p, p);
-               ret = add_new_kprobe(old_p, p);
-       } else {
-               DBPRINTF("kzalloc\n");
-#ifdef kzalloc
-               ap = kzalloc(sizeof(struct kprobe), GFP_KERNEL);
-#else
-               ap = kmalloc(sizeof(struct kprobe), GFP_KERNEL);
-               if (ap)
-                       memset(ap, 0, sizeof(struct kprobe));
-#endif
-               if (!ap)
-                       return -ENOMEM;
+       return ret;
+}
+
+static int pre_handler_multi(struct kp_core *core, struct pt_regs *regs)
+{
+       int i, ret = 0;
 
-               atomic_set(&ap->usage, 0);
-               add_aggr_kprobe(ap, old_p);
-               copy_kprobe(ap, p);
-               DBPRINTF("ap = %p p = %p old_p = %p\n", ap, p, old_p);
-               ret = add_new_kprobe(ap, p);
+       /* TODO: add sync use kprobe */
+       for (i = 0; i < ARRAY_SIZE(core->handlers.kps); ++i) {
+               struct kprobe *p = core->handlers.kps[i];
+
+               if (p && p->pre_handler) {
+                       ret = p->pre_handler(p, regs);
+                       if (ret)
+                               break;
+               }
        }
 
        return ret;
 }
 
-static void remove_kprobe(struct kprobe *p)
+static int kp_core_add_kprobe(struct kp_core *core, struct kprobe *p)
 {
-       /* TODO: check boostable for x86 and MIPS */
-       swap_slot_free(&sm, p->ainsn.insn);
+       int i, ret = 0;
+       unsigned long flags;
+       struct kp_handlers *h = &core->handlers;
+
+       write_lock_irqsave(&h->lock, flags);
+       if (h->pre == NULL) {
+               h->pre = pre_handler_one;
+       } else if (h->pre == pre_handler_one) {
+               h->pre = pre_handler_multi;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(core->handlers.kps); ++i) {
+               if (core->handlers.kps[i])
+                       continue;
+
+               core->handlers.kps[i] = p;
+               goto unlock;
+       }
+
+       pr_err("all kps slots is busy\n");
+       ret = -EBUSY;
+unlock:
+       write_unlock_irqrestore(&h->lock, flags);
+       return ret;
 }
 
-static void wait_kp(struct kprobe *p)
+static void kp_core_del_kprobe(struct kp_core *core, struct kprobe *p)
 {
-       while (atomic_read(&p->usage))
-               schedule();
+       int i, cnt = 0;
+       unsigned long flags;
+       struct kp_handlers *h = &core->handlers;
+
+       write_lock_irqsave(&h->lock, flags);
+       for (i = 0; i < ARRAY_SIZE(h->kps); ++i) {
+               if (h->kps[i] == p)
+                       h->kps[i] = NULL;
+
+               if (h->kps[i] == NULL)
+                       ++cnt;
+       }
+       write_unlock_irqrestore(&h->lock, flags);
+
+       if (cnt == ARRAY_SIZE(h->kps)) {
+               arch_kp_core_disarm(core);
+               synchronize_sched();
+
+               hlist_del_rcu(&core->hlist);
+               synchronize_rcu();
+
+               kp_core_wait(core);
+               kp_core_remove(core);
+               kp_core_free(core);
+       }
 }
 
+static DEFINE_MUTEX(kp_mtx);
 /**
  * @brief Registers kprobe.
  *
@@ -575,7 +472,8 @@ static void wait_kp(struct kprobe *p)
  */
 int swap_register_kprobe(struct kprobe *p)
 {
-       struct kprobe *old_p;
+       struct kp_core *core;
+       unsigned long addr;
        int ret = 0;
        /*
         * If we have a symbol_name argument look it up,
@@ -585,83 +483,45 @@ int swap_register_kprobe(struct kprobe *p)
        if (p->symbol_name) {
                if (p->addr)
                        return -EINVAL;
-               p->addr = (kprobe_opcode_t *)swap_ksyms(p->symbol_name);
+               p->addr = swap_ksyms(p->symbol_name);
        }
 
        if (!p->addr)
                return -EINVAL;
-       DBPRINTF("p->addr = 0x%p\n", p->addr);
-       p->addr = (kprobe_opcode_t *)(((char *)p->addr) + p->offset);
-       DBPRINTF("p->addr = 0x%p p = 0x%p\n", p->addr, p);
-
-       p->nmissed = 0;
-       INIT_LIST_HEAD(&p->list);
-       atomic_set(&p->usage, 0);
-
-       old_p = swap_get_kprobe(p->addr);
-       if (old_p) {
-               ret = register_aggr_kprobe(old_p, p);
-               if (!ret)
-                       atomic_inc(&kprobe_count);
-               goto out;
-       }
-       ret = swap_arch_prepare_kprobe(p, &sm);
-       if (ret != 0)
-               goto out;
-
-       DBPRINTF("before out ret = 0x%x\n", ret);
-       INIT_HLIST_NODE(&p->hlist);
-       hlist_add_head_rcu(&p->hlist,
-                          &kprobe_table[hash_ptr(p->addr, KPROBE_HASH_BITS)]);
-       swap_arch_arm_kprobe(p);
-
-out:
-       DBPRINTF("out ret = 0x%x\n", ret);
-       return ret;
-}
-EXPORT_SYMBOL_GPL(swap_register_kprobe);
-
-static void swap_unregister_valid_kprobe(struct kprobe *p, struct kprobe *old_p)
-{
-       struct kprobe *list_p;
 
-       BUG_ON(in_atomic());
+       addr = p->addr + p->offset;
 
-       if ((old_p == p) || ((old_p->pre_handler == aggr_pre_handler) &&
-           (p->list.next == &old_p->list) && (p->list.prev == &old_p->list))) {
-               /* Only probe on the hash list */
-               swap_arch_disarm_kprobe(p);
-
-               synchronize_sched();
-               wait_kp(old_p);
-
-               hlist_del_rcu(&old_p->hlist);
-               remove_kprobe(old_p);
-
-               if (p != old_p) {
-                       list_del_rcu(&old_p->list);
-                       kfree(old_p);
+       mutex_lock(&kp_mtx);
+       core = kp_core_by_addr(addr);
+       if (core == NULL) {
+               core = kp_core_create(addr);
+               if (core == NULL) {
+                       pr_err("Out of memory\n");
+                       ret = -ENOMEM;
+                       goto unlock;
                }
-               /* Synchronize and remove probe in bottom */
-       } else {
-               list_del_rcu(&p->list);
 
-               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)
-                                       goto out;
+               ret = arch_kp_core_prepare(core, &sm);
+               if (ret)
+                       goto unlock;
 
-                       old_p->post_handler = NULL;
+               ret = kp_core_add_kprobe(core, p);
+               if (ret) {
+                       kp_core_free(core);
+                       goto unlock;
                }
+
+               hlist_add_head_rcu(&core->hlist, kpt_head_by_addr(core->addr));
+               arch_kp_core_arm(core);
+       } else {
+               ret = kp_core_add_kprobe(core, p);
        }
 
-out:
-       /* Set NULL addr for reusability if symbol_name is used */
-       if (p->symbol_name)
-               p->addr = NULL;
+unlock:
+       mutex_unlock(&kp_mtx);
+       return ret;
 }
+EXPORT_SYMBOL_GPL(swap_register_kprobe);
 
 /**
  * @brief Unregistes kprobe.
@@ -669,24 +529,21 @@ out:
  * @param kp Pointer to the target kprobe.
  * @return Void.
  */
-void swap_unregister_kprobe(struct kprobe *kp)
+void swap_unregister_kprobe(struct kprobe *p)
 {
-       struct kprobe *old_p, *list_p;
-
-       old_p = swap_get_kprobe(kp->addr);
-       if (unlikely(!old_p))
-               return;
-
-       if (kp != old_p) {
-               list_for_each_entry_rcu(list_p, &old_p->list, list)
-                       if (list_p == kp)
-                               goto unreg_valid_kprobe;
-               /* kprobe invalid */
-               return;
-       }
+       unsigned long addr = p->addr + p->offset;
+       struct kp_core *core;
+
+       mutex_lock(&kp_mtx);
+       core = kp_core_by_addr(addr);
+       BUG_ON(core == NULL);
 
-unreg_valid_kprobe:
-       swap_unregister_valid_kprobe(kp, old_p);
+       kp_core_del_kprobe(core, p);
+       mutex_unlock(&kp_mtx);
+
+       /* Set 0 addr for reusability if symbol_name is used */
+       if (p->symbol_name)
+               p->addr = 0;
 }
 EXPORT_SYMBOL_GPL(swap_unregister_kprobe);
 
@@ -700,7 +557,6 @@ int swap_register_jprobe(struct jprobe *jp)
 {
        /* Todo: Verify probepoint is a function entry point */
        jp->kp.pre_handler = swap_setjmp_pre_handler;
-       jp->kp.break_handler = swap_longjmp_break_handler;
 
        return swap_register_kprobe(&jp->kp);
 }
@@ -773,14 +629,14 @@ int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
        unsigned long flags, orig_ret_address = 0;
        unsigned long trampoline_address;
 
-       struct kprobe_ctlblk *kcb;
+       struct kp_core_ctlblk *kcb;
 
        struct hlist_node *tmp;
        DECLARE_NODE_PTR_FOR_HLIST(node);
 
        trampoline_address = (unsigned long)&swap_kretprobe_trampoline;
 
-       kcb = swap_get_kprobe_ctlblk();
+       kcb = kp_core_ctlblk();
 
        spin_lock_irqsave(&kretprobe_lock, flags);
 
@@ -816,11 +672,14 @@ int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
                        /* another task is sharing our hash bucket */
                        continue;
                if (ri->rp && ri->rp->handler) {
-                       swap_kprobe_running_set(&ri->rp->kp);
-                       swap_get_kprobe_ctlblk()->kprobe_status =
-                               KPROBE_HIT_ACTIVE;
+                       /*
+                        * Set fake current probe, we don't
+                        * want to go into recursion
+                        */
+                       kp_core_running_set((struct kp_core *)0xfffff);
+                       kcb->kp_core_status = KPROBE_HIT_ACTIVE;
                        ri->rp->handler(ri, regs);
-                       swap_kprobe_running_set(NULL);
+                       kp_core_running_set(NULL);
                }
 
                orig_ret_address = (unsigned long)ri->ret_addr;
@@ -835,10 +694,10 @@ int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
        }
        kretprobe_assert(ri, orig_ret_address, trampoline_address);
 
-       if (kcb->kprobe_status == KPROBE_REENTER)
-               restore_previous_kprobe(kcb);
+       if (kcb->kp_core_status == KPROBE_REENTER)
+               restore_previous_kp_core(kcb);
        else
-               swap_kprobe_running_set(NULL);
+               kp_core_running_set(NULL);
 
        spin_unlock_irqrestore(&kretprobe_lock, flags);
 
@@ -862,7 +721,7 @@ static int alloc_nodes_kretprobe(struct kretprobe *rp)
 
        DBPRINTF("Alloc aditional mem for retprobes");
 
-       if ((unsigned long)rp->kp.addr == sched_addr) {
+       if (rp->kp.addr == sched_addr) {
                rp->maxactive += SCHED_RP_NR; /* max (100, 2 * NR_CPUS); */
                alloc_nodes = SCHED_RP_NR;
        } else {
@@ -905,21 +764,18 @@ int swap_register_kretprobe(struct kretprobe *rp)
        DBPRINTF("START");
 
        rp->kp.pre_handler = pre_handler_kretprobe;
-       rp->kp.post_handler = NULL;
-       rp->kp.fault_handler = NULL;
-       rp->kp.break_handler = NULL;
 
        /* Pre-allocate memory for max kretprobe instances */
-       if ((unsigned long)rp->kp.addr == exit_addr) {
+       if (rp->kp.addr == exit_addr) {
                rp->kp.pre_handler = NULL; /* not needed for do_exit */
                rp->maxactive = 0;
-       } else if ((unsigned long)rp->kp.addr == do_group_exit_addr) {
+       } else if (rp->kp.addr == do_group_exit_addr) {
                rp->kp.pre_handler = NULL;
                rp->maxactive = 0;
-       } else if ((unsigned long)rp->kp.addr == sys_exit_group_addr) {
+       } else if (rp->kp.addr == sys_exit_group_addr) {
                rp->kp.pre_handler = NULL;
                rp->maxactive = 0;
-       } else if ((unsigned long)rp->kp.addr == sys_exit_addr) {
+       } else if (rp->kp.addr == sys_exit_addr) {
                rp->kp.pre_handler = NULL;
                rp->maxactive = 0;
        } else if (rp->maxactive <= 0) {
@@ -972,7 +828,7 @@ static void swap_disarm_krp(struct kretprobe *rp)
                        printk(KERN_INFO "%s (%d/%d): cannot disarm "
                               "krp instance (%08lx)\n",
                               ri->task->comm, ri->task->tgid, ri->task->pid,
-                              (unsigned long)rp->kp.addr);
+                              rp->kp.addr);
                }
        }
 }
@@ -1139,7 +995,7 @@ static int swap_disarm_krp_inst(struct kretprobe_instance *ri)
                       ri->task->comm, ri->task->tgid, ri->task->pid,
                       pc, (long unsigned int)ri->ret_addr,
                       (long unsigned int)tramp,
-                      (long unsigned int)(ri->rp ? ri->rp->kp.addr : NULL));
+                      (ri->rp ? ri->rp->kp.addr : 0));
 
                /* __switch_to retprobe handling */
                if (pc == (unsigned long)tramp) {
@@ -1160,22 +1016,22 @@ static int swap_disarm_krp_inst(struct kretprobe_instance *ri)
 
        if (found) {
                printk(KERN_INFO "---> [%d] %s (%d/%d): tramp (%08lx) "
-                      "found at %08lx (%08lx /%+d) - %p\n",
+                      "found at %08lx (%08lx /%+d) - %08lx\n",
                       task_cpu(ri->task),
                       ri->task->comm, ri->task->tgid, ri->task->pid,
                       (long unsigned int)tramp,
                       (long unsigned int)found, (long unsigned int)ri->sp,
-                      found - ri->sp, ri->rp ? ri->rp->kp.addr : NULL);
+                      found - ri->sp, ri->rp ? ri->rp->kp.addr : 0);
                *found = (unsigned long)ri->ret_addr;
                retval = 0;
        } else {
                printk(KERN_INFO "---> [%d] %s (%d/%d): tramp (%08lx) "
-                      "NOT found at sp = %08lx - %p\n",
+                      "NOT found at sp = %08lx - %08lx\n",
                       task_cpu(ri->task),
                       ri->task->comm, ri->task->tgid, ri->task->pid,
                       (long unsigned int)tramp,
                       (long unsigned int)ri->sp,
-                      ri->rp ? ri->rp->kp.addr : NULL);
+                      ri->rp ? ri->rp->kp.addr : 0);
        }
 
        return retval;
@@ -1259,8 +1115,8 @@ static int once(void)
                goto not_found;
 
        sym = "__put_task_struct";
-       put_task_kp.addr = (void *)swap_ksyms(sym);
-       if (put_task_kp.addr == NULL)
+       put_task_kp.addr = swap_ksyms(sym);
+       if (put_task_kp.addr == 0)
                goto not_found;
 
        ret = init_module_deps();
index cadb852..c7f1d55 100644 (file)
@@ -53,7 +53,7 @@
 #endif
 
 
-/* kprobe_status settings */
+/* kp_core_status settings */
 /** Kprobe hit active */
 #define KPROBE_HIT_ACTIVE      0x00000001
 /** Kprobe hit ss */
@@ -114,44 +114,40 @@ typedef int (*kprobe_fault_handler_t) (struct kprobe *,
 typedef int (*kretprobe_handler_t) (struct kretprobe_instance *,
                                    struct pt_regs *);
 
+struct kprobe;
+struct kp_core;
+
+struct kp_handlers {
+       int (*pre)(struct kp_core *, struct pt_regs *);
+
+       rwlock_t lock;
+       struct kprobe *kps[4];
+};
+
+struct kp_core {
+       struct hlist_node hlist;
+       atomic_t usage;
+
+       struct kp_handlers handlers;
+
+       unsigned long addr;
+       kprobe_opcode_t opcode;
+
+       struct arch_specific_insn ainsn;
+
+       unsigned long ss_addr[NR_CPUS];
+};
+
 /**
  * @struct kprobe
  * @brief Main kprobe struct.
  */
 struct kprobe {
-       struct hlist_node                               hlist; /**< Hash list.*/
-       /** List of probes to search by instruction slot.*/
-       struct hlist_node                               is_hlist;
-       /** List of kprobes for multi-handler support.*/
-       struct list_head                                list;
-       /** Count the number of times this probe was temporarily disarmed.*/
-       unsigned long                                   nmissed;
-       /** Location of the probe point. */
-       kprobe_opcode_t                                 *addr;
-       /** Allow user to indicate symbol name of the probe point.*/
-       char                                            *symbol_name;
-       /** Offset into the symbol.*/
-       unsigned int                                    offset;
-       /** Called before addr is executed.*/
-       kprobe_pre_handler_t                            pre_handler;
-       /** Called after addr is executed, unless...*/
-       kprobe_post_handler_t                           post_handler;
-       /** ... called if executing addr causes a fault (eg. page fault).*/
-       kprobe_fault_handler_t                          fault_handler;
-       /** Return 1 if it handled fault, otherwise kernel will see it.*/
-       kprobe_break_handler_t                          break_handler;
-       /** Saved opcode (which has been replaced with breakpoint).*/
-       kprobe_opcode_t                                 opcode;
-       /** Copy of the original instruction.*/
-       struct arch_specific_insn                       ainsn;
-       /** 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. */
-       kprobe_opcode_t                                 *ss_addr[NR_CPUS];
-       atomic_t usage;
+       unsigned long addr;     /**< Location of the probe point. */
+       char *symbol_name;      /**< Symbol name of the probe point. */
+       unsigned long offset;   /**< Offset into the symbol.*/
+       /**< Called before addr is executed. */
+       kprobe_pre_handler_t pre_handler;
 };
 
 /**
@@ -242,8 +238,6 @@ struct kretprobe_instance {
 };
 
 
-extern void swap_kprobes_inc_nmissed_count(struct kprobe *p);
-
 /*
  * Large value for fast but memory consuming implementation
  * it is good when a lot of probes are instrumented
@@ -253,27 +247,23 @@ extern void swap_kprobes_inc_nmissed_count(struct kprobe *p);
 #define KPROBE_TABLE_SIZE (1 << KPROBE_HASH_BITS)
 
 
-static void inline get_kp(struct kprobe *p)
+static void inline kp_core_get(struct kp_core *p)
 {
        atomic_inc(&p->usage);
 }
 
-static void inline put_kp(struct kprobe *p)
+static void inline kp_core_put(struct kp_core *p)
 {
        atomic_dec(&p->usage);
 }
 
 
-/* Get the kprobe at this addr (if any) - called with preemption disabled */
-struct kprobe *swap_get_kprobe(void *addr);
-
+/* Get the kp_core at this addr (if any) - called with rcu_read_lock() */
+struct kp_core *kp_core_by_addr(unsigned long addr);
 
 int swap_register_kprobe(struct kprobe *p);
 void swap_unregister_kprobe(struct kprobe *p);
 
-int swap_setjmp_pre_handler(struct kprobe *, struct pt_regs *);
-int swap_longjmp_break_handler(struct kprobe *, struct pt_regs *);
-
 int swap_register_jprobe(struct jprobe *p);
 void swap_unregister_jprobe(struct jprobe *p);
 void swap_jprobe_return(void);
@@ -304,10 +294,9 @@ int trampoline_probe_handler (struct kprobe *p, struct pt_regs *regs);
 extern atomic_t kprobe_count;
 extern unsigned long sched_addr;
 
-struct kprobe *swap_kprobe_running(void);
-void swap_kprobe_running_set(struct kprobe *p);
-void swap_reset_current_kprobe(void);
-struct kprobe_ctlblk *swap_get_kprobe_ctlblk(void);
+struct kp_core *kp_core_running(void);
+void kp_core_running_set(struct kp_core *p);
+struct kp_core_ctlblk *kp_core_ctlblk(void);
 
 
 #endif /* _SWAP_KPROBES_H */
index f462e7a..a572b67 100644 (file)
@@ -123,7 +123,7 @@ static int entry_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
        if (rp && check_event(current)) {
                struct ks_probe *ksp = container_of(rp, struct ks_probe, rp);
                const char *fmt = ksp->args;
-               const unsigned long addr = (unsigned long)ksp->rp.kp.addr;
+               const unsigned long addr = ksp->rp.kp.addr;
                enum probe_t type = ksp->type;
 
                ksf_msg_entry(regs, addr, type, fmt);
@@ -138,7 +138,7 @@ static int ret_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
 
        if (rp && check_event(current)) {
                struct ks_probe *ksp = container_of(rp, struct ks_probe, rp);
-               const unsigned long func_addr = (unsigned long)rp->kp.addr;
+               const unsigned long func_addr = rp->kp.addr;
                const unsigned long ret_addr = (unsigned long)ri->ret_addr;
                enum probe_t type = ksp->type;
 
@@ -190,16 +190,12 @@ static int sc_enable;
  */
 int init_switch_context(void)
 {
-       unsigned long addr;
-
-       addr = swap_ksyms("__switch_to");
-       if (addr == 0) {
+       switch_rp.kp.addr = swap_ksyms("__switch_to");
+       if (switch_rp.kp.addr == 0) {
                printk(KERN_INFO "ERROR: not found '__switch_to'\n");
                return -EINVAL;
        }
 
-       switch_rp.kp.addr = (kprobe_opcode_t *)addr;
-
        return 0;
 }
 
@@ -264,7 +260,7 @@ static int register_syscall(size_t id)
        int ret;
        printk(KERN_INFO "register_syscall: %s\n", get_sys_name(id));
 
-       if (ksp[id].rp.kp.addr == NULL)
+       if (ksp[id].rp.kp.addr == 0)
                return 0;
 
        ksp[id].rp.entry_handler = entry_handler;
@@ -280,7 +276,7 @@ static int unregister_syscall(size_t id)
 {
        printk(KERN_INFO "unregister_syscall: %s\n", get_sys_name(id));
 
-       if (ksp[id].rp.kp.addr == NULL)
+       if (ksp[id].rp.kp.addr == 0)
                return 0;
 
        swap_unregister_kretprobe(&ksp[id].rp);
@@ -312,7 +308,7 @@ static int unregister_multiple_syscalls(size_t *id_p, size_t cnt)
 
        for (; cnt != end; --cnt) {
                id = id_p[cnt];
-               if (ksp[id].rp.kp.addr != NULL) {
+               if (ksp[id].rp.kp.addr) {
                                rpp[i] = &ksp[id].rp;
                                ++i;
                }
@@ -526,7 +522,7 @@ static int init_syscall_features(void)
                        addr = 0;
                }
 
-               ksp[i].rp.kp.addr = (kprobe_opcode_t *)addr;
+               ksp[i].rp.kp.addr = addr;
        }
 
        return 0;
index a8abc65..2a554e1 100644 (file)
@@ -43,7 +43,7 @@ static struct probe *create_probe(unsigned long addr, void *pre_handler,
        if (p == NULL)
                return NULL;
 
-       p->p.jp.kp.addr = p->p.rp.kp.addr = (void *)addr;
+       p->p.jp.kp.addr = p->p.rp.kp.addr = addr;
        p->p.jp.pre_entry = pre_handler;
        p->p.jp.entry = jp_handler;
        p->p.rp.handler = rp_handler;
index bf64106..2bbd046 100644 (file)
@@ -177,17 +177,6 @@ int taskctx_run(struct task_struct *task, taskctx_t func, void *data)
 EXPORT_SYMBOL_GPL(taskctx_run);
 
 
-static unsigned long cb_sig(void *data)
-{
-       struct call_task *call = *(struct call_task **)data;
-
-       complete(&call->comp0);
-       call->func(call->data);
-       complete(&call->comp1);
-
-       return 0;
-}
-
 static int sig_pre_handler(struct kprobe *p, struct pt_regs *regs)
 {
        struct call_task *call = call_get(current);
@@ -196,7 +185,9 @@ static int sig_pre_handler(struct kprobe *p, struct pt_regs *regs)
                call_set(current, NULL);
                call->is_running = true;
 
-               return set_kjump_cb(regs, cb_sig, &call, sizeof(call));
+               complete(&call->comp0);
+               call->func(call->data);
+               complete(&call->comp1);
        }
 
        return 0;
@@ -274,8 +265,8 @@ static int taskctx_once(void)
                goto not_found;
 
        sym = "get_signal_to_deliver";
-       sig_kprobe.addr = (kprobe_opcode_t *)swap_ksyms(sym);
-       if (sig_kprobe.addr == NULL)
+       sig_kprobe.addr = swap_ksyms(sym);
+       if (sig_kprobe.addr == 0)
                goto not_found;
 
        return 0;
index fedc68f..c6b5151 100644 (file)
@@ -707,8 +707,8 @@ int swap_arch_init_uprobes(void)
                goto not_found;
 
        sym = "do_exit";
-       kp_do_exit.addr = (void *)swap_ksyms(sym);
-       if (kp_do_exit.addr == NULL)
+       kp_do_exit.addr = swap_ksyms(sym);
+       if (kp_do_exit.addr == 0)
                goto not_found;
 
        ret = swap_td_raw_reg(&td_raw, sizeof(struct uprobe_ctlblk));
index e3dde3c..8a64b47 100644 (file)
@@ -210,36 +210,16 @@ static void rm_uprobes_child(struct kretprobe_instance *ri,
 }
 
 
-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);
-
-       atomic_dec(&pre_handler_cp_cnt);
-       return 0;
-}
-
 static int pre_handler_cp(struct kprobe *p, struct pt_regs *regs)
 {
-       int ret = 0;
-
        if (is_kthread(current))
                goto out;
 
-       if (!atomic_read(&stop_flag))
-               goto out;
+       if (atomic_read(&stop_flag))
+               call_mm_release(current);
 
-       ret = set_kjump_cb(regs, cp_cb, NULL, 0);
-       if (ret < 0) {
-               pr_err("set_kjump_cp, ret=%d\n", ret);
-               ret = 0;
-       } else {
-               atomic_inc(&pre_handler_cp_cnt);
-       }
 out:
-       return ret;
+       return 0;
 }
 
 
@@ -308,8 +288,7 @@ static void unregister_cp(void)
 
        do {
                synchronize_sched();
-       } while (atomic_read(&rm_uprobes_child_cnt)
-             || atomic_read(&pre_handler_cp_cnt));
+       } while (atomic_read(&rm_uprobes_child_cnt));
 }
 
 
@@ -321,17 +300,13 @@ static void unregister_cp(void)
  *                                mm_release()                                *
  ******************************************************************************
  */
-
-static atomic_t mm_release_cnt = ATOMIC_INIT(0);
-
-static unsigned long mr_cb(void *data)
+static void mr_handler(struct task_struct *task)
 {
-       struct task_struct *task = *(struct task_struct **)data;
        struct mm_struct *mm = task->mm;
 
        if (mm == NULL) {
                pr_err("mm is NULL\n");
-               return 0;
+               return;
        }
 
        /* TODO: this lock for synchronizing to disarm urp */
@@ -341,7 +316,7 @@ static unsigned long mr_cb(void *data)
 
                if (task != current) {
                        pr_err("call mm_release in isn't current context\n");
-                       return 0;
+                       return;
                }
 
                /* if the thread is killed we need to discard pending
@@ -353,31 +328,20 @@ static unsigned long mr_cb(void *data)
                call_mm_release(task);
        }
        up_write(&mm->mmap_sem);
-
-       atomic_dec(&mm_release_cnt);
-
-       return 0;
 }
 
 /* Detects when target process removes IPs. */
 static int mr_pre_handler(struct kprobe *p, struct pt_regs *regs)
 {
-       int ret = 0;
        struct task_struct *task = (struct task_struct *)swap_get_karg(regs, 0);
 
        if (is_kthread(task))
                goto out;
 
-       ret = set_kjump_cb(regs, mr_cb, (void *)&task, sizeof(task));
-       if (ret < 0) {
-               printk("##### ERROR: mr_pre_handler, ret=%d\n", ret);
-               ret = 0;
-       } else {
-               atomic_inc(&mm_release_cnt);
-       }
+       mr_handler(task);
 
 out:
-       return ret;
+       return 0;
 }
 
 static struct kprobe mr_kprobe = {
@@ -399,9 +363,6 @@ static int register_mr(void)
 static void unregister_mr(void)
 {
        swap_unregister_kprobe(&mr_kprobe);
-       do {
-               synchronize_sched();
-       } while (atomic_read(&mm_release_cnt));
 }
 
 
@@ -843,39 +804,39 @@ int once_helper(void)
        const char *sym;
 
        sym = "do_page_fault";
-       mf_kretprobe.kp.addr = (kprobe_opcode_t *)swap_ksyms(sym);
-       if (mf_kretprobe.kp.addr == NULL)
+       mf_kretprobe.kp.addr = swap_ksyms(sym);
+       if (mf_kretprobe.kp.addr == 0)
                goto not_found;
 
        sym = "copy_process";
-       cp_kretprobe.kp.addr = (kprobe_opcode_t *)swap_ksyms_substr(sym);
-       if (cp_kretprobe.kp.addr == NULL)
+       cp_kretprobe.kp.addr = swap_ksyms_substr(sym);
+       if (cp_kretprobe.kp.addr == 0)
                goto not_found;
        cp_kprobe.addr = cp_kretprobe.kp.addr;
 
        sym = "mm_release";
-       mr_kprobe.addr = (kprobe_opcode_t *)swap_ksyms(sym);
-       if (mr_kprobe.addr == NULL)
+       mr_kprobe.addr = swap_ksyms(sym);
+       if (mr_kprobe.addr == 0)
                goto not_found;
 
        sym = "do_munmap";
-       unmap_kretprobe.kp.addr = (kprobe_opcode_t *)swap_ksyms(sym);
-       if (unmap_kretprobe.kp.addr == NULL)
+       unmap_kretprobe.kp.addr = swap_ksyms(sym);
+       if (unmap_kretprobe.kp.addr == 0)
                goto not_found;
 
        sym = "do_mmap_pgoff";
-       mmap_kretprobe.kp.addr = (kprobe_opcode_t *)swap_ksyms(sym);
-       if (mmap_kretprobe.kp.addr == NULL)
+       mmap_kretprobe.kp.addr = swap_ksyms(sym);
+       if (mmap_kretprobe.kp.addr == 0)
                goto not_found;
 
        sym = "set_task_comm";
-       comm_kretprobe.kp.addr = (kprobe_opcode_t *)swap_ksyms(sym);
-       if (comm_kretprobe.kp.addr == NULL)
+       comm_kretprobe.kp.addr = swap_ksyms(sym);
+       if (comm_kretprobe.kp.addr == 0)
                goto not_found;
 
        sym = "release_task";
-       release_task_kp.addr = (kprobe_opcode_t *)swap_ksyms(sym);
-       if (release_task_kp.addr == NULL)
+       release_task_kp.addr = swap_ksyms(sym);
+       if (release_task_kp.addr == 0)
                goto not_found;
 
        return 0;