[FIX] US instrumentation running process
authorVyacheslav Cherkashin <v.cherkashin@samsung.com>
Mon, 25 Nov 2013 12:14:17 +0000 (16:14 +0400)
committerVyacheslav Cherkashin <v.cherkashin@samsung.com>
Thu, 28 Nov 2013 12:12:23 +0000 (16:12 +0400)
Signed-off-by: Vyacheslav Cherkashin <v.cherkashin@samsung.com>
Change-Id: Ib5c5f526e12d9abdb246b16b562637d620370f2b

kprobe/arch/asm-x86/dbi_kprobes.h
kprobe/dbi_insn_slots.c
kprobe/dbi_kprobes.h
uprobe/arch/asm-arm/swap_uprobes.c
uprobe/arch/asm-arm/swap_uprobes.h
uprobe/arch/asm-x86/swap_uprobes.c
uprobe/arch/asm-x86/swap_uprobes.h
uprobe/swap_uprobes.c
uprobe/swap_uprobes.h
us_manager/us_slot_manager.c

index 24cf06a..6850c24 100644 (file)
@@ -57,6 +57,7 @@ typedef u8 kprobe_opcode_t;
 #define BREAKPOINT_INSTRUCTION          0xcc
 #define RELATIVEJUMP_INSTRUCTION        0xe9
 
+#define BP_INSN_SIZE                    1
 #define MAX_INSN_SIZE                   16
 #define MAX_STACK_SIZE                  64
 
index fb4f6d1..5723935 100644 (file)
@@ -192,6 +192,9 @@ void free_insn_slot(struct slot_manager *sm, void *slot)
        struct fixed_alloc *fa;
        DECLARE_NODE_PTR_FOR_HLIST(pos);
 
