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 14 bool is_swbp_insn(uprobe_opcode_t *insn) 15 { 16 return (*insn & 0xffff) == UPROBE_SWBP_INSN; 17 } 18 19 unsigned long uprobe_get_swbp_addr(struct pt_regs *regs) 20 { 21 return instruction_pointer(regs); 22 } 23 24 int 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 48 int 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 62 int 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 75 bool 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 83 bool 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 100 void 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 probbed 106 * address. 107 */ 108 instruction_pointer_set(regs, utask->vaddr); 109 110 user_disable_single_step(current); 111 } 112 113 bool 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 122 unsigned long 123 arch_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 135 int arch_uprobe_exception_notify(struct notifier_block *self, 136 unsigned long val, void *data) 137 { 138 return NOTIFY_DONE; 139 } 140 141 int uprobe_breakpoint_handler(struct pt_regs *regs) 142 { 143 if (uprobe_pre_sstep_notifier(regs)) 144 return 1; 145 146 return 0; 147 } 148 149 int uprobe_single_step_handler(struct pt_regs *regs) 150 { 151 if (uprobe_post_sstep_notifier(regs)) 152 return 1; 153 154 return 0; 155 } 156