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) {
}
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;
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) {
}
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)
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)
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);
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];
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) {
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)
}
#endif
+ p->ainsn.insn = NULL;
p->mod_refcounted = 0;
p->nmissed = 0;
INIT_LIST_HEAD(&p->list);
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;
// 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:
* 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);
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) {