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 current->thread.trap_no = utask->autask.saved_trap_no; 68 69 instruction_pointer_set(regs, utask->vaddr + auprobe->insn_size); 70 71 user_disable_single_step(current); 72 73 return 0; 74} 75 76bool arch_uprobe_xol_was_trapped(struct task_struct *t) 77{ 78 if (t->thread.trap_no != 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 probe_opcode_t insn; 87 unsigned long addr; 88 89 if (!auprobe->simulate) 90 return false; 91 92 insn = *(probe_opcode_t *)(&auprobe->insn[0]); 93 addr = instruction_pointer(regs); 94 95 if (auprobe->api.handler) 96 auprobe->api.handler(insn, addr, regs); 97 98 return true; 99} 100 101void arch_uprobe_abort_xol(struct arch_uprobe *auprobe, struct pt_regs *regs) 102{ 103 struct uprobe_task *utask = current->utask; 104 105 current->thread.trap_no = utask->autask.saved_trap_no; 106 107 /* 108 * Task has received a fatal signal, so reset back to probed 109 * address. 110 */ 111 instruction_pointer_set(regs, utask->vaddr); 112 113 user_disable_single_step(current); 114} 115 116bool arch_uretprobe_is_alive(struct return_instance *ret, enum rp_check ctx, 117 struct pt_regs *regs) 118{ 119 if (ctx == RP_CHECK_CHAIN_CALL) 120 return regs->usp <= ret->stack; 121 else 122 return regs->usp < ret->stack; 123} 124 125unsigned long 126arch_uretprobe_hijack_return_addr(unsigned long trampoline_vaddr, 127 struct pt_regs *regs) 128{ 129 unsigned long ra; 130 131 ra = regs->lr; 132 133 regs->lr = trampoline_vaddr; 134 135 return ra; 136} 137 138int arch_uprobe_exception_notify(struct notifier_block *self, 139 unsigned long val, void *data) 140{ 141 return NOTIFY_DONE; 142} 143 144int uprobe_breakpoint_handler(struct pt_regs *regs) 145{ 146 if (uprobe_pre_sstep_notifier(regs)) 147 return 1; 148 149 return 0; 150} 151 152int uprobe_single_step_handler(struct pt_regs *regs) 153{ 154 if (uprobe_post_sstep_notifier(regs)) 155 return 1; 156 157 return 0; 158} 159