#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)
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;
}
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;
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;
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;
}
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;
}
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)
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);
}
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;
}