Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (C) 2012 Rabin Vincent <rabin at rab.in>
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     /* Replace the return addr with trampoline addr */
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     /* Thumb not yet support */
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;  /* Unconditional instruction */
0105     else
0106         bpinsn |= insn & 0xf0000000;  /* Copy condition from insn */
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     /* Initialize the slot */
0122     memcpy(dst, src, len);
0123 
0124     /* flush caches (dcache/icache) */
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);