File Index
Files and directories
Sign in
FILE

uprobes.c

File preview with syntax highlighting.

linux-6.19.14/arch/loongarch/kernel/uprobes.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2#include <linux/highmem.h>
  3#include <linux/ptrace.h>
  4#include <linux/sched.h>
  5#include <linux/uprobes.h>
  6#include <asm/cacheflush.h>
  7
  8#define UPROBE_TRAP_NR	UINT_MAX
  9
 10int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe,
 11			     struct mm_struct *mm, unsigned long addr)
 12{
 13	int idx;
 14	union loongarch_instruction insn;
 15
 16	if (addr & 0x3)
 17		return -EILSEQ;
 18
 19	for (idx = ARRAY_SIZE(auprobe->insn) - 1; idx >= 0; idx--) {
 20		insn.word = auprobe->insn[idx];
 21		if (insns_not_supported(insn))
 22			return -EINVAL;
 23	}
 24
 25	if (insns_need_simulation(insn)) {
 26		auprobe->ixol[0] = larch_insn_gen_nop();
 27		auprobe->simulate = true;
 28	} else {
 29		auprobe->ixol[0] = auprobe->insn[0];
 30		auprobe->simulate = false;
 31	}
 32
 33	auprobe->ixol[1] = UPROBE_XOLBP_INSN;
 34
 35	return 0;
 36}
 37
 38int arch_uprobe_pre_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
 39{
 40	struct uprobe_task *utask = current->utask;
 41
 42	utask->autask.saved_trap_nr = current->thread.trap_nr;
 43	current->thread.trap_nr = UPROBE_TRAP_NR;
 44	instruction_pointer_set(regs, utask->xol_vaddr);
 45
 46	return 0;
 47}
 48
 49int arch_uprobe_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
 50{
 51	struct uprobe_task *utask = current->utask;
 52
 53	WARN_ON_ONCE(current->thread.trap_nr != UPROBE_TRAP_NR);
 54	current->thread.trap_nr = utask->autask.saved_trap_nr;
 55	instruction_pointer_set(regs, utask->vaddr + LOONGARCH_INSN_SIZE);
 56
 57	return 0;
 58}
 59
 60void arch_uprobe_abort_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
 61{
 62	struct uprobe_task *utask = current->utask;
 63
 64	current->thread.trap_nr = utask->autask.saved_trap_nr;
 65	instruction_pointer_set(regs, utask->vaddr);
 66}
 67
 68bool arch_uprobe_xol_was_trapped(struct task_struct *t)
 69{
 70	if (t->thread.trap_nr != UPROBE_TRAP_NR)
 71		return true;
 72
 73	return false;
 74}
 75
 76bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs)
 77{
 78	union loongarch_instruction insn;
 79
 80	if (!auprobe->simulate)
 81		return false;
 82
 83	insn.word = auprobe->insn[0];
 84	arch_simulate_insn(insn, regs);
 85
 86	return true;
 87}
 88
 89unsigned long arch_uretprobe_hijack_return_addr(unsigned long trampoline_vaddr,
 90						struct pt_regs *regs)
 91{
 92	unsigned long ra = regs->regs[1];
 93
 94	regs->regs[1] = trampoline_vaddr;
 95
 96	return ra;
 97}
 98
 99bool arch_uretprobe_is_alive(struct return_instance *ret,
100			     enum rp_check ctx, struct pt_regs *regs)
101{
102	if (ctx == RP_CHECK_CHAIN_CALL)
103		return regs->regs[3] <= ret->stack;
104	else
105		return regs->regs[3] < ret->stack;
106}
107
108int arch_uprobe_exception_notify(struct notifier_block *self,
109				 unsigned long val, void *data)
110{
111	return NOTIFY_DONE;
112}
113
114bool uprobe_breakpoint_handler(struct pt_regs *regs)
115{
116	if (uprobe_pre_sstep_notifier(regs))
117		return true;
118
119	return false;
120}
121
122bool uprobe_singlestep_handler(struct pt_regs *regs)
123{
124	if (uprobe_post_sstep_notifier(regs))
125		return true;
126
127	return false;
128}
129
130unsigned long uprobe_get_swbp_addr(struct pt_regs *regs)
131{
132	return instruction_pointer(regs);
133}
134
135void arch_uprobe_copy_ixol(struct page *page, unsigned long vaddr,
136			   void *src, unsigned long len)
137{
138	void *kaddr = kmap_local_page(page);
139	void *dst = kaddr + (vaddr & ~PAGE_MASK);
140
141	memcpy(dst, src, len);
142	flush_icache_range((unsigned long)dst, (unsigned long)dst + len);
143	kunmap_local(kaddr);
144}
~/ Read-only file preview.