uprobes.c (3050B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Copyright (C) 2014-2016 Pratyush Anand <panand@redhat.com> 4 */ 5#include <linux/highmem.h> 6#include <linux/ptrace.h> 7#include <linux/uprobes.h> 8#include <asm/cacheflush.h> 9 10#include "decode-insn.h" 11 12#define UPROBE_TRAP_NR UINT_MAX 13 14bool is_swbp_insn(uprobe_opcode_t *insn) 15{ 16 return (*insn & 0xffff) == UPROBE_SWBP_INSN; 17} 18 19unsigned long uprobe_get_swbp_addr(struct pt_regs *regs) 20{ 21 return instruction_pointer(regs); 22} 23 24int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe, struct mm_struct *mm, 25 unsigned long addr) 26{ 27 probe_opcode_t insn; 28 29 insn = *(probe_opcode_t *)(&auprobe->insn[0]); 30 31 auprobe->insn_size = is_insn32(insn) ? 4 : 2; 32 33 switch (csky_probe_decode_insn(&insn, &auprobe->api)) { 34 case INSN_REJECTED: 35 return -EINVAL; 36 37 case INSN_GOOD_NO_SLOT: 38 auprobe->simulate = true; 39 break; 40 41 default: 42 break; 43 } 44 45 return 0; 46} 47 48int arch_uprobe_pre_xol(struct arch_uprobe *auprobe, struct pt_regs *regs) 49{ 50 struct uprobe_task *utask = current->utask; 51 52 utask->autask.saved_trap_no = current->thread.trap_no; 53 current->thread.trap_no = UPROBE_TRAP_NR; 54 55 instruction_pointer_set(regs, utask->xol_vaddr); 56 57 user_enable_single_step(current); 58 59 return 0; 60} 61 62int arch_uprobe_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs) 63{ 64 struct uprobe_task *utask = current->utask; 65 66 WARN_ON_ONCE(current->thread.trap_no != UPROBE_TRAP_NR); 67 68 instruction_pointer_set(regs, utask->vaddr + auprobe->insn_size); 69 70 user_disable_single_step(current); 71 72 return 0; 73} 74 75bool arch_uprobe_xol_was_trapped(struct task_struct *t) 76{ 77 if (t->thread.trap_no != UPROBE_TRAP_NR) 78 return true; 79 80 return false; 81} 82 83bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs) 84{ 85 probe_opcode_t insn; 86 unsigned long addr; 87 88 if (!auprobe->simulate) 89 return false; 90 91 insn = *(probe_opcode_t *)(&auprobe->insn[0]); 92 addr = instruction_pointer(regs); 93 94 if (auprobe->api.handler) 95 auprobe->api.handler(insn, addr, regs); 96 97 return true; 98} 99 100void arch_uprobe_abort_xol(struct arch_uprobe *auprobe, struct pt_regs *regs) 101{ 102 struct uprobe_task *utask = current->utask; 103 104 /* 105 * Task has received a fatal signal, so reset back to probed 106 * address. 107 */ 108 instruction_pointer_set(regs, utask->vaddr); 109 110 user_disable_single_step(current); 111} 112 113bool arch_uretprobe_is_alive(struct return_instance *ret, enum rp_check ctx, 114 struct pt_regs *regs) 115{ 116 if (ctx == RP_CHECK_CHAIN_CALL) 117 return regs->usp <= ret->stack; 118 else 119 return regs->usp < ret->stack; 120} 121 122unsigned long 123arch_uretprobe_hijack_return_addr(unsigned long trampoline_vaddr, 124 struct pt_regs *regs) 125{ 126 unsigned long ra; 127 128 ra = regs->lr; 129 130 regs->lr = trampoline_vaddr; 131 132 return ra; 133} 134 135int arch_uprobe_exception_notify(struct notifier_block *self, 136 unsigned long val, void *data) 137{ 138 return NOTIFY_DONE; 139} 140 141int uprobe_breakpoint_handler(struct pt_regs *regs) 142{ 143 if (uprobe_pre_sstep_notifier(regs)) 144 return 1; 145 146 return 0; 147} 148 149int uprobe_single_step_handler(struct pt_regs *regs) 150{ 151 if (uprobe_post_sstep_notifier(regs)) 152 return 1; 153 154 return 0; 155}