1 /* 2 * Copyright (C) 2012 Rabin Vincent <rabin at rab.in> 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License version 2 as 6 * published by the Free Software Foundation. 7 */ 8 9 #include <linux/kernel.h> 10 #include <linux/stddef.h> 11 #include <linux/errno.h> 12 #include <linux/highmem.h> 13 #include <linux/sched.h> 14 #include <linux/uprobes.h> 15 #include <linux/notifier.h> 16 17 #include <asm/opcodes.h> 18 #include <asm/traps.h> 19 20 #include "../decode.h" 21 #include "../decode-arm.h" 22 #include "core.h" 23 24 #define UPROBE_TRAP_NR UINT_MAX 25 26 bool is_swbp_insn(uprobe_opcode_t *insn) 27 { 28 return (__mem_to_opcode_arm(*insn) & 0x0fffffff) == 29 (UPROBE_SWBP_ARM_INSN & 0x0fffffff); 30 } 31 32 int set_swbp(struct arch_uprobe *auprobe, struct mm_struct *mm, 33 unsigned long vaddr) 34 { 35 return uprobe_write_opcode(mm, vaddr, 36 __opcode_to_mem_arm(auprobe->bpinsn)); 37 } 38 39 bool arch_uprobe_ignore(struct arch_uprobe *auprobe, struct pt_regs *regs) 40 { 41 if (!auprobe->asi.insn_check_cc(regs->ARM_cpsr)) { 42 regs->ARM_pc += 4; 43 return true; 44 } 45 46 return false; 47 } 48 49 bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs) 50 { 51 probes_opcode_t opcode; 52 53 if (!auprobe->simulate) 54 return false; 55 56 opcode = __mem_to_opcode_arm(*(unsigned int *) auprobe->insn); 57 58 auprobe->asi.insn_singlestep(opcode, &auprobe->asi, regs); 59 60 return true; 61 } 62 63 unsigned long 64 arch_uretprobe_hijack_return_addr(unsigned long trampoline_vaddr, 65 struct pt_regs *regs) 66 { 67 unsigned long orig_ret_vaddr; 68 69 orig_ret_vaddr = regs->ARM_lr; 70 /* Replace the return addr with trampoline addr */ 71 regs->ARM_lr = trampoline_vaddr; 72 return orig_ret_vaddr; 73 } 74 75 int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe, struct mm_struct *mm, 76 unsigned long addr) 77 { 78 unsigned int insn; 79 unsigned int bpinsn; 80 enum probes_insn ret; 81 82 /* Thumb not yet support */ 83 if (addr & 0x3) 84 return -EINVAL; 85 86 insn = __mem_to_opcode_arm(*(unsigned int *)auprobe->insn); 87 auprobe->ixol[0] = __opcode_to_mem_arm(insn); 88 auprobe->ixol[1] = __opcode_to_mem_arm(UPROBE_SS_ARM_INSN); 89 90 ret = arm_probes_decode_insn(insn, &auprobe->asi, false, 91 uprobes_probes_actions, NULL); 92 switch (ret) { 93 case INSN_REJECTED: 94 return -EINVAL; 95 96 case INSN_GOOD_NO_SLOT: 97 auprobe->simulate = true; 98 break; 99 100 case INSN_GOOD: 101 default: 102 break; 103 } 104 105 bpinsn = UPROBE_SWBP_ARM_INSN & 0x0fffffff; 106 if (insn >= 0xe0000000) 107 bpinsn |= 0xe0000000; /* Unconditional instruction */ 108 else 109 bpinsn |= insn & 0xf0000000; /* Copy condition from insn */ 110 111 auprobe->bpinsn = bpinsn; 112 113 return 0; 114 } 115 116 void arch_uprobe_copy_ixol(struct page *page, unsigned long vaddr, 117 void *src, unsigned long len) 118 { 119 void *xol_page_kaddr = kmap_atomic(page); 120 void *dst = xol_page_kaddr + (vaddr & ~PAGE_MASK); 121 122 preempt_disable(); 123 124 /* Initialize the slot */ 125 memcpy(dst, src, len); 126 127 /* flush caches (dcache/icache) */ 128 flush_uprobe_xol_access(page, vaddr, dst, len); 129 130 preempt_enable(); 131 132 kunmap_atomic(xol_page_kaddr); 133 } 134 135 136 int arch_uprobe_pre_xol(struct arch_uprobe *auprobe, struct pt_regs *regs) 137 { 138 struct uprobe_task *utask = current->utask; 139 140 if (auprobe->prehandler) 141 auprobe->prehandler(auprobe, &utask->autask, regs); 142 143 utask->autask.saved_trap_no = current->thread.trap_no; 144 current->thread.trap_no = UPROBE_TRAP_NR; 145 regs->ARM_pc = utask->xol_vaddr; 146 147 return 0; 148 } 149 150 int arch_uprobe_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs) 151 { 152 struct uprobe_task *utask = current->utask; 153 154 WARN_ON_ONCE(current->thread.trap_no != UPROBE_TRAP_NR); 155 156 current->thread.trap_no = utask->autask.saved_trap_no; 157 regs->ARM_pc = utask->vaddr + 4; 158 159 if (auprobe->posthandler) 160 auprobe->posthandler(auprobe, &utask->autask, regs); 161 162 return 0; 163 } 164 165 bool arch_uprobe_xol_was_trapped(struct task_struct *t) 166 { 167 if (t->thread.trap_no != UPROBE_TRAP_NR) 168 return true; 169 170 return false; 171 } 172 173 void arch_uprobe_abort_xol(struct arch_uprobe *auprobe, struct pt_regs *regs) 174 { 175 struct uprobe_task *utask = current->utask; 176 177 current->thread.trap_no = utask->autask.saved_trap_no; 178 instruction_pointer_set(regs, utask->vaddr); 179 } 180 181 int arch_uprobe_exception_notify(struct notifier_block *self, 182 unsigned long val, void *data) 183 { 184 return NOTIFY_DONE; 185 } 186 187 static int uprobe_trap_handler(struct pt_regs *regs, unsigned int instr) 188 { 189 unsigned long flags; 190 191 local_irq_save(flags); 192 instr &= 0x0fffffff; 193 if (instr == (UPROBE_SWBP_ARM_INSN & 0x0fffffff)) 194 uprobe_pre_sstep_notifier(regs); 195 else if (instr == (UPROBE_SS_ARM_INSN & 0x0fffffff)) 196 uprobe_post_sstep_notifier(regs); 197 local_irq_restore(flags); 198 199 return 0; 200 } 201 202 unsigned long uprobe_get_swbp_addr(struct pt_regs *regs) 203 { 204 return instruction_pointer(regs); 205 } 206 207 static struct undef_hook uprobes_arm_break_hook = { 208 .instr_mask = 0x0fffffff, 209 .instr_val = (UPROBE_SWBP_ARM_INSN & 0x0fffffff), 210 .cpsr_mask = MODE_MASK, 211 .cpsr_val = USR_MODE, 212 .fn = uprobe_trap_handler, 213 }; 214 215 static struct undef_hook uprobes_arm_ss_hook = { 216 .instr_mask = 0x0fffffff, 217 .instr_val = (UPROBE_SS_ARM_INSN & 0x0fffffff), 218 .cpsr_mask = MODE_MASK, 219 .cpsr_val = USR_MODE, 220 .fn = uprobe_trap_handler, 221 }; 222 223 static int arch_uprobes_init(void) 224 { 225 register_undef_hook(&uprobes_arm_break_hook); 226 register_undef_hook(&uprobes_arm_ss_hook); 227 228 return 0; 229 } 230 device_initcall(arch_uprobes_init); 231