Linux Audio

Check our new training course

Linux debugging, profiling, tracing and performance analysis training

Apr 14-17, 2025
Register
Loading...
Note: File does not exist in v5.9.
  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	user_enable_single_step(current);
 46
 47	return 0;
 48}
 49
 50int arch_uprobe_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
 51{
 52	struct uprobe_task *utask = current->utask;
 53
 54	WARN_ON_ONCE(current->thread.trap_nr != UPROBE_TRAP_NR);
 55	current->thread.trap_nr = utask->autask.saved_trap_nr;
 56
 57	if (auprobe->simulate)
 58		instruction_pointer_set(regs, auprobe->resume_era);
 59	else
 60		instruction_pointer_set(regs, utask->vaddr + LOONGARCH_INSN_SIZE);
 61
 62	user_disable_single_step(current);
 63
 64	return 0;
 65}
 66
 67void arch_uprobe_abort_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
 68{
 69	struct uprobe_task *utask = current->utask;
 70
 71	current->thread.trap_nr = utask->autask.saved_trap_nr;
 72	instruction_pointer_set(regs, utask->vaddr);
 73	user_disable_single_step(current);
 74}
 75
 76bool arch_uprobe_xol_was_trapped(struct task_struct *t)
 77{
 78	if (t->thread.trap_nr != UPROBE_TRAP_NR)
 79		return true;
 80
 81	return false;
 82}
 83
 84bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs)
 85{
 86	union loongarch_instruction insn;
 87
 88	if (!auprobe->simulate)
 89		return false;
 90
 91	insn.word = auprobe->insn[0];
 92	arch_simulate_insn(insn, regs);
 93	auprobe->resume_era = regs->csr_era;
 94
 95	return true;
 96}
 97
 98unsigned long arch_uretprobe_hijack_return_addr(unsigned long trampoline_vaddr,
 99						struct pt_regs *regs)
100{
101	unsigned long ra = regs->regs[1];
102
103	regs->regs[1] = trampoline_vaddr;
104
105	return ra;
106}
107
108bool arch_uretprobe_is_alive(struct return_instance *ret,
109			     enum rp_check ctx, struct pt_regs *regs)
110{
111	if (ctx == RP_CHECK_CHAIN_CALL)
112		return regs->regs[3] <= ret->stack;
113	else
114		return regs->regs[3] < ret->stack;
115}
116
117int arch_uprobe_exception_notify(struct notifier_block *self,
118				 unsigned long val, void *data)
119{
120	return NOTIFY_DONE;
121}
122
123bool uprobe_breakpoint_handler(struct pt_regs *regs)
124{
125	if (uprobe_pre_sstep_notifier(regs))
126		return true;
127
128	return false;
129}
130
131bool uprobe_singlestep_handler(struct pt_regs *regs)
132{
133	if (uprobe_post_sstep_notifier(regs))
134		return true;
135
136	return false;
137}
138
139unsigned long uprobe_get_swbp_addr(struct pt_regs *regs)
140{
141	return instruction_pointer(regs);
142}
143
144void arch_uprobe_copy_ixol(struct page *page, unsigned long vaddr,
145			   void *src, unsigned long len)
146{
147	void *kaddr = kmap_local_page(page);
148	void *dst = kaddr + (vaddr & ~PAGE_MASK);
149
150	memcpy(dst, src, len);
151	flush_icache_range((unsigned long)dst, (unsigned long)dst + len);
152	kunmap_local(kaddr);
153}