Skip to content

Commit 8f6bb79

Browse files
committed
csky: Add uprobes support
This patch adds support for uprobes on csky architecture. Just like kprobe, it support single-step and simulate instructions. Signed-off-by: Guo Ren <[email protected]> Cc: Arnd Bergmann <[email protected]> Cc: Steven Rostedt (VMware) <[email protected]>
1 parent 33e53ae commit 8f6bb79

File tree

8 files changed

+201
-1
lines changed

8 files changed

+201
-1
lines changed

arch/csky/Kconfig

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,9 @@ config CSKY
7575
config LOCKDEP_SUPPORT
7676
def_bool y
7777

78+
config ARCH_SUPPORTS_UPROBES
79+
def_bool y if !CPU_CK610
80+
7881
config CPU_HAS_CACHEV2
7982
bool
8083

arch/csky/include/asm/thread_info.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ static inline struct thread_info *current_thread_info(void)
5757
#define TIF_SYSCALL_TRACE 3 /* syscall trace active */
5858
#define TIF_SYSCALL_TRACEPOINT 4 /* syscall tracepoint instrumentation */
5959
#define TIF_SYSCALL_AUDIT 5 /* syscall auditing */
60+
#define TIF_UPROBE 6 /* uprobe breakpoint or singlestep */
6061
#define TIF_POLLING_NRFLAG 16 /* poll_idle() is TIF_NEED_RESCHED */
6162
#define TIF_MEMDIE 18 /* is terminating due to OOM killer */
6263
#define TIF_RESTORE_SIGMASK 20 /* restore signal mask in do_signal() */
@@ -68,6 +69,7 @@ static inline struct thread_info *current_thread_info(void)
6869
#define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE)
6970
#define _TIF_SYSCALL_TRACEPOINT (1 << TIF_SYSCALL_TRACEPOINT)
7071
#define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT)
72+
#define _TIF_UPROBE (1 << TIF_UPROBE)
7173
#define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG)
7274
#define _TIF_MEMDIE (1 << TIF_MEMDIE)
7375
#define _TIF_RESTORE_SIGMASK (1 << TIF_RESTORE_SIGMASK)

arch/csky/include/asm/uprobes.h

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/* SPDX-License-Identifier: GPL-2.0-only */
2+
3+
#ifndef __ASM_CSKY_UPROBES_H
4+
#define __ASM_CSKY_UPROBES_H
5+
6+
#include <asm/probes.h>
7+
8+
#define MAX_UINSN_BYTES 4
9+
10+
#define UPROBE_SWBP_INSN USR_BKPT
11+
#define UPROBE_SWBP_INSN_SIZE 2
12+
#define UPROBE_XOL_SLOT_BYTES MAX_UINSN_BYTES
13+
14+
typedef u32 uprobe_opcode_t;
15+
16+
struct arch_uprobe_task {
17+
unsigned long saved_trap_no;
18+
};
19+
20+
struct arch_uprobe {
21+
union {
22+
u8 insn[MAX_UINSN_BYTES];
23+
u8 ixol[MAX_UINSN_BYTES];
24+
};
25+
struct arch_probe_insn api;
26+
unsigned long insn_size;
27+
bool simulate;
28+
};
29+
30+
int uprobe_breakpoint_handler(struct pt_regs *regs);
31+
int uprobe_single_step_handler(struct pt_regs *regs);
32+
33+
#endif /* __ASM_CSKY_UPROBES_H */

arch/csky/kernel/entry.S

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ ret_from_exception:
221221
andn r9, r10
222222

223223
ldw r12, (r9, TINFO_FLAGS)
224-
andi r12, (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED)
224+
andi r12, (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | _TIF_UPROBE)
225225
cmpnei r12, 0
226226
bt exit_work
227227
1:

arch/csky/kernel/probes/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,6 @@
22
obj-$(CONFIG_KPROBES) += kprobes.o decode-insn.o simulate-insn.o
33
obj-$(CONFIG_KPROBES) += kprobes_trampoline.o
44
obj-$(CONFIG_KPROBES_ON_FTRACE) += ftrace.o
5+
obj-$(CONFIG_UPROBES) += uprobes.o decode-insn.o simulate-insn.o
56

67
CFLAGS_REMOVE_simulate-insn.o = $(CC_FLAGS_FTRACE)

