swap_uprobe-y := swap_uprobes.o
### ARM
-swap_uprobe-$(CONFIG_ARM) += arch/arm/swap-asm/swap_uprobes.o \
- arch/arm/swap-asm/trampoline_thumb.o
+swap_uprobe-$(CONFIG_ARM) += \
+ arch/arm/swap-asm/swap_uprobes.o \
+ arch/arm/swap-asm/trampoline_thumb.o \
+ arch/arm/swap-asm/decode_thumb.o \
+ arch/arm/swap-asm/thumb_tramps.o
### X86
--- /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, 2015
+ *
+ * 2015 Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include "decode_thumb.h"
+#include "thumb_tramps.h"
+
+
+#define GET_BIT(x, n) ((x >> n) & 0x1)
+#define GET_FIELD(x, s, l) ((x >> s) & ((1 << l) - 1))
+#define SET_FIELD(x, s, l, v) ({ \
+ typeof(x) mask = (((1 << l) - 1) << s); \
+ (x & ~mask) | ((v << s) & mask); \
+})
+
+
+typedef union thumb_insn {
+ unsigned long val;
+ struct {
+ unsigned short hw1;
+ unsigned short hw2;
+ } __packed;
+} thumb_insn_t;
+
+typedef int (*decode_handler_t)(thumb_insn_t insn, struct decode_info *info);
+
+
+static bool bad_reg(int n)
+{
+ return n == 13 || n == 15;
+}
+
+static int thumb_not_implement(thumb_insn_t insn, struct decode_info *info)
+{
+ return -EFAULT;
+}
+
+static int thumb_unpredictable(thumb_insn_t insn, struct decode_info *info)
+{
+ return -EINVAL;
+}
+
+/* hw1[1110 100x x1xx ????] */
+static int t32_ldrd_strd(thumb_insn_t insn, struct decode_info *info)
+{
+ int w = GET_BIT(insn.hw1, 5);
+ int n = GET_FIELD(insn.hw1, 0, 4);
+ int t = GET_FIELD(insn.hw2, 12, 4);
+ int t2 = GET_FIELD(insn.hw2, 8, 4);
+
+ if (bad_reg(t) || bad_reg(t2))
+ return thumb_unpredictable(insn, info);
+
+ /* check load flag */
+ if (GET_BIT(insn.hw1, 4)) {
+ /* LDRD */
+ if ((w && (n == 15)) || t == t2)
+ return thumb_unpredictable(insn, info);
+
+ if (n == 15) {
+ /* change PC -> SP */
+ insn.hw1 = SET_FIELD(insn.hw1, 0, 4, 13);
+ tt_make_pc_deps(info->tramp, insn.val,
+ info->vaddr, true);
+
+ return 0;
+ }
+ } else {
+ /* STRD */
+ if ((w && t == n) || (w && t2 == n) || (n == 15))
+ return thumb_unpredictable(insn, info);
+ }
+
+ tt_make_common(info->tramp, insn.val, info->vaddr, true);
+
+ return 0;
+}
+
+static int t32_b1110_100x_x1(thumb_insn_t insn, struct decode_info *info)
+{
+ /* check PW bits */
+ if (insn.hw1 & 0x120)
+ return t32_ldrd_strd(insn, info);
+
+ return thumb_not_implement(insn, info);
+}
+
+static int t32_b1110_100(thumb_insn_t insn, struct decode_info *info)
+{
+ if (GET_BIT(insn.hw1, 6))
+ return t32_b1110_100x_x1(insn, info);
+
+ return thumb_not_implement(insn, info);
+}
+
+static int b111(thumb_insn_t insn, struct decode_info *info)
+{
+ /* hw1[111x xxx? ???? ????] */
+ switch (GET_FIELD(insn.hw1, 9, 4)) {
+ case 0b0100:
+ return t32_b1110_100(insn, info);
+ }
+
+ return thumb_not_implement(insn, info);
+}
+
+
+decode_handler_t table_xxx[8] = {
+ /* 000 */ thumb_not_implement,
+ /* 001 */ thumb_not_implement,
+ /* 010 */ thumb_not_implement,
+ /* 011 */ thumb_not_implement,
+ /* 100 */ thumb_not_implement,
+ /* 101 */ thumb_not_implement,
+ /* 110 */ thumb_not_implement,
+ /* 111 */ b111,
+};
+
+
+int decode_thumb(unsigned long insn, struct decode_info *info)
+{
+ thumb_insn_t tinsn = { .val = insn };
+
+ /* check first 3 bits hw1[xxx? ???? ???? ????] */
+ return table_xxx[GET_FIELD(tinsn.hw1, 13, 3)](tinsn, info);
+}
--- /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, 2015
+ *
+ * 2015 Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#ifndef _ARM_DECODE_THUMB_H
+#define _ARM_DECODE_THUMB_H
+
+
+struct decode_info {
+ unsigned long vaddr;
+ void *tramp;
+};
+
+
+int decode_thumb(unsigned long insn, struct decode_info *info);
+
+
+#endif /* _ARM_DECODE_THUMB_H */
#include <swap-asm/swap_kprobes.h>
#include <swap-asm/trampoline_arm.h>
-
+#include "decode_thumb.h"
#include "swap_uprobes.h"
#include "trampoline_thumb.h"
return -EINVAL;
}
- ret = thumb_mode ?
- arch_make_trampoline_thumb(vaddr, insn,
- tramp, tramp_len) :
- arch_make_trampoline_arm(vaddr, insn, tramp);
+ if (thumb_mode) {
+ ret = arch_make_trampoline_thumb(vaddr, insn,
+ tramp, tramp_len);
+ if (ret) {
+ struct decode_info info = {
+ .vaddr = vaddr,
+ .tramp = tramp,
+ };
+
+ ret = decode_thumb(insn, &info);
+ }
+ } else {
+ ret = arch_make_trampoline_arm(vaddr, insn, tramp);
+ }
+
if (ret) {
pr_err("failed to make tramp, addr=%p\n", p->addr);
return ret;
--- /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, 2015
+ *
+ * 2015 Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#include <linux/string.h>
+#include <swap-asm/swap_kprobes.h>
+#include "trampoline_thumb.h"
+
+
+#define URET_BP 0xdeff /* breakpoint for uretprobe */
+
+
+static void make_def(void *tramp, unsigned long insn,
+ unsigned long vaddr, bool t2)
+{
+ unsigned long ret_addr;
+ unsigned short *tr = tramp;
+
+ /*
+ * thumb - +2
+ * thumb2 - +4
+ */
+ ret_addr = vaddr + (2 << t2);
+ tr[4] = insn & 0x0000ffff;
+ if (t2)
+ tr[5] = insn >> 16;
+
+ tr[13] = URET_BP;
+ tr[16] = (ret_addr & 0x0000ffff) | 0x1;
+ tr[17] = ret_addr >> 16;
+}
+
+void tt_make_common(void *tramp, unsigned long insn,
+ unsigned long vaddr, bool t2)
+{ memcpy(tramp, gen_insn_execbuf_thumb, 4 * UPROBES_TRAMP_LEN);
+ make_def(tramp, insn, vaddr, t2);
+}
+
+void tt_make_pc_deps(void *tramp, unsigned long mod_insn,
+ unsigned long vaddr, bool t2)
+{
+ unsigned long pc_val = vaddr + 4;
+ unsigned short *tr = tramp;
+
+ memcpy(tramp, pc_dep_insn_execbuf_thumb, 4 * UPROBES_TRAMP_LEN);
+ make_def(tramp, mod_insn, vaddr, t2);
+
+ /* save PC value */
+ tr[14] = pc_val & 0x0000ffff;
+ tr[15] = pc_val >> 16;
+}
--- /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, 2015
+ *
+ * 2015 Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#ifndef _ARM_THUMB_TRAMPS_H
+#define _ARM_THUMB_TRAMPS_H
+
+
+#include <linux/types.h>
+
+
+void tt_make_common(void *tramp, unsigned long insn,
+ unsigned long vaddr, bool t2);
+void tt_make_pc_deps(void *tramp, unsigned long mod_insn,
+ unsigned long vaddr, bool t2);
+
+
+#endif /* _ARM_THUMB_TRAMPS_H */