[IMPROVE] create slot_manager
[kernel/swap-modules.git] / uprobe / arch / asm-arm / swap_uprobes.c
index f0097a6..8ae763b 100644 (file)
@@ -5,13 +5,17 @@
 #include <swap_uprobes.h>
 #include <asm/swap_uprobes.h>
 #include <dbi_insn_slots.h>
+#include <dbi_kprobes_deps.h>
 #include "trampoline_thumb.h"
 
 // FIXME:
 #include <dbi_kdebug.h>
-extern struct hlist_head uprobe_insn_pages;
 
 
+#define flush_insns(addr, size)                                        \
+       flush_icache_range((unsigned long)(addr),               \
+                          (unsigned long)(addr) + (size))
+
 #define sign_extend(x, signbit) ((x) | (0 - ((x) & (1 << (signbit)))))
 #define branch_displacement(insn) sign_extend(((insn) & 0xffffff) << 2, 25)
 
@@ -532,7 +536,7 @@ static int arch_copy_trampoline_thumb_uprobe(struct kprobe *p, struct task_struc
        return 0;
 }
 
-int arch_prepare_uprobe(struct uprobe *up, int atomic)
+int arch_prepare_uprobe(struct uprobe *up, struct hlist_head *page_list, int atomic)
 {
        int ret = 0;
        struct kprobe *p = &up->kp;
@@ -549,7 +553,7 @@ int arch_prepare_uprobe(struct uprobe *up, int atomic)
        }
 
        p->opcode = insn[0];
-       p->ainsn.insn_arm = get_insn_slot(task, &uprobe_insn_pages, atomic);
+       p->ainsn.insn_arm = alloc_insn_slot(up->sm);
        if (!p->ainsn.insn_arm) {
                printk("Error in %s at %d: kprobe slot allocation error (arm)\n", __FILE__, __LINE__);
                return -ENOMEM;
@@ -557,11 +561,11 @@ int arch_prepare_uprobe(struct uprobe *up, int atomic)
 
        ret = arch_copy_trampoline_arm_uprobe(p, task, 1);
        if (ret) {
-               free_insn_slot(&uprobe_insn_pages, task, p->ainsn.insn_arm);
+               free_insn_slot(up->sm, p->ainsn.insn_arm);
                return -EFAULT;
        }
 
-       p->ainsn.insn_thumb = get_insn_slot(task, &uprobe_insn_pages, atomic);
+       p->ainsn.insn_thumb = alloc_insn_slot(up->sm);
        if (!p->ainsn.insn_thumb) {
                printk("Error in %s at %d: kprobe slot allocation error (thumb)\n", __FILE__, __LINE__);
                return -ENOMEM;
@@ -569,8 +573,8 @@ int arch_prepare_uprobe(struct uprobe *up, int atomic)
 
        ret = arch_copy_trampoline_thumb_uprobe(p, task, 1);
        if (ret) {
-               free_insn_slot(&uprobe_insn_pages, task, p->ainsn.insn_arm);
-               free_insn_slot(&uprobe_insn_pages, task, p->ainsn.insn_thumb);
+               free_insn_slot(up->sm, p->ainsn.insn_arm);
+               free_insn_slot(up->sm, p->ainsn.insn_thumb);
                return -EFAULT;
        }
 
@@ -581,8 +585,8 @@ int arch_prepare_uprobe(struct uprobe *up, int atomic)
                        panic("Failed to write memory %p!\n", p->addr);
                }
 
-               free_insn_slot(&uprobe_insn_pages, task, p->ainsn.insn_arm);
-               free_insn_slot(&uprobe_insn_pages, task, p->ainsn.insn_thumb);
+               free_insn_slot(up->sm, p->ainsn.insn_arm);
+               free_insn_slot(up->sm, p->ainsn.insn_thumb);
 
                return -EFAULT;
        }
@@ -638,13 +642,12 @@ unsigned long arch_get_trampoline_addr(struct kprobe *p, struct pt_regs *regs)
 void arch_set_orig_ret_addr(unsigned long orig_ret_addr, struct pt_regs *regs)
 {
        regs->ARM_lr = orig_ret_addr;
-       regs->ARM_pc = orig_ret_addr;
+       regs->ARM_pc = orig_ret_addr & ~0x1;
 
-       if (thumb_mode(regs) && !(regs->ARM_lr & 0x01)) {
-               regs->ARM_cpsr &= 0xFFFFFFDF;
-       } else if (user_mode(regs) && (regs->ARM_lr & 0x01)) {
-               regs->ARM_cpsr |= 0x20;
-       }
+       if (regs->ARM_lr & 0x1)
+               regs->ARM_cpsr |= PSR_T_BIT;
+       else
+               regs->ARM_cpsr &= ~PSR_T_BIT;
 }
 
 static int check_validity_insn(struct kprobe *p, struct pt_regs *regs)
@@ -683,6 +686,16 @@ disarm:
        return -1;
 }
 
+static void restore_opcode_for_thumb(struct kprobe *p, struct pt_regs *regs)
+{
+       if (thumb_mode(regs) && !is_thumb2(p->opcode)) {
+               u16 tmp = p->opcode >> 16;
+               write_proc_vm_atomic(current,
+                               (unsigned long)((u16*)p->addr + 1), &tmp, 2);
+               flush_insns(p->addr, 4);
+       }
+}
+
 static int uprobe_handler(struct pt_regs *regs)
 {
        kprobe_opcode_t *addr = (kprobe_opcode_t *)(regs->ARM_pc);
@@ -700,29 +713,16 @@ static int uprobe_handler(struct pt_regs *regs)
                }
 
                trampoline_uprobe_handler(p, regs);
-               return 0;
-       }
-
-       if (p && (check_validity_insn(p, regs) != 0)) {
+       } else if (check_validity_insn(p, regs) != 0) {
                printk("no_uprobe live\n");
-               return 0;
-       }
-
-       /* restore opcode for thumb app */
-       if (thumb_mode(regs)) {
-               if (!is_thumb2(p->opcode)) {
-                       unsigned long tmp = p->opcode >> 16;
-                       write_proc_vm_atomic(task, (unsigned long)((unsigned short*)p->addr + 1), &tmp, 2);
+       } else {
+               restore_opcode_for_thumb(p, regs);
 
-                       // "2*sizeof(kprobe_opcode_t)" - strange. Should be "sizeof(kprobe_opcode_t)", need to test
-                       flush_icache_range((unsigned int)p->addr, ((unsigned int)p->addr) + (2 * sizeof(kprobe_opcode_t)));
+               if (!p->pre_handler || !p->pre_handler(p, regs)) {
+                       prepare_singlestep(p, regs);
                }
        }
 
-       if (!p->pre_handler || !p->pre_handler(p, regs)) {
-               prepare_singlestep(p, regs);
-       }
-
        return 0;
 }