Skip to content

Commit 33e53ae

Browse files
committed
csky: Add kprobes supported
This patch enable kprobes, kretprobes, ftrace interface. It utilized software breakpoint and single step debug exceptions, instructions simulation on csky. We use USR_BKPT replace origin instruction, and the kprobe handler prepares an excutable memory slot for out-of-line execution with a copy of the original instruction being probed. Most of instructions could be executed by single-step, but some instructions need origin pc value to execute and we need software simulate these instructions. Signed-off-by: Guo Ren <[email protected]> Cc: Arnd Bergmann <[email protected]> Cc: Steven Rostedt (VMware) <[email protected]>
1 parent 000591f commit 33e53ae

File tree

16 files changed

+1197
-2
lines changed

16 files changed

+1197
-2
lines changed

arch/csky/Kconfig

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ config CSKY
4646
select HAVE_KERNEL_GZIP
4747
select HAVE_KERNEL_LZO
4848
select HAVE_KERNEL_LZMA
49+
select HAVE_KPROBES if !CPU_CK610
50+
select HAVE_KPROBES_ON_FTRACE if !CPU_CK610
51+
select HAVE_KRETPROBES if !CPU_CK610
4952
select HAVE_PERF_EVENTS
5053
select HAVE_PERF_REGS
5154
select HAVE_PERF_USER_STACK_DUMP

arch/csky/include/asm/Kbuild

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ generic-y += irq_regs.h
2020
generic-y += irq_work.h
2121
generic-y += kdebug.h
2222
generic-y += kmap_types.h
23-
generic-y += kprobes.h
2423
generic-y += kvm_para.h
2524
generic-y += linkage.h
2625
generic-y += local.h

arch/csky/include/asm/kprobes.h

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/* SPDX-License-Identifier: GPL-2.0-only */
2+
3+
#ifndef __ASM_CSKY_KPROBES_H
4+
#define __ASM_CSKY_KPROBES_H
5+
6+
#include <asm-generic/kprobes.h>
7+
8+
#ifdef CONFIG_KPROBES
9+
#include <linux/types.h>
10+
#include <linux/ptrace.h>
11+
#include <linux/percpu.h>
12+
13+
#define __ARCH_WANT_KPROBES_INSN_SLOT
14+
#define MAX_INSN_SIZE 1
15+
16+
#define flush_insn_slot(p) do { } while (0)
17+
#define kretprobe_blacklist_size 0
18+
19+
#include <asm/probes.h>
20+
21+
struct prev_kprobe {
22+
struct kprobe *kp;
23+
unsigned int status;
24+
};
25+
26+
/* Single step context for kprobe */
27+
struct kprobe_step_ctx {
28+
unsigned long ss_pending;
29+
unsigned long match_addr;
30+
};
31+
32+
/* per-cpu kprobe control block */
33+
struct kprobe_ctlblk {
34+
unsigned int kprobe_status;
35+
unsigned long saved_sr;
36+
struct prev_kprobe prev_kprobe;
37+
struct kprobe_step_ctx ss_ctx;
38+
};
39+
40+
void arch_remove_kprobe(struct kprobe *p);
41+
int kprobe_fault_handler(struct pt_regs *regs, unsigned int trapnr);
42+
int kprobe_breakpoint_handler(struct pt_regs *regs);
43+
int kprobe_single_step_handler(struct pt_regs *regs);
44+
void kretprobe_trampoline(void);
45+
void __kprobes *trampoline_probe_handler(struct pt_regs *regs);
46+
47+
#endif /* CONFIG_KPROBES */
48+
#endif /* __ASM_CSKY_KPROBES_H */

arch/csky/include/asm/probes.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
3+
#ifndef __ASM_CSKY_PROBES_H
4+
#define __ASM_CSKY_PROBES_H
5+
6+
typedef u32 probe_opcode_t;
7+
typedef void (probes_handler_t) (u32 opcode, long addr, struct pt_regs *);
8+
9+
/* architecture specific copy of original instruction */
10+
struct arch_probe_insn {
11+
probe_opcode_t *insn;
12+
probes_handler_t *handler;
13+
/* restore address after simulation */
14+
unsigned long restore;
15+
};
16+
17+
#ifdef CONFIG_KPROBES
18+
typedef u32 kprobe_opcode_t;
19+
struct arch_specific_insn {
20+
struct arch_probe_insn api;
21+
};
22+
#endif
23+
24+
#endif /* __ASM_CSKY_PROBES_H */

