0001
0002
0003
0004
0005
0006 #include <linux/kernel.h>
0007 #include <linux/stddef.h>
0008 #include <linux/errno.h>
0009 #include <linux/highmem.h>
0010 #include <linux/sched.h>
0011 #include <linux/uprobes.h>
0012 #include <linux/notifier.h>
0013
0014 #include <asm/opcodes.h>
0015 #include <asm/traps.h>
0016
0017 #include "../decode.h"
0018 #include "../decode-arm.h"
0019 #include "core.h"
0020
0021 #define UPROBE_TRAP_NR UINT_MAX
0022
0023 bool is_swbp_insn(uprobe_opcode_t *insn)
0024 {
0025 return (__mem_to_opcode_arm(*insn) & 0x0fffffff) ==
0026 (UPROBE_SWBP_ARM_INSN & 0x0fffffff);
0027 }
0028
0029 int set_swbp(struct arch_uprobe *auprobe, struct mm_struct *mm,
0030 unsigned long vaddr)
0031 {
0032 return uprobe_write_opcode(auprobe, mm, vaddr,
0033 __opcode_to_mem_arm(auprobe->bpinsn));
0034 }
0035
0036 bool arch_uprobe_ignore(struct arch_uprobe *auprobe, struct pt_regs *regs)
0037 {
0038 if (!auprobe->asi.insn_check_cc(regs->ARM_cpsr)) {
0039 regs->ARM_pc += 4;
0040 return true;
0041 }
0042
0043 return false;
0044 }
0045
0046 bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs)
0047 {
0048 probes_opcode_t opcode;
0049
0050 if (!auprobe->simulate)
0051 return false;
0052
0053 opcode = __mem_to_opcode_arm(*(unsigned int *) auprobe->insn);
0054
0055 auprobe->asi.insn_singlestep(opcode, &auprobe->asi, regs);
0056
0057 return true;
0058 }
0059
0060 unsigned long
0061 arch_uretprobe_hijack_return_addr(unsigned long trampoline_vaddr,
0062 struct pt_regs *regs)
0063 {
0064 unsigned long orig_ret_vaddr;
0065
0066 orig_ret_vaddr = regs->ARM_lr;
0067
0068 regs->ARM_lr = trampoline_vaddr;
0069 return orig_ret_vaddr;
0070 }
0071
0072 int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe, struct mm_struct *mm,
0073 unsigned long addr)
0074 {
0075 unsigned int insn;
0076 unsigned int bpinsn;
0077 enum probes_insn ret;
0078
0079
0080 if (addr & 0x3)
0081 return -EINVAL;
0082
0083 insn = __mem_to_opcode_arm(*(unsigned int *)auprobe->insn);
0084 auprobe->ixol[0] = __opcode_to_mem_arm(insn);
0085 auprobe->ixol[1] = __opcode_to_mem_arm(UPROBE_SS_ARM_INSN);
0086
0087 ret = arm_probes_decode_insn(insn, &auprobe->asi, false,
0088 uprobes_probes_actions, NULL);
0089 switch (ret) {
0090 case INSN_REJECTED:
0091 return -EINVAL;
0092
0093 case INSN_GOOD_NO_SLOT:
0094 auprobe->simulate = true;
0095 break;
0096
0097 case INSN_GOOD:
0098 default:
0099 break;
0100 }
0101
0102 bpinsn = UPROBE_SWBP_ARM_INSN & 0x0fffffff;
0103 if (insn >= 0xe0000000)
0104 bpinsn |= 0xe0000000;
0105 else
0106 bpinsn |= insn & 0xf0000000;
0107
0108 auprobe->bpinsn = bpinsn;
0109
0110 return 0;
0111 }
0112
0113 void arch_uprobe_copy_ixol(struct page *page, unsigned long vaddr,
0114 void *src, unsigned long len)
0115 {
0116 void *xol_page_kaddr = kmap_atomic(page);
0117 void *dst = xol_page_kaddr + (vaddr & ~PAGE_MASK);
0118
0119 preempt_disable();
0120
0121
0122 memcpy(dst, src, len);
0123
0124
0125 flush_uprobe_xol_access(page, vaddr, dst, len);
0126
0127 preempt_enable();
0128
0129 kunmap_atomic(xol_page_kaddr);
0130 }
0131
0132
0133 int arch_uprobe_pre_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
0134 {
0135 struct uprobe_task *utask = current->utask;
0136
0137 if (auprobe->prehandler)
0138 auprobe->prehandler(auprobe, &utask->autask, regs);
0139
0140 utask->autask.saved_trap_no = current->thread.trap_no;
0141 current->thread.trap_no = UPROBE_TRAP_NR;
0142 regs->ARM_pc = utask->xol_vaddr;
0143
0144 return 0;
0145 }
0146
0147 int arch_uprobe_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
0148 {
0149 struct uprobe_task *utask = current->utask;
0150
0151 WARN_ON_ONCE(current->thread.trap_no != UPROBE_TRAP_NR);
0152
0153 current->thread.trap_no = utask->autask.saved_trap_no;
0154 regs->ARM_pc = utask->vaddr + 4;
0155
0156 if (auprobe->posthandler)
0157 auprobe->posthandler(auprobe, &utask->autask, regs);
0158
0159 return 0;
0160 }
0161
0162 bool arch_uprobe_xol_was_trapped(struct task_struct *t)
0163 {
0164 if (t->thread.trap_no != UPROBE_TRAP_NR)
0165 return true;
0166
0167 return false;
0168 }
0169
0170 void arch_uprobe_abort_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
0171 {
0172 struct uprobe_task *utask = current->utask;
0173
0174 current->thread.trap_no = utask->autask.saved_trap_no;
0175 instruction_pointer_set(regs, utask->vaddr);
0176 }
0177
0178 int arch_uprobe_exception_notify(struct notifier_block *self,
0179 unsigned long val, void *data)
0180 {
0181 return NOTIFY_DONE;
0182 }
0183
0184 static int uprobe_trap_handler(struct pt_regs *regs, unsigned int instr)
0185 {
0186 unsigned long flags;
0187
0188 local_irq_save(flags);
0189 instr &= 0x0fffffff;
0190 if (instr == (UPROBE_SWBP_ARM_INSN & 0x0fffffff))
0191 uprobe_pre_sstep_notifier(regs);
0192 else if (instr == (UPROBE_SS_ARM_INSN & 0x0fffffff))
0193 uprobe_post_sstep_notifier(regs);
0194 local_irq_restore(flags);
0195
0196 return 0;
0197 }
0198
0199 unsigned long uprobe_get_swbp_addr(struct pt_regs *regs)
0200 {
0201 return instruction_pointer(regs);
0202 }
0203
0204 static struct undef_hook uprobes_arm_break_hook = {
0205 .instr_mask = 0x0fffffff,
0206 .instr_val = (UPROBE_SWBP_ARM_INSN & 0x0fffffff),
0207 .cpsr_mask = (PSR_T_BIT | MODE_MASK),
0208 .cpsr_val = USR_MODE,
0209 .fn = uprobe_trap_handler,
0210 };
0211
0212 static struct undef_hook uprobes_arm_ss_hook = {
0213 .instr_mask = 0x0fffffff,
0214 .instr_val = (UPROBE_SS_ARM_INSN & 0x0fffffff),
0215 .cpsr_mask = (PSR_T_BIT | MODE_MASK),
0216 .cpsr_val = USR_MODE,
0217 .fn = uprobe_trap_handler,
0218 };
0219
0220 static int arch_uprobes_init(void)
0221 {
0222 register_undef_hook(&uprobes_arm_break_hook);
0223 register_undef_hook(&uprobes_arm_ss_hook);
0224
0225 return 0;
0226 }
0227 device_initcall(arch_uprobes_init);