~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/arm/probes/kprobes/actions-common.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 ARM(            "stmdb  sp!, {%[regs], r11}     \n\t"   )
 88 THUMB(          "stmdb  sp!, {%[regs], r7}      \n\t"   )
 89                 "ldmia  %[regs], {r0-r12}       \n\t"
 90 #if __LINUX_ARM_ARCH__ >= 6
 91                 "blx    %[fn]                   \n\t"
 92 #else
 93                 "str    %[fn], [sp, #-4]!       \n\t"
 94                 "adr    lr, 1f                  \n\t"
 95                 "ldr    pc, [sp], #4            \n\t"
 96                 "1:                             \n\t"
 97 #endif
 98                 "ldr    lr, [sp], #4            \n\t" /* lr = regs */
 99                 "stmia  lr, {r0-r12}            \n\t"
100 ARM(            "ldr    r11, [sp], #4           \n\t"   )
101 THUMB(          "ldr    r7, [sp], #4            \n\t"   )
102                 : [regs] "=r" (rregs), [fn] "=r" (rfn)
103                 : "" (rregs), "1" (rfn)
104                 : "r0", "r2", "r3", "r4", "r5", "r6", ARM("r7") THUMB("r11"),
105                   "r8", "r9", "r10", "r12", "memory", "cc"
106                 );
107 }
108 
109 static void __kprobes
110 emulate_generic_r2_14_noflags(probes_opcode_t insn,
111         struct arch_probes_insn *asi, struct pt_regs *regs)
112 {
113         emulate_generic_r0_12_noflags(insn, asi,
114                 (struct pt_regs *)(regs->uregs+2));
115 }
116 
117 static void __kprobes
118 emulate_ldm_r3_15(probes_opcode_t insn,
119         struct arch_probes_insn *asi, struct pt_regs *regs)
120 {
121         emulate_generic_r0_12_noflags(insn, asi,
122                 (struct pt_regs *)(regs->uregs+3));
123         load_write_pc(regs->ARM_pc, regs);
124 }
125 
126 enum probes_insn __kprobes
127 kprobe_decode_ldmstm(probes_opcode_t insn, struct arch_probes_insn *asi,
128                 const struct decode_header *h)
129 {
130         probes_insn_handler_t *handler = 0;
131         unsigned reglist = insn & 0xffff;
132         int is_ldm = insn & 0x100000;
133         int rn = (insn >> 16) & 0xf;
134 
135         if (rn <= 12 && (reglist & 0xe000) == 0) {
136                 /* Instruction only uses registers in the range R0..R12 */
137                 handler = emulate_generic_r0_12_noflags;
138 
139         } else if (rn >= 2 && (reglist & 0x8003) == 0) {
140                 /* Instruction only uses registers in the range R2..R14 */
141                 rn -= 2;
142                 reglist >>= 2;
143                 handler = emulate_generic_r2_14_noflags;
144 
145         } else if (rn >= 3 && (reglist & 0x0007) == 0) {
146                 /* Instruction only uses registers in the range R3..R15 */
147                 if (is_ldm && (reglist & 0x8000)) {
148                         rn -= 3;
149                         reglist >>= 3;
150                         handler = emulate_ldm_r3_15;
151                 }
152         }
153 
154         if (handler) {
155                 /* We can emulate the instruction in (possibly) modified form */
156                 asi->insn[0] = __opcode_to_mem_arm((insn & 0xfff00000) |
157                                                    (rn << 16) | reglist);
158                 asi->insn_handler = handler;
159                 return INSN_GOOD;
160         }
161 
162         /* Fallback to slower simulation... */
163         if (reglist & 0x8000)
164                 handler = is_ldm ? simulate_ldm1_pc : simulate_stm1_pc;
165         else
166                 handler = simulate_ldm1stm1;
167         asi->insn_handler = handler;
168         return INSN_GOOD_NO_SLOT;
169 }
170 
171 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php