aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2015-07-29 16:44:53 -0400
committerRalf Baechle <ralf@linux-mips.org>2015-09-03 06:08:05 -0400
commit40e084a506eba78310cd5e8ab700fd1226c6130a (patch)
treea7d19eea2c8a72c78205f2403be2ea3cde24ce63
parente3b28831c18c6c95c51b6bb717fa116d2b658ba9 (diff)
MIPS: Add uprobes support.
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
-rw-r--r--arch/mips/Kconfig4
-rw-r--r--arch/mips/include/asm/kdebug.h4
-rw-r--r--arch/mips/include/asm/ptrace.h80
-rw-r--r--arch/mips/include/asm/thread_info.h5
-rw-r--r--arch/mips/include/asm/uprobes.h58
-rw-r--r--arch/mips/include/uapi/asm/break.h2
-rw-r--r--arch/mips/kernel/Makefile1
-rw-r--r--arch/mips/kernel/ptrace.c88
-rw-r--r--arch/mips/kernel/signal.c4
-rw-r--r--arch/mips/kernel/traps.c12
-rw-r--r--arch/mips/kernel/uprobes.c341
11 files changed, 597 insertions, 2 deletions
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 7e182424f119..7a9a2554fa00 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -1,6 +1,7 @@
1config MIPS 1config MIPS
2 bool 2 bool
3 default y 3 default y
4 select ARCH_SUPPORTS_UPROBES
4 select ARCH_MIGHT_HAVE_PC_PARPORT 5 select ARCH_MIGHT_HAVE_PC_PARPORT
5 select ARCH_MIGHT_HAVE_PC_SERIO 6 select ARCH_MIGHT_HAVE_PC_SERIO
6 select ARCH_USE_CMPXCHG_LOCKREF if 64BIT 7 select ARCH_USE_CMPXCHG_LOCKREF if 64BIT
@@ -1041,6 +1042,9 @@ config FW_CFE
1041config ARCH_DMA_ADDR_T_64BIT 1042config ARCH_DMA_ADDR_T_64BIT
1042 def_bool (HIGHMEM && ARCH_PHYS_ADDR_T_64BIT) || 64BIT 1043 def_bool (HIGHMEM && ARCH_PHYS_ADDR_T_64BIT) || 64BIT
1043 1044
1045config ARCH_SUPPORTS_UPROBES
1046 bool
1047
1044config DMA_MAYBE_COHERENT 1048config DMA_MAYBE_COHERENT
1045 select DMA_NONCOHERENT 1049 select DMA_NONCOHERENT
1046 bool 1050 bool
diff --git a/arch/mips/include/asm/kdebug.h b/arch/mips/include/asm/kdebug.h
index cba22ab7ad4d..8e3d08e739c1 100644
--- a/arch/mips/include/asm/kdebug.h
+++ b/arch/mips/include/asm/kdebug.h
@@ -11,7 +11,9 @@ enum die_val {
11 DIE_PAGE_FAULT, 11 DIE_PAGE_FAULT,
12 DIE_BREAK, 12 DIE_BREAK,
13 DIE_SSTEPBP, 13 DIE_SSTEPBP,
14 DIE_MSAFP 14 DIE_MSAFP,
15 DIE_UPROBE,
16 DIE_UPROBE_XOL,
15}; 17};
16 18
17#endif /* _ASM_MIPS_KDEBUG_H */ 19#endif /* _ASM_MIPS_KDEBUG_H */
diff --git a/arch/mips/include/asm/ptrace.h b/arch/mips/include/asm/ptrace.h
index ffc320389f40..f6fc6aac5496 100644
--- a/arch/mips/include/asm/ptrace.h
+++ b/arch/mips/include/asm/ptrace.h
@@ -14,11 +14,16 @@
14#include <linux/linkage.h> 14#include <linux/linkage.h>
15#include <linux/types.h> 15#include <linux/types.h>
16#include <asm/isadep.h> 16#include <asm/isadep.h>
17#include <asm/page.h>
18#include <asm/thread_info.h>
17#include <uapi/asm/ptrace.h> 19#include <uapi/asm/ptrace.h>
18 20
19/* 21/*
20 * This struct defines the way the registers are stored on the stack during a 22 * This struct defines the way the registers are stored on the stack during a
21 * system call/exception. As usual the registers k0/k1 aren't being saved. 23 * system call/exception. As usual the registers k0/k1 aren't being saved.
24 *
25 * If you add a register here, also add it to regoffset_table[] in
26 * arch/mips/kernel/ptrace.c.
22 */ 27 */
23struct pt_regs { 28struct pt_regs {
24#ifdef CONFIG_32BIT 29#ifdef CONFIG_32BIT
@@ -43,8 +48,83 @@ struct pt_regs {
43 unsigned long long mpl[6]; /* MTM{0-5} */ 48 unsigned long long mpl[6]; /* MTM{0-5} */
44 unsigned long long mtp[6]; /* MTP{0-5} */ 49 unsigned long long mtp[6]; /* MTP{0-5} */
45#endif 50#endif
51 unsigned long __last[0];
46} __aligned(8); 52} __aligned(8);
47 53
54static inline unsigned long kernel_stack_pointer(struct pt_regs *regs)
55{
56 return regs->regs[31];
57}
58
59/*
60 * Don't use asm-generic/ptrace.h it defines FP accessors that don't make
61 * sense on MIPS. We rather want an error if they get invoked.
62 */
63
64static inline void instruction_pointer_set(struct pt_regs *regs,
65 unsigned long val)
66{
67 regs->cp0_epc = val;
68}
69
70/* Query offset/name of register from its name/offset */
71extern int regs_query_register_offset(const char *name);
72#define MAX_REG_OFFSET (offsetof(struct pt_regs, __last))
73
74/**
75 * regs_get_register() - get register value from its offset
76 * @regs: pt_regs from which register value is gotten.
77 * @offset: offset number of the register.
78 *
79 * regs_get_register returns the value of a register. The @offset is the
80 * offset of the register in struct pt_regs address which specified by @regs.
81 * If @offset is bigger than MAX_REG_OFFSET, this returns 0.
82 */
83static inline unsigned long regs_get_register(struct pt_regs *regs,
84 unsigned int offset)
85{
86 if (unlikely(offset > MAX_REG_OFFSET))
87 return 0;
88
89 return *(unsigned long *)((unsigned long)regs + offset);
90}
91
92/**
93 * regs_within_kernel_stack() - check the address in the stack
94 * @regs: pt_regs which contains kernel stack pointer.
95 * @addr: address which is checked.
96 *
97 * regs_within_kernel_stack() checks @addr is within the kernel stack page(s).
98 * If @addr is within the kernel stack, it returns true. If not, returns false.
99 */
100static inline int regs_within_kernel_stack(struct pt_regs *regs,
101 unsigned long addr)
102{
103 return ((addr & ~(THREAD_SIZE - 1)) ==
104 (kernel_stack_pointer(regs) & ~(THREAD_SIZE - 1)));
105}
106
107/**
108 * regs_get_kernel_stack_nth() - get Nth entry of the stack
109 * @regs: pt_regs which contains kernel stack pointer.
110 * @n: stack entry number.
111 *
112 * regs_get_kernel_stack_nth() returns @n th entry of the kernel stack which
113 * is specified by @regs. If the @n th entry is NOT in the kernel stack,
114 * this returns 0.
115 */
116static inline unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs,
117 unsigned int n)
118{
119 unsigned long *addr = (unsigned long *)kernel_stack_pointer(regs);
120
121 addr += n;
122 if (regs_within_kernel_stack(regs, (unsigned long)addr))
123 return *addr;
124 else
125 return 0;
126}
127
48struct task_struct; 128struct task_struct;
49 129
50extern int ptrace_getregs(struct task_struct *child, 130extern int ptrace_getregs(struct task_struct *child,
diff --git a/arch/mips/include/asm/thread_info.h b/arch/mips/include/asm/thread_info.h
index 9c0014e87c17..e309d8fcb516 100644
--- a/arch/mips/include/asm/thread_info.h
+++ b/arch/mips/include/asm/thread_info.h
@@ -99,6 +99,7 @@ static inline struct thread_info *current_thread_info(void)
99#define TIF_SYSCALL_AUDIT 3 /* syscall auditing active */ 99#define TIF_SYSCALL_AUDIT 3 /* syscall auditing active */
100#define TIF_SECCOMP 4 /* secure computing */ 100#define TIF_SECCOMP 4 /* secure computing */
101#define TIF_NOTIFY_RESUME 5 /* callback before returning to user */ 101#define TIF_NOTIFY_RESUME 5 /* callback before returning to user */
102#define TIF_UPROBE 6 /* breakpointed or singlestepping */
102#define TIF_RESTORE_SIGMASK 9 /* restore signal mask in do_signal() */ 103#define TIF_RESTORE_SIGMASK 9 /* restore signal mask in do_signal() */
103#define TIF_USEDFPU 16 /* FPU was used by this task this quantum (SMP) */ 104#define TIF_USEDFPU 16 /* FPU was used by this task this quantum (SMP) */
104#define TIF_MEMDIE 18 /* is terminating due to OOM killer */ 105#define TIF_MEMDIE 18 /* is terminating due to OOM killer */
@@ -122,6 +123,7 @@ static inline struct thread_info *current_thread_info(void)
122#define _TIF_SYSCALL_AUDIT (1<<TIF_SYSCALL_AUDIT) 123#define _TIF_SYSCALL_AUDIT (1<<TIF_SYSCALL_AUDIT)
123#define _TIF_SECCOMP (1<<TIF_SECCOMP) 124#define _TIF_SECCOMP (1<<TIF_SECCOMP)
124#define _TIF_NOTIFY_RESUME (1<<TIF_NOTIFY_RESUME) 125#define _TIF_NOTIFY_RESUME (1<<TIF_NOTIFY_RESUME)
126#define _TIF_UPROBE (1<<TIF_UPROBE)
125#define _TIF_USEDFPU (1<<TIF_USEDFPU) 127#define _TIF_USEDFPU (1<<TIF_USEDFPU)
126#define _TIF_NOHZ (1<<TIF_NOHZ) 128#define _TIF_NOHZ (1<<TIF_NOHZ)
127#define _TIF_FIXADE (1<<TIF_FIXADE) 129#define _TIF_FIXADE (1<<TIF_FIXADE)
@@ -146,7 +148,8 @@ static inline struct thread_info *current_thread_info(void)
146 148
147/* work to do on interrupt/exception return */ 149/* work to do on interrupt/exception return */
148#define _TIF_WORK_MASK \ 150#define _TIF_WORK_MASK \
149 (_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_NOTIFY_RESUME) 151 (_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_NOTIFY_RESUME | \
152 _TIF_UPROBE)
150/* work to do on any return to u-space */ 153/* work to do on any return to u-space */
151#define _TIF_ALLWORK_MASK (_TIF_NOHZ | _TIF_WORK_MASK | \ 154#define _TIF_ALLWORK_MASK (_TIF_NOHZ | _TIF_WORK_MASK | \
152 _TIF_WORK_SYSCALL_EXIT | \ 155 _TIF_WORK_SYSCALL_EXIT | \
diff --git a/arch/mips/include/asm/uprobes.h b/arch/mips/include/asm/uprobes.h
new file mode 100644
index 000000000000..34c325c674c4
--- /dev/null
+++ b/arch/mips/include/asm/uprobes.h
@@ -0,0 +1,58 @@
1/*
2 * This file is subject to the terms and conditions of the GNU General Public
3 * License. See the file "COPYING" in the main directory of this archive
4 * for more details.
5 */
6#ifndef __ASM_UPROBES_H
7#define __ASM_UPROBES_H
8
9#include <linux/notifier.h>
10#include <linux/types.h>
11
12#include <asm/break.h>
13#include <asm/inst.h>
14
15/*
16 * We want this to be defined as union mips_instruction but that makes the
17 * generic code blow up.
18 */
19typedef u32 uprobe_opcode_t;
20
21/*
22 * Classic MIPS (note this implementation doesn't consider microMIPS yet)
23 * instructions are always 4 bytes but in order to deal with branches and
24 * their delay slots, we treat instructions as having 8 bytes maximum.
25 */
26#define MAX_UINSN_BYTES 8
27#define UPROBE_XOL_SLOT_BYTES 128 /* Max. cache line size */
28
29#define UPROBE_BRK_UPROBE 0x000d000d /* break 13 */
30#define UPROBE_BRK_UPROBE_XOL 0x000e000d /* break 14 */
31
32#define UPROBE_SWBP_INSN UPROBE_BRK_UPROBE
33#define UPROBE_SWBP_INSN_SIZE 4
34
35struct arch_uprobe {
36 unsigned long resume_epc;
37 u32 insn[2];
38 u32 ixol[2];
39 union mips_instruction orig_inst[MAX_UINSN_BYTES / 4];
40};
41
42struct arch_uprobe_task {
43 unsigned long saved_trap_nr;
44};
45
46extern int arch_uprobe_analyze_insn(struct arch_uprobe *aup,
47 struct mm_struct *mm, unsigned long addr);
48extern int arch_uprobe_pre_xol(struct arch_uprobe *aup, struct pt_regs *regs);
49extern int arch_uprobe_post_xol(struct arch_uprobe *aup, struct pt_regs *regs);
50extern bool arch_uprobe_xol_was_trapped(struct task_struct *tsk);
51extern int arch_uprobe_exception_notify(struct notifier_block *self,
52 unsigned long val, void *data);
53extern void arch_uprobe_abort_xol(struct arch_uprobe *aup,
54 struct pt_regs *regs);
55extern unsigned long arch_uretprobe_hijack_return_addr(
56 unsigned long trampoline_vaddr, struct pt_regs *regs);
57
58#endif /* __ASM_UPROBES_H */
diff --git a/arch/mips/include/uapi/asm/break.h b/arch/mips/include/uapi/asm/break.h
index 002c39ea20c3..9c4265cbf151 100644
--- a/arch/mips/include/uapi/asm/break.h
+++ b/arch/mips/include/uapi/asm/break.h
@@ -21,6 +21,8 @@
21#define BRK_DIVZERO 7 /* Divide by zero check */ 21#define BRK_DIVZERO 7 /* Divide by zero check */
22#define BRK_RANGE 8 /* Range error check */ 22#define BRK_RANGE 8 /* Range error check */
23#define BRK_BUG 12 /* Used by BUG() */ 23#define BRK_BUG 12 /* Used by BUG() */
24#define BRK_UPROBE 13 /* See <asm/uprobes.h> */
25#define BRK_UPROBE_XOL 14 /* See <asm/uprobes.h> */
24#define BRK_MEMU 514 /* Used by FPU emulator */ 26#define BRK_MEMU 514 /* Used by FPU emulator */
25#define BRK_KPROBE_BP 515 /* Kprobe break */ 27#define BRK_KPROBE_BP 515 /* Kprobe break */
26#define BRK_KPROBE_SSTEPBP 516 /* Kprobe single step software implementation */ 28#define BRK_KPROBE_SSTEPBP 516 /* Kprobe single step software implementation */
diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile
index 3f5cf8aff6f3..a61435b1ceb1 100644
--- a/arch/mips/kernel/Makefile
+++ b/arch/mips/kernel/Makefile
@@ -100,6 +100,7 @@ obj-$(CONFIG_PERF_EVENTS) += perf_event.o
100obj-$(CONFIG_HW_PERF_EVENTS) += perf_event_mipsxx.o 100obj-$(CONFIG_HW_PERF_EVENTS) += perf_event_mipsxx.o
101 101
102obj-$(CONFIG_JUMP_LABEL) += jump_label.o 102obj-$(CONFIG_JUMP_LABEL) += jump_label.o
103obj-$(CONFIG_UPROBES) += uprobes.o
103 104
104obj-$(CONFIG_MIPS_CM) += mips-cm.o 105obj-$(CONFIG_MIPS_CM) += mips-cm.o
105obj-$(CONFIG_MIPS_CPC) += mips-cpc.o 106obj-$(CONFIG_MIPS_CPC) += mips-cpc.o
diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c
index e933a309f2ea..4f0ac78d17f1 100644
--- a/arch/mips/kernel/ptrace.c
+++ b/arch/mips/kernel/ptrace.c
@@ -25,6 +25,7 @@
25#include <linux/regset.h> 25#include <linux/regset.h>
26#include <linux/smp.h> 26#include <linux/smp.h>
27#include <linux/security.h> 27#include <linux/security.h>
28#include <linux/stddef.h>
28#include <linux/tracehook.h> 29#include <linux/tracehook.h>
29#include <linux/audit.h> 30#include <linux/audit.h>
30#include <linux/seccomp.h> 31#include <linux/seccomp.h>
@@ -490,6 +491,93 @@ enum mips_regset {
490 REGSET_FPR, 491 REGSET_FPR,
491}; 492};
492 493
494struct pt_regs_offset {
495 const char *name;
496 int offset;
497};
498
499#define REG_OFFSET_NAME(reg, r) { \
500 .name = #reg, \
501 .offset = offsetof(struct pt_regs, r) \
502}
503
504#define REG_OFFSET_END { \
505 .name = NULL, \
506 .offset = 0 \
507}
508
509static const struct pt_regs_offset regoffset_table[] = {
510 REG_OFFSET_NAME(r0, regs[0]),
511 REG_OFFSET_NAME(r1, regs[1]),
512 REG_OFFSET_NAME(r2, regs[2]),
513 REG_OFFSET_NAME(r3, regs[3]),
514 REG_OFFSET_NAME(r4, regs[4]),
515 REG_OFFSET_NAME(r5, regs[5]),
516 REG_OFFSET_NAME(r6, regs[6]),
517 REG_OFFSET_NAME(r7, regs[7]),
518 REG_OFFSET_NAME(r8, regs[8]),
519 REG_OFFSET_NAME(r9, regs[9]),
520 REG_OFFSET_NAME(r10, regs[10]),
521 REG_OFFSET_NAME(r11, regs[11]),
522 REG_OFFSET_NAME(r12, regs[12]),
523 REG_OFFSET_NAME(r13, regs[13]),
524 REG_OFFSET_NAME(r14, regs[14]),
525 REG_OFFSET_NAME(r15, regs[15]),
526 REG_OFFSET_NAME(r16, regs[16]),
527 REG_OFFSET_NAME(r17, regs[17]),
528 REG_OFFSET_NAME(r18, regs[18]),
529 REG_OFFSET_NAME(r19, regs[19]),
530 REG_OFFSET_NAME(r20, regs[20]),
531 REG_OFFSET_NAME(r21, regs[21]),
532 REG_OFFSET_NAME(r22, regs[22]),
533 REG_OFFSET_NAME(r23, regs[23]),
534 REG_OFFSET_NAME(r24, regs[24]),
535 REG_OFFSET_NAME(r25, regs[25]),
536 REG_OFFSET_NAME(r26, regs[26]),
537 REG_OFFSET_NAME(r27, regs[27]),
538 REG_OFFSET_NAME(r28, regs[28]),
539 REG_OFFSET_NAME(r29, regs[29]),
540 REG_OFFSET_NAME(r30, regs[30]),
541 REG_OFFSET_NAME(r31, regs[31]),
542 REG_OFFSET_NAME(c0_status, cp0_status),
543 REG_OFFSET_NAME(hi, hi),
544 REG_OFFSET_NAME(lo, lo),
545#ifdef CONFIG_CPU_HAS_SMARTMIPS
546 REG_OFFSET_NAME(acx, acx),
547#endif
548 REG_OFFSET_NAME(c0_badvaddr, cp0_badvaddr),
549 REG_OFFSET_NAME(c0_cause, cp0_cause),
550 REG_OFFSET_NAME(c0_epc, cp0_epc),
551#ifdef CONFIG_MIPS_MT_SMTC
552 REG_OFFSET_NAME(c0_tcstatus, cp0_tcstatus),
553#endif
554#ifdef CONFIG_CPU_CAVIUM_OCTEON
555 REG_OFFSET_NAME(mpl0, mpl[0]),
556 REG_OFFSET_NAME(mpl1, mpl[1]),
557 REG_OFFSET_NAME(mpl2, mpl[2]),
558 REG_OFFSET_NAME(mtp0, mtp[0]),
559 REG_OFFSET_NAME(mtp1, mtp[1]),
560 REG_OFFSET_NAME(mtp2, mtp[2]),
561#endif
562 REG_OFFSET_END,
563};
564
565/**
566 * regs_query_register_offset() - query register offset from its name
567 * @name: the name of a register
568 *
569 * regs_query_register_offset() returns the offset of a register in struct
570 * pt_regs from its name. If the name is invalid, this returns -EINVAL;
571 */
572int regs_query_register_offset(const char *name)
573{
574 const struct pt_regs_offset *roff;
575 for (roff = regoffset_table; roff->name != NULL; roff++)
576 if (!strcmp(roff->name, name))
577 return roff->offset;
578 return -EINVAL;
579}
580
493#if defined(CONFIG_32BIT) || defined(CONFIG_MIPS32_O32) 581#if defined(CONFIG_32BIT) || defined(CONFIG_MIPS32_O32)
494 582
495static const struct user_regset mips_regsets[] = { 583static const struct user_regset mips_regsets[] = {
diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c
index fa13a52713df..2fec67bfc457 100644
--- a/arch/mips/kernel/signal.c
+++ b/arch/mips/kernel/signal.c
@@ -21,6 +21,7 @@
21#include <linux/wait.h> 21#include <linux/wait.h>
22#include <linux/ptrace.h> 22#include <linux/ptrace.h>
23#include <linux/unistd.h> 23#include <linux/unistd.h>
24#include <linux/uprobes.h>
24#include <linux/compiler.h> 25#include <linux/compiler.h>
25#include <linux/syscalls.h> 26#include <linux/syscalls.h>
26#include <linux/uaccess.h> 27#include <linux/uaccess.h>
@@ -856,6 +857,9 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, void *unused,
856 857
857 user_exit(); 858 user_exit();
858 859
860 if (thread_info_flags & _TIF_UPROBE)
861 uprobe_notify_resume(regs);
862
859 /* deal with pending signal delivery */ 863 /* deal with pending signal delivery */
860 if (thread_info_flags & _TIF_SIGPENDING) 864 if (thread_info_flags & _TIF_SIGPENDING)
861 do_signal(regs); 865 do_signal(regs);
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
index cea964daf400..fdb392b27e81 100644
--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -984,6 +984,18 @@ asmlinkage void do_bp(struct pt_regs *regs)
984 * pertain to them. 984 * pertain to them.
985 */ 985 */
986 switch (bcode) { 986 switch (bcode) {
987 case BRK_UPROBE:
988 if (notify_die(DIE_UPROBE, "uprobe", regs, bcode,
989 current->thread.trap_nr, SIGTRAP) == NOTIFY_STOP)
990 goto out;
991 else
992 break;
993 case BRK_UPROBE_XOL:
994 if (notify_die(DIE_UPROBE_XOL, "uprobe_xol", regs, bcode,
995 current->thread.trap_nr, SIGTRAP) == NOTIFY_STOP)
996 goto out;
997 else
998 break;
987 case BRK_KPROBE_BP: 999 case BRK_KPROBE_BP:
988 if (notify_die(DIE_BREAK, "debug", regs, bcode, 1000 if (notify_die(DIE_BREAK, "debug", regs, bcode,
989 current->thread.trap_nr, SIGTRAP) == NOTIFY_STOP) 1001 current->thread.trap_nr, SIGTRAP) == NOTIFY_STOP)
diff --git a/arch/mips/kernel/uprobes.c b/arch/mips/kernel/uprobes.c
new file mode 100644
index 000000000000..8452d933a645
--- /dev/null
+++ b/arch/mips/kernel/uprobes.c
@@ -0,0 +1,341 @@
1#include <linux/highmem.h>
2#include <linux/kdebug.h>
3#include <linux/types.h>
4#include <linux/notifier.h>
5#include <linux/sched.h>
6#include <linux/uprobes.h>
7
8#include <asm/branch.h>
9#include <asm/cpu-features.h>
10#include <asm/ptrace.h>
11#include <asm/inst.h>
12
13static inline int insn_has_delay_slot(const union mips_instruction insn)
14{
15 switch (insn.i_format.opcode) {
16 /*
17 * jr and jalr are in r_format format.
18 */
19 case spec_op:
20 switch (insn.r_format.func) {
21 case jalr_op:
22 case jr_op:
23 return 1;
24 }
25 break;
26
27 /*
28 * This group contains:
29 * bltz_op, bgez_op, bltzl_op, bgezl_op,
30 * bltzal_op, bgezal_op, bltzall_op, bgezall_op.
31 */
32 case bcond_op:
33 switch (insn.i_format.rt) {
34 case bltz_op:
35 case bltzl_op:
36 case bgez_op:
37 case bgezl_op:
38 case bltzal_op:
39 case bltzall_op:
40 case bgezal_op:
41 case bgezall_op:
42 case bposge32_op:
43 return 1;
44 }
45 break;
46
47 /*
48 * These are unconditional and in j_format.
49 */
50 case jal_op:
51 case j_op:
52 case beq_op:
53 case beql_op:
54 case bne_op:
55 case bnel_op:
56 case blez_op: /* not really i_format */
57 case blezl_op:
58 case bgtz_op:
59 case bgtzl_op:
60 return 1;
61
62 /*
63 * And now the FPA/cp1 branch instructions.
64 */
65 case cop1_op:
66#ifdef CONFIG_CPU_CAVIUM_OCTEON
67 case lwc2_op: /* This is bbit0 on Octeon */
68 case ldc2_op: /* This is bbit032 on Octeon */
69 case swc2_op: /* This is bbit1 on Octeon */
70 case sdc2_op: /* This is bbit132 on Octeon */
71#endif
72 return 1;
73 }
74
75 return 0;
76}
77
78/**
79 * arch_uprobe_analyze_insn - instruction analysis including validity and fixups.
80 * @mm: the probed address space.
81 * @arch_uprobe: the probepoint information.
82 * @addr: virtual address at which to install the probepoint
83 * Return 0 on success or a -ve number on error.
84 */
85int arch_uprobe_analyze_insn(struct arch_uprobe *aup,
86 struct mm_struct *mm, unsigned long addr)
87{
88 union mips_instruction inst;
89
90 /*
91 * For the time being this also blocks attempts to use uprobes with
92 * MIPS16 and microMIPS.
93 */
94 if (addr & 0x03)
95 return -EINVAL;
96
97 inst.word = aup->insn[0];
98 aup->ixol[0] = aup->insn[insn_has_delay_slot(inst)];
99 aup->ixol[1] = UPROBE_BRK_UPROBE_XOL; /* NOP */
100
101 return 0;
102}
103
104/**
105 * is_trap_insn - check if the instruction is a trap variant
106 * @insn: instruction to be checked.
107 * Returns true if @insn is a trap variant.
108 *
109 * This definition overrides the weak definition in kernel/events/uprobes.c.
110 * and is needed for the case where an architecture has multiple trap
111 * instructions (like PowerPC or MIPS). We treat BREAK just like the more
112 * modern conditional trap instructions.
113 */
114bool is_trap_insn(uprobe_opcode_t *insn)
115{
116 union mips_instruction inst;
117
118 inst.word = *insn;
119
120 switch (inst.i_format.opcode) {
121 case spec_op:
122 switch (inst.r_format.func) {
123 case break_op:
124 case teq_op:
125 case tge_op:
126 case tgeu_op:
127 case tlt_op:
128 case tltu_op:
129 case tne_op:
130 return 1;
131 }
132 break;
133
134 case bcond_op: /* Yes, really ... */
135 switch (inst.u_format.rt) {
136 case teqi_op:
137 case tgei_op:
138 case tgeiu_op:
139 case tlti_op:
140 case tltiu_op:
141 case tnei_op:
142 return 1;
143 }
144 break;
145 }
146
147 return 0;
148}
149
150#define UPROBE_TRAP_NR ULONG_MAX
151
152/*
153 * arch_uprobe_pre_xol - prepare to execute out of line.
154 * @auprobe: the probepoint information.
155 * @regs: reflects the saved user state of current task.
156 */
157int arch_uprobe_pre_xol(struct arch_uprobe *aup, struct pt_regs *regs)
158{
159 struct uprobe_task *utask = current->utask;
160 union mips_instruction insn;
161
162 /*
163 * Now find the EPC where to resume after the breakpoint has been
164 * dealt with. This may require emulation of a branch.
165 */
166 aup->resume_epc = regs->cp0_epc + 4;
167 if (insn_has_delay_slot((union mips_instruction) aup->insn[0])) {
168 unsigned long epc;
169
170 epc = regs->cp0_epc;
171 __compute_return_epc_for_insn(regs, insn);
172 aup->resume_epc = regs->cp0_epc;
173 }
174
175 utask->autask.saved_trap_nr = current->thread.trap_nr;
176 current->thread.trap_nr = UPROBE_TRAP_NR;
177 regs->cp0_epc = current->utask->xol_vaddr;
178
179 return 0;
180}
181
182int arch_uprobe_post_xol(struct arch_uprobe *aup, struct pt_regs *regs)
183{
184 struct uprobe_task *utask = current->utask;
185
186 current->thread.trap_nr = utask->autask.saved_trap_nr;
187 regs->cp0_epc = aup->resume_epc;
188
189 return 0;
190}
191
192/*
193 * If xol insn itself traps and generates a signal(Say,
194 * SIGILL/SIGSEGV/etc), then detect the case where a singlestepped
195 * instruction jumps back to its own address. It is assumed that anything
196 * like do_page_fault/do_trap/etc sets thread.trap_nr != -1.
197 *
198 * arch_uprobe_pre_xol/arch_uprobe_post_xol save/restore thread.trap_nr,
199 * arch_uprobe_xol_was_trapped() simply checks that ->trap_nr is not equal to
200 * UPROBE_TRAP_NR == -1 set by arch_uprobe_pre_xol().
201 */
202bool arch_uprobe_xol_was_trapped(struct task_struct *tsk)
203{
204 if (tsk->thread.trap_nr != UPROBE_TRAP_NR)
205 return true;
206
207 return false;
208}
209
210int arch_uprobe_exception_notify(struct notifier_block *self,
211 unsigned long val, void *data)
212{
213 struct die_args *args = data;
214 struct pt_regs *regs = args->regs;
215
216 /* regs == NULL is a kernel bug */
217 if (WARN_ON(!regs))
218 return NOTIFY_DONE;
219
220 /* We are only interested in userspace traps */
221 if (!user_mode(regs))
222 return NOTIFY_DONE;
223
224 switch (val) {
225 case DIE_BREAK:
226 if (uprobe_pre_sstep_notifier(regs))
227 return NOTIFY_STOP;
228 break;
229 case DIE_UPROBE_XOL:
230 if (uprobe_post_sstep_notifier(regs))
231 return NOTIFY_STOP;
232 default:
233 break;
234 }
235
236 return 0;
237}
238
239/*
240 * This function gets called when XOL instruction either gets trapped or
241 * the thread has a fatal signal. Reset the instruction pointer to its
242 * probed address for the potential restart or for post mortem analysis.
243 */
244void arch_uprobe_abort_xol(struct arch_uprobe *aup,
245 struct pt_regs *regs)
246{
247 struct uprobe_task *utask = current->utask;
248
249 instruction_pointer_set(regs, utask->vaddr);
250}
251
252unsigned long arch_uretprobe_hijack_return_addr(
253 unsigned long trampoline_vaddr, struct pt_regs *regs)
254{
255 unsigned long ra;
256
257 ra = regs->regs[31];
258
259 /* Replace the return address with the trampoline address */
260 regs->regs[31] = ra;
261
262 return ra;
263}
264
265/**
266 * set_swbp - store breakpoint at a given address.
267 * @auprobe: arch specific probepoint information.
268 * @mm: the probed process address space.
269 * @vaddr: the virtual address to insert the opcode.
270 *
271 * For mm @mm, store the breakpoint instruction at @vaddr.
272 * Return 0 (success) or a negative errno.
273 *
274 * This version overrides the weak version in kernel/events/uprobes.c.
275 * It is required to handle MIPS16 and microMIPS.
276 */
277int __weak set_swbp(struct arch_uprobe *auprobe, struct mm_struct *mm,
278 unsigned long vaddr)
279{
280 return uprobe_write_opcode(mm, vaddr, UPROBE_SWBP_INSN);
281}
282
283/**
284 * set_orig_insn - Restore the original instruction.
285 * @mm: the probed process address space.
286 * @auprobe: arch specific probepoint information.
287 * @vaddr: the virtual address to insert the opcode.
288 *
289 * For mm @mm, restore the original opcode (opcode) at @vaddr.
290 * Return 0 (success) or a negative errno.
291 *
292 * This overrides the weak version in kernel/events/uprobes.c.
293 */
294int set_orig_insn(struct arch_uprobe *auprobe, struct mm_struct *mm,
295 unsigned long vaddr)
296{
297 return uprobe_write_opcode(mm, vaddr,
298 *(uprobe_opcode_t *)&auprobe->orig_inst[0].word);
299}
300
301void __weak arch_uprobe_copy_ixol(struct page *page, unsigned long vaddr,
302 void *src, unsigned long len)
303{
304 void *kaddr;
305
306 /* Initialize the slot */
307 kaddr = kmap_atomic(page);
308 memcpy(kaddr + (vaddr & ~PAGE_MASK), src, len);
309 kunmap_atomic(kaddr);
310
311 /*
312 * The MIPS version of flush_icache_range will operate safely on
313 * user space addresses and more importantly, it doesn't require a
314 * VMA argument.
315 */
316 flush_icache_range(vaddr, vaddr + len);
317}
318
319/**
320 * uprobe_get_swbp_addr - compute address of swbp given post-swbp regs
321 * @regs: Reflects the saved state of the task after it has hit a breakpoint
322 * instruction.
323 * Return the address of the breakpoint instruction.
324 *
325 * This overrides the weak version in kernel/events/uprobes.c.
326 */
327unsigned long uprobe_get_swbp_addr(struct pt_regs *regs)
328{
329 return instruction_pointer(regs);
330}
331
332/*
333 * See if the instruction can be emulated.
334 * Returns true if instruction was emulated, false otherwise.
335 *
336 * For now we always emulate so this function just returns 0.
337 */
338bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs)
339{
340 return 0;
341}