void ujprobe_event_handler (unsigned long arg1, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5, unsigned long arg6)
{
us_proc_ip_t *ip = __get_cpu_var (gpCurIp);
+
+#if defined(CONFIG_ARM)
+ if (ip->offset & 0x01)
+ {
+ pack_event_info (US_PROBE_ID, RECORD_ENTRY, "ppppppp", ((unsigned long)ip->jprobe.kp.addr | 0x01), arg1, arg2, arg3, arg4, arg5, arg6);
+ }else{
+ pack_event_info (US_PROBE_ID, RECORD_ENTRY, "ppppppp", ip->jprobe.kp.addr, arg1, arg2, arg3, arg4, arg5, arg6);
+ }
+#else
pack_event_info (US_PROBE_ID, RECORD_ENTRY, "ppppppp", ip->jprobe.kp.addr, arg1, arg2, arg3, arg4, arg5, arg6);
+#endif
uprobe_return ();
}
int uretprobe_event_handler (struct kretprobe_instance *probe, struct pt_regs *regs, us_proc_ip_t * ip)
{
int retval = regs_return_value(regs);
+
+#if defined(CONFIG_ARM)
+ if (ip->offset & 0x01)
+ {
+ pack_event_info (US_PROBE_ID, RECORD_RET, "pd", ((unsigned long)ip->retprobe.kp.addr | 0x01), retval);
+ }else{
+ pack_event_info (US_PROBE_ID, RECORD_RET, "pd", ip->retprobe.kp.addr, retval);
+ }
+#else
pack_event_info (US_PROBE_ID, RECORD_RET, "pd", ip->retprobe.kp.addr, retval);
+#endif
return 0;
}
}
+
+int prep_pc_dep_insn_execbuf_thumb (kprobe_opcode_t * insns, kprobe_opcode_t insn, int uregs)
+{
+ unsigned char mreg = 0;
+ unsigned char reg = ((insn & 0xffff) & uregs) >> 8;
+
+ printk ("prep_pc_dep_insn_execbuf_thumb: using PC, changing Rd = R%x\n", reg);
+
+ if (reg == 6 || reg == 7)
+ {
+ printk(" >>>>> R%d in use!\n", reg);
+
+ mreg = reg - 2;
+ printk(" >>>>> remap to R%d\n", mreg);
+
+ *((unsigned short*)insns + 0) = (*((unsigned short*)insns + 0) & 0x00ff) | (mreg | (mreg + 1));
+ *((unsigned short*)insns + 1) = (*((unsigned short*)insns + 1) & 0xf8ff) | (mreg << 8);
+ *((unsigned short*)insns + 2) = (*((unsigned short*)insns + 2) & 0xfff8) | (mreg + 1);
+ *((unsigned short*)insns + 3) = (*((unsigned short*)insns + 3) & 0xffc7) | (mreg << 3);
+ *((unsigned short*)insns + 5) = (*((unsigned short*)insns + 5) & 0xf8ff) | (mreg << 8);
+ *((unsigned short*)insns + 6) = (*((unsigned short*)insns + 6) & 0xffc7) | ((mreg + 1) << 3);
+ *((unsigned short*)insns + 7) = (*((unsigned short*)insns + 7) & 0xffc7) | ((mreg + 1) << 3);
+ *((unsigned short*)insns + 8) = (*((unsigned short*)insns + 0) & 0x00ff) | (mreg | (mreg + 1));
+ }
+
+ if (THUMB_INSN_MATCH (APC, insn))
+ {
+// ADD Rd, PC, #immed_8*4 -> ADD Rd, SP, #immed_8*4
+ *((unsigned short*)insns + 4) = ((insn & 0xffff) | 0x800); // ADD Rd, SP, #immed_8*4
+ }else{
+ if (THUMB_INSN_MATCH (LRO3, insn))
+ {
+// LDR Rd, [PC, #immed_8*4] -> LDR Rd, [SP, #immed_8*4]
+ *((unsigned short*)insns + 4) = ((insn & 0xffff) + 0x5000); // LDR Rd, [SP, #immed_8*4]
+ }
+ }
+ return 0;
+}
+
+
+
int arch_check_insn_arm (struct arch_specific_insn *ainsn)
{
int ret = 0;
THUMB2_INSN_MATCH (BLX1, ainsn->insn[0]) ||
THUMB_INSN_MATCH (BLX2, ainsn->insn[0]) ||
THUMB_INSN_MATCH (BX, ainsn->insn[0]) ||
- THUMB2_INSN_MATCH (BXJ, ainsn->insn[0]) ||
- THUMB_INSN_MATCH (LRO3, ainsn->insn[0])) // LDR Rd, [PC, #<immed_8> * 4]
+ THUMB2_INSN_MATCH (BXJ, ainsn->insn[0]))
{
DBPRINTF ("Bad insn arch_check_insn_thumb: %lx\n", ainsn->insn[0]);
ret = -EFAULT;
{
int ret = 0;
- my_p[my_probe] = p;
- my_task[my_probe] = task;
- my_atomic[my_probe] = atomic;
-
- my_probe++;
-
if ((unsigned long) p->addr & 0x01)
{
DBPRINTF ("Attempt to register kprobe at an unaligned address");
}
if (!ret)
{
+ my_p[my_probe] = p;
+ my_task[my_probe] = task;
+ my_atomic[my_probe] = atomic;
+
+ my_probe++;
+
kprobe_opcode_t insn[MAX_INSN_SIZE];
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);
kprobe_opcode_t insn[MAX_INSN_SIZE];
struct arch_specific_insn ainsn;
- *p->addr = p->opcode;
- flush_icache_range ((unsigned long) p->addr, (unsigned long) p->addr + sizeof (kprobe_opcode_t));
-
+// *p->addr = p->opcode;
+// flush_icache_range ((unsigned long) p->addr, (unsigned long) p->addr + sizeof (kprobe_opcode_t));
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);
+ insn[0] = p->opcode;
+
ainsn.insn = insn;
ret = arch_check_insn_arm (&ainsn);
}
}
}
+
return ret;
}
int arch_copy_trampoline_thumb_uprobe (struct kprobe *p, struct task_struct *task, int atomic)
{
int ret = 0;
+ int uregs;
- kprobe_opcode_t insns[UPROBES_TRAMP_LEN];
+ kprobe_opcode_t insns[UPROBES_TRAMP_LEN * 2];
if ((unsigned long) p->addr & 0x01)
{
kprobe_opcode_t insn[MAX_INSN_SIZE];
struct arch_specific_insn ainsn;
- *p->addr = p->opcode;
- flush_icache_range ((unsigned long) p->addr, (unsigned long) p->addr + sizeof (kprobe_opcode_t));
+// *p->addr = p->opcode;
+// flush_icache_range ((unsigned long) p->addr, (unsigned long) p->addr + sizeof (kprobe_opcode_t));
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);
+ insn[0] = p->opcode;
+
ainsn.insn = insn;
ret = arch_check_insn_thumb (&ainsn);
if (!p->ainsn.insn)
return -ENOMEM;
- memcpy (insns, gen_insn_execbuf_thumb, 14*2);
- *((unsigned short*)insns + 2) = insn[0];
- *((unsigned short*)insns + 9) = 0xffff;
- *((unsigned short*)insns + 12) = ((unsigned short) (p->addr) + 2) & 0x0000ffff;
- *((unsigned short*)insns + 13) = ((unsigned short) (p->addr) + 2) >> 16;
+ if (THUMB_INSN_MATCH (APC, insn[0]) || THUMB_INSN_MATCH (LRO3, insn[0]))
+ {
+ uregs = 0x0700;// Rd 8-10
+
+ memcpy (insns, pc_dep_insn_execbuf_thumb, 16 * 2);
+ if (prep_pc_dep_insn_execbuf_thumb (insns, insn[0], uregs) != 0)
+ {
+ DBPRINTF ("failed to prepare exec buffer for insn %lx!", insn[0]);
+ free_insn_slot (&uprobe_insn_pages, task, p->ainsn.insn, 0);
+ return -EINVAL;
+ }
+ *((unsigned short*)insns + 11) = 0xffff;
+
+ *((unsigned short*)insns + 12) = ((unsigned short) (p->addr) + 4) & 0x0000ffff;
+ *((unsigned short*)insns + 13) = ((unsigned short) (p->addr) + 4) >> 16;
+
+ *((unsigned short*)insns + 14) = ((unsigned short) (p->addr) + 2) & 0x0000ffff;
+ *((unsigned short*)insns + 15) = ((unsigned short) (p->addr) + 2) >> 16;
+ }else{
+ memcpy (insns, gen_insn_execbuf_thumb, 16 * 2);
+ *((unsigned short*)insns + 2) = insn[0];
+ *((unsigned short*)insns + 11) = 0xffff;
+ *((unsigned short*)insns + 14) = ((unsigned short) (p->addr) + 2) & 0x0000ffff;
+ *((unsigned short*)insns + 15) = ((unsigned short) (p->addr) + 2) >> 16;
+ }
if (!write_proc_vm_atomic (task, (unsigned long) p->ainsn.insn, insns, sizeof (insns)))
{
}
}
}
+
return ret;
}
kprobe_opcode_t *addr = NULL, *ssaddr = 0;
struct kprobe_ctlblk *kcb;
int my_pr = 0;
+ int i = 0;
if (user_mode(regs))
{
if (!thumb_mode ( regs )) addr = (kprobe_opcode_t *) (regs->uregs[15] - 4);
else addr = (kprobe_opcode_t *) (regs->uregs[15] - 2);
- int i;
for(i = 0; i < my_probe; i++)
{
if (my_p[i]->addr == addr)
my_handler_lock = 1;
}
}
- }
- if (0 == my_handler_lock)
- {
- if (user_mode(regs))
+ if (0 == my_handler_lock)
{
my_handler_lock = 1;
if (!thumb_mode ( regs ))
p = get_kprobe_by_insn_slot (addr-UPROBES_TRAMP_RET_BREAK_IDX, pid, current);
else
- p = get_kprobe_by_insn_slot ((unsigned long)addr - 0x12, pid, current);
+ p = get_kprobe_by_insn_slot ((unsigned long)addr - 0x16, pid, current);
if (p) {
save_previous_kprobe (kcb, p);
if (!thumb_mode ( regs ))
p = get_kprobe_by_insn_slot (addr-UPROBES_TRAMP_RET_BREAK_IDX, pid, current);
else
- p = get_kprobe_by_insn_slot ((unsigned long)addr - 0x12, pid, current);
+ p = get_kprobe_by_insn_slot ((unsigned long)addr - 0x16, pid, current);
if (!p) {
/* Not one of ours: let kernel handle it */
}
}
+
// restore second opcode for thumb app
if (user_mode( regs ) && thumb_mode( regs ))
{
*((unsigned short*)p->addr + 1) = p->opcode >> 16;
flush_icache_range ((unsigned int) p->addr, (unsigned int) (((unsigned int) p->addr) + (sizeof (kprobe_opcode_t) * 2)));
}
+
set_current_kprobe (p, regs, kcb);
if(!reenter)
if (!thumb_mode( regs ))
trampoline_address = (unsigned long)(p->ainsn.insn + UPROBES_TRAMP_RET_BREAK_IDX);
else
- trampoline_address = (unsigned long)(p->ainsn.insn + 0x13);
+ trampoline_address = (unsigned long)(p->ainsn.insn + 0x17);
}
INIT_HLIST_HEAD (&empty_rp);
if (thumb_mode( regs ) && !(regs->uregs[14] & 0x01))
{
- regs->ARM_cpsr ^= 0x20;
+ regs->ARM_cpsr &= 0xFFFFFFDF;
}else{
if (user_mode( regs ) && (regs->uregs[14] & 0x01))
{
if (!thumb_mode( regs ))
regs->uregs[14] = (unsigned long) (rp->kp.ainsn.insn + UPROBES_TRAMP_RET_BREAK_IDX);
else
- regs->uregs[14] = (unsigned long) (rp->kp.ainsn.insn) + 0x13;
+ regs->uregs[14] = (unsigned long) (rp->kp.ainsn.insn) + 0x17;
else /* Replace the return addr with trampoline addr */
regs->uregs[14] = (unsigned long) &kretprobe_trampoline;