+       if (slot == NULL)
+               return;
+
        swap_hlist_for_each_entry_rcu(fa, pos, &sm->page_list, hlist) {
                if (!chunk_check_ptr(&fa->chunk, slot, PAGE_SIZE))
                        continue;
index 67d7ff1..9b187aa 100644 (file)
@@ -98,12 +98,7 @@ struct kprobe
 {
        struct hlist_node                               hlist;
        /*list of probes to search by instruction slot*/
-#ifdef CONFIG_ARM
-       struct hlist_node                               is_hlist_arm;
-       struct hlist_node                               is_hlist_thumb;
-#else /* CONFIG_ARM */
        struct hlist_node                               is_hlist;
-#endif /* CONFIG_ARM */
        /* list of kprobes for multi-handler support */
        struct list_head                                list;
        /* Indicates that the corresponding module has been ref counted */
index 81b7d4d..0fd22e6 100644 (file)
@@ -95,12 +95,12 @@ static int is_thumb2(kprobe_opcode_t insn)
 
 static int arch_copy_trampoline_arm_uprobe(struct uprobe *up)
 {
-       struct task_struct *task = up->task;
        struct kprobe *p = up2kp(up);
-       unsigned long insns[UPROBES_TRAMP_LEN];
+       int uregs, pc_dep;
        unsigned long insn = p->opcode;
        unsigned long vaddr = (unsigned long)p->addr;
-       int uregs, pc_dep;
+       unsigned long *tramp = up->atramp.tramp_arm;
+       enum { tramp_len = sizeof(up->atramp.tramp_arm) };
 
        p->safe_arm = 1;
        if (vaddr & 0x03) {
@@ -162,61 +162,56 @@ static int arch_copy_trampoline_arm_uprobe(struct uprobe *up)
        }
 
        if (unlikely(uregs && pc_dep)) {
-               memcpy(insns, pc_dep_insn_execbuf, sizeof(insns));
-               if (prep_pc_dep_insn_execbuf(insns, insn, uregs) != 0) {
+               memcpy(tramp, pc_dep_insn_execbuf, tramp_len);
+               if (prep_pc_dep_insn_execbuf(tramp, insn, uregs) != 0) {
                        printk("Error in %s at %d: failed "
                               "to prepare exec buffer for insn %lx!",
                               __FILE__, __LINE__, insn);
                        p->safe_arm = 1;
                }
 
-               insns[6] = vaddr + 8;
+               tramp[6] = vaddr + 8;
        } else {
-               memcpy(insns, gen_insn_execbuf, sizeof(insns));
-               insns[UPROBES_TRAMP_INSN_IDX] = insn;
+               memcpy(tramp, gen_insn_execbuf, tramp_len);
+               tramp[UPROBES_TRAMP_INSN_IDX] = insn;
        }
 
-       insns[UPROBES_TRAMP_RET_BREAK_IDX] = BREAKPOINT_INSTRUCTION;
-       insns[7] = vaddr + 4;
+       tramp[UPROBES_TRAMP_RET_BREAK_IDX] = BREAKPOINT_INSTRUCTION;
+       tramp[7] = vaddr + 4;
 
        /* B */
        if (ARM_INSN_MATCH(B, insn) &&
            !ARM_INSN_MATCH(BLX1, insn)) {
                /* B check can be false positive on BLX1 instruction */
-               memcpy(insns, b_cond_insn_execbuf, sizeof(insns));
-               insns[UPROBES_TRAMP_RET_BREAK_IDX] = BREAKPOINT_INSTRUCTION;
-               insns[0] |= insn & 0xf0000000;
-               insns[6] = get_addr_b(insn, vaddr);
-               insns[7] = vaddr + 4;
+               memcpy(tramp, b_cond_insn_execbuf, tramp_len);
+               tramp[UPROBES_TRAMP_RET_BREAK_IDX] = BREAKPOINT_INSTRUCTION;
+               tramp[0] |= insn & 0xf0000000;
+               tramp[6] = get_addr_b(insn, vaddr);
+               tramp[7] = vaddr + 4;
        /* BX, BLX (Rm) */
        } else if (ARM_INSN_MATCH(BX, insn) ||
                   ARM_INSN_MATCH(BLX2, insn)) {
-               memcpy(insns, b_r_insn_execbuf, sizeof (insns));
-               insns[0] = insn;
-               insns[UPROBES_TRAMP_RET_BREAK_IDX] = BREAKPOINT_INSTRUCTION;
-               insns[7] = vaddr + 4;
+               memcpy(tramp, b_r_insn_execbuf, tramp_len);
+               tramp[0] = insn;
+               tramp[UPROBES_TRAMP_RET_BREAK_IDX] = BREAKPOINT_INSTRUCTION;
+               tramp[7] = vaddr + 4;
        /* BL, BLX (Off) */
        } else if (ARM_INSN_MATCH(BLX1, insn)) {
-               memcpy(insns, blx_off_insn_execbuf, sizeof(insns));
-               insns[0] |= 0xe0000000;
-               insns[1] |= 0xe0000000;
-               insns[UPROBES_TRAMP_RET_BREAK_IDX] = BREAKPOINT_INSTRUCTION;
-               insns[6] = get_addr_b(insn, vaddr) +
+               memcpy(tramp, blx_off_insn_execbuf, tramp_len);
+               tramp[0] |= 0xe0000000;
+               tramp[1] |= 0xe0000000;
+               tramp[UPROBES_TRAMP_RET_BREAK_IDX] = BREAKPOINT_INSTRUCTION;
+               tramp[6] = get_addr_b(insn, vaddr) +
                           2 * (insn & 01000000) + 1; /* jump to thumb */
-               insns[7] = vaddr + 4;
+               tramp[7] = vaddr + 4;
        /* BL */
        } else if (ARM_INSN_MATCH(BL, insn)) {
-               memcpy(insns, blx_off_insn_execbuf, sizeof(insns));
-               insns[0] |= insn & 0xf0000000;
-               insns[1] |= insn & 0xf0000000;
-               insns[UPROBES_TRAMP_RET_BREAK_IDX] = BREAKPOINT_INSTRUCTION;
-               insns[6] = get_addr_b(insn, vaddr);
-               insns[7] = vaddr + 4;
-       }
-
-       if (!write_proc_vm_atomic(task, (unsigned long)p->ainsn.insn_arm,
-                                 insns, sizeof(insns))) {
-               panic("failed to write memory %p!\n", p->ainsn.insn_arm);
+               memcpy(tramp, blx_off_insn_execbuf, tramp_len);
+               tramp[0] |= insn & 0xf0000000;
+               tramp[1] |= insn & 0xf0000000;
+               tramp[UPROBES_TRAMP_RET_BREAK_IDX] = BREAKPOINT_INSTRUCTION;
+               tramp[6] = get_addr_b(insn, vaddr);
+               tramp[7] = vaddr + 4;
        }
 
        return 0;
@@ -485,13 +480,12 @@ static int prep_pc_dep_insn_execbuf_thumb(kprobe_opcode_t * insns, kprobe_opcode
 static int arch_copy_trampoline_thumb_uprobe(struct uprobe *up)
 {
        int uregs, pc_dep;
-       struct task_struct *task = up->task;
        struct kprobe *p = up2kp(up);
        unsigned int addr;
        unsigned long vaddr = (unsigned long)p->addr;
        unsigned long insn = p->opcode;
-       /* TODO: or array size UPROBES_TRAMP_LEN?! */
-       unsigned long insns[UPROBES_TRAMP_LEN * 2];
+       unsigned long *tramp = up->atramp.tramp_thumb;
+       enum { tramp_len = sizeof(up->atramp.tramp_thumb) };
 
        p->safe_thumb = 1;
        if (vaddr & 0x01) {
@@ -562,158 +556,132 @@ static int arch_copy_trampoline_thumb_uprobe(struct uprobe *up)
        }
 
        if (unlikely(uregs && pc_dep)) {
-               memcpy(insns, pc_dep_insn_execbuf_thumb, 18 * 2);
-               if (prep_pc_dep_insn_execbuf_thumb(insns, insn, uregs) != 0) {
+               memcpy(tramp, pc_dep_insn_execbuf_thumb, tramp_len);
+               if (prep_pc_dep_insn_execbuf_thumb(tramp, insn, uregs) != 0) {
                        printk("Error in %s at %d: failed to prepare exec buffer for insn %lx!",
                               __FILE__, __LINE__, insn);
                        p->safe_thumb = 1;
                }
 
                addr = vaddr + 4;
-               *((unsigned short*)insns + 13) = 0xdeff;
-               *((unsigned short*)insns + 14) = addr & 0x0000ffff;
-               *((unsigned short*)insns + 15) = addr >> 16;
+               *((unsigned short*)tramp + 13) = 0xdeff;
+               *((unsigned short*)tramp + 14) = addr & 0x0000ffff;
+               *((unsigned short*)tramp + 15) = addr >> 16;
                if (!is_thumb2(insn)) {
                        addr = vaddr + 2;
-                       *((unsigned short*)insns + 16) = (addr & 0x0000ffff) | 0x1;
-                       *((unsigned short*)insns + 17) = addr >> 16;
+                       *((unsigned short*)tramp + 16) = (addr & 0x0000ffff) | 0x1;
+                       *((unsigned short*)tramp + 17) = addr >> 16;
                } else {
                        addr = vaddr + 4;
-                       *((unsigned short*)insns + 16) = (addr & 0x0000ffff) | 0x1;
-                       *((unsigned short*)insns + 17) = addr >> 16;
+                       *((unsigned short*)tramp + 16) = (addr & 0x0000ffff) | 0x1;
+                       *((unsigned short*)tramp + 17) = addr >> 16;
                }
        } else {
-               memcpy(insns, gen_insn_execbuf_thumb, 18 * 2);
-               *((unsigned short*)insns + 13) = 0xdeff;
+               memcpy(tramp, gen_insn_execbuf_thumb, tramp_len);
+               *((unsigned short*)tramp + 13) = 0xdeff;
                if (!is_thumb2(insn)) {
                        addr = vaddr + 2;
-                       *((unsigned short*)insns + 2) = insn;
-                       *((unsigned short*)insns + 16) = (addr & 0x0000ffff) | 0x1;
-                       *((unsigned short*)insns + 17) = addr >> 16;
+                       *((unsigned short*)tramp + 2) = insn;
+                       *((unsigned short*)tramp + 16) = (addr & 0x0000ffff) | 0x1;
+                       *((unsigned short*)tramp + 17) = addr >> 16;
                } else {
                        addr = vaddr + 4;
-                       insns[1] = insn;
-                       *((unsigned short*)insns + 16) = (addr & 0x0000ffff) | 0x1;
-                       *((unsigned short*)insns + 17) = addr >> 16;
+                       tramp[1] = insn;
+                       *((unsigned short*)tramp + 16) = (addr & 0x0000ffff) | 0x1;
+                       *((unsigned short*)tramp + 17) = addr >> 16;
                }
        }
 
        if (THUMB_INSN_MATCH(B2, insn)) {
-               memcpy(insns, b_off_insn_execbuf_thumb, sizeof(insns));
-               *((unsigned short*)insns + 13) = 0xdeff;
+               memcpy(tramp, b_off_insn_execbuf_thumb, tramp_len);
+               *((unsigned short*)tramp + 13) = 0xdeff;
                addr = branch_t16_dest(insn, vaddr);
-               *((unsigned short*)insns + 14) = (addr & 0x0000ffff) | 0x1;
-               *((unsigned short*)insns + 15) = addr >> 16;
-               *((unsigned short*)insns + 16) = 0;
-               *((unsigned short*)insns + 17) = 0;
+               *((unsigned short*)tramp + 14) = (addr & 0x0000ffff) | 0x1;
+               *((unsigned short*)tramp + 15) = addr >> 16;
+               *((unsigned short*)tramp + 16) = 0;
+               *((unsigned short*)tramp + 17) = 0;
 
        } else if (THUMB_INSN_MATCH(B1, insn)) {
-               memcpy(insns, b_cond_insn_execbuf_thumb, sizeof(insns));
-               *((unsigned short*)insns + 13) = 0xdeff;
-               *((unsigned short*)insns + 0) |= (insn & 0xf00);
+               memcpy(tramp, b_cond_insn_execbuf_thumb, tramp_len);
+               *((unsigned short*)tramp + 13) = 0xdeff;
+               *((unsigned short*)tramp + 0) |= (insn & 0xf00);
                addr = branch_cond_t16_dest(insn, vaddr);
-               *((unsigned short*)insns + 14) = (addr & 0x0000ffff) | 0x1;
-               *((unsigned short*)insns + 15) = addr >> 16;
+               *((unsigned short*)tramp + 14) = (addr & 0x0000ffff) | 0x1;
+               *((unsigned short*)tramp + 15) = addr >> 16;
                addr = vaddr + 2;
-               *((unsigned short*)insns + 16) = (addr & 0x0000ffff) | 0x1;
-               *((unsigned short*)insns + 17) = addr >> 16;
+               *((unsigned short*)tramp + 16) = (addr & 0x0000ffff) | 0x1;
+               *((unsigned short*)tramp + 17) = addr >> 16;
 
        } else if (THUMB_INSN_MATCH(BLX2, insn) ||
                   THUMB_INSN_MATCH(BX, insn)) {
-               memcpy(insns, b_r_insn_execbuf_thumb, sizeof(insns));
-               *((unsigned short*)insns + 13) = 0xdeff;
-               *((unsigned short*)insns + 4) = insn;
+               memcpy(tramp, b_r_insn_execbuf_thumb, tramp_len);
+               *((unsigned short*)tramp + 13) = 0xdeff;
+               *((unsigned short*)tramp + 4) = insn;
                addr = vaddr + 2;
-               *((unsigned short*)insns + 16) = (addr & 0x0000ffff) | 0x1;
-               *((unsigned short*)insns + 17) = addr >> 16;
+               *((unsigned short*)tramp + 16) = (addr & 0x0000ffff) | 0x1;
+               *((unsigned short*)tramp + 17) = addr >> 16;
 
        } else if (THUMB2_INSN_MATCH(BLX1, insn) ||
                   THUMB2_INSN_MATCH(BL, insn)) {
-               memcpy(insns, blx_off_insn_execbuf_thumb, sizeof(insns));
-               *((unsigned short*)insns + 13) = 0xdeff;
+               memcpy(tramp, blx_off_insn_execbuf_thumb, tramp_len);
+               *((unsigned short*)tramp + 13) = 0xdeff;
                addr = branch_t32_dest(insn, vaddr);
-               *((unsigned short*)insns + 14) = (addr & 0x0000ffff);
-               *((unsigned short*)insns + 15) = addr >> 16;
+               *((unsigned short*)tramp + 14) = (addr & 0x0000ffff);
+               *((unsigned short*)tramp + 15) = addr >> 16;
                addr = vaddr + 4;
-               *((unsigned short*)insns + 16) = (addr & 0x0000ffff) | 0x1;
-               *((unsigned short*)insns + 17) = addr >> 16;
+               *((unsigned short*)tramp + 16) = (addr & 0x0000ffff) | 0x1;
+               *((unsigned short*)tramp + 17) = addr >> 16;
 
        } else if (THUMB_INSN_MATCH(CBZ, insn)) {
-               memcpy(insns, cbz_insn_execbuf_thumb, sizeof(insns));
-               *((unsigned short*)insns + 13) = 0xdeff;
-               *((unsigned short*)insns + 0) = insn &  (~insn & 0xf8);
-               *((unsigned short*)insns + 0) &= 0x20;
+               memcpy(tramp, cbz_insn_execbuf_thumb, tramp_len);
+               *((unsigned short*)tramp + 13) = 0xdeff;
+               *((unsigned short*)tramp + 0) = insn &  (~insn & 0xf8);
+               *((unsigned short*)tramp + 0) &= 0x20;
                addr = cbz_t16_dest(insn, vaddr);
-               *((unsigned short*)insns + 14) = (addr & 0x0000ffff) | 0x1;
-               *((unsigned short*)insns + 15) = addr >> 16;
+               *((unsigned short*)tramp + 14) = (addr & 0x0000ffff) | 0x1;
+               *((unsigned short*)tramp + 15) = addr >> 16;
                addr = vaddr + 2;
-               *((unsigned short*)insns + 16) = (addr & 0x0000ffff) | 0x1;
-               *((unsigned short*)insns + 17) = addr >> 16;
-       }
-
-       if (!write_proc_vm_atomic(task, (unsigned long)p->ainsn.insn_thumb, insns, 18 * 2)) {
-               panic("failed to write memory %p!\n", p->ainsn.insn_thumb);
+               *((unsigned short*)tramp + 16) = (addr & 0x0000ffff) | 0x1;
+               *((unsigned short*)tramp + 17) = addr >> 16;
        }
 
        return 0;
 }
 
-int arch_prepare_uprobe(struct uprobe *up, struct hlist_head *page_list)
+int arch_prepare_uprobe(struct uprobe *up)
 {
-       int ret = 0;
-       struct kprobe *p = &up->kp;
+       struct kprobe *p = up2kp(up);
        struct task_struct *task = up->task;
-       kprobe_opcode_t insn[MAX_INSN_SIZE];
+       unsigned long vaddr = (unsigned long)p->addr;
+       unsigned long insn;
 
-       if ((unsigned long)p->addr & 0x01) {
-               printk("Error in %s at %d: attempt to register kprobe at an unaligned address\n", __FILE__, __LINE__);
+       if (vaddr & 0x01) {
+               printk("Error in %s at %d: attempt to register uprobe "
+                      "at an unaligned address\n", __FILE__, __LINE__);
                return -EINVAL;
        }
 
-       if (!read_proc_vm_atomic(task, (unsigned long)p->addr, &insn, MAX_INSN_SIZE * sizeof(kprobe_opcode_t))) {
-               panic("Failed to read memory task[tgid=%u, comm=%s] %p!\n", task->tgid, task->comm, p->addr);
-       }
-
-       p->opcode = insn[0];
-       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;
-       }
-
-       ret = arch_copy_trampoline_arm_uprobe(up);
-       if (ret) {
-               free_insn_slot(up->sm, p->ainsn.insn_arm);
-               return -EFAULT;
-       }
+       if (!read_proc_vm_atomic(task, vaddr, &insn, sizeof(insn)))
+               panic("failed to read memory %lx!\n", vaddr);
 
-       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;
-       }
+       p->opcode = insn;
 
-       ret = arch_copy_trampoline_thumb_uprobe(up);
-       if (ret) {
-               free_insn_slot(up->sm, p->ainsn.insn_arm);
-               free_insn_slot(up->sm, p->ainsn.insn_thumb);
-               return -EFAULT;
-       }
+       arch_copy_trampoline_arm_uprobe(up);
+       arch_copy_trampoline_thumb_uprobe(up);
 
        if ((p->safe_arm) && (p->safe_thumb)) {
-               printk("Error in %s at %d: failed arch_copy_trampoline_*_uprobe() (both) [tgid=%u, addr=%lx, data=%lx]\n",
-                      __FILE__, __LINE__, task->tgid, (unsigned long)p->addr, (unsigned long)p->opcode);
-               if (!write_proc_vm_atomic(task, (unsigned long)p->addr, &p->opcode, sizeof(p->opcode))) {
-                       panic("Failed to write memory %p!\n", p->addr);
-               }
+               printk("Error in %s at %d: failed "
+                      "arch_copy_trampoline_*_uprobe() (both) "
+                      "[tgid=%u, addr=%lx, data=%lx]\n",
+                      __FILE__, __LINE__, task->tgid, vaddr, insn);
 
-               free_insn_slot(up->sm, p->ainsn.insn_arm);
-               free_insn_slot(up->sm, p->ainsn.insn_thumb);
+               if (!write_proc_vm_atomic(task, vaddr, &insn, sizeof(insn)))
+                       panic("Failed to write memory %p!\n", p->addr);
 
                return -EFAULT;
        }
 
-       return ret;
+       return 0;
 }
 
 void arch_opcode_analysis_uretprobe(struct uretprobe *rp)
@@ -784,50 +752,63 @@ void arch_set_orig_ret_addr(unsigned long orig_ret_addr, struct pt_regs *regs)
                regs->ARM_cpsr &= ~PSR_T_BIT;
 }
 
-static int check_validity_insn(struct kprobe *p, struct pt_regs *regs)
+static void restore_opcode_for_thumb(struct kprobe *p, struct pt_regs *regs)
 {
-       struct kprobe *kp;
+       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);
+       }
+}
 
-       if (unlikely(thumb_mode(regs))) {
-               if (p->safe_thumb) {
-                       goto disarm;
-               }
+static int make_trampoline(struct uprobe *up, struct pt_regs *regs)
+{
+       unsigned long *tramp, *utramp;
+       struct kprobe *p = up2kp(up);
+       int sw;
+
+       /*
+        * 0 bit - thumb mode           (0 - arm, 1 - thumb)
+        * 1 bit - arm mode support     (0 - off, 1  on)
+        * 2 bit - thumb mode support   (0 - off, 1  on)`
+        */
+       sw = (!!thumb_mode(regs)) |
+            (int)!p->safe_arm << 1 |
+            (int)!p->safe_thumb << 2;
+
+       switch (sw) {
+       /* ARM */
+       case 0b110:
+       case 0b010:
+               tramp = up->atramp.tramp_arm;
+               break;
+       /* THUMB */
+       case 0b111:
+       case 0b101:
+               restore_opcode_for_thumb(p, regs);
+               tramp = up->atramp.tramp_thumb;
+               break;
+       default:
+               printk("Error in %s at %d: we are in arm mode "
+                      "(!) and check instruction was fail "
+                      "(%0lX instruction at %p address)!\n",
+                      __FILE__, __LINE__, p->opcode, p->addr);
 
-               p->ainsn.insn = p->ainsn.insn_thumb;
-               list_for_each_entry_rcu(kp, &p->list, list) {
-                       kp->ainsn.insn = p->ainsn.insn_thumb;
-               }
-       } else {
-               if (p->safe_arm) {
-                       goto disarm;
-               }
+               disarm_uprobe(p, up->task);
 
-               p->ainsn.insn = p->ainsn.insn_arm;
-               list_for_each_entry_rcu(kp, &p->list, list) {
-                       kp->ainsn.insn = p->ainsn.insn_arm;
-               }
+               return 1;
        }
 
-       return 0;
+       utramp = alloc_insn_slot(up->sm);
 
-disarm:
-       printk("Error in %s at %d: we are in arm mode (!) and check "
-              "instruction was fail (%0lX instruction at %p address)!\n",
-              __FILE__, __LINE__, p->opcode, p->addr);
+       if (!write_proc_vm_atomic(up->task, (unsigned long)utramp, tramp,
+                                 UPROBES_TRAMP_LEN * sizeof(*tramp)))
+               panic("failed to write memory %p!\n", utramp);
 
-       /* Test case when we do our actions on already running application */
-       disarm_uprobe(p, kp2up(p)->task);
-       return -1;
-}
+       p->ainsn.insn = utramp;
 
-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);
-       }
+       return 0;
 }
 
 static int uprobe_handler(struct pt_regs *regs)
