xref: /linux/arch/riscv/kernel/probes/uprobes.c (revision b701f9e726f0a30a94ea6af596b74c1f07b95b6b)
174784081SGuo Ren // SPDX-License-Identifier: GPL-2.0-only
274784081SGuo Ren 
374784081SGuo Ren #include <linux/highmem.h>
474784081SGuo Ren #include <linux/ptrace.h>
574784081SGuo Ren #include <linux/uprobes.h>
6*b701f9e7SNam Cao #include <asm/insn.h>
774784081SGuo Ren 
874784081SGuo Ren #include "decode-insn.h"
974784081SGuo Ren 
1074784081SGuo Ren #define UPROBE_TRAP_NR	UINT_MAX
1174784081SGuo Ren 
1274784081SGuo Ren bool is_swbp_insn(uprobe_opcode_t *insn)
1374784081SGuo Ren {
1474784081SGuo Ren #ifdef CONFIG_RISCV_ISA_C
1574784081SGuo Ren 	return (*insn & 0xffff) == UPROBE_SWBP_INSN;
1674784081SGuo Ren #else
1774784081SGuo Ren 	return *insn == UPROBE_SWBP_INSN;
1874784081SGuo Ren #endif
1974784081SGuo Ren }
2074784081SGuo Ren 
21*b701f9e7SNam Cao bool is_trap_insn(uprobe_opcode_t *insn)
22*b701f9e7SNam Cao {
23*b701f9e7SNam Cao 	return riscv_insn_is_ebreak(*insn) || riscv_insn_is_c_ebreak(*insn);
24*b701f9e7SNam Cao }
25*b701f9e7SNam Cao 
2674784081SGuo Ren unsigned long uprobe_get_swbp_addr(struct pt_regs *regs)
2774784081SGuo Ren {
2874784081SGuo Ren 	return instruction_pointer(regs);
2974784081SGuo Ren }
3074784081SGuo Ren 
3174784081SGuo Ren int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe, struct mm_struct *mm,
3274784081SGuo Ren 			     unsigned long addr)
3374784081SGuo Ren {
3474784081SGuo Ren 	probe_opcode_t opcode;
3574784081SGuo Ren 
3674784081SGuo Ren 	opcode = *(probe_opcode_t *)(&auprobe->insn[0]);
3774784081SGuo Ren 
3874784081SGuo Ren 	auprobe->insn_size = GET_INSN_LENGTH(opcode);
3974784081SGuo Ren 
4074784081SGuo Ren 	switch (riscv_probe_decode_insn(&opcode, &auprobe->api)) {
4174784081SGuo Ren 	case INSN_REJECTED:
4274784081SGuo Ren 		return -EINVAL;
4374784081SGuo Ren 
4474784081SGuo Ren 	case INSN_GOOD_NO_SLOT:
4574784081SGuo Ren 		auprobe->simulate = true;
4674784081SGuo Ren 		break;
4774784081SGuo Ren 
4874784081SGuo Ren 	case INSN_GOOD:
4974784081SGuo Ren 		auprobe->simulate = false;
5074784081SGuo Ren 		break;
5174784081SGuo Ren 
5274784081SGuo Ren 	default:
5374784081SGuo Ren 		return -EINVAL;
5474784081SGuo Ren 	}
5574784081SGuo Ren 
5674784081SGuo Ren 	return 0;
5774784081SGuo Ren }
5874784081SGuo Ren 
5974784081SGuo Ren int arch_uprobe_pre_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
6074784081SGuo Ren {
6174784081SGuo Ren 	struct uprobe_task *utask = current->utask;
6274784081SGuo Ren 
6374784081SGuo Ren 	utask->autask.saved_cause = current->thread.bad_cause;
6474784081SGuo Ren 	current->thread.bad_cause = UPROBE_TRAP_NR;
6574784081SGuo Ren 
6674784081SGuo Ren 	instruction_pointer_set(regs, utask->xol_vaddr);
6774784081SGuo Ren 
6874784081SGuo Ren 	return 0;
6974784081SGuo Ren }
7074784081SGuo Ren 
7174784081SGuo Ren int arch_uprobe_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
7274784081SGuo Ren {
7374784081SGuo Ren 	struct uprobe_task *utask = current->utask;
7474784081SGuo Ren 
7574784081SGuo Ren 	WARN_ON_ONCE(current->thread.bad_cause != UPROBE_TRAP_NR);
7658b1294dSTiezhu Yang 	current->thread.bad_cause = utask->autask.saved_cause;
7774784081SGuo Ren 
7874784081SGuo Ren 	instruction_pointer_set(regs, utask->vaddr + auprobe->insn_size);
7974784081SGuo Ren 
8074784081SGuo Ren 	return 0;
8174784081SGuo Ren }
8274784081SGuo Ren 
8374784081SGuo Ren bool arch_uprobe_xol_was_trapped(struct task_struct *t)
8474784081SGuo Ren {
8574784081SGuo Ren 	if (t->thread.bad_cause != UPROBE_TRAP_NR)
8674784081SGuo Ren 		return true;
8774784081SGuo Ren 
8874784081SGuo Ren 	return false;
8974784081SGuo Ren }
9074784081SGuo Ren 
9174784081SGuo Ren bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs)
9274784081SGuo Ren {
9374784081SGuo Ren 	probe_opcode_t insn;
9474784081SGuo Ren 	unsigned long addr;
9574784081SGuo Ren 
9674784081SGuo Ren 	if (!auprobe->simulate)
9774784081SGuo Ren 		return false;
9874784081SGuo Ren 
9974784081SGuo Ren 	insn = *(probe_opcode_t *)(&auprobe->insn[0]);
10074784081SGuo Ren 	addr = instruction_pointer(regs);
10174784081SGuo Ren 
10274784081SGuo Ren 	if (auprobe->api.handler)
10374784081SGuo Ren 		auprobe->api.handler(insn, addr, regs);
10474784081SGuo Ren 
10574784081SGuo Ren 	return true;
10674784081SGuo Ren }
10774784081SGuo Ren 
10874784081SGuo Ren void arch_uprobe_abort_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
10974784081SGuo Ren {
11074784081SGuo Ren 	struct uprobe_task *utask = current->utask;
11174784081SGuo Ren 
11258b1294dSTiezhu Yang 	current->thread.bad_cause = utask->autask.saved_cause;
11374784081SGuo Ren 	/*
11474784081SGuo Ren 	 * Task has received a fatal signal, so reset back to probbed
11574784081SGuo Ren 	 * address.
11674784081SGuo Ren 	 */
11774784081SGuo Ren 	instruction_pointer_set(regs, utask->vaddr);
11874784081SGuo Ren }
11974784081SGuo Ren 
12074784081SGuo Ren bool arch_uretprobe_is_alive(struct return_instance *ret, enum rp_check ctx,
12174784081SGuo Ren 		struct pt_regs *regs)
12274784081SGuo Ren {
12374784081SGuo Ren 	if (ctx == RP_CHECK_CHAIN_CALL)
12474784081SGuo Ren 		return regs->sp <= ret->stack;
12574784081SGuo Ren 	else
12674784081SGuo Ren 		return regs->sp < ret->stack;
12774784081SGuo Ren }
12874784081SGuo Ren 
12974784081SGuo Ren unsigned long
13074784081SGuo Ren arch_uretprobe_hijack_return_addr(unsigned long trampoline_vaddr,
13174784081SGuo Ren 				  struct pt_regs *regs)
13274784081SGuo Ren {
13374784081SGuo Ren 	unsigned long ra;
13474784081SGuo Ren 
13574784081SGuo Ren 	ra = regs->ra;
13674784081SGuo Ren 
13774784081SGuo Ren 	regs->ra = trampoline_vaddr;
13874784081SGuo Ren 
13974784081SGuo Ren 	return ra;
14074784081SGuo Ren }
14174784081SGuo Ren 
14274784081SGuo Ren int arch_uprobe_exception_notify(struct notifier_block *self,
14374784081SGuo Ren 				 unsigned long val, void *data)
14474784081SGuo Ren {
14574784081SGuo Ren 	return NOTIFY_DONE;
14674784081SGuo Ren }
14774784081SGuo Ren 
14874784081SGuo Ren bool uprobe_breakpoint_handler(struct pt_regs *regs)
14974784081SGuo Ren {
15074784081SGuo Ren 	if (uprobe_pre_sstep_notifier(regs))
15174784081SGuo Ren 		return true;
15274784081SGuo Ren 
15374784081SGuo Ren 	return false;
15474784081SGuo Ren }
15574784081SGuo Ren 
15674784081SGuo Ren bool uprobe_single_step_handler(struct pt_regs *regs)
15774784081SGuo Ren {
15874784081SGuo Ren 	if (uprobe_post_sstep_notifier(regs))
15974784081SGuo Ren 		return true;
16074784081SGuo Ren 
16174784081SGuo Ren 	return false;
16274784081SGuo Ren }
16374784081SGuo Ren 
16474784081SGuo Ren void arch_uprobe_copy_ixol(struct page *page, unsigned long vaddr,
16574784081SGuo Ren 			   void *src, unsigned long len)
16674784081SGuo Ren {
16774784081SGuo Ren 	/* Initialize the slot */
16874784081SGuo Ren 	void *kaddr = kmap_atomic(page);
16974784081SGuo Ren 	void *dst = kaddr + (vaddr & ~PAGE_MASK);
17074784081SGuo Ren 
17174784081SGuo Ren 	memcpy(dst, src, len);
17274784081SGuo Ren 
17374784081SGuo Ren 	/* Add ebreak behind opcode to simulate singlestep */
17474784081SGuo Ren 	if (vaddr) {
17574784081SGuo Ren 		dst += GET_INSN_LENGTH(*(probe_opcode_t *)src);
17674784081SGuo Ren 		*(uprobe_opcode_t *)dst = __BUG_INSN_32;
17774784081SGuo Ren 	}
17874784081SGuo Ren 
17974784081SGuo Ren 	kunmap_atomic(kaddr);
18074784081SGuo Ren 
18174784081SGuo Ren 	/*
18274784081SGuo Ren 	 * We probably need flush_icache_user_page() but it needs vma.
18374784081SGuo Ren 	 * This should work on most of architectures by default. If
18474784081SGuo Ren 	 * architecture needs to do something different it can define
18574784081SGuo Ren 	 * its own version of the function.
18674784081SGuo Ren 	 */
18774784081SGuo Ren 	flush_dcache_page(page);
18874784081SGuo Ren }
189