arch/csky/kernel/probes/uprobes.c

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
/*
3+
* Copyright (C) 2014-2016 Pratyush Anand <[email protected]>
4+
*/
5+
#include <linux/highmem.h>
6+
#include <linux/ptrace.h>
7+
#include <linux/uprobes.h>
8+
#include <asm/cacheflush.h>
9+
10+
#include "decode-insn.h"
11+
12+
#define UPROBE_TRAP_NR UINT_MAX
13+
14+
unsigned long uprobe_get_swbp_addr(struct pt_regs *regs)
15+
{
16+
return instruction_pointer(regs);
17+
}
18+
19+
int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe, struct mm_struct *mm,
20+
unsigned long addr)
21+
{
22+
probe_opcode_t insn;
23+
24+
insn = *(probe_opcode_t *)(&auprobe->insn[0]);
25+
26+
auprobe->insn_size = is_insn32(insn) ? 4 : 2;
27+
28+
switch (csky_probe_decode_insn(&insn, &auprobe->api)) {
29+
case INSN_REJECTED:
30+
return -EINVAL;
31+
32+
case INSN_GOOD_NO_SLOT:
33+
auprobe->simulate = true;
34+
break;
35+
36+
default:
37+
break;
38+
}
39+
40+
return 0;
41+
}
42+
43+
int arch_uprobe_pre_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
44+
{
45+
struct uprobe_task *utask = current->utask;
46+
47+
utask->autask.saved_trap_no = current->thread.trap_no;
48+
current->thread.trap_no = UPROBE_TRAP_NR;
49+
50+
instruction_pointer_set(regs, utask->xol_vaddr);
51+
52+
user_enable_single_step(current);
53+
54+
return 0;
55+
}
56+
57+
int arch_uprobe_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
58+
{
59+
struct uprobe_task *utask = current->utask;
60+
61+
WARN_ON_ONCE(current->thread.trap_no != UPROBE_TRAP_NR);
62+
63+
instruction_pointer_set(regs, utask->vaddr + auprobe->insn_size);
64+
65+
user_disable_single_step(current);
66+
67+
return 0;
68+
}
69+
70+
bool arch_uprobe_xol_was_trapped(struct task_struct *t)
71+
{
72+
if (t->thread.trap_no != UPROBE_TRAP_NR)
73+
return true;
74+
75+
return false;
76+
}
77+
78+
bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs)
79+
{
80+
probe_opcode_t insn;
81+
unsigned long addr;
82+
83+
if (!auprobe->simulate)
84+
return false;
85+
86+
insn = *(probe_opcode_t *)(&auprobe->insn[0]);
87+
addr = instruction_pointer(regs);
88+
89+
if (auprobe->api.handler)
90+
auprobe->api.handler(insn, addr, regs);
91+
92+
return true;
93+
}
94+
95+
void arch_uprobe_abort_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
96+
{
97+
struct uprobe_task *utask = current->utask;
98+
99+
/*
100+
* Task has received a fatal signal, so reset back to probbed
101+
* address.
102+
*/
103+
instruction_pointer_set(regs, utask->vaddr);
104+
105+
user_disable_single_step(current);
106+
}
107+
108+
bool arch_uretprobe_is_alive(struct return_instance *ret, enum rp_check ctx,
109+
struct pt_regs *regs)
110+
{
111+
if (ctx == RP_CHECK_CHAIN_CALL)
112+
return regs->usp <= ret->stack;
113+
else
114+
return regs->usp < ret->stack;
115+
}
116+
117+
unsigned long
118+
arch_uretprobe_hijack_return_addr(unsigned long trampoline_vaddr,
119+
struct pt_regs *regs)
120+
{
121+
unsigned long ra;
122+
123+
ra = regs->lr;
124+
125+
regs->lr = trampoline_vaddr;
126+
127+
return ra;
128+
}
129+
130+
int arch_uprobe_exception_notify(struct notifier_block *self,
131+
unsigned long val, void *data)
132+
{
133+
return NOTIFY_DONE;
134+
}
135+
136+
int uprobe_breakpoint_handler(struct pt_regs *regs)
137+
{
138+
if (uprobe_pre_sstep_notifier(regs))
139+
return 1;
140+
141+
return 0;
142+
}
143+
144+
int uprobe_single_step_handler(struct pt_regs *regs)
145+
{
146+
if (uprobe_post_sstep_notifier(regs))
147+
return 1;
148+
149+
return 0;
150+
}

arch/csky/kernel/signal.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,9 @@ static void do_signal(struct pt_regs *regs)
253253
asmlinkage void do_notify_resume(struct pt_regs *regs,
254254
unsigned long thread_info_flags)
255255
{
256+
if (thread_info_flags & _TIF_UPROBE)
257+
uprobe_notify_resume(regs);
258+
256259
/* Handle pending signal delivery */
257260
if (thread_info_flags & _TIF_SIGPENDING)
258261
do_signal(regs);

arch/csky/kernel/traps.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,10 @@ asmlinkage void trap_c(struct pt_regs *regs)
129129
#ifdef CONFIG_KPROBES
130130
if (kprobe_single_step_handler(regs))
131131
return;
132+
#endif
133+
#ifdef CONFIG_UPROBES
134+
if (uprobe_single_step_handler(regs))
135+
return;
132136
#endif
133137
info.si_code = TRAP_TRACE;
134138
sig = SIGTRAP;
@@ -138,6 +142,10 @@ asmlinkage void trap_c(struct pt_regs *regs)
138142
#ifdef CONFIG_KPROBES
139143
if (kprobe_breakpoint_handler(regs))
140144
return;
145+
#endif
146+
#ifdef CONFIG_UPROBES
147+
if (uprobe_breakpoint_handler(regs))
148+
return;
141149
#endif
142150
die_if_kernel("Kernel mode ILLEGAL", regs, vector);
143151
#ifndef CONFIG_CPU_NO_USER_BKPT

0 commit comments

Comments
 (0)