Add k/uprobe & fentry & error_injection supported
Subsystems (5)
[email protected]
maintainerv5 cover Add k/uprobe & fentry & error_injection supported
From: Guo Ren <[email protected]>
This the 5th round of riscv k/uprobe support patchset, it's based on linux-5.10 and you can test it with the repo:
https://github.com/c-sky/csky-linux/tree/linux-5.10-probe-dev
The important fixup is about the trampoline call site, we change the prologue of the function call site from:
<funca>:
nop -> addi sp, sp, -SZREG
nop -> REG_S ra, (sp)
nop -> auipc ra, 0x?
nop -> jalr ?(ra)
nop -> REG_L ra, (sp)
nop -> addi sp, sp, -SZREG
...to:
<funca>:
nop -> REG_S ra, -SZREG(sp)
nop -> auipc ra, 0x?
nop -> jalr ?(ra)
nop -> REG_L ra, -SZREG(sp)
...It's wrong to change the sp in callsite, because when you change the value of ra then the sp is broken and the same with HAVE_OPTPROBES.
The patchset includes kprobe/uprobe support and some related fixups. Patrick provides HAVE_REGS_AND_STACK_ACCESS_API support and some kprobe's code. The framework of k/uprobe is from csky but also refers to other arches'. kprobes on ftrace is also supported in the patchset. Modify dynamic ftrace mechanism from mcount to fentry.
There is no single step exception in riscv ISA, only single-step facility for jtag. See riscv-Privileged spec:
Interrupt Exception Code-Description
1 0 Reserved
1 1 Supervisor software interrupt
1 2–4 Reserved
1 5 Supervisor timer interrupt
1 6–8 Reserved
1 9 Supervisor external interrupt
1 10–15 Reserved
1 ≥16 Available for platform use
0 0 Instruction address misaligned
0 1 Instruction access fault
0 2 Illegal instruction
0 3 Breakpoint
0 4 Load address misaligned
0 5 Load access fault
0 6 Store/AMO address misaligned
0 7 Store/AMO access fault
0 8 Environment call from U-mode
0 9 Environment call from S-mode
0 10–11 Reserved
0 12 Instruction page fault
0 13 Load page fault
0 14 Reserved
0 15 Store/AMO page fault
0 16–23 Reserved
0 24–31 Available for custom use
0 32–47 Reserved
0 48–63 Available for custom use
0 ≥64 Reserved
No single step!
Other arches use hardware single-step exception for k/uprobe, eg:
- powerpc: regs->msr |= MSR_SINGLESTEP
- arm/arm64: PSTATE.D for enabling software step exceptions
- s390: Set PER control regs, turns on single step for the given address
- x86: regs->flags |= X86_EFLAGS_TF
- csky: of course use hw single step :)
All the above arches use a hardware single-step exception mechanism to execute the instruction that was replaced with a probe breakpoint. So utilize ebreak to simulate.
Some pc related instructions couldn't be executed out of line and some system/fence instructions couldn't be a trace site at all. So we give out a reject list and simulate list in decode-insn.c.
You could use uprobe to test simulate code like this:
echo 'p:enter_current_state_one /hello:0x6e4 a0=%a0 a1=%a1' >> /sys/kernel/debug/tracing/uprobe_events echo 1 > /sys/kernel/debug/tracing/events/uprobes/enable
/hello
^C
cat /sys/kernel/debug/tracing/trace
tracer: nop
entries-in-buffer/entries-written: 1/1 #P:1
_-----=> irqs-off
/ _----=> need-resched
| / _---=> hardirq/softirq
|| / _--=> preempt-depth
||| / delay
TASK-PID CPU# |||| TIMESTAMP FUNCTION
| | | |||| | |
hello-94 [000] d... 55.404242: enter_current_state_one: (0x106e4) a0=0x1 a1=0x3fffa8ada8Be care /hello:0x6e4 is the file offset in elf and it relate to 0x106e4 in memory and hello is your target elf program.
Try kprobe like this:
echo 'p:myprobe sys_clone a0=%a0 a1=%a1 a2=%a2 a3=%a3 stach_val=+4($stack)' > /sys/kernel/debug/tracing/kprobe_events echo 'r:myretprobe sys_clone $retval' >> /sys/kernel/debug/tracing/kprobe_events
echo 1 > /sys/kernel/debug/tracing/events/kprobes/enable
cat /sys/kernel/debug/tracing/trace
tracer: nop
entries-in-buffer/entries-written: 2/2 #P:1
_-----=> irqs-off
/ _----=> need-resched
| / _---=> hardirq/softirq
|| / _--=> preempt-depth
||| / delay
TASK-PID CPU# |||| TIMESTAMP FUNCTION
| | | |||| | |
sh-92 [000] .n.. 8506.435857: myprobe: (sys_clone+0x0/0x28) a0=0x1200011 a1=0x0 a2=0x0 a3=0x0 stach_val=0x2044ecffffffe0
sh-92 [000] d... 8506.445620: myretprobe: (ret_from_syscall+0x0/0x2 <- sys_clone) arg1=0x64Changlog v5:
- Fixup fentry modified sp cause fail_inject error
- Fixup function_graph broken
- Update to linux-5.10
- Fixup checkpatch.pl issues
Changlog v4:
- Revert fixup kprobes handler couldn't change pc
- Using PATCHABLE_FUNCTION_ENTRY instead of MCOUNT
- rebase on linux-tree:
commit 071a0578b0ce0b0e543d1e38ee6926b9cc21c198
Merge: fad7011 be4df0c
Author: Linus Torvalds <[email protected]>
Date: Fri Oct 16 15:29:46 2020 -0700
Merge tag 'ovl-update-5.10' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs
Changlog v3:
- Add upport for function error injection
- Fixup kprobes handler couldn't change pc
Changlog v2:
- Add Reviewed-by, Tested-by, Acked-by, thx for all of you
- Add kprobes on ftrace feature
- Use __always_inline as same as fix_to_virt for fixup BUILD_BUG_ON
- Use const "const unsigned int" for 2th param for fixup BUILD_BUG_ON
Guo Ren (8):
riscv: Fixup compile error BUILD_BUG_ON failed
riscv: Fixup wrong ftrace remove cflag
riscv: Fixup patch_text panic in ftrace
riscv: Using PATCHABLE_FUNCTION_ENTRY instead of MCOUNT
riscv: Add kprobes supported
riscv: Add KPROBES_ON_FTRACE supported
riscv: Add uprobes supported
riscv: Add support for function error injection
Patrick Stählin (1):
RISC-V: Implement ptrace regs and stack API
arch/riscv/Kconfig | 8 + arch/riscv/Makefile | 2 + arch/riscv/include/asm/kprobes.h | 40 +++ arch/riscv/include/asm/probes.h | 24 ++ arch/riscv/include/asm/processor.h | 1 + arch/riscv/include/asm/ptrace.h | 35 +++ arch/riscv/include/asm/thread_info.h | 4 +- arch/riscv/include/asm/uprobes.h | 40 +++ arch/riscv/kernel/Makefile | 6 +- arch/riscv/kernel/ftrace.c | 95 +++--- arch/riscv/kernel/mcount-dyn.S | 342 ++++++++++------------ arch/riscv/kernel/patch.c | 8 +- arch/riscv/kernel/probes/Makefile | 6 + arch/riscv/kernel/probes/decode-insn.c | 48 ++++ arch/riscv/kernel/probes/decode-insn.h | 18 ++ arch/riscv/kernel/probes/ftrace.c | 53 ++++ arch/riscv/kernel/probes/kprobes.c | 398 ++++++++++++++++++++++++++ arch/riscv/kernel/probes/kprobes_trampoline.S | 93 ++++++ arch/riscv/kernel/probes/simulate-insn.c | 85 ++++++ arch/riscv/kernel/probes/simulate-insn.h | 47 +++ arch/riscv/kernel/probes/uprobes.c | 186 ++++++++++++ arch/riscv/kernel/ptrace.c | 99 +++++++ arch/riscv/kernel/signal.c | 3 + arch/riscv/kernel/traps.c | 19 ++ arch/riscv/lib/Makefile | 2 + arch/riscv/lib/error-inject.c | 10 + arch/riscv/mm/Makefile | 3 +- arch/riscv/mm/fault.c | 10 + 28 files changed, 1444 insertions(+), 241 deletions(-) create mode 100644 arch/riscv/include/asm/probes.h create mode 100644 arch/riscv/include/asm/uprobes.h create mode 100644 arch/riscv/kernel/probes/Makefile create mode 100644 arch/riscv/kernel/probes/decode-insn.c create mode 100644 arch/riscv/kernel/probes/decode-insn.h create mode 100644 arch/riscv/kernel/probes/ftrace.c create mode 100644 arch/riscv/kernel/probes/kprobes.c create mode 100644 arch/riscv/kernel/probes/kprobes_trampoline.S create mode 100644 arch/riscv/kernel/probes/simulate-insn.c create mode 100644 arch/riscv/kernel/probes/simulate-insn.h create mode 100644 arch/riscv/kernel/probes/uprobes.c create mode 100644 arch/riscv/lib/error-inject.c
Signature · 7 lines
2.7.4 _______________________________________________ linux-riscv mailing list [email protected] http://lists.infradead.org/mailman/listinfo/linux-riscv
[email protected]
maintainerPATCH v5 1/9 RISC-V: Implement ptrace regs and stack API
From: Patrick Stählin <[email protected]>
Needed for kprobes support. Copied and adapted from arm64 code.
Guo Ren fixup pt_regs type for linux-5.8-rc1.
--- arch/riscv/Kconfig | 1 + arch/riscv/include/asm/ptrace.h | 29 ++++++++++++ arch/riscv/kernel/ptrace.c | 99 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 129 insertions(+)
arch/riscv/Kconfig +1 -0
@@ -72,6 +72,7 @@ config RISCV select HAVE_PERF_EVENTS select HAVE_PERF_REGS select HAVE_PERF_USER_STACK_DUMP + select HAVE_REGS_AND_STACK_ACCESS_API select HAVE_STACKPROTECTOR select HAVE_SYSCALL_TRACEPOINTS select IRQ_DOMAIN
arch/riscv/include/asm/ptrace.h +29 -0
@@ -8,6 +8,7 @@#include <uapi/asm/ptrace.h> #include <asm/csr.h> +#include <linux/compiler.h> #ifndef __ASSEMBLY__
@@ -60,6 +61,7 @@ struct pt_regs {#define user_mode (regs) (((regs)->status & SR_PP) == 0) +#define MAX_REG_OFFSET offsetof(struct pt_regs, orig_a0)/* Helpers for working with the instruction pointer */ static inline unsigned long instruction_pointer (struct pt_regs *regs)
@@ -85,6 +87,12 @@ static inline void user_stack_pointer_set(struct pt_regs *regs, regs->sp = val; } +/* Valid only for Kernel mode traps. */ +static inline unsigned long kernel_stack_pointer (struct pt_regs *regs) +{ +return regs->sp; +} +/* Helpers for working with the frame pointer */ static inline unsigned long frame_pointer (struct pt_regs *regs) {
@@ -101,6 +109,27 @@ static inline unsigned long regs_return_value(struct pt_regs *regs)return regs->a0; } +extern int regs_query_register_offset (const char *name); +extern unsigned long regs_get_kernel_stack_nth (struct pt_regs *regs, +unsigned int n); + +/** +* regs_get_register() - get register value from its offset +* @regs: pt_regs from which register value is gotten +* @offset: offset of the register. +* +* regs_get_register returns the value of a register whose offset from @regs. +* The @offset is the offset of the register in struct pt_regs. +* If @offset is bigger than MAX_REG_OFFSET, this returns 0. +*/ +static inline unsigned long regs_get_register (struct pt_regs *regs, +unsigned int offset) +{ +if (unlikely (offset >MAX_REG_OFFSET )) +return 0 ; + +return *(unsigned long *)((unsigned long )regs + offset); +}#endif /* __ASSEMBLY__ */ #endif /* _ASM_RISCV_PTRACE_H */
arch/riscv/kernel/ptrace.c +99 -0
105 lines not on this page · raw message
Signature · 7 lines
2.7.4 _______________________________________________ linux-riscv mailing list [email protected] http://lists.infradead.org/mailman/listinfo/linux-riscv
[email protected]
maintainerPATCH v5 2/9 riscv: Fixup compile error BUILD_BUG_ON failed
In reply to [email protected]From: Guo Ren <[email protected]>
Unfortunately, the current code couldn't be compiled:
CC arch/riscv/kernel/patch.o
In file included from ./include/linux/kernel.h:11,
from ./include/linux/list.h:9,
from ./include/linux/preempt.h:11,
from ./include/linux/spinlock.h:51,
from arch/riscv/kernel/patch.c:6:In function ‘fix_to_virt’,
inlined from ‘patch_map’ at arch/riscv/kernel/patch.c:37:17:./include/linux/compiler.h:392:38: error: call to ‘__compiletime_assert_205’ declared with attribute error: BUILD_BUG_ON failed: idx >= __end_of_fixed_addresses
_compiletime_assert(condition, msg, __compiletime_assert_, __COUNTER__)
^
./include/linux/compiler.h:373:4: note: in definition of macro ‘__compiletime_assert’
prefix ## suffix(); \
^~~~~~./include/linux/compiler.h:392:2: note: in expansion of macro ‘_compiletime_assert’
_compiletime_assert(condition, msg, __compiletime_assert_, __COUNTER__) ^~~~~~~~~~~~~~~~~~~./include/linux/build_bug.h:39:37: note: in expansion of macro ‘compiletime_assert’
#define BUILD_BUG_ON_MSG(cond, msg) compiletime_assert(!(cond), msg)
^~~~~~~~~~~~~~~~~~./include/linux/build_bug.h:50:2: note: in expansion of macro ‘BUILD_BUG_ON_MSG’
BUILD_BUG_ON_MSG(condition, "BUILD_BUG_ON failed: " #condition) ^~~~~~~~~~~~~~~~./include/asm-generic/fixmap.h:32:2: note: in expansion of macro ‘BUILD_BUG_ON’
BUILD_BUG_ON(idx >= __end_of_fixed_addresses);
^~~~~~~~~~~~
Because fix_to_virt(, idx) needs a const value, not a dynamic variable of reg-a0 or BUILD_BUG_ON failed with "idx >= __end_of_fixed_addresses".
--- arch/riscv/kernel/patch.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
arch/riscv/kernel/patch.c +6 -2
@@ -20,7 +20,12 @@ struct patch_insn { };#ifdef CONFIG_MMU -static void *patch_map (void *addr,int fixmap) +/* +* The fix_to_virt(, idx) needs a const value (not a dynamic variable of +* reg-a0) or BUILD_BUG_ON failed with "idx >= __end_of_fixed_addresses". +* So use '__always_inline' and 'const unsigned int fixmap' here. +*/ +static __always_inline void *patch_map(void *addr, const unsigned int fixmap) {uintptr_t uintaddr = (uintptr_t ) addr;struct page *page;
@@ -37,7 +42,6 @@ static void *patch_map(void *addr, int fixmap)return (void *)set_fixmap_offset (fixmap,page_to_phys (page) + (uintaddr & ~PAGE_MASK )); } -NOKPROBE_SYMBOL (patch_map);static void patch_unmap (int fixmap) {
Signature · 7 lines
2.7.4 _______________________________________________ linux-riscv mailing list [email protected] http://lists.infradead.org/mailman/listinfo/linux-riscv
[email protected]
maintainerPATCH v5 3/9 riscv: Fixup wrong ftrace remove cflag
In reply to [email protected]From: Guo Ren <[email protected]>
We must use $(CC_FLAGS_FTRACE) instead of directly using -pg. It will cause -fpatchable-function-entry error.
--- arch/riscv/kernel/Makefile | 4 ++-- arch/riscv/mm/Makefile | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-)
arch/riscv/kernel/Makefile +2 -2
@@ -4,8 +4,8 @@ # ifdef CONFIG_FTRACE -CFLAGS_REMOVE_ftrace.o = -pg -CFLAGS_REMOVE_patch.o = -pg +CFLAGS_REMOVE_ftrace.o = $(CC_FLAGS_FTRACE) +CFLAGS_REMOVE_patch.o = $(CC_FLAGS_FTRACE) endif extra-y += head.o
arch/riscv/mm/Makefile +1 -1
@@ -2,7 +2,7 @@ CFLAGS_init.o := -mcmodel=medany ifdef CONFIG_FTRACE -CFLAGS_REMOVE_init.o = -pg +CFLAGS_REMOVE_init.o = $(CC_FLAGS_FTRACE) endif KCOV_INSTRUMENT_init.o := n
Signature · 7 lines
2.7.4 _______________________________________________ linux-riscv mailing list [email protected] http://lists.infradead.org/mailman/listinfo/linux-riscv
[email protected]
maintainerPATCH v5 4/9 riscv: Fixup patch_text panic in ftrace
In reply to [email protected]From: Guo Ren <[email protected]>
Just like arm64, we can't trace the function in the patch_text path.
Here is the bug log:
[ 45.234334] Unable to handle kernel paging request at virtual address ffffffd38ae80900 [ 45.242313] Oops [#1] [ 45.244600] Modules linked in: [ 45.247678] CPU: 0 PID: 11 Comm: migration/0 Not tainted 5.9.0-00025-g9b7db83-dirty #215 [ 45.255797] epc: ffffffe00021689a ra : ffffffe00021718e sp : ffffffe01afabb58 [ 45.262955] gp : ffffffe00136afa0 tp : ffffffe01af94d00 t0 : 0000000000000002 [ 45.270200] t1 : 0000000000000000 t2 : 0000000000000001 s0 : ffffffe01afabc08 [ 45.277443] s1 : ffffffe0013718a8 a0 : 0000000000000000 a1 : ffffffe01afabba8 [ 45.284686] a2 : 0000000000000000 a3 : 0000000000000000 a4 : c4c16ad38ae80900 [ 45.291929] a5 : 0000000000000000 a6 : 0000000000000000 a7 : 0000000052464e43 [ 45.299173] s2 : 0000000000000001 s3 : ffffffe000206a60 s4 : ffffffe000206a60 [ 45.306415] s5 : 00000000000009ec s6 : ffffffe0013718a8 s7 : c4c16ad38ae80900 [ 45.313658] s8 : 0000000000000004 s9 : 0000000000000001 s10: 0000000000000001 [ 45.320902] s11: 0000000000000003 t3 : 0000000000000001 t4 : ffffffffd192fe79 [ 45.328144] t5 : ffffffffb8f80000 t6 : 0000000000040000 [ 45.333472] status: 0000000200000100 badaddr: ffffffd38ae80900 cause: 000000000000000f [ 45.341514] ---[ end trace d95102172248fdcf ]--- [ 45.346176] note: migration/0[11] exited with preempt_count 1
(gdb) x /2i $pc
=> 0xffffffe00021689a <__do_proc_dointvec+196>: sd zero,0(s7)
0xffffffe00021689e <__do_proc_dointvec+200>: li s11,0
(gdb) bt
0 __do_proc_dointvec (tbl_data=0x0, table=0xffffffe01afabba8, write=0, buffer=0x0, lenp=0x7bf897061f9a0800, ppos=0x4, conv=0x0, data=0x52464e43) at kernel/sysctl.c:581
1 0xffffffe00021718e in do_proc_dointvec (data=<optimized out>, conv=<optimized out>, ppos=<optimized out>, lenp=<optimized out>, buffer=<optimized out>, write=<optimized out>, table=<optimized out>) at kernel/sysctl.c:964
2 proc_dointvec_minmax (ppos=<optimized out>, lenp=<optimized out>, buffer=<optimized out>, write=<optimized out>, table=<optimized out>) at kernel/sysctl.c:964
3 proc_do_static_key (table=<optimized out>, write=1, buffer=0x0, lenp=0x0, ppos=0x7bf897061f9a0800) at kernel/sysctl.c:1643
4 0xffffffe000206792 in ftrace_make_call (rec=<optimized out>, addr=<optimized out>) at arch/riscv/kernel/ftrace.c:109
5 0xffffffe0002c9c04 in __ftrace_replace_code (rec=0xffffffe01ae40c30, enable=3) at kernel/trace/ftrace.c:2503
6 0xffffffe0002ca0b2 in ftrace_replace_code (mod_flags=<optimized out>) at kernel/trace/ftrace.c:2530
7 0xffffffe0002ca26a in ftrace_modify_all_code (command=5) at kernel/trace/ftrace.c:2677
8 0xffffffe0002ca30e in __ftrace_modify_code (data=<optimized out>) at kernel/trace/ftrace.c:2703
9 0xffffffe0002c13b0 in multi_cpu_stop (data=0x0) at kernel/stop_machine.c:224 10 0xffffffe0002c0fde in cpu_stopper_thread (cpu=<optimized out>) at kernel/stop_machine.c:491
11 0xffffffe0002343de in smpboot_thread_fn (data=0x0) at kernel/smpboot.c:165 12 0xffffffe00022f8b4 in kthread (_create=0xffffffe01af0c040) at kernel/kthread.c:292
13 0xffffffe000201fac in handle_exception () at arch/riscv/kernel/entry.S:236
0xffffffe00020678a <+114>: auipc ra,0xffffe 0xffffffe00020678e <+118>: jalr -118(ra) # 0xffffffe000204714 <patch_text_nosync> 0xffffffe000206792 <+122>: snez a0,a0
(gdb) disassemble patch_text_nosync
Dump of assembler code for function patch_text_nosync:
0xffffffe000204714 <+0>: addi sp,sp,-32 0xffffffe000204716 <+2>: sd s0,16(sp) 0xffffffe000204718 <+4>: sd ra,24(sp) 0xffffffe00020471a <+6>: addi s0,sp,32 0xffffffe00020471c <+8>: auipc ra,0x0 0xffffffe000204720 <+12>: jalr -384(ra) # 0xffffffe00020459c <patch_insn_write> 0xffffffe000204724 <+16>: beqz a0,0xffffffe00020472e <patch_text_nosync+26> 0xffffffe000204726 <+18>: ld ra,24(sp) 0xffffffe000204728 <+20>: ld s0,16(sp) 0xffffffe00020472a <+22>: addi sp,sp,32 0xffffffe00020472c <+24>: ret 0xffffffe00020472e <+26>: sd a0,-24(s0) 0xffffffe000204732 <+30>: auipc ra,0x4 0xffffffe000204736 <+34>: jalr -1464(ra) # 0xffffffe00020817a <flush_icache_all> 0xffffffe00020473a <+38>: ld a0,-24(s0) 0xffffffe00020473e <+42>: ld ra,24(sp) 0xffffffe000204740 <+44>: ld s0,16(sp) 0xffffffe000204742 <+46>: addi sp,sp,32 0xffffffe000204744 <+48>: ret
(gdb) disassemble flush_icache_all-4
Dump of assembler code for function flush_icache_all:
0xffffffe00020817a <+0>: addi sp,sp,-8 0xffffffe00020817c <+2>: sd ra,0(sp) 0xffffffe00020817e <+4>: auipc ra,0xfffff 0xffffffe000208182 <+8>: jalr -1822(ra) # 0xffffffe000206a60 <ftrace_caller> 0xffffffe000208186 <+12>: ld ra,0(sp) 0xffffffe000208188 <+14>: addi sp,sp,8 0xffffffe00020818a <+0>: addi sp,sp,-16 0xffffffe00020818c <+2>: sd s0,0(sp) 0xffffffe00020818e <+4>: sd ra,8(sp) 0xffffffe000208190 <+6>: addi s0,sp,16 0xffffffe000208192 <+8>: li a0,0 0xffffffe000208194 <+10>: auipc ra,0xfffff 0xffffffe000208198 <+14>: jalr -410(ra) # 0xffffffe000206ffa <sbi_remote_fence_i> 0xffffffe00020819c <+18>: ld s0,0(sp) 0xffffffe00020819e <+20>: ld ra,8(sp) 0xffffffe0002081a0 <+22>: addi sp,sp,16 0xffffffe0002081a2 <+24>: ret
(gdb) frame 5
(rec=0xffffffe01ae40c30, enable=3) at kernel/trace/ftrace.c:2503
2503 return ftrace_make_call(rec, ftrace_addr);
(gdb) p /x rec->ip
$2 = 0xffffffe00020817a -> flush_icache_all !
When we modified flush_icache_all's patchable-entry with ftrace_caller:
- Insert ftrace_caller at flush_icache_all prologue.
- Call flush_icache_all to sync I/Dcache, but flush_icache_all is
just we modified by half.
--- arch/riscv/kernel/Makefile | 1 + arch/riscv/mm/Makefile | 1 + 2 files changed, 2 insertions(+)
arch/riscv/kernel/Makefile +1 -0
@@ -6,6 +6,7 @@ ifdef CONFIG_FTRACE CFLAGS_REMOVE_ftrace.o = $(CC_FLAGS_FTRACE) CFLAGS_REMOVE_patch.o = $(CC_FLAGS_FTRACE) +CFLAGS_REMOVE_sbi.o = $(CC_FLAGS_FTRACE) endif extra-y += head.o
arch/riscv/mm/Makefile +1 -0
@@ -3,6 +3,7 @@ CFLAGS_init.o := -mcmodel=medany ifdef CONFIG_FTRACE CFLAGS_REMOVE_init.o = $(CC_FLAGS_FTRACE) +CFLAGS_REMOVE_cacheflush.o = $(CC_FLAGS_FTRACE) endif KCOV_INSTRUMENT_init.o := n
Signature · 7 lines
2.7.4 _______________________________________________ linux-riscv mailing list [email protected] http://lists.infradead.org/mailman/listinfo/linux-riscv
Re: [PATCH v5 4/9] riscv: Fixup patch_text panic in ftrace
Quoted 155 lines · On Thu, Dec 17, 2020 at 8:04 AM <[email protected]> wrote:
From: Guo Ren <[email protected]>
Just like arm64, we can't trace the function in the
patch_textpath.Here is the bug log:
[ 45.234334] Unable to handle kernel paging request at virtual address ffffffd38ae80900 [ 45.242313] Oops [#1] [ 45.244600] Modules linked in: [ 45.247678] CPU: 0 PID: 11 Comm: migration/0 Not tainted 5.9.0-00025-g9b7db83-dirty #215 [ 45.255797] epc: ffffffe00021689a ra : ffffffe00021718e sp : ffffffe01afabb58 [ 45.262955] gp : ffffffe00136afa0 tp : ffffffe01af94d00 t0 : 0000000000000002 [ 45.270200] t1 : 0000000000000000 t2 : 0000000000000001 s0 : ffffffe01afabc08 [ 45.277443] s1 : ffffffe0013718a8 a0 : 0000000000000000 a1 : ffffffe01afabba8 [ 45.284686] a2 : 0000000000000000 a3 : 0000000000000000 a4 : c4c16ad38ae80900 [ 45.291929] a5 : 0000000000000000 a6 : 0000000000000000 a7 : 0000000052464e43 [ 45.299173] s2 : 0000000000000001 s3 : ffffffe000206a60 s4 : ffffffe000206a60 [ 45.306415] s5 : 00000000000009ec s6 : ffffffe0013718a8 s7 : c4c16ad38ae80900 [ 45.313658] s8 : 0000000000000004 s9 : 0000000000000001 s10: 0000000000000001 [ 45.320902] s11: 0000000000000003 t3 : 0000000000000001 t4 : ffffffffd192fe79 [ 45.328144] t5 : ffffffffb8f80000 t6 : 0000000000040000 [ 45.333472] status: 0000000200000100 badaddr: ffffffd38ae80900 cause: 000000000000000f [ 45.341514] ---[ end trace d95102172248fdcf ]--- [ 45.346176] note: migration/0[11] exited with preempt_count 1(gdb) x /2i $pc
=>0xffffffe00021689a<__do_proc_dointvec+196>: sd zero,0(s7)
0xffffffe00021689e<__do_proc_dointvec+200>: li s11,0(gdb) bt
0__do_proc_dointvec(tbl_data=0x0, table=0xffffffe01afabba8, write=0, buffer=0x0, lenp=0x7bf897061f9a0800, ppos=0x4, conv=0x0, data=0x52464e43) atkernel/sysctl.c:581
10xffffffe00021718eindo_proc_dointvec(data=<optimized out>, conv=<optimized out>, ppos=<optimized out>, lenp=<optimized out>, buffer=<optimized out>, write=<optimized out>, table=<optimized out>) atkernel/sysctl.c:964
2proc_dointvec_minmax(ppos=<optimized out>, lenp=<optimized out>, buffer=<optimized out>, write=<optimized out>, table=<optimized out>) atkernel/sysctl.c:964
3proc_do_static_key(table=<optimized out>, write=1, buffer=0x0, lenp=0x0, ppos=0x7bf897061f9a0800) atkernel/sysctl.c:1643
40xffffffe000206792inftrace_make_call(rec=<optimized out>, addr=<optimized out>) atarch/riscv/kernel/ftrace.c:109
50xffffffe0002c9c04in__ftrace_replace_code(rec=0xffffffe01ae40c30, enable=3) atkernel/trace/ftrace.c:2503
60xffffffe0002ca0b2inftrace_replace_code(mod_flags=<optimized out>) atkernel/trace/ftrace.c:2530
70xffffffe0002ca26ainftrace_modify_all_code(command=5) atkernel/trace/ftrace.c:2677
80xffffffe0002ca30ein__ftrace_modify_code(data=<optimized out>) atkernel/trace/ftrace.c:2703
90xffffffe0002c13b0inmulti_cpu_stop(data=0x0) atkernel/stop_machine.c:224100xffffffe0002c0fdeincpu_stopper_thread(cpu=<optimized out>) atkernel/stop_machine.c:491
110xffffffe0002343deinsmpboot_thread_fn(data=0x0) atkernel/smpboot.c:165120xffffffe00022f8b4in kthread (_create=0xffffffe01af0c040) atkernel/kthread.c:292
130xffffffe000201facinhandle_exception() atarch/riscv/kernel/entry.S:2360xffffffe00020678a <+114>: auipc ra,0xffffe 0xffffffe00020678e <+118>: jalr -118(ra) # 0xffffffe000204714 <patch_text_nosync> 0xffffffe000206792 <+122>: snez a0,a0(gdb) disassemble
patch_text_nosync
Dump of assembler code for functionpatch_text_nosync:0xffffffe000204714 <+0>: addi sp,sp,-32 0xffffffe000204716 <+2>: sd s0,16(sp) 0xffffffe000204718 <+4>: sd ra,24(sp) 0xffffffe00020471a <+6>: addi s0,sp,32 0xffffffe00020471c <+8>: auipc ra,0x0 0xffffffe000204720 <+12>: jalr -384(ra) # 0xffffffe00020459c <patch_insn_write> 0xffffffe000204724 <+16>: beqz a0,0xffffffe00020472e <patch_text_nosync+26> 0xffffffe000204726 <+18>: ld ra,24(sp) 0xffffffe000204728 <+20>: ld s0,16(sp) 0xffffffe00020472a <+22>: addi sp,sp,32 0xffffffe00020472c <+24>: ret 0xffffffe00020472e <+26>: sd a0,-24(s0) 0xffffffe000204732 <+30>: auipc ra,0x4 0xffffffe000204736 <+34>: jalr -1464(ra) # 0xffffffe00020817a <flush_icache_all> 0xffffffe00020473a <+38>: ld a0,-24(s0) 0xffffffe00020473e <+42>: ld ra,24(sp) 0xffffffe000204740 <+44>: ld s0,16(sp) 0xffffffe000204742 <+46>: addi sp,sp,32 0xffffffe000204744 <+48>: ret(gdb) disassemble flush_icache_all-4
Dump of assembler code for functionflush_icache_all:0xffffffe00020817a <+0>: addi sp,sp,-8 0xffffffe00020817c <+2>: sd ra,0(sp) 0xffffffe00020817e <+4>: auipc ra,0xfffff 0xffffffe000208182 <+8>: jalr -1822(ra) # 0xffffffe000206a60 <ftrace_caller> 0xffffffe000208186 <+12>: ld ra,0(sp) 0xffffffe000208188 <+14>: addi sp,sp,8 0xffffffe00020818a <+0>: addi sp,sp,-16 0xffffffe00020818c <+2>: sd s0,0(sp) 0xffffffe00020818e <+4>: sd ra,8(sp) 0xffffffe000208190 <+6>: addi s0,sp,16 0xffffffe000208192 <+8>: li a0,0 0xffffffe000208194 <+10>: auipc ra,0xfffff 0xffffffe000208198 <+14>: jalr -410(ra) # 0xffffffe000206ffa <sbi_remote_fence_i> 0xffffffe00020819c <+18>: ld s0,0(sp) 0xffffffe00020819e <+20>: ld ra,8(sp) 0xffffffe0002081a0 <+22>: addi sp,sp,16 0xffffffe0002081a2 <+24>: ret(gdb) frame 5
(rec=0xffffffe01ae40c30, enable=3) atkernel/trace/ftrace.c:2503
2503 returnftrace_make_call(rec, ftrace_addr);
(gdb) p /xrec->ip
$2 =0xffffffe00020817a->flush_icache_all!When we modified flush_icache_all's patchable-entry with
ftrace_caller:
- Insertftrace_calleratflush_icache_allprologue.
- Callflush_icache_allto sync I/Dcache, butflush_icache_allis
just we modified by half.Link https://lore.kernel.org/linux-riscv/CAJF2gTT=oDWesWe0JVWvTpGi60-gpbNhYLdFWN_5EbyeqoEDdw@mail.gmail.com/T/#t open hereSigned-off-by Guo Ren <[email protected]>Cc Atish Patra <[email protected]>Cc Steven Rostedt (VMware) <[email protected]>--- arch/riscv/kernel/Makefile | 1 + arch/riscv/mm/Makefile | 1 + 2 files changed, 2 insertions(+)arch/riscv/kernel/Makefile +1
-0@@ -6,6 +6,7 @@ ifdef CONFIG_FTRACE CFLAGS_REMOVE_ftrace.o = $(CC_FLAGS_FTRACE) CFLAGS_REMOVE_patch.o = $(CC_FLAGS_FTRACE) +CFLAGS_REMOVE_sbi.o = $(CC_FLAGS_FTRACE) endif extra-y += head.oarch/riscv/mm/Makefile +1
-1@@ -3,6 +3,7 @@ CFLAGS_init.o := -mcmodel=medany ifdef CONFIG_FTRACE CFLAGS_REMOVE_init.o = $(CC_FLAGS_FTRACE) +CFLAGS_REMOVE_cacheflush.o = $(CC_FLAGS_FTRACE) endif KCOV_INSTRUMENT_init.o := n --2.7.4
Quoted 4 lines
_______________________________________________
linux-riscv mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-riscv
Signature · 7 lines
Regards, Atish _______________________________________________ linux-riscv mailing list [email protected] http://lists.infradead.org/mailman/listinfo/linux-riscv
[email protected]
maintainerPATCH v5 5/9 riscv: Using PATCHABLE_FUNCTION_ENTRY instead of MCOUNT
In reply to [email protected]From: Guo Ren <[email protected]>
This patch changes the current detour mechanism of dynamic ftrace which has been discussed during LPC 2020 RISCV-MC [1].
Before the patch, we used mcount for detour:
<funca>:
addi sp,sp,-16 sd ra,8(sp) sd s0,0(sp) addi s0,sp,16 mv a5,ra mv a0,a5 auipc ra,0x0 -> nop jalr -296(ra) <_mcount@plt> ->nop ...
After the patch, we use nop call site area for detour:
<funca>:
nop -> REG_S ra, -SZREG(sp) nop -> auipc ra, 0x? nop -> jalr ?(ra) nop -> REG_L ra, -SZREG(sp) ...
The mcount mechanism is mixed with gcc function prologue which is not very clear. The patchable function entry just put 16 bytes nop before the front of the function prologue which could be filled with a separated detour mechanism.
[1] https://www.linuxplumbersconf.org/event/7/contributions/807/
--- arch/riscv/Makefile | 2 + arch/riscv/kernel/ftrace.c | 95 ++++++------ arch/riscv/kernel/mcount-dyn.S | 342 ++++++++++++++++++----------------------- 3 files changed, 204 insertions(+), 235 deletions(-)
arch/riscv/Makefile +2 -0
@@ -12,6 +12,8 @@ OBJCOPYFLAGS := -O binary LDFLAGS_vmlinux := ifeq ($(CONFIG_DYNAMIC_FTRACE),y) LDFLAGS_vmlinux := --no-relax + KBUILD_CPPFLAGS += -DCC_USING_PATCHABLE_FUNCTION_ENTRY + CC_FLAGS_FTRACE := -fpatchable-function-entry=8 endif ifeq ($(CONFIG_64BIT)$(CONFIG_CMODEL_MEDLOW),yy)
arch/riscv/kernel/ftrace.c +50 -45
147 lines not on this page · raw message
arch/riscv/kernel/mcount-dyn.S +152 -190
376 lines not on this page · raw message
Signature · 7 lines
2.7.4 _______________________________________________ linux-riscv mailing list [email protected] http://lists.infradead.org/mailman/listinfo/linux-riscv
[email protected]
maintainerPATCH v5 6/9 riscv: Add kprobes supported
In reply to [email protected]From: Guo Ren <[email protected]>
This patch enables "kprobe & kretprobe" to work with ftrace interface. It utilized software breakpoint as single-step mechanism.
Some instructions which can't be single-step executed must be simulated in kernel execution slot, such as: branch, jal, auipc, la ...
Some instructions should be rejected for probing and we use a blacklist to filter, such as: ecall, ebreak, ...
We use ebreak & c.ebreak to replace origin instruction and the kprobe handler prepares an executable memory slot for out-of-line execution with a copy of the original instruction being probed. In execution slot we add ebreak behind original instruction to simulate a single-setp mechanism.
The patch is based on packi's work [1] and csky's work [2].
- The kprobes_trampoline.S is all from packi's patch
- The single-step mechanism is new designed for riscv without hw single-step trap
- The simulation codes are from csky
- Frankly, all codes refer to other archs' implementation
[1] https://lore.kernel.org/linux-riscv/[email protected]/
[2] https://lore.kernel.org/linux-csky/[email protected]/
--- arch/riscv/Kconfig | 2 + arch/riscv/include/asm/kprobes.h | 40 +++ arch/riscv/include/asm/probes.h | 24 ++ arch/riscv/kernel/Makefile | 1 + arch/riscv/kernel/probes/Makefile | 4 + arch/riscv/kernel/probes/decode-insn.c | 48 ++++ arch/riscv/kernel/probes/decode-insn.h | 18 ++ arch/riscv/kernel/probes/kprobes.c | 398 ++++++++++++++++++++++++++ arch/riscv/kernel/probes/kprobes_trampoline.S | 93 ++++++ arch/riscv/kernel/probes/simulate-insn.c | 85 ++++++ arch/riscv/kernel/probes/simulate-insn.h | 47 +++ arch/riscv/kernel/traps.c | 9 + arch/riscv/mm/fault.c | 4 + 13 files changed, 773 insertions(+) create mode 100644 arch/riscv/include/asm/probes.h create mode 100644 arch/riscv/kernel/probes/Makefile create mode 100644 arch/riscv/kernel/probes/decode-insn.c create mode 100644 arch/riscv/kernel/probes/decode-insn.h create mode 100644 arch/riscv/kernel/probes/kprobes.c create mode 100644 arch/riscv/kernel/probes/kprobes_trampoline.S create mode 100644 arch/riscv/kernel/probes/simulate-insn.c create mode 100644 arch/riscv/kernel/probes/simulate-insn.h
arch/riscv/Kconfig +2 -0
@@ -68,6 +68,8 @@ config RISCV select HAVE_FUTEX_CMPXCHG if FUTEX select HAVE_GCC_PLUGINS select HAVE_GENERIC_VDSO if MMU && 64BIT + select HAVE_KPROBES + select HAVE_KRETPROBES select HAVE_PCI select HAVE_PERF_EVENTS select HAVE_PERF_REGS
arch/riscv/include/asm/kprobes.h +40 -0
@@ -11,4 +11,44 @@#include <asm-generic/kprobes.h> +#ifdef CONFIG_KPROBES +#include <linux/types.h> +#include <linux/ptrace.h> +#include <linux/percpu.h> + +#define __ARCH_WANT_KPROBES_INSN_SLOT +#define MAX_INSN_SIZE 2 + +#define flush_insn_slot (p) do { } while (0) +#define kretprobe_blacklist_size 0 + +#include <asm/probes.h> + +struct prev_kprobe { +struct kprobe *kp; +unsigned int status; +}; + +/* Single step context for kprobe */ +struct kprobe_step_ctx { +unsigned long ss_pending; +unsigned long match_addr; +}; + +/* per-cpu kprobe control block */ +struct kprobe_ctlblk { +unsigned int kprobe_status; +unsigned long saved_status; +struct prev_kprobe prev_kprobe; +struct kprobe_step_ctx ss_ctx; +}; + +void arch_remove_kprobe (struct kprobe *p); +int kprobe_fault_handler (struct pt_regs *regs,unsigned int trapnr); +bool kprobe_breakpoint_handler (struct pt_regs *regs); +bool kprobe_single_step_handler (struct pt_regs *regs); +void kretprobe_trampoline (void ); +void __kprobes *trampoline_probe_handler (struct pt_regs *regs); + +#endif /* CONFIG_KPROBES */ #endif /* _ASM_RISCV_KPROBES_H */
arch/riscv/include/asm/probes.h new file +24 -0
@@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef _ASM_RISCV_PROBES_H +#define _ASM_RISCV_PROBES_H + +typedef u32 probe_opcode_t ; +typedef bool (probes_handler_t ) (u32 opcode,unsigned long addr,struct pt_regs *); + +/* architecture specific copy of original instruction */ +struct arch_probe_insn { +probe_opcode_t *insn; +probes_handler_t *handler; +/* restore address after simulation */ +unsigned long restore; +}; + +#ifdef CONFIG_KPROBES +typedef u32 kprobe_opcode_t ; +struct arch_specific_insn { +struct arch_probe_insn api; +}; +#endif + +#endif /* _ASM_RISCV_PROBES_H */
arch/riscv/kernel/Makefile +1 -0
@@ -30,6 +30,7 @@ obj-y += riscv_ksyms.o obj-y += stacktrace.o obj-y += cacheinfo.o obj-y += patch.o +obj-y += probes/ obj-$(CONFIG_MMU) += vdso.o vdso/ obj-$(CONFIG_RISCV_M_MODE) += traps_misaligned.o
arch/riscv/kernel/probes/Makefile new file +4 -0
@@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_KPROBES) += kprobes.o decode-insn.o simulate-insn.o +obj-$(CONFIG_KPROBES) += kprobes_trampoline.o +CFLAGS_REMOVE_simulate-insn.o = $(CC_FLAGS_FTRACE)
arch/riscv/kernel/probes/decode-insn.c new file +48 -0
48 lines not on this page · raw message
arch/riscv/kernel/probes/decode-insn.h new file +18 -0
@@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ + +#ifndef _RISCV_KERNEL_KPROBES_DECODE_INSN_H +#define _RISCV_KERNEL_KPROBES_DECODE_INSN_H + +#include <asm/sections.h> +#include <asm/kprobes.h> + +enum probe_insn { +INSN_REJECTED , +INSN_GOOD_NO_SLOT , +INSN_GOOD , +}; + +enum probe_insn __kprobes +riscv_probe_decode_insn (probe_opcode_t *addr,struct arch_probe_insn *asi); + +#endif /* _RISCV_KERNEL_KPROBES_DECODE_INSN_H */
arch/riscv/kernel/probes/kprobes.c new file +398 -0
398 lines not on this page · raw message
arch/riscv/kernel/probes/kprobes_trampoline.S new file +93 -0
93 lines not on this page · raw message
arch/riscv/kernel/probes/simulate-insn.c new file +85 -0
85 lines not on this page · raw message
arch/riscv/kernel/probes/simulate-insn.h new file +47 -0
47 lines not on this page · raw message
arch/riscv/kernel/traps.c +9 -0
@@ -12,6 +12,7 @@#include <linux/signal.h> #include <linux/kdebug.h> #include <linux/uaccess.h> +#include <linux/kprobes.h> #include <linux/mm.h> #include <linux/module.h> #include <linux/irq.h>
@@ -145,6 +146,14 @@ static inline unsigned long get_break_insn_length(unsigned long pc) asmlinkage __visible void do_trap_break(struct pt_regs *regs) { +#ifdef CONFIG_KPROBES +if (kprobe_single_step_handler (regs)) +return ; + +if (kprobe_breakpoint_handler (regs)) +return ; +#endif +if (user_mode (regs))force_sig_fault (SIGTRAP ,TRAP_BRKPT , (void __user *)regs->epc);#ifdef CONFIG_KGDB
arch/riscv/mm/fault.c +4 -0
@@ -13,6 +13,7 @@#include <linux/perf_event.h> #include <linux/signal.h> #include <linux/uaccess.h> +#include <linux/kprobes.h> #include <asm/ptrace.h> #include <asm/tlbflush.h>
@@ -202,6 +203,9 @@ asmlinkage void do_page_fault(struct pt_regs *regs) tsk = current; mm = tsk->mm; +if (kprobe_page_fault (regs, cause)) +return ; +/* * Fault-in kernel-space virtual memory on-demand. * The 'reference' page table is init_mm.pgd.
Signature · 7 lines
2.7.4 _______________________________________________ linux-riscv mailing list [email protected] http://lists.infradead.org/mailman/listinfo/linux-riscv
[email protected]
maintainerPATCH v5 7/9 riscv: Add KPROBES_ON_FTRACE supported
In reply to [email protected]From: Guo Ren <[email protected]>
This patch adds support for kprobes on ftrace call sites to avoids much of the overhead with regular kprobes. Try it with simple steps:
echo 'p:myprobe sys_clone a0=%a0 a1=%a1 stack_val=+4($stack)' > /sys/kernel/de
bug/tracing/kprobe_events
echo 1 > /sys/kernel/debug/tracing/events/kprobes/enable
cat /sys/kernel/debug/tracing/trace
tracer: nop
entries-in-buffer/entries-written: 1/1 #P:1
_-----=> irqs-off
/ _----=> need-resched
| / _---=> hardirq/softirq
|| / _--=> preempt-depth
||| / delay
TASK-PID CPU# |||| TIMESTAMP FUNCTION
| | | |||| | |
sh-92 [000] .... 369.899962: myprobe: (sys_clone+0x0/0x28) a0=0x1200011 a1=0x0 stack_val=0x201c20ffffffe0
cat /sys/kernel/debug/kprobes/list
ffffffe00020b584 k sys_clone+0x0 [FTRACE]
^^^^^^--- arch/riscv/Kconfig | 1 + arch/riscv/kernel/probes/Makefile | 1 + arch/riscv/kernel/probes/ftrace.c | 53 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+) create mode 100644 arch/riscv/kernel/probes/ftrace.c
arch/riscv/Kconfig +1 -0
@@ -69,6 +69,7 @@ config RISCV select HAVE_GCC_PLUGINS select HAVE_GENERIC_VDSO if MMU && 64BIT select HAVE_KPROBES + select HAVE_KPROBES_ON_FTRACE select HAVE_KRETPROBES select HAVE_PCI select HAVE_PERF_EVENTS
arch/riscv/kernel/probes/Makefile +1 -0
@@ -1,4 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_KPROBES) += kprobes.o decode-insn.o simulate-insn.o obj-$(CONFIG_KPROBES) += kprobes_trampoline.o +obj-$(CONFIG_KPROBES_ON_FTRACE) += ftrace.o CFLAGS_REMOVE_simulate-insn.o = $(CC_FLAGS_FTRACE)
arch/riscv/kernel/probes/ftrace.c new file +53 -0
53 lines not on this page · raw message
Signature · 7 lines
2.7.4 _______________________________________________ linux-riscv mailing list [email protected] http://lists.infradead.org/mailman/listinfo/linux-riscv
[email protected]
maintainerPATCH v5 8/9 riscv: Add uprobes supported
In reply to [email protected]From: Guo Ren <[email protected]>
This patch adds support for uprobes on riscv architecture.
Just like kprobe, it support single-step and simulate instructions.
--- arch/riscv/Kconfig | 3 + arch/riscv/include/asm/processor.h | 1 + arch/riscv/include/asm/thread_info.h | 4 +- arch/riscv/include/asm/uprobes.h | 40 ++++++++ arch/riscv/kernel/probes/Makefile | 1 + arch/riscv/kernel/probes/uprobes.c | 186 +++++++++++++++++++++++++++++++++++ arch/riscv/kernel/signal.c | 3 + arch/riscv/kernel/traps.c | 10 ++ arch/riscv/mm/fault.c | 6 ++ 9 files changed, 253 insertions(+), 1 deletion(-) create mode 100644 arch/riscv/include/asm/uprobes.h create mode 100644 arch/riscv/kernel/probes/uprobes.c
arch/riscv/Kconfig +3 -0
@@ -160,6 +160,9 @@ config ARCH_WANT_GENERAL_HUGETLB config ARCH_SUPPORTS_DEBUG_PAGEALLOC def_bool y +config ARCH_SUPPORTS_UPROBES + def_bool y + config SYS_SUPPORTS_HUGETLBFS depends on MMU def_bool y
arch/riscv/include/asm/processor.h +1 -0
@@ -34,6 +34,7 @@ struct thread_struct {unsigned long sp;/* Kernel mode stack */ unsigned long s[12 ];/* s[0]: frame pointer */ struct __riscv_d_ext_state fstate; +unsigned long bad_cause; };#define INIT_THREAD { \
arch/riscv/include/asm/thread_info.h +3 -1
@@ -74,6 +74,7 @@ struct thread_info {#define TIF_SYSCALL_TRACEPOINT 6/* syscall tracepoint instrumentation */ #define TIF_SYSCALL_AUDIT 7/* syscall auditing */ #define TIF_SECCOMP 8/* syscall secure computing */ +#define TIF_UPROBE 9/* uprobe breakpoint or singlestep */ #define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE)#define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME)
@@ -82,9 +83,10 @@ struct thread_info {#define _TIF_SYSCALL_TRACEPOINT (1 << TIF_SYSCALL_TRACEPOINT)#define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT)#define _TIF_SECCOMP (1 << TIF_SECCOMP) +#define _TIF_UPROBE (1 << TIF_UPROBE)#define _TIF_WORK_MASK \ - (_TIF_NOTIFY_RESUME | _TIF_SIGPENDING | _TIF_NEED_RESCHED) + (_TIF_NOTIFY_RESUME | _TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_UPROBE)#define _TIF_SYSCALL_WORK \ (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_TRACEPOINT | _TIF_SYSCALL_AUDIT | \
arch/riscv/include/asm/uprobes.h new file +40 -0
@@ -0,0 +1,40 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef _ASM_RISCV_UPROBES_H +#define _ASM_RISCV_UPROBES_H + +#include <asm/probes.h> +#include <asm/patch.h> +#include <asm/bug.h> + +#define MAX_UINSN_BYTES 8 + +#ifdef CONFIG_RISCV_ISA_C +#define UPROBE_SWBP_INSN __BUG_INSN_16 +#define UPROBE_SWBP_INSN_SIZE 2 +#else +#define UPROBE_SWBP_INSN __BUG_INSN_32 +#define UPROBE_SWBP_INSN_SIZE 4 +#endif +#define UPROBE_XOL_SLOT_BYTES MAX_UINSN_BYTES + +typedef u32 uprobe_opcode_t ; + +struct arch_uprobe_task { +unsigned long saved_cause; +}; + +struct arch_uprobe { +union { +u8 insn[MAX_UINSN_BYTES ]; +u8 ixol[MAX_UINSN_BYTES ]; + }; +struct arch_probe_insn api; +unsigned long insn_size; +bool simulate; +}; + +bool uprobe_breakpoint_handler (struct pt_regs *regs); +bool uprobe_single_step_handler (struct pt_regs *regs); + +#endif /* _ASM_RISCV_UPROBES_H */
arch/riscv/kernel/probes/Makefile +1 -0
@@ -2,4 +2,5 @@ obj-$(CONFIG_KPROBES) += kprobes.o decode-insn.o simulate-insn.o obj-$(CONFIG_KPROBES) += kprobes_trampoline.o obj-$(CONFIG_KPROBES_ON_FTRACE) += ftrace.o +obj-$(CONFIG_UPROBES) += uprobes.o decode-insn.o simulate-insn.o CFLAGS_REMOVE_simulate-insn.o = $(CC_FLAGS_FTRACE)
arch/riscv/kernel/probes/uprobes.c new file +186 -0
186 lines not on this page · raw message
arch/riscv/kernel/signal.c +3 -0
@@ -309,6 +309,9 @@ static void do_signal(struct pt_regs *regs) asmlinkage __visible void do_notify_resume(struct pt_regs *regs,unsigned long thread_info_flags) { +if (thread_info_flags & _TIF_UPROBE) +uprobe_notify_resume (regs); +/* Handle pending signal delivery */ if (thread_info_flags & _TIF_SIGPENDING)do_signal (regs);
arch/riscv/kernel/traps.c +10 -0
@@ -76,6 +76,8 @@ void do_trap(struct pt_regs *regs, int signo, int code, unsigned long addr)static void do_trap_error (struct pt_regs *regs,int signo,int code,unsigned long addr,const char *str) { + current->thread.bad_cause = regs->cause; +if (user_mode (regs)) {do_trap (regs, signo, code, addr); }else {
@@ -153,6 +155,14 @@ asmlinkage __visible void do_trap_break(struct pt_regs *regs)if (kprobe_breakpoint_handler (regs))return ;#endif +#ifdef CONFIG_UPROBES +if (uprobe_single_step_handler (regs)) +return ; + +if (uprobe_breakpoint_handler (regs)) +return ; +#endif + current->thread.bad_cause = regs->cause;if (user_mode (regs))force_sig_fault (SIGTRAP ,TRAP_BRKPT , (void __user *)regs->epc);
arch/riscv/mm/fault.c +6 -0
@@ -229,6 +229,7 @@ asmlinkage void do_page_fault(struct pt_regs *regs)* in an atomic region, then we must not take the fault. */ if (unlikely (faulthandler_disabled () || !mm)) { + tsk->thread.bad_cause = cause;no_context (regs, addr);return ; }
@@ -246,16 +247,19 @@ asmlinkage void do_page_fault(struct pt_regs *regs)mmap_read_lock (mm); vma =find_vma (mm, addr);if (unlikely (!vma)) { + tsk->thread.bad_cause = cause;bad_area (regs, mm, code, addr);return ; }if (likely (vma->vm_start <= addr)) goto good_area;if (unlikely (!(vma->vm_flags &VM_GROWSDOWN ))) { + tsk->thread.bad_cause = cause;bad_area (regs, mm, code, addr);return ; }if (unlikely (expand_stack (vma, addr))) { + tsk->thread.bad_cause = cause;bad_area (regs, mm, code, addr);return ; }
@@ -268,6 +272,7 @@ asmlinkage void do_page_fault(struct pt_regs *regs) code =SEGV_ACCERR ;if (unlikely (access_error (cause, vma))) { + tsk->thread.bad_cause = cause;bad_area (regs, mm, code, addr);return ; }
@@ -301,6 +306,7 @@ asmlinkage void do_page_fault(struct pt_regs *regs)mmap_read_unlock (mm);if (unlikely (fault &VM_FAULT_ERROR )) { + tsk->thread.bad_cause = cause;mm_fault_error (regs, addr, fault);return ; }
Signature · 7 lines
2.7.4 _______________________________________________ linux-riscv mailing list [email protected] http://lists.infradead.org/mailman/listinfo/linux-riscv
[email protected]
maintainerPATCH v5 9/9 riscv: Add support for function error injection
In reply to [email protected]From: Guo Ren <[email protected]>
Inspired by the commit 42d038c4fb00 ("arm64: Add support for function error injection"), this patch supports function error injection for riscv.
This patch mainly support two functions: one is regs_set_return_value() which is used to overwrite the return value; the another function is override_function_with_return() which is to override the probed function returning and jump to its caller.
Test log:
cd /sys/kernel/debug/fail_function
echo sys_clone > inject
echo 100 > probability
echo 1 > interval
ls /
[ 313.176875] FAULT_INJECTION: forcing a failure. [ 313.176875] name fail_function, interval 1, probability 100, space 0, times 1 [ 313.184357] CPU: 0 PID: 87 Comm: sh Not tainted 5.8.0-rc5-00007-g6a758cc #117 [ 313.187616] Call Trace: [ 313.189100] [<ffffffe0002036b6>] walk_stackframe+0x0/0xc2 [ 313.191626] [<ffffffe00020395c>] show_stack+0x40/0x4c [ 313.193927] [<ffffffe000556c60>] dump_stack+0x7c/0x96 [ 313.194795] [<ffffffe0005522e8>] should_fail+0x140/0x142 [ 313.195923] [<ffffffe000299ffc>] fei_kprobe_handler+0x2c/0x5a [ 313.197687] [<ffffffe0009e2ec4>] kprobe_breakpoint_handler+0xb4/0x18a [ 313.200054] [<ffffffe00020357e>] do_trap_break+0x36/0xca [ 313.202147] [<ffffffe000201bca>] ret_from_exception+0x0/0xc [ 313.204556] [<ffffffe000201bbc>] ret_from_syscall+0x0/0x2
-sh: can't fork: Invalid argument
--- arch/riscv/Kconfig | 1 + arch/riscv/include/asm/ptrace.h | 6 ++++++ arch/riscv/lib/Makefile | 2 ++ arch/riscv/lib/error-inject.c | 10 ++++++++++ 4 files changed, 19 insertions(+) create mode 100644 arch/riscv/lib/error-inject.c
arch/riscv/Kconfig +1 -0
@@ -67,6 +67,7 @@ config RISCV select HAVE_EBPF_JIT if MMU select HAVE_FUTEX_CMPXCHG if FUTEX select HAVE_GCC_PLUGINS + select HAVE_FUNCTION_ERROR_INJECTION select HAVE_GENERIC_VDSO if MMU && 64BIT select HAVE_KPROBES select HAVE_KPROBES_ON_FTRACE
arch/riscv/include/asm/ptrace.h +6 -0
@@ -109,6 +109,12 @@ static inline unsigned long regs_return_value(struct pt_regs *regs)return regs->a0; } +static inline void regs_set_return_value (struct pt_regs *regs, +unsigned long val) +{ + regs->a0 = val; +} +extern int regs_query_register_offset (const char *name);extern unsigned long regs_get_kernel_stack_nth (struct pt_regs *regs,unsigned int n);
arch/riscv/lib/Makefile +2 -0
@@ -4,3 +4,5 @@ lib-y += memcpy.o lib-y += memset.o lib-$(CONFIG_MMU) += uaccess.o lib-$(CONFIG_64BIT) += tishift.o + +obj-$(CONFIG_FUNCTION_ERROR_INJECTION) += error-inject.o
arch/riscv/lib/error-inject.c new file +10 -0
@@ -0,0 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include <linux/error-injection.h> +#include <linux/kprobes.h> + +void override_function_with_return (struct pt_regs *regs) +{ +instruction_pointer_set (regs, regs->ra); +} +NOKPROBE_SYMBOL (override_function_with_return);
Signature · 7 lines
2.7.4 _______________________________________________ linux-riscv mailing list [email protected] http://lists.infradead.org/mailman/listinfo/linux-riscv
Quoted 206 lines · On Thu, 17 Dec 2020 08:01:36 PST (-0800), [email protected] wrote:
From: Guo Ren <[email protected]>
This the 5th round of riscv k/uprobe support patchset, it's based on linux-5.10 and you can test it with the repo:
https://github.com/c-sky/csky-linux/tree/linux-5.10-probe-dev
The important fixup is about the trampoline call site, we change the prologue of the function call site from:
<funca>: nop -> addi sp, sp, -SZREG nop -> REG_S ra, (sp) nop -> auipc ra, 0x? nop -> jalr ?(ra) nop -> REG_L ra, (sp) nop -> addi sp, sp, -SZREG ...to:
<funca>: nop -> REG_S ra, -SZREG(sp) nop -> auipc ra, 0x? nop -> jalr ?(ra) nop -> REG_L ra, -SZREG(sp) ...It's wrong to change the sp in callsite, because when you change the value of ra then the sp is broken and the same with
HAVE_OPTPROBES.The patchset includes kprobe/uprobe support and some related fixups. Patrick provides
HAVE_REGS_AND_STACK_ACCESS_APIsupport and some kprobe's code. The framework of k/uprobe is from csky but also refers to other arches'. kprobes on ftrace is also supported in the patchset. Modify dynamic ftrace mechanism from mcount to fentry.There is no single step exception in riscv ISA, only single-step facility for jtag. See riscv-Privileged spec:
Interrupt Exception Code-Description
1 0 Reserved
1 1 Supervisor software interrupt
1 2–4 Reserved
1 5 Supervisor timer interrupt
1 6–8 Reserved
1 9 Supervisor external interrupt
1 10–15 Reserved
1 ≥16 Available for platform use
0 0 Instruction address misaligned
0 1 Instruction access fault
0 2 Illegal instruction
0 3 Breakpoint
0 4 Load address misaligned
0 5 Load access fault
0 6 Store/AMO address misaligned
0 7 Store/AMO access fault
0 8 Environment call from U-mode
0 9 Environment call from S-mode
0 10–11 Reserved
0 12 Instruction page fault
0 13 Load page fault
0 14 Reserved
0 15 Store/AMO page fault
0 16–23 Reserved
0 24–31 Available for custom use
0 32–47 Reserved
0 48–63 Available for custom use
0 ≥64 ReservedNo single step!
Other arches use hardware single-step exception for k/uprobe, eg:
- powerpc:regs->msr|=MSR_SINGLESTEP
- arm/arm64: PSTATE.D for enabling software step exceptions
- s390: Set PER control regs, turns on single step for the given address
- x86:regs->flags|=X86_EFLAGS_TF
- csky: of course use hw single step :)All the above arches use a hardware single-step exception mechanism to execute the instruction that was replaced with a probe breakpoint. So utilize ebreak to simulate.
Some pc related instructions couldn't be executed out of line and some system/fence instructions couldn't be a trace site at all. So we give out a reject list and simulate list in
decode-insn.c.You could use uprobe to test simulate code like this:
echo 'p:enter_current_state_one /hello:0x6e4 a0=%a0 a1=%a1' >>
/sys/kernel/debug/tracing/uprobe_eventsecho 1 >/sys/kernel/debug/tracing/events/uprobes/enable
/hello
^C
cat/sys/kernel/debug/tracing/trace
tracer: nopentries-in-buffer/entries-written: 1/1 #P:1
_-----=> irqs-off / _----=> need-resched | / _---=> hardirq/softirq || / _--=> preempt-depth ||| / delay TASK-PID CPU# |||| TIMESTAMP FUNCTION | | | |||| | | hello-94 [000] d... 55.404242: enter_current_state_one: (0x106e4) a0=0x1 a1=0x3fffa8ada8Be care /hello:0x6e4 is the file offset in elf and it relate to
0x106e4in memory and hello is your target elf program.Try kprobe like this:
echo 'p:myprobe
sys_clonea0=%a0 a1=%a1 a2=%a2 a3=%a3 stach_val=+4($stack)' >/sys/kernel/debug/tracing/kprobe_eventsecho 'r:myretprobesys_clone$retval' >>/sys/kernel/debug/tracing/kprobe_events
echo 1 >/sys/kernel/debug/tracing/events/kprobes/enable
cat/sys/kernel/debug/tracing/trace
tracer: nopentries-in-buffer/entries-written: 2/2 #P:1
_-----=> irqs-off / _----=> need-resched | / _---=> hardirq/softirq || / _--=> preempt-depth ||| / delay TASK-PID CPU# |||| TIMESTAMP FUNCTION | | | |||| | | sh-92 [000] .n.. 8506.435857: myprobe: (sys_clone+0x0/0x28) a0=0x1200011 a1=0x0 a2=0x0 a3=0x0 stach_val=0x2044ecffffffe0 sh-92 [000] d... 8506.445620: myretprobe: (ret_from_syscall+0x0/0x2 <- sys_clone) arg1=0x64Changlog v5:
- Fixup fentry modified sp causefail_injecterror
- Fixupfunction_graphbroken
- Update to linux-5.10
- Fixup checkpatch.pl issuesChanglog v4:
- Revert fixup kprobes handler couldn't change pc
- UsingPATCHABLE_FUNCTION_ENTRYinstead of MCOUNT
- rebase on linux-tree:
commit071a0578b0ce0b0e543d1e38ee6926b9cc21c198
Merge: fad7011 be4df0c
Author: Linus Torvalds <[email protected]>
Date: Fri Oct 16 15:29:46 2020 -0700Merge tag 'ovl-update-5.10' of
git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfsChanglog v3:
- Add upport for function error injection
- Fixup kprobes handler couldn't change pcChanglog v2:
- Add Reviewed-by, Tested-by, Acked-by, thx for all of you
- Add kprobes on ftrace feature
- Use__always_inlineas same asfix_to_virtfor fixupBUILD_BUG_ON
- Use const "const unsigned int" for 2th param for fixupBUILD_BUG_ONGuo Ren (8):
riscv: Fixup compile errorBUILD_BUG_ONfailed
riscv: Fixup wrong ftrace remove cflag
riscv: Fixuppatch_textpanic in ftrace
riscv: UsingPATCHABLE_FUNCTION_ENTRYinstead of MCOUNT
riscv: Add kprobes supported
riscv: AddKPROBES_ON_FTRACEsupported
riscv: Add uprobes supported
riscv: Add support for function error injectionPatrick Stählin (1):
RISC-V: Implement ptrace regs and stack APIarch/riscv/Kconfig | 8 + arch/riscv/Makefile | 2 + arch/riscv/include/asm/kprobes.h | 40 +++ arch/riscv/include/asm/probes.h | 24 ++ arch/riscv/include/asm/processor.h | 1 + arch/riscv/include/asm/ptrace.h | 35 +++ arch/riscv/include/asm/thread_info.h | 4 +- arch/riscv/include/asm/uprobes.h | 40 +++ arch/riscv/kernel/Makefile | 6 +- arch/riscv/kernel/ftrace.c | 95 +++--- arch/riscv/kernel/mcount-dyn.S | 342 ++++++++++------------ arch/riscv/kernel/patch.c | 8 +- arch/riscv/kernel/probes/Makefile | 6 + arch/riscv/kernel/probes/decode-insn.c | 48 ++++ arch/riscv/kernel/probes/decode-insn.h | 18 ++ arch/riscv/kernel/probes/ftrace.c | 53 ++++ arch/riscv/kernel/probes/kprobes.c | 398 ++++++++++++++++++++++++++ arch/riscv/kernel/probes/kprobes_trampoline.S | 93 ++++++ arch/riscv/kernel/probes/simulate-insn.c | 85 ++++++ arch/riscv/kernel/probes/simulate-insn.h | 47 +++ arch/riscv/kernel/probes/uprobes.c | 186 ++++++++++++ arch/riscv/kernel/ptrace.c | 99 +++++++ arch/riscv/kernel/signal.c | 3 + arch/riscv/kernel/traps.c | 19 ++ arch/riscv/lib/Makefile | 2 + arch/riscv/lib/error-inject.c | 10 + arch/riscv/mm/Makefile | 3 +- arch/riscv/mm/fault.c | 10 + 28 files changed, 1444 insertions(+), 241 deletions(-) create mode 100644 arch/riscv/include/asm/probes.h create mode 100644 arch/riscv/include/asm/uprobes.h create mode 100644 arch/riscv/kernel/probes/Makefile create mode 100644 arch/riscv/kernel/probes/decode-insn.c
Quoted 8 lines
create mode 100644 arch/riscv/kernel/probes/decode-insn.h create mode 100644 arch/riscv/kernel/probes/ftrace.c create mode 100644 arch/riscv/kernel/probes/kprobes.c create mode 100644 arch/riscv/kernel/probes/kprobes_trampoline.S create mode 100644 arch/riscv/kernel/probes/simulate-insn.c create mode 100644 arch/riscv/kernel/probes/simulate-insn.h create mode 100644 arch/riscv/kernel/probes/uprobes.c create mode 100644 arch/riscv/lib/error-inject.c
Thanks, these are on for-next. I've fixed up a few things, LMK if there were any issues.
_______________________________________________
linux-riscv mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-riscv