diff options
| author | Jon Medhurst <tixy@yxit.co.uk> | 2011-06-13 13:39:29 -0400 |
|---|---|---|
| committer | Tixy <tixy@medhuaa1.miniserver.com> | 2011-07-13 13:32:51 -0400 |
| commit | 8f2ffa00fb3c05ec0659cd7b056c4e8e106072f1 (patch) | |
| tree | 859596b031ebfde5a44ade734a4c61ff22b1eb8b | |
| parent | 0239269db6ba1ea908006fe309ade12991dd4e21 (diff) | |
ARM: kprobes: Remove now unused code
Signed-off-by: Jon Medhurst <tixy@yxit.co.uk>
Acked-by: Nicolas Pitre <nicolas.pitre@linaro.org>
| -rw-r--r-- | arch/arm/kernel/kprobes-arm.c | 738 |
1 files changed, 0 insertions, 738 deletions
diff --git a/arch/arm/kernel/kprobes-arm.c b/arch/arm/kernel/kprobes-arm.c index 8a58c99f658..79203ee1d03 100644 --- a/arch/arm/kernel/kprobes-arm.c +++ b/arch/arm/kernel/kprobes-arm.c | |||
| @@ -74,300 +74,6 @@ | |||
| 74 | "mov pc, "reg" \n\t" | 74 | "mov pc, "reg" \n\t" |
| 75 | #endif | 75 | #endif |
| 76 | 76 | ||
| 77 | #define is_r15(insn, bitpos) (((insn) & (0xf << bitpos)) == (0xf << bitpos)) | ||
| 78 | |||
| 79 | #define PSR_fs (PSR_f|PSR_s) | ||
| 80 | |||
| 81 | #define KPROBE_RETURN_INSTRUCTION 0xe1a0f00e /* mov pc, lr */ | ||
| 82 | |||
| 83 | typedef long (insn_0arg_fn_t)(void); | ||
| 84 | typedef long (insn_1arg_fn_t)(long); | ||
| 85 | typedef long (insn_2arg_fn_t)(long, long); | ||
| 86 | typedef long (insn_3arg_fn_t)(long, long, long); | ||
| 87 | typedef long (insn_4arg_fn_t)(long, long, long, long); | ||
| 88 | typedef long long (insn_llret_0arg_fn_t)(void); | ||
| 89 | typedef long long (insn_llret_3arg_fn_t)(long, long, long); | ||
| 90 | typedef long long (insn_llret_4arg_fn_t)(long, long, long, long); | ||
| 91 | |||
| 92 | union reg_pair { | ||
| 93 | long long dr; | ||
| 94 | #ifdef __LITTLE_ENDIAN | ||
| 95 | struct { long r0, r1; }; | ||
| 96 | #else | ||
| 97 | struct { long r1, r0; }; | ||
| 98 | #endif | ||
| 99 | }; | ||
| 100 | |||
| 101 | /* | ||
| 102 | * The insnslot_?arg_r[w]flags() functions below are to keep the | ||
| 103 | * msr -> *fn -> mrs instruction sequences indivisible so that | ||
| 104 | * the state of the CPSR flags aren't inadvertently modified | ||
| 105 | * just before or just after the call. | ||
| 106 | */ | ||
| 107 | |||
| 108 | static inline long __kprobes | ||
| 109 | insnslot_0arg_rflags(long cpsr, insn_0arg_fn_t *fn) | ||
| 110 | { | ||
| 111 | register long ret asm("r0"); | ||
| 112 | |||
| 113 | __asm__ __volatile__ ( | ||
| 114 | "msr cpsr_fs, %[cpsr] \n\t" | ||
| 115 | "mov lr, pc \n\t" | ||
| 116 | "mov pc, %[fn] \n\t" | ||
| 117 | : "=r" (ret) | ||
| 118 | : [cpsr] "r" (cpsr), [fn] "r" (fn) | ||
| 119 | : "lr", "cc" | ||
| 120 | ); | ||
| 121 | return ret; | ||
| 122 | } | ||
| 123 | |||
| 124 | static inline long long __kprobes | ||
| 125 | insnslot_llret_0arg_rflags(long cpsr, insn_llret_0arg_fn_t *fn) | ||
| 126 | { | ||
| 127 | register long ret0 asm("r0"); | ||
| 128 | register long ret1 asm("r1"); | ||
| 129 | union reg_pair fnr; | ||
| 130 | |||
| 131 | __asm__ __volatile__ ( | ||
| 132 | "msr cpsr_fs, %[cpsr] \n\t" | ||
| 133 | "mov lr, pc \n\t" | ||
| 134 | "mov pc, %[fn] \n\t" | ||
| 135 | : "=r" (ret0), "=r" (ret1) | ||
| 136 | : [cpsr] "r" (cpsr), [fn] "r" (fn) | ||
| 137 | : "lr", "cc" | ||
| 138 | ); | ||
| 139 | fnr.r0 = ret0; | ||
| 140 | fnr.r1 = ret1; | ||
| 141 | return fnr.dr; | ||
| 142 | } | ||
| 143 | |||
| 144 | static inline long __kprobes | ||
| 145 | insnslot_1arg_rflags(long r0, long cpsr, insn_1arg_fn_t *fn) | ||
| 146 | { | ||
| 147 | register long rr0 asm("r0") = r0; | ||
| 148 | register long ret asm("r0"); | ||
| 149 | |||
| 150 | __asm__ __volatile__ ( | ||
| 151 | "msr cpsr_fs, %[cpsr] \n\t" | ||
| 152 | "mov lr, pc \n\t" | ||
| 153 | "mov pc, %[fn] \n\t" | ||
| 154 | : "=r" (ret) | ||
| 155 | : "0" (rr0), [cpsr] "r" (cpsr), [fn] "r" (fn) | ||
| 156 | : "lr", "cc" | ||
| 157 | ); | ||
| 158 | return ret; | ||
| 159 | } | ||
| 160 | |||
| 161 | static inline long __kprobes | ||
| 162 | insnslot_2arg_rflags(long r0, long r1, long cpsr, insn_2arg_fn_t *fn) | ||
| 163 | { | ||
| 164 | register long rr0 asm("r0") = r0; | ||
| 165 | register long rr1 asm("r1") = r1; | ||
| 166 | register long ret asm("r0"); | ||
| 167 | |||
| 168 | __asm__ __volatile__ ( | ||
| 169 | "msr cpsr_fs, %[cpsr] \n\t" | ||
| 170 | "mov lr, pc \n\t" | ||
| 171 | "mov pc, %[fn] \n\t" | ||
| 172 | : "=r" (ret) | ||
| 173 | : "0" (rr0), "r" (rr1), | ||
| 174 | [cpsr] "r" (cpsr), [fn] "r" (fn) | ||
| 175 | : "lr", "cc" | ||
| 176 | ); | ||
| 177 | return ret; | ||
| 178 | } | ||
| 179 | |||
| 180 | static inline long __kprobes | ||
| 181 | insnslot_3arg_rflags(long r0, long r1, long r2, long cpsr, insn_3arg_fn_t *fn) | ||
| 182 | { | ||
| 183 | register long rr0 asm("r0") = r0; | ||
| 184 | register long rr1 asm("r1") = r1; | ||
| 185 | register long rr2 asm("r2") = r2; | ||
| 186 | register long ret asm("r0"); | ||
| 187 | |||
| 188 | __asm__ __volatile__ ( | ||
| 189 | "msr cpsr_fs, %[cpsr] \n\t" | ||
| 190 | "mov lr, pc \n\t" | ||
| 191 | "mov pc, %[fn] \n\t" | ||
| 192 | : "=r" (ret) | ||
| 193 | : "0" (rr0), "r" (rr1), "r" (rr2), | ||
| 194 | [cpsr] "r" (cpsr), [fn] "r" (fn) | ||
| 195 | : "lr", "cc" | ||
| 196 | ); | ||
| 197 | return ret; | ||
| 198 | } | ||
| 199 | |||
| 200 | static inline long long __kprobes | ||
| 201 | insnslot_llret_3arg_rflags(long r0, long r1, long r2, long cpsr, | ||
| 202 | insn_llret_3arg_fn_t *fn) | ||
| 203 | { | ||
| 204 | register long rr0 asm("r0") = r0; | ||
| 205 | register long rr1 asm("r1") = r1; | ||
| 206 | register long rr2 asm("r2") = r2; | ||
| 207 | register long ret0 asm("r0"); | ||
| 208 | register long ret1 asm("r1"); | ||
| 209 | union reg_pair fnr; | ||
| 210 | |||
| 211 | __asm__ __volatile__ ( | ||
| 212 | "msr cpsr_fs, %[cpsr] \n\t" | ||
| 213 | "mov lr, pc \n\t" | ||
| 214 | "mov pc, %[fn] \n\t" | ||
| 215 | : "=r" (ret0), "=r" (ret1) | ||
| 216 | : "0" (rr0), "r" (rr1), "r" (rr2), | ||
| 217 | [cpsr] "r" (cpsr), [fn] "r" (fn) | ||
| 218 | : "lr", "cc" | ||
| 219 | ); | ||
| 220 | fnr.r0 = ret0; | ||
| 221 | fnr.r1 = ret1; | ||
| 222 | return fnr.dr; | ||
| 223 | } | ||
| 224 | |||
| 225 | static inline long __kprobes | ||
| 226 | insnslot_4arg_rflags(long r0, long r1, long r2, long r3, long cpsr, | ||
| 227 | insn_4arg_fn_t *fn) | ||
| 228 | { | ||
| 229 | register long rr0 asm("r0") = r0; | ||
| 230 | register long rr1 asm("r1") = r1; | ||
| 231 | register long rr2 asm("r2") = r2; | ||
| 232 | register long rr3 asm("r3") = r3; | ||
| 233 | register long ret asm("r0"); | ||
| 234 | |||
| 235 | __asm__ __volatile__ ( | ||
| 236 | "msr cpsr_fs, %[cpsr] \n\t" | ||
| 237 | "mov lr, pc \n\t" | ||
| 238 | "mov pc, %[fn] \n\t" | ||
| 239 | : "=r" (ret) | ||
| 240 | : "0" (rr0), "r" (rr1), "r" (rr2), "r" (rr3), | ||
| 241 | [cpsr] "r" (cpsr), [fn] "r" (fn) | ||
| 242 | : "lr", "cc" | ||
| 243 | ); | ||
| 244 | return ret; | ||
| 245 | } | ||
| 246 | |||
| 247 | static inline long __kprobes | ||
| 248 | insnslot_1arg_rwflags(long r0, long *cpsr, insn_1arg_fn_t *fn) | ||
| 249 | { | ||
| 250 | register long rr0 asm("r0") = r0; | ||
| 251 | register long ret asm("r0"); | ||
| 252 | long oldcpsr = *cpsr; | ||
| 253 | long newcpsr; | ||
| 254 | |||
| 255 | __asm__ __volatile__ ( | ||
| 256 | "msr cpsr_fs, %[oldcpsr] \n\t" | ||
| 257 | "mov lr, pc \n\t" | ||
| 258 | "mov pc, %[fn] \n\t" | ||
| 259 | "mrs %[newcpsr], cpsr \n\t" | ||
| 260 | : "=r" (ret), [newcpsr] "=r" (newcpsr) | ||
| 261 | : "0" (rr0), [oldcpsr] "r" (oldcpsr), [fn] "r" (fn) | ||
| 262 | : "lr", "cc" | ||
| 263 | ); | ||
| 264 | *cpsr = (oldcpsr & ~PSR_fs) | (newcpsr & PSR_fs); | ||
| 265 | return ret; | ||
| 266 | } | ||
| 267 | |||
| 268 | static inline long __kprobes | ||
| 269 | insnslot_2arg_rwflags(long r0, long r1, long *cpsr, insn_2arg_fn_t *fn) | ||
| 270 | { | ||
| 271 | register long rr0 asm("r0") = r0; | ||
| 272 | register long rr1 asm("r1") = r1; | ||
| 273 | register long ret asm("r0"); | ||
| 274 | long oldcpsr = *cpsr; | ||
| 275 | long newcpsr; | ||
| 276 | |||
| 277 | __asm__ __volatile__ ( | ||
| 278 | "msr cpsr_fs, %[oldcpsr] \n\t" | ||
| 279 | "mov lr, pc \n\t" | ||
| 280 | "mov pc, %[fn] \n\t" | ||
| 281 | "mrs %[newcpsr], cpsr \n\t" | ||
| 282 | : "=r" (ret), [newcpsr] "=r" (newcpsr) | ||
| 283 | : "0" (rr0), "r" (rr1), [oldcpsr] "r" (oldcpsr), [fn] "r" (fn) | ||
| 284 | : "lr", "cc" | ||
| 285 | ); | ||
| 286 | *cpsr = (oldcpsr & ~PSR_fs) | (newcpsr & PSR_fs); | ||
| 287 | return ret; | ||
| 288 | } | ||
| 289 | |||
| 290 | static inline long __kprobes | ||
| 291 | insnslot_3arg_rwflags(long r0, long r1, long r2, long *cpsr, | ||
| 292 | insn_3arg_fn_t *fn) | ||
| 293 | { | ||
| 294 | register long rr0 asm("r0") = r0; | ||
| 295 | register long rr1 asm("r1") = r1; | ||
| 296 | register long rr2 asm("r2") = r2; | ||
| 297 | register long ret asm("r0"); | ||
| 298 | long oldcpsr = *cpsr; | ||
| 299 | long newcpsr; | ||
| 300 | |||
| 301 | __asm__ __volatile__ ( | ||
| 302 | "msr cpsr_fs, %[oldcpsr] \n\t" | ||
| 303 | "mov lr, pc \n\t" | ||
| 304 | "mov pc, %[fn] \n\t" | ||
| 305 | "mrs %[newcpsr], cpsr \n\t" | ||
| 306 | : "=r" (ret), [newcpsr] "=r" (newcpsr) | ||
| 307 | : "0" (rr0), "r" (rr1), "r" (rr2), | ||
| 308 | [oldcpsr] "r" (oldcpsr), [fn] "r" (fn) | ||
| 309 | : "lr", "cc" | ||
| 310 | ); | ||
| 311 | *cpsr = (oldcpsr & ~PSR_fs) | (newcpsr & PSR_fs); | ||
| 312 | return ret; | ||
| 313 | } | ||
| 314 | |||
| 315 | static inline long __kprobes | ||
| 316 | insnslot_4arg_rwflags(long r0, long r1, long r2, long r3, long *cpsr, | ||
| 317 | insn_4arg_fn_t *fn) | ||
| 318 | { | ||
| 319 | register long rr0 asm("r0") = r0; | ||
| 320 | register long rr1 asm("r1") = r1; | ||
| 321 | register long rr2 asm("r2") = r2; | ||
| 322 | register long rr3 asm("r3") = r3; | ||
| 323 | register long ret asm("r0"); | ||
| 324 | long oldcpsr = *cpsr; | ||
| 325 | long newcpsr; | ||
| 326 | |||
| 327 | __asm__ __volatile__ ( | ||
| 328 | "msr cpsr_fs, %[oldcpsr] \n\t" | ||
| 329 | "mov lr, pc \n\t" | ||
| 330 | "mov pc, %[fn] \n\t" | ||
| 331 | "mrs %[newcpsr], cpsr \n\t" | ||
| 332 | : "=r" (ret), [newcpsr] "=r" (newcpsr) | ||
| 333 | : "0" (rr0), "r" (rr1), "r" (rr2), "r" (rr3), | ||
| 334 | [oldcpsr] "r" (oldcpsr), [fn] "r" (fn) | ||
| 335 | : "lr", "cc" | ||
| 336 | ); | ||
| 337 | *cpsr = (oldcpsr & ~PSR_fs) | (newcpsr & PSR_fs); | ||
| 338 | return ret; | ||
| 339 | } | ||
| 340 | |||
| 341 | static inline long long __kprobes | ||
| 342 | insnslot_llret_4arg_rwflags(long r0, long r1, long r2, long r3, long *cpsr, | ||
| 343 | insn_llret_4arg_fn_t *fn) | ||
| 344 | { | ||
| 345 | register long rr0 asm("r0") = r0; | ||
| 346 | register long rr1 asm("r1") = r1; | ||
| 347 | register long rr2 asm("r2") = r2; | ||
| 348 | register long rr3 asm("r3") = r3; | ||
| 349 | register long ret0 asm("r0"); | ||
| 350 | register long ret1 asm("r1"); | ||
| 351 | long oldcpsr = *cpsr; | ||
| 352 | long newcpsr; | ||
| 353 | union reg_pair fnr; | ||
| 354 | |||
| 355 | __asm__ __volatile__ ( | ||
| 356 | "msr cpsr_fs, %[oldcpsr] \n\t" | ||
| 357 | "mov lr, pc \n\t" | ||
| 358 | "mov pc, %[fn] \n\t" | ||
| 359 | "mrs %[newcpsr], cpsr \n\t" | ||
| 360 | : "=r" (ret0), "=r" (ret1), [newcpsr] "=r" (newcpsr) | ||
| 361 | : "0" (rr0), "r" (rr1), "r" (rr2), "r" (rr3), | ||
| 362 | [oldcpsr] "r" (oldcpsr), [fn] "r" (fn) | ||
| 363 | : "lr", "cc" | ||
| 364 | ); | ||
| 365 | *cpsr = (oldcpsr & ~PSR_fs) | (newcpsr & PSR_fs); | ||
| 366 | fnr.r0 = ret0; | ||
| 367 | fnr.r1 = ret1; | ||
| 368 | return fnr.dr; | ||
| 369 | } | ||
| 370 | |||
| 371 | /* | 77 | /* |
| 372 | * To avoid the complications of mimicing single-stepping on a | 78 | * To avoid the complications of mimicing single-stepping on a |
| 373 | * processor without a Next-PC or a single-step mode, and to | 79 | * processor without a Next-PC or a single-step mode, and to |
| @@ -449,450 +155,6 @@ static void __kprobes simulate_mov_ipsp(struct kprobe *p, struct pt_regs *regs) | |||
| 449 | regs->uregs[12] = regs->uregs[13]; | 155 | regs->uregs[12] = regs->uregs[13]; |
| 450 | } | 156 | } |
| 451 | 157 | ||
| 452 | static void __kprobes emulate_ldrd(struct kprobe *p, struct pt_regs *regs) | ||
| 453 | { | ||
| 454 | insn_2arg_fn_t *i_fn = (insn_2arg_fn_t *)&p->ainsn.insn[0]; | ||
| 455 | kprobe_opcode_t insn = p->opcode; | ||
| 456 | long ppc = (long)p->addr + 8; | ||
| 457 | int rd = (insn >> 12) & 0xf; | ||
| 458 | int rn = (insn >> 16) & 0xf; | ||
| 459 | int rm = insn & 0xf; /* rm may be invalid, don't care. */ | ||
| 460 | long rmv = (rm == 15) ? ppc : regs->uregs[rm]; | ||
| 461 | long rnv = (rn == 15) ? ppc : regs->uregs[rn]; | ||
| 462 | |||
| 463 | /* Not following the C calling convention here, so need asm(). */ | ||
| 464 | __asm__ __volatile__ ( | ||
| 465 | "ldr r0, %[rn] \n\t" | ||
| 466 | "ldr r1, %[rm] \n\t" | ||
| 467 | "msr cpsr_fs, %[cpsr]\n\t" | ||
| 468 | "mov lr, pc \n\t" | ||
| 469 | "mov pc, %[i_fn] \n\t" | ||
| 470 | "str r0, %[rn] \n\t" /* in case of writeback */ | ||
| 471 | "str r2, %[rd0] \n\t" | ||
| 472 | "str r3, %[rd1] \n\t" | ||
| 473 | : [rn] "+m" (rnv), | ||
| 474 | [rd0] "=m" (regs->uregs[rd]), | ||
| 475 | [rd1] "=m" (regs->uregs[rd+1]) | ||
| 476 | : [rm] "m" (rmv), | ||
| 477 | [cpsr] "r" (regs->ARM_cpsr), | ||
| 478 | [i_fn] "r" (i_fn) | ||
| 479 | : "r0", "r1", "r2", "r3", "lr", "cc" | ||
| 480 | ); | ||
| 481 | if (is_writeback(insn)) | ||
| 482 | regs->uregs[rn] = rnv; | ||
| 483 | } | ||
| 484 | |||
| 485 | static void __kprobes emulate_strd(struct kprobe *p, struct pt_regs *regs) | ||
| 486 | { | ||
| 487 | insn_4arg_fn_t *i_fn = (insn_4arg_fn_t *)&p->ainsn.insn[0]; | ||
| 488 | kprobe_opcode_t insn = p->opcode; | ||
| 489 | long ppc = (long)p->addr + 8; | ||
| 490 | int rd = (insn >> 12) & 0xf; | ||
| 491 | int rn = (insn >> 16) & 0xf; | ||
| 492 | int rm = insn & 0xf; | ||
| 493 | long rnv = (rn == 15) ? ppc : regs->uregs[rn]; | ||
| 494 | /* rm/rmv may be invalid, don't care. */ | ||
| 495 | long rmv = (rm == 15) ? ppc : regs->uregs[rm]; | ||
| 496 | long rnv_wb; | ||
| 497 | |||
| 498 | rnv_wb = insnslot_4arg_rflags(rnv, rmv, regs->uregs[rd], | ||
| 499 | regs->uregs[rd+1], | ||
| 500 | regs->ARM_cpsr, i_fn); | ||
| 501 | if (is_writeback(insn)) | ||
| 502 | regs->uregs[rn] = rnv_wb; | ||
| 503 | } | ||
| 504 | |||
| 505 | static void __kprobes emulate_ldr_old(struct kprobe *p, struct pt_regs *regs) | ||
| 506 | { | ||
| 507 | insn_llret_3arg_fn_t *i_fn = (insn_llret_3arg_fn_t *)&p->ainsn.insn[0]; | ||
| 508 | kprobe_opcode_t insn = p->opcode; | ||
| 509 | long ppc = (long)p->addr + 8; | ||
| 510 | union reg_pair fnr; | ||
| 511 | int rd = (insn >> 12) & 0xf; | ||
| 512 | int rn = (insn >> 16) & 0xf; | ||
| 513 | int rm = insn & 0xf; | ||
| 514 | long rdv; | ||
| 515 | long rnv = (rn == 15) ? ppc : regs->uregs[rn]; | ||
| 516 | long rmv = (rm == 15) ? ppc : regs->uregs[rm]; | ||
| 517 | long cpsr = regs->ARM_cpsr; | ||
| 518 | |||
| 519 | fnr.dr = insnslot_llret_3arg_rflags(rnv, 0, rmv, cpsr, i_fn); | ||
| 520 | if (rn != 15) | ||
| 521 | regs->uregs[rn] = fnr.r0; /* Save Rn in case of writeback. */ | ||
| 522 | rdv = fnr.r1; | ||
| 523 | |||
| 524 | if (rd == 15) { | ||
| 525 | #if __LINUX_ARM_ARCH__ >= 5 | ||
| 526 | cpsr &= ~PSR_T_BIT; | ||
| 527 | if (rdv & 0x1) | ||
| 528 | cpsr |= PSR_T_BIT; | ||
| 529 | regs->ARM_cpsr = cpsr; | ||
| 530 | rdv &= ~0x1; | ||
| 531 | #else | ||
| 532 | rdv &= ~0x2; | ||
| 533 | #endif | ||
| 534 | } | ||
| 535 | regs->uregs[rd] = rdv; | ||
| 536 | } | ||
| 537 | |||
| 538 | static void __kprobes emulate_str_old(struct kprobe *p, struct pt_regs *regs) | ||
| 539 | { | ||
| 540 | insn_3arg_fn_t *i_fn = (insn_3arg_fn_t *)&p->ainsn.insn[0]; | ||
| 541 | kprobe_opcode_t insn = p->opcode; | ||
| 542 | long iaddr = (long)p->addr; | ||
| 543 | int rd = (insn >> 12) & 0xf; | ||
| 544 | int rn = (insn >> 16) & 0xf; | ||
| 545 | int rm = insn & 0xf; | ||
| 546 | long rdv = (rd == 15) ? iaddr + str_pc_offset : regs->uregs[rd]; | ||
| 547 | long rnv = (rn == 15) ? iaddr + 8 : regs->uregs[rn]; | ||
| 548 | long rmv = regs->uregs[rm]; /* rm/rmv may be invalid, don't care. */ | ||
| 549 | long rnv_wb; | ||
| 550 | |||
| 551 | rnv_wb = insnslot_3arg_rflags(rnv, rdv, rmv, regs->ARM_cpsr, i_fn); | ||
| 552 | if (rn != 15) | ||
| 553 | regs->uregs[rn] = rnv_wb; /* Save Rn in case of writeback. */ | ||
| 554 | } | ||
| 555 | |||
| 556 | static void __kprobes emulate_sat(struct kprobe *p, struct pt_regs *regs) | ||
| 557 | { | ||
| 558 | insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; | ||
| 559 | kprobe_opcode_t insn = p->opcode; | ||
| 560 | int rd = (insn >> 12) & 0xf; | ||
| 561 | int rm = insn & 0xf; | ||
| 562 | long rmv = regs->uregs[rm]; | ||
| 563 | |||
| 564 | /* Writes Q flag */ | ||
| 565 | regs->uregs[rd] = insnslot_1arg_rwflags(rmv, ®s->ARM_cpsr, i_fn); | ||
| 566 | } | ||
| 567 | |||
| 568 | static void __kprobes emulate_sel(struct kprobe *p, struct pt_regs *regs) | ||
| 569 | { | ||
| 570 | insn_2arg_fn_t *i_fn = (insn_2arg_fn_t *)&p->ainsn.insn[0]; | ||
| 571 | kprobe_opcode_t insn = p->opcode; | ||
| 572 | int rd = (insn >> 12) & 0xf; | ||
| 573 | int rn = (insn >> 16) & 0xf; | ||
| 574 | int rm = insn & 0xf; | ||
| 575 | long rnv = regs->uregs[rn]; | ||
| 576 | long rmv = regs->uregs[rm]; | ||
| 577 | |||
| 578 | /* Reads GE bits */ | ||
| 579 | regs->uregs[rd] = insnslot_2arg_rflags(rnv, rmv, regs->ARM_cpsr, i_fn); | ||
| 580 | } | ||
| 581 | |||
| 582 | static void __kprobes emulate_none(struct kprobe *p, struct pt_regs *regs) | ||
| 583 | { | ||
| 584 | insn_0arg_fn_t *i_fn = (insn_0arg_fn_t *)&p->ainsn.insn[0]; | ||
| 585 | |||
| 586 | insnslot_0arg_rflags(regs->ARM_cpsr, i_fn); | ||
| 587 | } | ||
| 588 | |||
| 589 | static void __kprobes emulate_nop(struct kprobe *p, struct pt_regs *regs) | ||
| 590 | { | ||
| 591 | } | ||
| 592 | |||
| 593 | static void __kprobes | ||
| 594 | emulate_rd12_modify(struct kprobe *p, struct pt_regs *regs) | ||
| 595 | { | ||
| 596 | insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; | ||
| 597 | kprobe_opcode_t insn = p->opcode; | ||
| 598 | int rd = (insn >> 12) & 0xf; | ||
| 599 | long rdv = regs->uregs[rd]; | ||
| 600 | |||
| 601 | regs->uregs[rd] = insnslot_1arg_rflags(rdv, regs->ARM_cpsr, i_fn); | ||
| 602 | } | ||
| 603 | |||
| 604 | static void __kprobes | ||
| 605 | emulate_rd12rn0_modify(struct kprobe *p, struct pt_regs *regs) | ||
| 606 | { | ||
| 607 | insn_2arg_fn_t *i_fn = (insn_2arg_fn_t *)&p->ainsn.insn[0]; | ||
| 608 | kprobe_opcode_t insn = p->opcode; | ||
| 609 | int rd = (insn >> 12) & 0xf; | ||
| 610 | int rn = insn & 0xf; | ||
| 611 | long rdv = regs->uregs[rd]; | ||
| 612 | long rnv = regs->uregs[rn]; | ||
| 613 | |||
| 614 | regs->uregs[rd] = insnslot_2arg_rflags(rdv, rnv, regs->ARM_cpsr, i_fn); | ||
| 615 | } | ||
| 616 | |||
| 617 | static void __kprobes emulate_rd12rm0(struct kprobe *p, struct pt_regs *regs) | ||
| 618 | { | ||
| 619 | insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; | ||
| 620 | kprobe_opcode_t insn = p->opcode; | ||
| 621 | int rd = (insn >> 12) & 0xf; | ||
| 622 | int rm = insn & 0xf; | ||
| 623 | long rmv = regs->uregs[rm]; | ||
| 624 | |||
| 625 | regs->uregs[rd] = insnslot_1arg_rflags(rmv, regs->ARM_cpsr, i_fn); | ||
| 626 | } | ||
| 627 | |||
| 628 | static void __kprobes | ||
| 629 | emulate_rd12rn16rm0_rwflags(struct kprobe *p, struct pt_regs *regs) | ||
| 630 | { | ||
| 631 | insn_2arg_fn_t *i_fn = (insn_2arg_fn_t *)&p->ainsn.insn[0]; | ||
| 632 | kprobe_opcode_t insn = p->opcode; | ||
| 633 | int rd = (insn >> 12) & 0xf; | ||
| 634 | int rn = (insn >> 16) & 0xf; | ||
| 635 | int rm = insn & 0xf; | ||
| 636 | long rnv = regs->uregs[rn]; | ||
| 637 | long rmv = regs->uregs[rm]; | ||
| 638 | |||
| 639 | regs->uregs[rd] = | ||
| 640 | insnslot_2arg_rwflags(rnv, rmv, ®s->ARM_cpsr, i_fn); | ||
| 641 | } | ||
| 642 | |||
| 643 | static void __kprobes | ||
| 644 | emulate_rd16rn12rs8rm0_rwflags(struct kprobe *p, struct pt_regs *regs) | ||
| 645 | { | ||
| 646 | insn_3arg_fn_t *i_fn = (insn_3arg_fn_t *)&p->ainsn.insn[0]; | ||
| 647 | kprobe_opcode_t insn = p->opcode; | ||
| 648 | int rd = (insn >> 16) & 0xf; | ||
| 649 | int rn = (insn >> 12) & 0xf; | ||
| 650 | int rs = (insn >> 8) & 0xf; | ||
| 651 | int rm = insn & 0xf; | ||
| 652 | long rnv = regs->uregs[rn]; | ||
| 653 | long rsv = regs->uregs[rs]; | ||
| 654 | long rmv = regs->uregs[rm]; | ||
| 655 | |||
| 656 | regs->uregs[rd] = | ||
| 657 | insnslot_3arg_rwflags(rnv, rsv, rmv, ®s->ARM_cpsr, i_fn); | ||
| 658 | } | ||
| 659 | |||
| 660 | static void __kprobes | ||
| 661 | emulate_rd16rs8rm0_rwflags(struct kprobe *p, struct pt_regs *regs) | ||
| 662 | { | ||
| 663 | insn_2arg_fn_t *i_fn = (insn_2arg_fn_t *)&p->ainsn.insn[0]; | ||
| 664 | kprobe_opcode_t insn = p->opcode; | ||
| 665 | int rd = (insn >> 16) & 0xf; | ||
| 666 | int rs = (insn >> 8) & 0xf; | ||
| 667 | int rm = insn & 0xf; | ||
| 668 | long rsv = regs->uregs[rs]; | ||
| 669 | long rmv = regs->uregs[rm]; | ||
| 670 | |||
| 671 | regs->uregs[rd] = | ||
| 672 | insnslot_2arg_rwflags(rsv, rmv, ®s->ARM_cpsr, i_fn); | ||
| 673 | } | ||
| 674 | |||
| 675 | static void __kprobes | ||
| 676 | emulate_rdhi16rdlo12rs8rm0_rwflags(struct kprobe *p, struct pt_regs *regs) | ||
| 677 | { | ||
| 678 | insn_llret_4arg_fn_t *i_fn = (insn_llret_4arg_fn_t *)&p->ainsn.insn[0]; | ||
| 679 | kprobe_opcode_t insn = p->opcode; | ||
| 680 | union reg_pair fnr; | ||
| 681 | int rdhi = (insn >> 16) & 0xf; | ||
| 682 | int rdlo = (insn >> 12) & 0xf; | ||
| 683 | int rs = (insn >> 8) & 0xf; | ||
| 684 | int rm = insn & 0xf; | ||
| 685 | long rsv = regs->uregs[rs]; | ||
| 686 | long rmv = regs->uregs[rm]; | ||
| 687 | |||
| 688 | fnr.dr = insnslot_llret_4arg_rwflags(regs->uregs[rdhi], | ||
| 689 | regs->uregs[rdlo], rsv, rmv, | ||
| 690 | ®s->ARM_cpsr, i_fn); | ||
| 691 | regs->uregs[rdhi] = fnr.r0; | ||
| 692 | regs->uregs[rdlo] = fnr.r1; | ||
| 693 | } | ||
| 694 | |||
| 695 | static void __kprobes | ||
| 696 | emulate_alu_imm_rflags(struct kprobe *p, struct pt_regs *regs) | ||
| 697 | { | ||
| 698 | insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; | ||
| 699 | kprobe_opcode_t insn = p->opcode; | ||
| 700 | int rd = (insn >> 12) & 0xf; | ||
| 701 | int rn = (insn >> 16) & 0xf; | ||
| 702 | long rnv = (rn == 15) ? (long)p->addr + 8 : regs->uregs[rn]; | ||
| 703 | |||
| 704 | regs->uregs[rd] = insnslot_1arg_rflags(rnv, regs->ARM_cpsr, i_fn); | ||
| 705 | } | ||
| 706 | |||
| 707 | static void __kprobes | ||
| 708 | emulate_alu_imm_rwflags(struct kprobe *p, struct pt_regs *regs) | ||
| 709 | { | ||
| 710 | insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; | ||
| 711 | kprobe_opcode_t insn = p->opcode; | ||
| 712 | int rd = (insn >> 12) & 0xf; | ||
| 713 | int rn = (insn >> 16) & 0xf; | ||
| 714 | long rnv = (rn == 15) ? (long)p->addr + 8 : regs->uregs[rn]; | ||
| 715 | |||
| 716 | regs->uregs[rd] = insnslot_1arg_rwflags(rnv, ®s->ARM_cpsr, i_fn); | ||
| 717 | } | ||
| 718 | |||
| 719 | static void __kprobes | ||
| 720 | emulate_alu_tests_imm(struct kprobe *p, struct pt_regs *regs) | ||
| 721 | { | ||
| 722 | insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; | ||
| 723 | kprobe_opcode_t insn = p->opcode; | ||
| 724 | int rn = (insn >> 16) & 0xf; | ||
| 725 | long rnv = (rn == 15) ? (long)p->addr + 8 : regs->uregs[rn]; | ||
| 726 | |||
| 727 | insnslot_1arg_rwflags(rnv, ®s->ARM_cpsr, i_fn); | ||
| 728 | } | ||
| 729 | |||
| 730 | static void __kprobes | ||
| 731 | emulate_alu_rflags(struct kprobe *p, struct pt_regs *regs) | ||
| 732 | { | ||
| 733 | insn_3arg_fn_t *i_fn = (insn_3arg_fn_t *)&p->ainsn.insn[0]; | ||
| 734 | kprobe_opcode_t insn = p->opcode; | ||
| 735 | long ppc = (long)p->addr + 8; | ||
| 736 | int rd = (insn >> 12) & 0xf; | ||
| 737 | int rn = (insn >> 16) & 0xf; /* rn/rnv/rs/rsv may be */ | ||
| 738 | int rs = (insn >> 8) & 0xf; /* invalid, don't care. */ | ||
| 739 | int rm = insn & 0xf; | ||
| 740 | long rnv = (rn == 15) ? ppc : regs->uregs[rn]; | ||
| 741 | long rmv = (rm == 15) ? ppc : regs->uregs[rm]; | ||
| 742 | long rsv = regs->uregs[rs]; | ||
| 743 | |||
| 744 | regs->uregs[rd] = | ||
| 745 | insnslot_3arg_rflags(rnv, rmv, rsv, regs->ARM_cpsr, i_fn); | ||
| 746 | } | ||
| 747 | |||
| 748 | static void __kprobes | ||
| 749 | emulate_alu_rwflags(struct kprobe *p, struct pt_regs *regs) | ||
| 750 | { | ||
| 751 | insn_3arg_fn_t *i_fn = (insn_3arg_fn_t *)&p->ainsn.insn[0]; | ||
| 752 | kprobe_opcode_t insn = p->opcode; | ||
| 753 | long ppc = (long)p->addr + 8; | ||
| 754 | int rd = (insn >> 12) & 0xf; | ||
| 755 | int rn = (insn >> 16) & 0xf; /* rn/rnv/rs/rsv may be */ | ||
| 756 | int rs = (insn >> 8) & 0xf; /* invalid, don't care. */ | ||
| 757 | int rm = insn & 0xf; | ||
| 758 | long rnv = (rn == 15) ? ppc : regs->uregs[rn]; | ||
| 759 | long rmv = (rm == 15) ? ppc : regs->uregs[rm]; | ||
| 760 | long rsv = regs->uregs[rs]; | ||
| 761 | |||
| 762 | regs->uregs[rd] = | ||
| 763 | insnslot_3arg_rwflags(rnv, rmv, rsv, ®s->ARM_cpsr, i_fn); | ||
| 764 | } | ||
| 765 | |||
| 766 | static void __kprobes | ||
| 767 | emulate_alu_tests(struct kprobe *p, struct pt_regs *regs) | ||
| 768 | { | ||
| 769 | insn_3arg_fn_t *i_fn = (insn_3arg_fn_t *)&p->ainsn.insn[0]; | ||
| 770 | kprobe_opcode_t insn = p->opcode; | ||
| 771 | long ppc = (long)p->addr + 8; | ||
| 772 | int rn = (insn >> 16) & 0xf; | ||
| 773 | int rs = (insn >> 8) & 0xf; /* rs/rsv may be invalid, don't care. */ | ||
| 774 | int rm = insn & 0xf; | ||
| 775 | long rnv = (rn == 15) ? ppc : regs->uregs[rn]; | ||
| 776 | long rmv = (rm == 15) ? ppc : regs->uregs[rm]; | ||
| 777 | long rsv = regs->uregs[rs]; | ||
| 778 | |||
| 779 | insnslot_3arg_rwflags(rnv, rmv, rsv, ®s->ARM_cpsr, i_fn); | ||
| 780 | } | ||
| 781 | |||
| 782 | static enum kprobe_insn __kprobes | ||
| 783 | prep_emulate_ldr_str(kprobe_opcode_t insn, struct arch_specific_insn *asi) | ||
| 784 | { | ||
| 785 | int not_imm = (insn & (1 << 26)) ? (insn & (1 << 25)) | ||
| 786 | : (~insn & (1 << 22)); | ||
| 787 | |||
| 788 | if (is_writeback(insn) && is_r15(insn, 16)) | ||
| 789 | return INSN_REJECTED; /* Writeback to PC */ | ||
| 790 | |||
| 791 | insn &= 0xfff00fff; | ||
| 792 | insn |= 0x00001000; /* Rn = r0, Rd = r1 */ | ||
| 793 | if (not_imm) { | ||
| 794 | insn &= ~0xf; | ||
| 795 | insn |= 2; /* Rm = r2 */ | ||
| 796 | } | ||
| 797 | asi->insn[0] = insn; | ||
| 798 | asi->insn_handler = (insn & (1 << 20)) ? emulate_ldr_old : emulate_str_old; | ||
| 799 | return INSN_GOOD; | ||
| 800 | } | ||
| 801 | |||
| 802 | static enum kprobe_insn __kprobes | ||
| 803 | prep_emulate_rd12_modify(kprobe_opcode_t insn, struct arch_specific_insn *asi) | ||
| 804 | { | ||
| 805 | if (is_r15(insn, 12)) | ||
| 806 | return INSN_REJECTED; /* Rd is PC */ | ||
| 807 | |||
| 808 | insn &= 0xffff0fff; /* Rd = r0 */ | ||
| 809 | asi->insn[0] = insn; | ||
| 810 | asi->insn_handler = emulate_rd12_modify; | ||
| 811 | return INSN_GOOD; | ||
| 812 | } | ||
| 813 | |||
| 814 | static enum kprobe_insn __kprobes | ||
| 815 | prep_emulate_rd12rn0_modify(kprobe_opcode_t insn, | ||
| 816 | struct arch_specific_insn *asi) | ||
| 817 | { | ||
| 818 | if (is_r15(insn, 12)) | ||
| 819 | return INSN_REJECTED; /* Rd is PC */ | ||
| 820 | |||
| 821 | insn &= 0xffff0ff0; /* Rd = r0 */ | ||
| 822 | insn |= 0x00000001; /* Rn = r1 */ | ||
| 823 | asi->insn[0] = insn; | ||
| 824 | asi->insn_handler = emulate_rd12rn0_modify; | ||
| 825 | return INSN_GOOD; | ||
| 826 | } | ||
| 827 | |||
| 828 | static enum kprobe_insn __kprobes | ||
| 829 | prep_emulate_rd12rm0(kprobe_opcode_t insn, struct arch_specific_insn *asi) | ||
| 830 | { | ||
| 831 | if (is_r15(insn, 12)) | ||
| 832 | return INSN_REJECTED; /* Rd is PC */ | ||
| 833 | |||
| 834 | insn &= 0xffff0ff0; /* Rd = r0, Rm = r0 */ | ||
| 835 | asi->insn[0] = insn; | ||
| 836 | asi->insn_handler = emulate_rd12rm0; | ||
| 837 | return INSN_GOOD; | ||
| 838 | } | ||
| 839 | |||
| 840 | static enum kprobe_insn __kprobes | ||
| 841 | prep_emulate_rd12rn16rm0_wflags(kprobe_opcode_t insn, | ||
| 842 | struct arch_specific_insn *asi) | ||
| 843 | { | ||
| 844 | if (is_r15(insn, 12)) | ||
| 845 | return INSN_REJECTED; /* Rd is PC */ | ||
| 846 | |||
| 847 | insn &= 0xfff00ff0; /* Rd = r0, Rn = r0 */ | ||
| 848 | insn |= 0x00000001; /* Rm = r1 */ | ||
| 849 | asi->insn[0] = insn; | ||
| 850 | asi->insn_handler = emulate_rd12rn16rm0_rwflags; | ||
| 851 | return INSN_GOOD; | ||
| 852 | } | ||
| 853 | |||
| 854 | static enum kprobe_insn __kprobes | ||
| 855 | prep_emulate_rd16rs8rm0_wflags(kprobe_opcode_t insn, | ||
| 856 | struct arch_specific_insn *asi) | ||
| 857 | { | ||
| 858 | if (is_r15(insn, 16)) | ||
| 859 | return INSN_REJECTED; /* Rd is PC */ | ||
| 860 | |||
| 861 | insn &= 0xfff0f0f0; /* Rd = r0, Rs = r0 */ | ||
| 862 | insn |= 0x00000001; /* Rm = r1 */ | ||
| 863 | asi->insn[0] = insn; | ||
| 864 | asi->insn_handler = emulate_rd16rs8rm0_rwflags; | ||
| 865 | return INSN_GOOD; | ||
| 866 | } | ||
| 867 | |||
| 868 | static enum kprobe_insn __kprobes | ||
| 869 | prep_emulate_rd16rn12rs8rm0_wflags(kprobe_opcode_t insn, | ||
| 870 | struct arch_specific_insn *asi) | ||
| 871 | { | ||
| 872 | if (is_r15(insn, 16)) | ||
| 873 | return INSN_REJECTED; /* Rd is PC */ | ||
| 874 | |||
| 875 | insn &= 0xfff000f0; /* Rd = r0, Rn = r0 */ | ||
| 876 | insn |= 0x00000102; /* Rs = r1, Rm = r2 */ | ||
| 877 | asi->insn[0] = insn; | ||
| 878 | asi->insn_handler = emulate_rd16rn12rs8rm0_rwflags; | ||
| 879 | return INSN_GOOD; | ||
| 880 | } | ||
| 881 | |||
| 882 | static enum kprobe_insn __kprobes | ||
| 883 | prep_emulate_rdhi16rdlo12rs8rm0_wflags(kprobe_opcode_t insn, | ||
| 884 | struct arch_specific_insn *asi) | ||
| 885 | { | ||
| 886 | if (is_r15(insn, 16) || is_r15(insn, 12)) | ||
| 887 | return INSN_REJECTED; /* RdHi or RdLo is PC */ | ||
| 888 | |||
| 889 | insn &= 0xfff000f0; /* RdHi = r0, RdLo = r1 */ | ||
| 890 | insn |= 0x00001203; /* Rs = r2, Rm = r3 */ | ||
| 891 | asi->insn[0] = insn; | ||
| 892 | asi->insn_handler = emulate_rdhi16rdlo12rs8rm0_rwflags; | ||
| 893 | return INSN_GOOD; | ||
| 894 | } | ||
| 895 | |||
| 896 | static void __kprobes | 158 | static void __kprobes |
| 897 | emulate_ldrdstrd(struct kprobe *p, struct pt_regs *regs) | 159 | emulate_ldrdstrd(struct kprobe *p, struct pt_regs *regs) |
| 898 | { | 160 | { |
