root/arch/arm/probes/kprobes/actions-common.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. simulate_ldm1stm1
  2. simulate_stm1_pc
  3. simulate_ldm1_pc
  4. emulate_generic_r0_12_noflags
  5. emulate_generic_r2_14_noflags
  6. emulate_ldm_r3_15
  7. kprobe_decode_ldmstm

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * arch/arm/probes/kprobes/actions-common.c
   4  *
   5  * Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>.
   6  *
   7  * Some contents moved here from arch/arm/include/asm/kprobes-arm.c which is
   8  * Copyright (C) 2006, 2007 Motorola Inc.
   9  */
  10 
  11 #include <linux/kernel.h>
  12 #include <linux/kprobes.h>
  13 #include <asm/opcodes.h>
  14 
  15 #include "core.h"
  16 
  17 
  18 static void __kprobes simulate_ldm1stm1(probes_opcode_t insn,
  19                 struct arch_probes_insn *asi,
  20                 struct pt_regs *regs)
  21 {
  22         int rn = (insn >> 16) & 0xf;
  23         int lbit = insn & (1 << 20);
  24         int wbit = insn & (1 << 21);
  25         int ubit = insn & (1 << 23);
  26         int pbit = insn & (1 << 24);
  27         long *addr = (long *)regs->uregs[rn];
  28         int reg_bit_vector;
  29         int reg_count;
  30 
  31         reg_count = 0;
  32         reg_bit_vector = insn & 0xffff;
  33         while (reg_bit_vector) {
  34                 reg_bit_vector &= (reg_bit_vector - 1);
  35                 ++reg_count;
  36         }
  37 
  38         if (!ubit)
  39                 addr -= reg_count;
  40         addr += (!pbit == !ubit);
  41 
  42         reg_bit_vector = insn & 0xffff;
  43         while (reg_bit_vector) {
  44                 int reg = __ffs(reg_bit_vector);
  45                 reg_bit_vector &= (reg_bit_vector - 1);
  46                 if (lbit)
  47                         regs->uregs[reg] = *addr++;
  48                 else
  49                         *addr++ = regs->uregs[reg];
  50         }
  51 
  52         if (wbit) {
  53                 if (!ubit)
  54                         addr -= reg_count;
  55                 addr -= (!pbit == !ubit);
  56                 regs->uregs[rn] = (long)addr;
  57         }
  58 }
  59 
  60 static void __kprobes simulate_stm1_pc(probes_opcode_t insn,
  61         struct arch_probes_insn *asi,
  62         struct pt_regs *regs)
  63 {
  64         unsigned long addr = regs->ARM_pc - 4;
  65 
  66         regs->ARM_pc = (long)addr + str_pc_offset;
  67         simulate_ldm1stm1(insn, asi, regs);
  68         regs->ARM_pc = (long)addr + 4;
  69 }
  70 
  71 static void __kprobes simulate_ldm1_pc(probes_opcode_t insn,
  72         struct arch_probes_insn *asi,
  73         struct pt_regs *regs)
  74 {
  75         simulate_ldm1stm1(insn, asi, regs);
  76         load_write_pc(regs->ARM_pc, regs);
  77 }
  78 
  79 static void __kprobes
  80 emulate_generic_r0_12_noflags(probes_opcode_t insn,
  81         struct arch_probes_insn *asi, struct pt_regs *regs)
  82 {
  83         register void *rregs asm("r1") = regs;
  84         register void *rfn asm("lr") = asi->insn_fn;
  85 
  86         __asm__ __volatile__ (
  87                 "stmdb  sp!, {%[regs], r11}     \n\t"
  88                 "ldmia  %[regs], {r0-r12}       \n\t"
  89 #if __LINUX_ARM_ARCH__ >= 6
  90                 "blx    %[fn]                   \n\t"
  91 #else
  92                 "str    %[fn], [sp, #-4]!       \n\t"
  93                 "adr    lr, 1f                  \n\t"
  94                 "ldr    pc, [sp], #4            \n\t"
  95                 "1:                             \n\t"
  96 #endif
  97                 "ldr    lr, [sp], #4            \n\t" /* lr = regs */
  98                 "stmia  lr, {r0-r12}            \n\t"
  99                 "ldr    r11, [sp], #4           \n\t"
 100                 : [regs] "=r" (rregs), [fn] "=r" (rfn)
 101                 : "0" (rregs), "1" (rfn)
 102                 : "r0", "r2", "r3", "r4", "r5", "r6", "r7",
 103                   "r8", "r9", "r10", "r12", "memory", "cc"
 104                 );
 105 }
 106 
 107 static void __kprobes
 108 emulate_generic_r2_14_noflags(probes_opcode_t insn,
 109         struct arch_probes_insn *asi, struct pt_regs *regs)
 110 {
 111         emulate_generic_r0_12_noflags(insn, asi,
 112                 (struct pt_regs *)(regs->uregs+2));
 113 }
 114 
 115 static void __kprobes
 116 emulate_ldm_r3_15(probes_opcode_t insn,
 117         struct arch_probes_insn *asi, struct pt_regs *regs)
 118 {
 119         emulate_generic_r0_12_noflags(insn, asi,
 120                 (struct pt_regs *)(regs->uregs+3));
 121         load_write_pc(regs->ARM_pc, regs);
 122 }
 123 
 124 enum probes_insn __kprobes
 125 kprobe_decode_ldmstm(probes_opcode_t insn, struct arch_probes_insn *asi,
 126                 const struct decode_header *h)
 127 {
 128         probes_insn_handler_t *handler = 0;
 129         unsigned reglist = insn & 0xffff;
 130         int is_ldm = insn & 0x100000;
 131         int rn = (insn >> 16) & 0xf;
 132 
 133         if (rn <= 12 && (reglist & 0xe000) == 0) {
 134                 /* Instruction only uses registers in the range R0..R12 */
 135                 handler = emulate_generic_r0_12_noflags;
 136 
 137         } else if (rn >= 2 && (reglist & 0x8003) == 0) {
 138                 /* Instruction only uses registers in the range R2..R14 */
 139                 rn -= 2;
 140                 reglist >>= 2;
 141                 handler = emulate_generic_r2_14_noflags;
 142 
 143         } else if (rn >= 3 && (reglist & 0x0007) == 0) {
 144                 /* Instruction only uses registers in the range R3..R15 */
 145                 if (is_ldm && (reglist & 0x8000)) {
 146                         rn -= 3;
 147                         reglist >>= 3;
 148                         handler = emulate_ldm_r3_15;
 149                 }
 150         }
 151 
 152         if (handler) {
 153                 /* We can emulate the instruction in (possibly) modified form */
 154                 asi->insn[0] = __opcode_to_mem_arm((insn & 0xfff00000) |
 155                                                    (rn << 16) | reglist);
 156                 asi->insn_handler = handler;
 157                 return INSN_GOOD;
 158         }
 159 
 160         /* Fallback to slower simulation... */
 161         if (reglist & 0x8000)
 162                 handler = is_ldm ? simulate_ldm1_pc : simulate_stm1_pc;
 163         else
 164                 handler = simulate_ldm1stm1;
 165         asi->insn_handler = handler;
 166         return INSN_GOOD_NO_SLOT;
 167 }
 168 

/* [<][>][^][v][top][bottom][index][help] */