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

TOMOYO Linux Cross Reference
Linux/arch/arm/probes/kprobes/actions-arm.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-arm.c
  4  *
  5  * Copyright (C) 2006, 2007 Motorola Inc.
  6  */
  7 
  8 /*
  9  * We do not have hardware single-stepping on ARM, This
 10  * effort is further complicated by the ARM not having a
 11  * "next PC" register.  Instructions that change the PC
 12  * can't be safely single-stepped in a MP environment, so
 13  * we have a lot of work to do:
 14  *
 15  * In the prepare phase:
 16  *   *) If it is an instruction that does anything
 17  *      with the CPU mode, we reject it for a kprobe.
 18  *      (This is out of laziness rather than need.  The
 19  *      instructions could be simulated.)
 20  *
 21  *   *) Otherwise, decode the instruction rewriting its
 22  *      registers to take fixed, ordered registers and
 23  *      setting a handler for it to run the instruction.
 24  *
 25  * In the execution phase by an instruction's handler:
 26  *
 27  *   *) If the PC is written to by the instruction, the
 28  *      instruction must be fully simulated in software.
 29  *
 30  *   *) Otherwise, a modified form of the instruction is
 31  *      directly executed.  Its handler calls the
 32  *      instruction in insn[0].  In insn[1] is a
 33  *      "mov pc, lr" to return.
 34  *
 35  *      Before calling, load up the reordered registers
 36  *      from the original instruction's registers.  If one
 37  *      of the original input registers is the PC, compute
 38  *      and adjust the appropriate input register.
 39  *
 40  *      After call completes, copy the output registers to
 41  *      the original instruction's original registers.
 42  *
 43  * We don't use a real breakpoint instruction since that
 44  * would have us in the kernel go from SVC mode to SVC
 45  * mode losing the link register.  Instead we use an
 46  * undefined instruction.  To simplify processing, the
 47  * undefined instruction used for kprobes must be reserved
 48  * exclusively for kprobes use.
 49  *
 50  * TODO: ifdef out some instruction decoding based on architecture.
 51  */
 52 
 53 #include <linux/kernel.h>
 54 #include <linux/kprobes.h>
 55 #include <linux/ptrace.h>
 56 
 57 #include "../decode-arm.h"
 58 #include "core.h"
 59 #include "checkers.h"
 60 
 61 #if  __LINUX_ARM_ARCH__ >= 6
 62 #define BLX(reg)        "blx    "reg"           \n\t"
 63 #else
 64 #define BLX(reg)        "mov    lr, pc          \n\t"   \
 65                         "mov    pc, "reg"       \n\t"
 66 #endif
 67 
 68 static void __kprobes
 69 emulate_ldrdstrd(probes_opcode_t insn,
 70         struct arch_probes_insn *asi, struct pt_regs *regs)
 71 {
 72         unsigned long pc = regs->ARM_pc + 4;
 73         int rt = (insn >> 12) & 0xf;
 74         int rn = (insn >> 16) & 0xf;
 75         int rm = insn & 0xf;
 76 
 77         register unsigned long rtv asm("r0") = regs->uregs[rt];
 78         register unsigned long rt2v asm("r1") = regs->uregs[rt+1];
 79         register unsigned long rnv asm("r2") = (rn == 15) ? pc
 80                                                           : regs->uregs[rn];
 81         register unsigned long rmv asm("r3") = regs->uregs[rm];
 82 
 83         __asm__ __volatile__ (
 84                 BLX("%[fn]")
 85                 : "=r" (rtv), "=r" (rt2v), "=r" (rnv)
 86                 : "" (rtv), "1" (rt2v), "2" (rnv), "r" (rmv),
 87                   [fn] "r" (asi->insn_fn)
 88                 : "lr", "memory", "cc"
 89         );
 90 
 91         regs->uregs[rt] = rtv;
 92         regs->uregs[rt+1] = rt2v;
 93         if (is_writeback(insn))
 94                 regs->uregs[rn] = rnv;
 95 }
 96 
 97 static void __kprobes
 98 emulate_ldr(probes_opcode_t insn,
 99         struct arch_probes_insn *asi, struct pt_regs *regs)