arch/csky/include/asm/ptrace.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313

1414
#define PS_S 0x80000000 /* Supervisor Mode */
1515

16+
#define USR_BKPT 0x1464
17+
1618
#define arch_has_single_step() (1)
1719
#define current_pt_regs() \
1820
({ (struct pt_regs *)((char *)current_thread_info() + THREAD_SIZE) - 1; })

arch/csky/kernel/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ extra-y := head.o vmlinux.lds
44
obj-y += entry.o atomic.o signal.o traps.o irq.o time.o vdso.o
55
obj-y += power.o syscall.o syscall_table.o setup.o
66
obj-y += process.o cpu-probe.o ptrace.o dumpstack.o
7+
obj-y += probes/
78

89
obj-$(CONFIG_MODULES) += module.o
910
obj-$(CONFIG_SMP) += smp.o

arch/csky/kernel/probes/Makefile

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# SPDX-License-Identifier: GPL-2.0
2+
obj-$(CONFIG_KPROBES) += kprobes.o decode-insn.o simulate-insn.o
3+
obj-$(CONFIG_KPROBES) += kprobes_trampoline.o
4+
obj-$(CONFIG_KPROBES_ON_FTRACE) += ftrace.o
5+
6+
CFLAGS_REMOVE_simulate-insn.o = $(CC_FLAGS_FTRACE)

arch/csky/kernel/probes/decode-insn.c

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// SPDX-License-Identifier: GPL-2.0+
2+
3+
#include <linux/kernel.h>
4+
#include <linux/kprobes.h>
5+
#include <linux/module.h>
6+
#include <linux/kallsyms.h>
7+
#include <asm/sections.h>
8+
9+
#include "decode-insn.h"
10+
#include "simulate-insn.h"
11+
12+
/* Return:
13+
* INSN_REJECTED If instruction is one not allowed to kprobe,
14+
* INSN_GOOD_NO_SLOT If instruction is supported but doesn't use its slot.
15+
*/
16+
enum probe_insn __kprobes
17+
csky_probe_decode_insn(probe_opcode_t *addr, struct arch_probe_insn *api)
18+
{
19+
probe_opcode_t insn = le32_to_cpu(*addr);
20+
21+
CSKY_INSN_SET_SIMULATE(br16, insn);
22+
CSKY_INSN_SET_SIMULATE(bt16, insn);
23+
CSKY_INSN_SET_SIMULATE(bf16, insn);
24+
CSKY_INSN_SET_SIMULATE(jmp16, insn);
25+
CSKY_INSN_SET_SIMULATE(jsr16, insn);
26+
CSKY_INSN_SET_SIMULATE(lrw16, insn);
27+
CSKY_INSN_SET_SIMULATE(pop16, insn);
28+
29+
CSKY_INSN_SET_SIMULATE(br32, insn);
30+
CSKY_INSN_SET_SIMULATE(bt32, insn);
31+
CSKY_INSN_SET_SIMULATE(bf32, insn);
32+
CSKY_INSN_SET_SIMULATE(jmp32, insn);
33+
CSKY_INSN_SET_SIMULATE(jsr32, insn);
34+
CSKY_INSN_SET_SIMULATE(lrw32, insn);
35+
CSKY_INSN_SET_SIMULATE(pop32, insn);
36+
37+
CSKY_INSN_SET_SIMULATE(bez32, insn);
38+
CSKY_INSN_SET_SIMULATE(bnez32, insn);
39+
CSKY_INSN_SET_SIMULATE(bnezad32, insn);
40+
CSKY_INSN_SET_SIMULATE(bhsz32, insn);
41+
CSKY_INSN_SET_SIMULATE(bhz32, insn);
42+
CSKY_INSN_SET_SIMULATE(blsz32, insn);
43+
CSKY_INSN_SET_SIMULATE(blz32, insn);
44+
CSKY_INSN_SET_SIMULATE(bsr32, insn);
45+
CSKY_INSN_SET_SIMULATE(jmpi32, insn);
46+
CSKY_INSN_SET_SIMULATE(jsri32, insn);
47+
48+
return INSN_GOOD;
49+
}

