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