--- /dev/null
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) Samsung Electronics, 2016
+ *
+ * 2016 Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#ifndef _SWAP_ASM_COMPAT_ARM64_H
+#define _SWAP_ASM_COMPAT_ARM64_H
+
+
+#ifdef CONFIG_ARM64
+
+# define PSR_T_BIT COMPAT_PSR_T_BIT
+
+# define ARM_r0 compat_usr(0)
+# define ARM_r1 compat_usr(1)
+# define ARM_r2 compat_usr(2)
+# define ARM_r3 compat_usr(3)
+# define ARM_r4 compat_usr(4)
+# define ARM_r5 compat_usr(5)
+# define ARM_r6 compat_usr(6)
+# define ARM_r7 compat_usr(7)
+# define ARM_r8 compat_usr(8)
+# define ARM_r9 compat_usr(9)
+# define ARM_r10 compat_usr(10)
+# define ARM_fp compat_fp
+# define ARM_ip compat_usr(12)
+# define ARM_sp compat_sp
+# define ARM_lr compat_lr
+# define ARM_pc pc
+# define ARM_cpsr pstate
+
+# define thumb_mode(regs) compat_thumb_mode(regs)
+
+#endif /* CONFIG_ARM64 */
+
+
+#endif /* _SWAP_ASM_COMPAT_ARM64_H */
+
+
+
+
+
+
#include <linux/ptrace.h>
#include "decode_thumb.h"
#include "tramps_thumb.h"
+#include "compat_arm64.h"
#define GET_BIT(x, n) ((x >> n) & 0x1)
--- /dev/null
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) Samsung Electronics, 2016
+ *
+ * 2016 Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ */
+
+
+
+#include <arch/arm/probes/probes.h>
+#include <arch/arm/probes/probes_arm.h>
+#include <arch/arm/probes/probes_thumb.h>
+#include <uprobe/swap_uprobes.h>
+#include <kprobe/swap_kprobes_deps.h>
+#include <kprobe/swap_slots.h>
+
+
+#define flush_insns(addr, size) \
+ flush_icache_range((unsigned long)(addr), \
+ (unsigned long)(addr) + (size))
+
+
+/**
+ * @brief Prepares uprobe for ARM.
+ *
+ * @param up Pointer to the uprobe.
+ * @return 0 on success,\n
+ * negative error code on error.
+ */
+int arch_prepare_uprobe_arm(struct uprobe *p)
+{
+ int ret;
+ struct task_struct *task = p->task;
+ unsigned long vaddr = (unsigned long)p->addr;
+ u32 insn;
+ u32 tramp[UPROBES_TRAMP_LEN];
+ u32 __user *utramp;
+ enum { tramp_len = sizeof(tramp) };
+
+ if (!read_proc_vm_atomic(task, vaddr & ~1, &insn, sizeof(insn))) {
+ printk(KERN_ERR "failed to read memory %lx!\n", vaddr);
+ return -EINVAL;
+ }
+
+ ret = make_tramp(&p->ainsn.insn, vaddr, insn, tramp, tramp_len);
+ if (ret) {
+ pr_err("failed to make tramp, addr=%p\n", p->addr);
+ return ret;
+ }
+
+ utramp = swap_slot_alloc(p->sm);
+ if (utramp == NULL) {
+ printk(KERN_INFO "Error: swap_slot_alloc failed (%08lx)\n",
+ vaddr);
+ return -ENOMEM;
+ }
+
+ if (!write_proc_vm_atomic(p->task, (unsigned long)utramp, tramp,
+ tramp_len)) {
+ pr_err("failed to write memory tramp=%p!\n", utramp);
+ swap_slot_free(p->sm, utramp);
+ return -EINVAL;
+ }
+
+ flush_insns(utramp, tramp_len);
+ p->insn = utramp;
+ p->opcode = insn;
+
+ return 0;
+}
+
+int arch_arm_uprobe_arm(struct uprobe *p)
+{
+ int ret;
+ unsigned long vaddr = (unsigned long)p->addr & ~((unsigned long)1);
+ int thumb_mode = (unsigned long)p->addr & 1;
+ int len = 4 >> thumb_mode; /* if thumb_mode then len = 2 */
+ unsigned long insn = thumb_mode ? BREAK_THUMB : BREAK_ARM;
+
+ ret = write_proc_vm_atomic(p->task, vaddr, &insn, len);
+ if (!ret) {
+ pr_err("failed to write memory tgid=%u addr=%08lx len=%d\n",
+ p->task->tgid, vaddr, len);
+
+ return -EACCES;
+ } else {
+ flush_insns(vaddr, len);
+ }
+
+ return 0;
+}
+
+void arch_disarm_uprobe_arm(struct uprobe *p, struct task_struct *task)
+{
+ int ret;
+
+ unsigned long vaddr = (unsigned long)p->addr & ~((unsigned long)1);
+ int thumb_mode = (unsigned long)p->addr & 1;
+ int len = 4 >> thumb_mode; /* if thumb_mode then len = 2 */
+
+ ret = write_proc_vm_atomic(task, vaddr, &p->opcode, len);
+ if (!ret) {
+ pr_err("Failed to write memory tgid=%u addr=%08lx len=%d\n",
+ task->tgid, vaddr, len);
+ } else {
+ flush_insns(vaddr, len);
+ }
+}
--- /dev/null
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) Samsung Electronics, 2016
+ *
+ * 2016 Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#ifndef _SWAP_ASM_ARM_UPROBE_H
+#define _SWAP_ASM_ARM_UPROBE_H
+
+
+#include <linux/uaccess.h>
+#include "../probes/compat_arm64.h"
+
+
+struct pt_regs;
+struct uprobe;
+struct uretprobe;
+struct uretprobe_instance;
+
+
+static inline unsigned long swap_get_uarg_arm(struct pt_regs *regs,
+ unsigned long n)
+{
+ u32 *ptr, val = 0;
+
+ switch (n) {
+ case 0:
+ return regs->ARM_r0;
+ case 1:
+ return regs->ARM_r1;
+ case 2:
+ return regs->ARM_r2;
+ case 3:
+ return regs->ARM_r3;
+ default:
+ ptr = (u32 *)regs->ARM_sp + n - 4;
+ if (get_user(val, ptr))
+ pr_err("Failed to dereference a pointer[%p]\n", ptr);
+ break;
+ }
+
+ return val;
+}
+
+static inline void swap_put_uarg_arm(struct pt_regs *regs, unsigned long n,
+ unsigned long val)
+{
+ u32 *ptr;
+
+ switch (n) {
+ case 0:
+ regs->ARM_r0 = val;
+ break;
+ case 1:
+ regs->ARM_r1 = val;
+ break;
+ case 2:
+ regs->ARM_r2 = val;
+ break;
+ case 3:
+ regs->ARM_r3 = val;
+ break;
+ default:
+ ptr = (u32 *)regs->ARM_sp + n - 4;
+ if (put_user(val, ptr))
+ pr_err("Failed to dereference a pointer[%p]\n", ptr);
+ }
+}
+
+int arch_prepare_uprobe_arm(struct uprobe *p);
+int arch_arm_uprobe_arm(struct uprobe *p);
+void arch_disarm_uprobe_arm(struct uprobe *p, struct task_struct *task);
+
+
+#endif /* _SWAP_ASM_ARM_UPROBE_H */
+
../arch/arm/probes/probes_thumb.o \
../arch/arm/probes/decode_thumb.o \
../arch/arm/probes/tramps_thumb_img.o \
- ../arch/arm/probes/probes.o
+ ../arch/arm/probes/probes.o \
+ ../arch/arm/uprobe/swap_uprobe.o
### ARM64
swap_uprobe-$(CONFIG_ARM64) += \
arch/arm64/swap-asm/swap_uprobes.o \
- arch/arm64/swap-asm/uprobes-arm64.o
+ arch/arm64/swap-asm/uprobes-arm64.o \
+ ../arch/arm/probes/probes_arm.o \
+ ../arch/arm/probes/tramps_arm_img.o \
+ ../arch/arm/probes/decode_thumb.o \
+ ../arch/arm/probes/probes_thumb.o \
+ ../arch/arm/probes/tramps_thumb_img.o \
+ ../arch/arm/probes/probes.o \
+ ../arch/arm/uprobe/swap_uprobe.o
### X86
/**
- * @def flush_insns
- * @brief Flushes instructions.
- */
-#define flush_insns(addr, size) \
- flush_icache_range((unsigned long)(addr), \
- (unsigned long)(addr) + (size))
-
-/**
* @brief Prepares uprobe for ARM.
*
* @param up Pointer to the uprobe.
int arch_prepare_uprobe(struct uprobe *p)
{
int ret;
- struct task_struct *task = p->task;
- unsigned long vaddr = (unsigned long)p->addr;
- unsigned long insn;
- u32 tramp[UPROBES_TRAMP_LEN];
- unsigned long __user *utramp;
- enum { tramp_len = sizeof(tramp) };
-
- if (!read_proc_vm_atomic(task, vaddr & ~1, &insn, sizeof(insn))) {
- printk(KERN_ERR "failed to read memory %lx!\n", vaddr);
- return -EINVAL;
- }
- ret = make_tramp(&p->ainsn.insn, vaddr, insn, tramp, tramp_len);
- if (ret) {
- pr_err("failed to make tramp, addr=%p\n", p->addr);
- return ret;
- }
-
- utramp = swap_slot_alloc(p->sm);
- if (utramp == NULL) {
- printk(KERN_INFO "Error: swap_slot_alloc failed (%08lx)\n",
- vaddr);
- return -ENOMEM;
- }
-
- if (!write_proc_vm_atomic(p->task, (unsigned long)utramp, tramp,
- tramp_len)) {
- pr_err("failed to write memory tramp=%p!\n", utramp);
- swap_slot_free(p->sm, utramp);
- return -EINVAL;
+ ret = arch_prepare_uprobe_arm(p);
+ if (!ret) {
+ /* for uretprobe */
+ add_uprobe_table(p);
}
- flush_insns(utramp, tramp_len);
- p->insn = utramp;
- p->opcode = insn;
-
- /* for uretprobe */
- add_uprobe_table(p);
-
- return 0;
+ return ret;
}
/**
swap_slot_free(up->sm, up->insn);
}
-int arch_arm_uprobe(struct uprobe *p)
-{
- int ret;
- unsigned long vaddr = (unsigned long)p->addr & ~((unsigned long)1);
- int thumb_mode = (unsigned long)p->addr & 1;
- int len = 4 >> thumb_mode; /* if thumb_mode then len = 2 */
- unsigned long insn = thumb_mode ? BREAK_THUMB : BREAK_ARM;
-
- ret = write_proc_vm_atomic(p->task, vaddr, &insn, len);
- if (!ret) {
- pr_err("arch_arm_uprobe: failed to write memory tgid=%u addr=%08lx len=%d\n",
- p->task->tgid, vaddr, len);
-
- return -EACCES;
- } else {
- flush_insns(vaddr, len);
- }
-
- return 0;
-}
-
-void arch_disarm_uprobe(struct uprobe *p, struct task_struct *task)
-{
- int ret;
-
- unsigned long vaddr = (unsigned long)p->addr & ~((unsigned long)1);
- int thumb_mode = (unsigned long)p->addr & 1;
- int len = 4 >> thumb_mode; /* if thumb_mode then len = 2 */
-
- ret = write_proc_vm_atomic(task, vaddr, &p->opcode, len);
- if (!ret) {
- pr_err("arch_disarm_uprobe: failed to write memory tgid=%u addr=%08lx len=%d\n",
- task->tgid, vaddr, len);
- } else {
- flush_insns(vaddr, len);
- }
-}
-
static int urp_handler(struct pt_regs *regs, pid_t tgid)
{
struct uprobe *p;
if (p) {
get_up(p);
local_irq_restore(flags);
- pr_err("invalid mode: thumb=%d addr=%p insn=%08lx\n",
+ pr_err("invalid mode: thumb=%d addr=%p insn=%08x\n",
!!thumb_mode(regs), p->addr, p->opcode);
ret = 0;
#include <linux/uaccess.h>
#include <arch/arm/probes/probes.h>
+#include <arch/arm/uprobe/swap_uprobe.h>
/** Uprobes trampoline length */
struct uretprobe;
struct uretprobe_instance;
-typedef unsigned long uprobe_opcode_t;
+typedef u32 uprobe_opcode_t;
/**
}
int arch_prepare_uprobe(struct uprobe *up);
-
int setjmp_upre_handler(struct uprobe *p, struct pt_regs *regs);
static inline int longjmp_break_uhandler(struct uprobe *p, struct pt_regs *regs)
{
unsigned long arch_get_trampoline_addr(struct uprobe *p, struct pt_regs *regs);
void arch_set_orig_ret_addr(unsigned long orig_ret_addr, struct pt_regs *regs);
void arch_remove_uprobe(struct uprobe *up);
-int arch_arm_uprobe(struct uprobe *p);
-void arch_disarm_uprobe(struct uprobe *p, struct task_struct *task);
+
+static inline int arch_arm_uprobe(struct uprobe *p)
+{
+ return arch_arm_uprobe_arm(p);
+}
+
+static inline void arch_disarm_uprobe(struct uprobe *p, struct task_struct *task)
+{
+ arch_disarm_uprobe_arm(p, task);
+}
static inline unsigned long swap_get_uarg(struct pt_regs *regs, unsigned long n)
{
- u32 *ptr, addr = 0;
-
- switch (n) {
- case 0:
- return regs->ARM_r0;
- case 1:
- return regs->ARM_r1;
- case 2:
- return regs->ARM_r2;
- case 3:
- return regs->ARM_r3;
- }
-
- ptr = (u32 *)regs->ARM_sp + n - 4;
- if (get_user(addr, ptr))
- printk(KERN_INFO "failed to dereference a pointer, ptr=%p\n",
- ptr);
-
- return addr;
+ return swap_get_uarg_arm(regs, n);
}
static inline void swap_put_uarg(struct pt_regs *regs, unsigned long n,
unsigned long val)
{
- u32 *ptr;
-
- switch (n) {
- case 0:
- regs->ARM_r0 = val;
- break;
- case 1:
- regs->ARM_r1 = val;
- break;
- case 2:
- regs->ARM_r2 = val;
- break;
- case 3:
- regs->ARM_r3 = val;
- break;
- default:
- ptr = (u32 *)regs->ARM_sp + n - 4;
- if (put_user(val, ptr))
- pr_err("failed to dereference a pointer[%p]\n", ptr);
- }
+ swap_put_uarg_arm(regs, n, val);
}
int swap_arch_init_uprobes(void);
#include <linux/types.h>
+#include <asm/traps.h>
+#include <arch/arm/uprobe/swap_uprobe.h>
#include <uprobe/swap_uprobes.h>
#include <kprobe/swap_slots.h>
#include <kprobe/swap_td_raw.h>
#include <kprobe/swap_kprobes_deps.h> /* FIXME: remove it */
+#include <swap-asm/swap_probes.h>
#include <swap-asm/dbg_interface.h>
#include "uprobes-arm64.h"
#define BRK64_OPCODE_URP MAKE_BRK(BRK_URP)
+enum arch_mode {
+ AM_UNKNOWN,
+ AM_THUMB,
+ AM_ARM,
+ AM_ARM64
+};
+
+#define ARM64_MODE_VADDR_MASK ((unsigned long)1 << 63)
+
+static enum arch_mode get_arch_mode(unsigned long vaddr)
+{
+ if (vaddr & 1)
+ return AM_THUMB;
+
+ if (vaddr & ARM64_MODE_VADDR_MASK)
+ return AM_ARM64;
+
+ return AM_ARM;
+}
+
+static unsigned long get_real_addr(unsigned long vaddr)
+{
+ return vaddr & ~(ARM64_MODE_VADDR_MASK | 1);
+}
+
+
struct uprobe_ctlblk {
struct uprobe *p;
};
return DBG_HANDLED;
}
-
-int arch_arm_uprobe(struct uprobe *p)
+static int arch_arm_uprobe_arm64(struct uprobe *p)
{
- uprobe_opcode_t insn = BRK64_OPCODE_BP;
- int ret = write_proc_vm_atomic(p->task, (unsigned long)p->addr,
- &insn, sizeof(insn));
+ int ret;
+ unsigned long vaddr = (unsigned long)p->addr;
+ unsigned long raddr = get_real_addr(vaddr);
+ u32 insn = BRK64_OPCODE_BP;
+
+ ret = write_proc_vm_atomic(p->task, raddr, &insn, sizeof(insn));
if (!ret) {
- pr_err("failed to write memory addr=%p\n", p->addr);
+ pr_err("failed to write memory addr=%lx\n", vaddr);
return -EACCES;
}
return 0;
}
-void arch_disarm_uprobe(struct uprobe *p, struct task_struct *task)
+static void arch_disarm_uprobe_arm64(struct uprobe *p,
+ struct task_struct *task)
{
+ unsigned long vaddr = (unsigned long)p->addr;
+ unsigned long raddr = get_real_addr(vaddr);
int ret;
- ret = write_proc_vm_atomic(task, (unsigned long)p->addr,
- &p->opcode, sizeof(p->opcode));
+ ret = write_proc_vm_atomic(task, raddr, &p->opcode, sizeof(p->opcode));
if (!ret)
- pr_err("failed to write memory addr=%p!\n", p->addr);
+ pr_err("failed to write memory vaddr=%lx\n", vaddr);
+}
+
+int arch_arm_uprobe(struct uprobe *p)
+{
+ int ret;
+ unsigned long vaddr = (unsigned long)p->addr;
+
+ switch (get_arch_mode(vaddr)) {
+ case AM_THUMB:
+ case AM_ARM:
+ ret = arch_arm_uprobe_arm(p);
+ break;
+ case AM_ARM64:
+ ret = arch_arm_uprobe_arm64(p);
+ break;
+ default:
+ pr_err("Error: unknown mode vaddr=%lx\n", vaddr);
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+void arch_disarm_uprobe(struct uprobe *p, struct task_struct *task)
+{
+ unsigned long vaddr = (unsigned long)p->addr;
+
+ switch (get_arch_mode(vaddr)) {
+ case AM_THUMB:
+ case AM_ARM:
+ arch_disarm_uprobe_arm(p, task);
+ break;
+ case AM_ARM64:
+ arch_disarm_uprobe_arm64(p, task);
+ break;
+ default:
+ pr_err("Error: unknown mode vaddr=%lx\n", vaddr);
+ break;
+ }
}
}
-static int arch_prepare_uprobe_arm64(struct uprobe *p, u32 insn)
+static int arch_prepare_uprobe_arm64(struct uprobe *p)
{
+ struct task_struct *task = p->task;
+ unsigned long vaddr = (unsigned long)p->addr;
+ unsigned long raddr = get_real_addr(vaddr);
+ u32 insn;
+
+ if (!read_proc_vm_atomic(task, raddr, &insn, sizeof(insn))) {
+ pr_err("failed to read memory %lx!\n", raddr);
+ return -EINVAL;
+ }
+
+ p->ainsn.matrioshka_flags = 0;
+
switch (arm64_uprobe_decode_insn(insn, &p->ainsn)) {
case INSN_REJECTED: /* insn not supported */
return -EINVAL;
int arch_prepare_uprobe(struct uprobe *p)
{
- struct task_struct *task = p->task;
- unsigned long vaddr = (unsigned long)p->addr;
- u32 insn;
+ int ret;
- if (vaddr & 0x01) {
- pr_err("Error in %s at %d: attempt to register uprobe "
- "at an unaligned address\n", __FILE__, __LINE__);
- return -EINVAL;
+ if (get_arch_mode((unsigned long)p->addr) == AM_ARM64) {
+ ret = arch_prepare_uprobe_arm64(p);
+ } else {
+ ret = arch_prepare_uprobe_arm(p);
}
- if (!read_proc_vm_atomic(task, vaddr, &insn, sizeof(insn)))
- pr_err("failed to read memory %lx!\n", vaddr);
-
- p->opcode = insn;
- p->ainsn.matrioshka_flags = 0;
-
- return arch_prepare_uprobe_arm64(p, insn);
+ return ret;
}
void arch_remove_uprobe(struct uprobe *p)
};
+static void arch_prepare_singlestep(struct uprobe *p, struct pt_regs *regs)
+{
+ if (p->ainsn.insn.handler) {
+ regs->pc += 4;
+ p->ainsn.insn.handler(p->opcode, &p->ainsn.insn, regs);
+ } else {
+ regs->pc = (unsigned long)p->insn;
+ }
+}
+
+static int uprobe_handler_aarch32(struct pt_regs *regs, u32 instr)
+{
+ struct uprobe *p;
+ unsigned long flags;
+ unsigned long vaddr = regs->pc | !!compat_thumb_mode(regs);
+ pid_t tgid = current->tgid;
+
+ local_irq_enable();
+
+ local_irq_save(flags);
+ p = get_uprobe((uprobe_opcode_t *)vaddr, tgid);
+ if (p) {
+ get_up(p);
+ local_irq_restore(flags);
+
+ if (!p->pre_handler || !p->pre_handler(p, regs))
+ arch_prepare_singlestep(p, regs);
+
+ put_up(p);
+ } else {
+ local_irq_restore(flags);
+ }
+
+ return 0;
+}
+
+
+static void (*__register_undef_hook)(struct undef_hook *hook);
+static void (*__unregister_undef_hook)(struct undef_hook *hook);
+
+static int undef_hook_once(void)
+{
+ const char *sym;
+
+ sym = "register_undef_hook";
+ __register_undef_hook = (void *)swap_ksyms(sym);
+ if (__register_undef_hook == NULL)
+ goto not_found;
+
+ sym = "unregister_undef_hook";
+ __unregister_undef_hook = (void *)swap_ksyms(sym);
+ if (__unregister_undef_hook == NULL)
+ goto not_found;
+
+ return 0;
+
+not_found:
+ pr_err("ERROR: symbol '%s' not found\n", sym);
+ return -ESRCH;
+
+}
+
+static struct undef_hook undef_hook_arm = {
+ .instr_mask = 0xffffffff,
+ .instr_val = BREAK_ARM,
+ .pstate_mask = COMPAT_PSR_MODE_MASK,
+ .pstate_val = COMPAT_PSR_MODE_USR,
+ .fn = uprobe_handler_aarch32,
+};
+
+static struct undef_hook undef_hook_thumb = {
+ .instr_mask = 0xffff,
+ .instr_val = BREAK_THUMB,
+ .pstate_mask = COMPAT_PSR_MODE_MASK,
+ .pstate_val = COMPAT_PSR_MODE_USR,
+ .fn = uprobe_handler_aarch32,
+};
+
int swap_arch_init_uprobes(void)
{
int ret;
+ ret = undef_hook_once();
+ if (ret)
+ return ret;
+
ret = swap_td_raw_reg(&td_raw, sizeof(struct uprobe_ctlblk));
if (ret)
return ret;
+ /* for aarch64 */
dbg_brk_hook_reg(&dbg_up_ss);
dbg_brk_hook_reg(&dbg_up_bp);
dbg_brk_hook_reg(&dbg_urp_bp);
+ /* for aarch32 */
+ __register_undef_hook(&undef_hook_arm);
+ __register_undef_hook(&undef_hook_thumb);
+
return 0;
}
void swap_arch_exit_uprobes(void)
{
+ /* for aarch32 */
+ __unregister_undef_hook(&undef_hook_thumb);
+ __unregister_undef_hook(&undef_hook_arm);
+
+ /* for aarch64 */
dbg_brk_hook_unreg(&dbg_urp_bp);
dbg_brk_hook_unreg(&dbg_up_bp);
dbg_brk_hook_unreg(&dbg_up_ss);
#include <linux/types.h>
+#include <arch/arm/probes/probes.h>
#define UP_TRAMP_INSN_CNT 3 /* | opcode | ss_bp | urp_bp | */
struct arch_insn {
+ /* arm */
+ struct arch_insn_arm insn;
+
+ /* arm64 */
unsigned long matrioshka_flags;
uprobes_pstate_check_t *pstate_cc;
uprobes_condition_check_t *check_condn;
return -EINVAL;
}
- up->addr = (kprobe_opcode_t *)ip->orig_addr;
+ up->addr = (uprobe_opcode_t *)ip->orig_addr;
up->task = ip->page->file->proc->leader;
up->sm = ip->page->file->proc->sm;