@@ -838,20 +819,32 @@ static int uprobe_handler(struct pt_regs *regs)
        struct kprobe *p;
 
        p = get_ukprobe(addr, tgid);
-
        if (p == NULL) {
-               p = get_ukprobe_by_insn_slot(addr, tgid, regs);
+               unsigned long offset_bp = thumb_mode(regs) ?
+                                         0x1a :
+                                         4 * UPROBES_TRAMP_RET_BREAK_IDX;
+               void *tramp_addr = (void *)addr - offset_bp;
+
+               p = get_ukprobe_by_insn_slot(tramp_addr, tgid, regs);
                if (p == NULL) {
-                       printk("no_kprobe: Not one of ours: let "
+                       printk("no_uprobe: Not one of ours: let "
                               "kernel handle it %p\n", addr);
                        return 1;
                }
 
                trampoline_uprobe_handler(p, regs);
-       } else if (check_validity_insn(p, regs) != 0) {
-               printk("no_uprobe live\n");
        } else {
-               restore_opcode_for_thumb(p, regs);
+               if (p->ainsn.insn == NULL) {
+                       struct uprobe *up = kp2up(p);
+
+                       if (make_trampoline(up, regs)) {
+                               printk("no_uprobe live\n");
+                               return 0;
+                       }
+
+                       /* for uretprobe */
+                       add_uprobe_table(p);
+               }
 
                if (!p->pre_handler || !p->pre_handler(p, regs)) {
                        prepare_singlestep(p, regs);
index 80ccbdd..8dce806 100644 (file)
@@ -38,6 +38,13 @@ struct uprobe;
 struct uretprobe;
 struct uretprobe_instance;
 
+
+struct arch_specific_tramp {
+       unsigned long tramp_arm[UPROBES_TRAMP_LEN];
+       unsigned long tramp_thumb[UPROBES_TRAMP_LEN];
+};
+
+
 static inline u32 swap_get_urp_float(struct pt_regs *regs)
 {
        return regs->ARM_r0;
@@ -53,7 +60,7 @@ static inline void arch_ujprobe_return(void)
 {
 }
 
-int arch_prepare_uprobe(struct uprobe *up, struct hlist_head *page_list);
+int arch_prepare_uprobe(struct uprobe *up);
 
 int setjmp_upre_handler(struct kprobe *p, struct pt_regs *regs);
 static inline int longjmp_break_uhandler(struct kprobe *p, struct pt_regs *regs)
index cafb79f..7a5015d 100644 (file)
@@ -63,43 +63,23 @@ static void restore_current_flags(struct pt_regs *regs)
        regs->EREG(flags) |= __get_cpu_var(ucb).flags & IF_MASK;
 }
 
-int arch_prepare_uprobe(struct uprobe *up, struct hlist_head *page_list)
+int arch_prepare_uprobe(struct uprobe *up)
 {
        int ret = 0;
-       struct kprobe *p = &up->kp;
+       struct kprobe *p = up2kp(up);
        struct task_struct *task = up->task;
-       kprobe_opcode_t insns[UPROBES_TRAMP_LEN];
-
-       if (!ret) {
-               kprobe_opcode_t insn[MAX_INSN_SIZE];
-               struct arch_specific_insn ainsn;
-
-               if (!read_proc_vm_atomic(task, (unsigned long)p->addr, &insn, MAX_INSN_SIZE * sizeof(kprobe_opcode_t)))
-                       panic("failed to read memory %p!\n", p->addr);
-
-               ainsn.insn = insn;
-               ret = arch_check_insn(&ainsn);
-               if (!ret) {
-                       p->opcode = insn[0];
-                       p->ainsn.insn = alloc_insn_slot(up->sm);
-                       if (!p->ainsn.insn)
-                               return -ENOMEM;
-
-                       if (can_boost(insn))
-                               p->ainsn.boostable = 0;
-                       else
-                               p->ainsn.boostable = -1;
-
-                       memcpy(&insns[UPROBES_TRAMP_INSN_IDX], insn, MAX_INSN_SIZE*sizeof(kprobe_opcode_t));
-                       insns[UPROBES_TRAMP_RET_BREAK_IDX] = BREAKPOINT_INSTRUCTION;
-
-                       if (!write_proc_vm_atomic(task, (unsigned long)p->ainsn.insn, insns, sizeof(insns))) {
-                               free_insn_slot(up->sm, p->ainsn.insn);
-                               panic("failed to write memory %p!\n", p->ainsn.insn);
-                               return -EINVAL;
-                       }
-               }
-       }
+       u8 *tramp = up->atramp.tramp;
+
+       if (!read_proc_vm_atomic(task, (unsigned long)p->addr,
+                                tramp, MAX_INSN_SIZE))
+               panic("failed to read memory %p!\n", p->addr);
+
+       tramp[UPROBES_TRAMP_RET_BREAK_IDX] = BREAKPOINT_INSTRUCTION;
+
+       /* TODO: remove dual info */
+       p->opcode = tramp[0];
+
+       p->ainsn.boostable = can_boost(tramp) ? 0 : -1;
 
        return ret;
 }
@@ -256,6 +236,31 @@ no_change:
        return;
 }
 
+static int make_trampoline(struct uprobe *up)
+{
+       struct kprobe *p = up2kp(up);
+       struct task_struct *task = up->task;
+       void *tramp;
+
+       tramp = alloc_insn_slot(up->sm);
+       if (tramp == 0) {
+               printk("trampoline out of memory\n");
+               return -ENOMEM;
+       }
+
+       if (!write_proc_vm_atomic(task, (unsigned long)tramp,
+                                 up->atramp.tramp,
+                                 sizeof(up->atramp.tramp))) {
+               free_insn_slot(up->sm, tramp);
+               panic("failed to write memory %p!\n", tramp);
+               return -EINVAL;
+       }
+
+       p->ainsn.insn = tramp;
+
+       return 0;
+}
+
 static int uprobe_handler(struct pt_regs *regs)
 {
        struct kprobe *p;
@@ -269,8 +274,9 @@ static int uprobe_handler(struct pt_regs *regs)
        p = get_ukprobe(addr, tgid);
 
        if (p == NULL) {
-               p = get_ukprobe_by_insn_slot(addr, tgid, regs);
+               void *tramp_addr = (void *)addr - UPROBES_TRAMP_RET_BREAK_IDX;
 
+               p = get_ukprobe_by_insn_slot(tramp_addr, tgid, regs);
                if (p == NULL) {
                        printk("no_uprobe\n");
                        return 0;
@@ -279,6 +285,15 @@ static int uprobe_handler(struct pt_regs *regs)
                trampoline_uprobe_handler(p, regs);
                return 1;
        } else {
+               if (p->ainsn.insn == NULL) {
+                       struct uprobe *up = kp2up(p);
+
+                       make_trampoline(up);
+
+                       /* for uretprobe */
+                       add_uprobe_table(p);
+               }
+
                if (!p->pre_handler || !p->pre_handler(p, regs)) {
                        if (p->ainsn.boostable == 1 && !p->post_handler) {
                                regs->EREG(ip) = (unsigned long)p->ainsn.insn;
index 6aa764c..8e34225 100644 (file)
@@ -36,6 +36,10 @@ struct uretprobe;
 struct uretprobe_instance;
 
 
+struct arch_specific_tramp {
+       u8 tramp[UPROBES_TRAMP_LEN + BP_INSN_SIZE];     /* BP for uretprobe */
+};
+
 
 static inline u32 swap_get_urp_float(struct pt_regs *regs)
 {
@@ -59,7 +63,7 @@ static inline void arch_ujprobe_return(void)
 {
 }
 
-int arch_prepare_uprobe(struct uprobe *up, struct hlist_head *page_list);
+int arch_prepare_uprobe(struct uprobe *up);
 int setjmp_upre_handler(struct kprobe *p, struct pt_regs *regs);
 static inline int longjmp_break_uhandler(struct kprobe *p, struct pt_regs *regs)
 {
index acb9760..fdb5677 100644 (file)
@@ -43,7 +43,6 @@ enum {
 
 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];
@@ -299,69 +298,18 @@ struct kprobe *get_ukprobe(void *addr, pid_t tgid)
        return NULL;
 }
 
-static void add_uprobe_table(struct kprobe *p)
+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 kprobe *p;
-       DECLARE_NODE_PTR_FOR_HLIST(node);
-
-       /* TODO: test - two processes invokes instrumented function */
-       head = &uprobe_insn_slot_table[hash_ptr(addr, UPROBE_HASH_BITS)];
-       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 kprobe *p;
-       DECLARE_NODE_PTR_FOR_HLIST(node);
-
-       /* TODO: test - two processes invokes instrumented function */
-       head = &uprobe_insn_slot_table[hash_ptr(addr, UPROBE_HASH_BITS)];
-       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 kprobe *p;
        DECLARE_NODE_PTR_FOR_HLIST(node);
 
-       addr -= UPROBES_TRAMP_RET_BREAK_IDX;
-
        /* TODO: test - two processes invokes instrumented function */
        head = &uprobe_insn_slot_table[hash_ptr(addr, UPROBE_HASH_BITS)];
        swap_hlist_for_each_entry_rcu(p, node, head, is_hlist) {
@@ -372,19 +320,13 @@ struct kprobe *get_ukprobe_by_insn_slot(void *addr, pid_t tgid, struct pt_regs *
 
        return NULL;
 }
-#endif /* CONFIG_ARM */
 
 
 static void remove_uprobe(struct uprobe *up)
 {
-       struct kprobe *p = &up->kp;
+       struct kprobe *p = up2kp(up);
 
-#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)
@@ -527,6 +469,7 @@ int dbi_register_uprobe(struct uprobe *up)
        }
 #endif
 
+       p->ainsn.insn = NULL;
        p->mod_refcounted = 0;
        p->nmissed = 0;
        INIT_LIST_HEAD(&p->list);
@@ -544,15 +487,11 @@ int dbi_register_uprobe(struct uprobe *up)
                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);
+       ret = arch_prepare_uprobe(up);
        if (ret) {
                DBPRINTF("goto out\n", ret);
                goto out;
@@ -563,7 +502,6 @@ int dbi_register_uprobe(struct uprobe *up)
        // 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:
@@ -667,18 +605,9 @@ void __dbi_unregister_ujprobe(struct ujprobe *jp, int disarm)
         * 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 */
 }
 EXPORT_SYMBOL_GPL(__dbi_unregister_ujprobe);
 
@@ -932,19 +861,10 @@ void __dbi_unregister_uretprobe(struct uretprobe *rp, int disarm)
 
        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) {
index bdad748..1d6afbf 100644 (file)
  */
 
 #include <kprobe/dbi_kprobes.h>
+#include <uprobe/arch/asm/swap_uprobes.h>
+
 
 struct uprobe {
        struct kprobe kp;
        struct task_struct *task;
        struct slot_manager *sm;
+       struct arch_specific_tramp atramp;
 };
 
 typedef unsigned long (*uprobe_pre_entry_handler_t)(void *priv_arg, struct pt_regs * regs);
@@ -119,4 +122,6 @@ void disarm_uprobe(struct kprobe *p, struct task_struct *task);
 
 int trampoline_uprobe_handler(struct kprobe *p, struct pt_regs *regs);
 
+void add_uprobe_table(struct kprobe *p);
+
 #endif /*  _DBI_UPROBES_H */
index 4558d9a..e7b94c6 100644 (file)
 #include <kprobe/arch/asm/dbi_kprobes.h>
 #include "us_manager_common.h"
 
-static unsigned long alloc_user_pages(struct task_struct *task, unsigned long len, unsigned long prot, unsigned long flags)
-{
-       unsigned long ret = 0;
-       struct task_struct *otask = current;
-       struct mm_struct *mm;
-       int atomic = in_atomic();
-
-       mm = atomic ? task->active_mm : get_task_mm(task);
-       if (mm) {
-               if (!atomic) {
-                       if (!down_write_trylock(&mm->mmap_sem)) {
-                               rcu_read_lock();
-
-                               up_read(&mm->mmap_sem);
-                               down_write(&mm->mmap_sem);
-
-                               rcu_read_unlock();
-                       }
-               }
-               // FIXME: its seems to be bad decision to replace 'current' pointer temporarily
-               current_thread_info()->task = task;
-               ret = swap_do_mmap(NULL, 0, len, prot, flags, 0);
-               current_thread_info()->task = otask;
-               if (!atomic) {
-                       downgrade_write (&mm->mmap_sem);
-                       mmput(mm);
-               }
-       } else {
-               printk("proc %d has no mm", task->tgid);
-       }
-
-       return ret;
-}
 
 static void *sm_alloc_us(struct slot_manager *sm)
 {
-       struct task_struct *task = sm->data;
+       unsigned long addr;
 
-       return (void *)alloc_user_pages(task, PAGE_SIZE,
-                                       PROT_EXEC|PROT_READ|PROT_WRITE,
-                                       MAP_ANONYMOUS|MAP_PRIVATE);
+       addr = swap_do_mmap(NULL, 0, PAGE_SIZE, PROT_EXEC|PROT_READ|PROT_WRITE,
+                           MAP_ANONYMOUS|MAP_PRIVATE, 0);
+       return (void *)addr;
 }
 
 static void sm_free_us(struct slot_manager *sm, void *ptr)