FILE
uprobes.c
File preview with syntax highlighting.
linux-6.19.14/arch/loongarch/kernel/uprobes.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.