100 {
101         unsigned long pc = regs->ARM_pc + 4;
102         int rt = (insn >> 12) & 0xf;
103         int rn = (insn >> 16) & 0xf;
104         int rm = insn & 0xf;
105 
106         register unsigned long rtv asm("r0");
107         register unsigned long rnv asm("r2") = (rn == 15) ? pc
108                                                           : regs->uregs[rn];
109         register unsigned long rmv asm("r3") = regs->uregs[rm];
110 
111         __asm__ __volatile__ (
112                 BLX("%[fn]")
113                 : "=r" (rtv), "=r" (rnv)
114                 : "1" (rnv), "r" (rmv), [fn] "r" (asi->insn_fn)
115                 : "lr", "memory", "cc"
116         );
117 
118         if (rt == 15)
119                 load_write_pc(rtv, regs);
120         else
121                 regs->uregs[rt] = rtv;
122 
123         if (is_writeback(insn))
124                 regs->uregs[rn] = rnv;
125 }
126 
127 static void __kprobes
128 emulate_str(probes_opcode_t insn,
129         struct arch_probes_insn *asi, struct pt_regs *regs)
130 {
131         unsigned long rtpc = regs->ARM_pc - 4 + str_pc_offset;
132         unsigned long rnpc = regs->ARM_pc + 4;
133         int rt = (insn >> 12) & 0xf;
134         int rn = (insn >> 16) & 0xf;
135         int rm = insn & 0xf;
136 
137         register unsigned long rtv asm("r0") = (rt == 15) ? rtpc
138                                                           : regs->uregs[rt];
139         register unsigned long rnv asm("r2") = (rn == 15) ? rnpc
140                                                           : regs->uregs[rn];
141         register unsigned long rmv asm("r3") = regs->uregs[rm];
142 
143         __asm__ __volatile__ (
144                 BLX("%[fn]")
145                 : "=r" (rnv)
146                 : "r" (rtv), "" (rnv), "r" (rmv), [fn] "r" (asi->insn_fn)
147                 : "lr", "memory", "cc"
148         );
149 
150         if (is_writeback(insn))
151                 regs->uregs[rn] = rnv;
152 }
153 
154 static void __kprobes
155 emulate_rd12rn16rm0rs8_rwflags(probes_opcode_t insn,
156         struct arch_probes_insn *asi, struct pt_regs *regs)
157 {
158         unsigned long pc = regs->ARM_pc + 4;
159         int rd = (insn >> 12) & 0xf;
160         int rn = (insn >> 16) & 0xf;
161         int rm = insn & 0xf;
162         int rs = (insn >> 8) & 0xf;
163 
164         register unsigned long rdv asm("r0") = regs->uregs[rd];
165         register unsigned long rnv asm("r2") = (rn == 15) ? pc
166                                                           : regs->uregs[rn];
167         register unsigned long rmv asm("r3") = (rm == 15) ? pc
168                                                           : regs->uregs[rm];
169         register unsigned long rsv asm("r1") = regs->uregs[rs];
170         unsigned long cpsr = regs->ARM_cpsr;
171 
172         __asm__ __volatile__ (
173                 "msr    cpsr_fs, %[cpsr]        \n\t"
174                 BLX("%[fn]")
175                 "mrs    %[cpsr], cpsr           \n\t"
176                 : "=r" (rdv), [cpsr] "=r" (cpsr)
177                 : "" (rdv), "r" (rnv), "r" (rmv), "r" (rsv),
178                   "1" (cpsr), [fn] "r" (asi->insn_fn)
179                 : "lr", "memory", "cc"
180         );
181 
182         if (rd == 15)
183                 alu_write_pc(rdv, regs);
184         else
185                 regs->uregs[rd] = rdv;
186         regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK);
187 }
188 
189 static void __kprobes
190 emulate_rd12rn16rm0_rwflags_nopc(probes_opcode_t insn,
191         struct arch_probes_insn *asi, struct pt_regs *regs)
192 {
193         int rd = (insn >> 12) & 0xf;
194         int rn = (insn >> 16) & 0xf;
195         int rm = insn & 0xf;
196 
197         register unsigned long rdv asm("r0") = regs->uregs[rd];
198         register unsigned long rnv asm("r2") = regs->uregs[rn];
199         register unsigned long rmv asm("r3") = regs->uregs[rm];
200         unsigned long cpsr = regs->ARM_cpsr;
201 
202         __asm__ __volatile__ (
203                 "msr    cpsr_fs, %[cpsr]        \n\t"
204                 BLX("%[fn]")
205                 "mrs    %[cpsr], cpsr           \n\t"
206                 : "=r" (rdv), [cpsr] "=r" (cpsr)
207                 : "" (rdv), "r" (rnv), "r" (rmv),
208                   "1" (cpsr), [fn] "r" (asi->insn_fn)
209                 : "lr", "memory", "cc"
210         );
211 
212         regs->uregs[rd] = rdv;
213         regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK);
214 }
215 
216 static void __kprobes
217 emulate_rd16rn12rm0rs8_rwflags_nopc(probes_opcode_t insn,
218         struct arch_probes_insn *asi,
219         struct pt_regs *regs)
220 {
221         int rd = (insn >> 16) & 0xf;
222         int rn = (insn >> 12) & 0xf;
223         int rm = insn & 0xf;
224         int rs = (insn >> 8) & 0xf;
225 
226         register unsigned long rdv asm("r2") = regs->uregs[rd];
227         register unsigned long rnv asm("r0") = regs->uregs[rn];
228         register unsigned long rmv asm("r3") = regs->uregs[rm];
229         register unsigned long rsv asm("r1") = regs->uregs[rs];
230         unsigned long cpsr = regs->ARM_cpsr;
231 
232         __asm__ __volatile__ (
233                 "msr    cpsr_fs, %[cpsr]        \n\t"
234                 BLX("%[fn]")
235                 "mrs    %[cpsr], cpsr           \n\t"
236                 : "=r" (rdv), [cpsr] "=r" (cpsr)
237                 : "" (rdv), "r" (rnv), "r" (rmv), "r" (rsv),
238                   "1" (cpsr), [fn] "r" (asi->insn_fn)
239                 : "lr", "memory", "cc"
240         );
241 
242         regs->uregs[rd] = rdv;
243         regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK);
244 }
245 
246 static void __kprobes
247 emulate_rd12rm0_noflags_nopc(probes_opcode_t insn,
248         struct arch_probes_insn *asi, struct pt_regs *regs)
249 {
250         int rd = (insn >> 12) & 0xf;
251         int rm = insn & 0xf;
252 
253         register unsigned long rdv asm("r0") = regs->uregs[rd];
254         register unsigned long rmv asm("r3") = regs->uregs[rm];
255 
256         __asm__ __volatile__ (
257                 BLX("%[fn]")
258                 : "=r" (rdv)
259                 : "" (rdv), "r" (rmv), [fn] "r" (asi->insn_fn)
260                 : "lr", "memory", "cc"
261         );
262 
263         regs->uregs[rd] = rdv;
264 }
265 
266 static void __kprobes
267 emulate_rdlo12rdhi16rn0rm8_rwflags_nopc(probes_opcode_t insn,
268         struct arch_probes_insn *asi,
269         struct pt_regs *regs)
270 {
271         int rdlo = (insn >> 12) & 0xf;
272         int rdhi = (insn >> 16) & 0xf;
273         int rn = insn & 0xf;
274         int rm = (insn >> 8) & 0xf;
275 
276         register unsigned long rdlov asm("r0") = regs->uregs[rdlo];
277         register unsigned long rdhiv asm("r2") = regs->uregs[rdhi];
278         register unsigned long rnv asm("r3") = regs->uregs[rn];
279         register unsigned long rmv asm("r1") = regs->uregs[rm];
280         unsigned long cpsr = regs->ARM_cpsr;
281 
282         __asm__ __volatile__ (
283                 "msr    cpsr_fs, %[cpsr]        \n\t"
284                 BLX("%[fn]")
285                 "mrs    %[cpsr], cpsr           \n\t"
286                 : "=r" (rdlov), "=r" (rdhiv), [cpsr] "=r" (cpsr)
287                 : "" (rdlov), "1" (rdhiv), "r" (rnv), "r" (rmv),
288                   "2" (cpsr), [fn] "r" (asi->insn_fn)
289                 : "lr", "memory", "cc"
290         );
291 
292         regs->uregs[rdlo] = rdlov;
293         regs->uregs[rdhi] = rdhiv;
294         regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK);
295 }
296 
297 const union decode_action kprobes_arm_actions[NUM_PROBES_ARM_ACTIONS] = {
298         [PROBES_PRELOAD_IMM] = {.handler = probes_simulate_nop},
299         [PROBES_PRELOAD_REG] = {.handler = probes_simulate_nop},
300         [PROBES_BRANCH_IMM] = {.handler = simulate_blx1},
301         [PROBES_MRS] = {.handler = simulate_mrs},
302         [PROBES_BRANCH_REG] = {.handler = simulate_blx2bx},
303         [PROBES_CLZ] = {.handler = emulate_rd12rm0_noflags_nopc},
304         [PROBES_SATURATING_ARITHMETIC] = {
305                 .handler = emulate_rd12rn16rm0_rwflags_nopc},
306         [PROBES_MUL1] = {.handler = emulate_rdlo12rdhi16rn0rm8_rwflags_nopc},
307         [PROBES_MUL2] = {.handler = emulate_rd16rn12rm0rs8_rwflags_nopc},
308         [PROBES_SWP] = {.handler = emulate_rd12rn16rm0_rwflags_nopc},
309         [PROBES_LDRSTRD] = {.handler = emulate_ldrdstrd},
310         [PROBES_LOAD_EXTRA] = {.handler = emulate_ldr},
311         [PROBES_LOAD] = {.handler = emulate_ldr},
312         [PROBES_STORE_EXTRA] = {.handler = emulate_str},
313         [PROBES_STORE] = {.handler = emulate_str},
314         [PROBES_MOV_IP_SP] = {.handler = simulate_mov_ipsp},
315         [PROBES_DATA_PROCESSING_REG] = {
316                 .handler = emulate_rd12rn16rm0rs8_rwflags},
317         [PROBES_DATA_PROCESSING_IMM] = {
318                 .handler = emulate_rd12rn16rm0rs8_rwflags},
319         [PROBES_MOV_HALFWORD] = {.handler = emulate_rd12rm0_noflags_nopc},
320         [PROBES_SEV] = {.handler = probes_emulate_none},
321         [PROBES_WFE] = {.handler = probes_simulate_nop},
322         [PROBES_SATURATE] = {.handler = emulate_rd12rn16rm0_rwflags_nopc},
323         [PROBES_REV] = {.handler = emulate_rd12rm0_noflags_nopc},
324         [PROBES_MMI] = {.handler = emulate_rd12rn16rm0_rwflags_nopc},
325         [PROBES_PACK] = {.handler = emulate_rd12rn16rm0_rwflags_nopc},
326         [PROBES_EXTEND] = {.handler = emulate_rd12rm0_noflags_nopc},
327         [PROBES_EXTEND_ADD] = {.handler = emulate_rd12rn16rm0_rwflags_nopc},
328         [PROBES_MUL_ADD_LONG] = {
329                 .handler = emulate_rdlo12rdhi16rn0rm8_rwflags_nopc},
330         [PROBES_MUL_ADD] = {.handler = emulate_rd16rn12rm0rs8_rwflags_nopc},
331         [PROBES_BITFIELD] = {.handler = emulate_rd12rm0_noflags_nopc},
332         [PROBES_BRANCH] = {.handler = simulate_bbl},
333         [PROBES_LDMSTM] = {.decoder = kprobe_decode_ldmstm}
334 };
335 
336 const struct decode_checker *kprobes_arm_checkers[] = {arm_stack_checker, arm_regs_checker, NULL};
337 

~ [ 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