arch/csky/kernel/probes/decode-insn.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/* SPDX-License-Identifier: GPL-2.0+ */
2+
3+
#ifndef __CSKY_KERNEL_KPROBES_DECODE_INSN_H
4+
#define __CSKY_KERNEL_KPROBES_DECODE_INSN_H
5+
6+
#include <asm/sections.h>
7+
#include <asm/kprobes.h>
8+
9+
enum probe_insn {
10+
INSN_REJECTED,
11+
INSN_GOOD_NO_SLOT,
12+
INSN_GOOD,
13+
};
14+
15+
#define is_insn32(insn) ((insn & 0xc000) == 0xc000)
16+
17+
enum probe_insn __kprobes
18+
csky_probe_decode_insn(probe_opcode_t *addr, struct arch_probe_insn *asi);
19+
20+
#endif /* __CSKY_KERNEL_KPROBES_DECODE_INSN_H */

arch/csky/kernel/probes/ftrace.c

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
#include <linux/kprobes.h>
4+
5+
int arch_check_ftrace_location(struct kprobe *p)
6+
{
7+
if (ftrace_location((unsigned long)p->addr))
8+
p->flags |= KPROBE_FLAG_FTRACE;
9+
return 0;
10+
}
11+
12+
/* Ftrace callback handler for kprobes -- called under preepmt disabed */
13+
void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip,
14+
struct ftrace_ops *ops, struct pt_regs *regs)
15+
{
16+
bool lr_saver = false;
17+
struct kprobe *p;
18+
struct kprobe_ctlblk *kcb;
19+
20+
/* Preempt is disabled by ftrace */
21+
p = get_kprobe((kprobe_opcode_t *)ip);
22+
if (!p) {
23+
p = get_kprobe((kprobe_opcode_t *)(ip - MCOUNT_INSN_SIZE));
24+
if (unlikely(!p) || kprobe_disabled(p))
25+
return;
26+
lr_saver = true;
27+
}
28+
29+
kcb = get_kprobe_ctlblk();
30+
if (kprobe_running()) {
31+
kprobes_inc_nmissed_count(p);
32+
} else {
33+
unsigned long orig_ip = instruction_pointer(regs);
34+
35+
if (lr_saver)
36+
ip -= MCOUNT_INSN_SIZE;
37+
instruction_pointer_set(regs, ip);
38+
__this_cpu_write(current_kprobe, p);
39+
kcb->kprobe_status = KPROBE_HIT_ACTIVE;
40+
if (!p->pre_handler || !p->pre_handler(p, regs)) {
41+
/*
42+
* Emulate singlestep (and also recover regs->pc)
43+
* as if there is a nop
44+
*/
45+
instruction_pointer_set(regs,
46+
(unsigned long)p->addr + MCOUNT_INSN_SIZE);
47+
if (unlikely(p->post_handler)) {
48+
kcb->kprobe_status = KPROBE_HIT_SSDONE;
49+
p->post_handler(p, regs, 0);
50+
}
51+
instruction_pointer_set(regs, orig_ip);
52+
}
53+
/*
54+
* If pre_handler returns !0, it changes regs->pc. We have to
55+
* skip emulating post_handler.
56+
*/
57+
__this_cpu_write(current_kprobe, NULL);
58+
}
59+
}
60+
NOKPROBE_SYMBOL(kprobe_ftrace_handler);
61+
62+
int arch_prepare_kprobe_ftrace(struct kprobe *p)
63+
{
64+
p->ainsn.api.insn = NULL;
65+
return 0;
66+
}

0 commit comments

Comments
 (0)