diff options
| -rw-r--r-- | arch/arm/include/asm/probes.h | 1 | ||||
| -rw-r--r-- | arch/arm/probes/decode.c | 10 | ||||
| -rw-r--r-- | arch/arm/probes/kprobes/Makefile | 6 | ||||
| -rw-r--r-- | arch/arm/probes/kprobes/actions-arm.c | 3 | ||||
| -rw-r--r-- | arch/arm/probes/kprobes/actions-thumb.c | 5 | ||||
| -rw-r--r-- | arch/arm/probes/kprobes/checkers-arm.c | 99 | ||||
| -rw-r--r-- | arch/arm/probes/kprobes/checkers-common.c | 101 | ||||
| -rw-r--r-- | arch/arm/probes/kprobes/checkers-thumb.c | 110 | ||||
| -rw-r--r-- | arch/arm/probes/kprobes/checkers.h | 54 |
9 files changed, 383 insertions, 6 deletions
diff --git a/arch/arm/include/asm/probes.h b/arch/arm/include/asm/probes.h index 806cfe622a9e..6026deb28794 100644 --- a/arch/arm/include/asm/probes.h +++ b/arch/arm/include/asm/probes.h | |||
| @@ -38,6 +38,7 @@ struct arch_probes_insn { | |||
| 38 | probes_check_cc *insn_check_cc; | 38 | probes_check_cc *insn_check_cc; |
| 39 | probes_insn_singlestep_t *insn_singlestep; | 39 | probes_insn_singlestep_t *insn_singlestep; |
| 40 | probes_insn_fn_t *insn_fn; | 40 | probes_insn_fn_t *insn_fn; |
| 41 | int stack_space; | ||
| 41 | }; | 42 | }; |
| 42 | 43 | ||
| 43 | #endif | 44 | #endif |
diff --git a/arch/arm/probes/decode.c b/arch/arm/probes/decode.c index c7d442018902..f9d7c423f2cc 100644 --- a/arch/arm/probes/decode.c +++ b/arch/arm/probes/decode.c | |||
| @@ -425,6 +425,16 @@ probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi, | |||
| 425 | */ | 425 | */ |
| 426 | probes_opcode_t origin_insn = insn; | 426 | probes_opcode_t origin_insn = insn; |
| 427 | 427 | ||
| 428 | /* | ||
| 429 | * stack_space is initialized to 0 here. Checker functions | ||
| 430 | * should update is value if they find this is a stack store | ||
| 431 | * instruction: positive value means bytes of stack usage, | ||
| 432 | * negitive value means unable to determine stack usage | ||
| 433 | * statically. For instruction doesn't store to stack, checker | ||
| 434 | * do nothing with it. | ||
| 435 | */ | ||
| 436 | asi->stack_space = 0; | ||
| 437 | |||
| 428 | if (emulate) | 438 | if (emulate) |
| 429 | insn = prepare_emulated_insn(insn, asi, thumb); | 439 | insn = prepare_emulated_insn(insn, asi, thumb); |
| 430 | 440 | ||
diff --git a/arch/arm/probes/kprobes/Makefile b/arch/arm/probes/kprobes/Makefile index eb38a428ecd6..bc8d504c3d78 100644 --- a/arch/arm/probes/kprobes/Makefile +++ b/arch/arm/probes/kprobes/Makefile | |||
| @@ -1,11 +1,11 @@ | |||
| 1 | obj-$(CONFIG_KPROBES) += core.o actions-common.o | 1 | obj-$(CONFIG_KPROBES) += core.o actions-common.o checkers-common.o |
| 2 | obj-$(CONFIG_ARM_KPROBES_TEST) += test-kprobes.o | 2 | obj-$(CONFIG_ARM_KPROBES_TEST) += test-kprobes.o |
| 3 | test-kprobes-objs := test-core.o | 3 | test-kprobes-objs := test-core.o |
| 4 | 4 | ||
| 5 | ifdef CONFIG_THUMB2_KERNEL | 5 | ifdef CONFIG_THUMB2_KERNEL |
| 6 | obj-$(CONFIG_KPROBES) += actions-thumb.o | 6 | obj-$(CONFIG_KPROBES) += actions-thumb.o checkers-thumb.o |
| 7 | test-kprobes-objs += test-thumb.o | 7 | test-kprobes-objs += test-thumb.o |
| 8 | else | 8 | else |
| 9 | obj-$(CONFIG_KPROBES) += actions-arm.o | 9 | obj-$(CONFIG_KPROBES) += actions-arm.o checkers-arm.o |
| 10 | test-kprobes-objs += test-arm.o | 10 | test-kprobes-objs += test-arm.o |
| 11 | endif | 11 | endif |
diff --git a/arch/arm/probes/kprobes/actions-arm.c b/arch/arm/probes/kprobes/actions-arm.c index fbd93a9ada75..06988ef7eeb7 100644 --- a/arch/arm/probes/kprobes/actions-arm.c +++ b/arch/arm/probes/kprobes/actions-arm.c | |||
| @@ -64,6 +64,7 @@ | |||
| 64 | 64 | ||
| 65 | #include "../decode-arm.h" | 65 | #include "../decode-arm.h" |
| 66 | #include "core.h" | 66 | #include "core.h" |
| 67 | #include "checkers.h" | ||
| 67 | 68 | ||
| 68 | #if __LINUX_ARM_ARCH__ >= 6 | 69 | #if __LINUX_ARM_ARCH__ >= 6 |
| 69 | #define BLX(reg) "blx "reg" \n\t" | 70 | #define BLX(reg) "blx "reg" \n\t" |
| @@ -340,4 +341,4 @@ const union decode_action kprobes_arm_actions[NUM_PROBES_ARM_ACTIONS] = { | |||
| 340 | [PROBES_LDMSTM] = {.decoder = kprobe_decode_ldmstm} | 341 | [PROBES_LDMSTM] = {.decoder = kprobe_decode_ldmstm} |
| 341 | }; | 342 | }; |
| 342 | 343 | ||
| 343 | const struct decode_checker *kprobes_arm_checkers[] = {NULL}; | 344 | const struct decode_checker *kprobes_arm_checkers[] = {arm_stack_checker, NULL}; |
diff --git a/arch/arm/probes/kprobes/actions-thumb.c b/arch/arm/probes/kprobes/actions-thumb.c index 2796121fe90e..07cfd9bef340 100644 --- a/arch/arm/probes/kprobes/actions-thumb.c +++ b/arch/arm/probes/kprobes/actions-thumb.c | |||
| @@ -15,6 +15,7 @@ | |||
| 15 | 15 | ||
| 16 | #include "../decode-thumb.h" | 16 | #include "../decode-thumb.h" |
| 17 | #include "core.h" | 17 | #include "core.h" |
| 18 | #include "checkers.h" | ||
| 18 | 19 | ||
| 19 | /* These emulation encodings are functionally equivalent... */ | 20 | /* These emulation encodings are functionally equivalent... */ |
| 20 | #define t32_emulate_rd8rn16rm0ra12_noflags \ | 21 | #define t32_emulate_rd8rn16rm0ra12_noflags \ |
| @@ -665,5 +666,5 @@ const union decode_action kprobes_t32_actions[NUM_PROBES_T32_ACTIONS] = { | |||
| 665 | .handler = t32_emulate_rdlo12rdhi8rn16rm0_noflags}, | 666 | .handler = t32_emulate_rdlo12rdhi8rn16rm0_noflags}, |
| 666 | }; | 667 | }; |
| 667 | 668 | ||
| 668 | const struct decode_checker *kprobes_t32_checkers[] = {NULL}; | 669 | const struct decode_checker *kprobes_t32_checkers[] = {t32_stack_checker, NULL}; |
| 669 | const struct decode_checker *kprobes_t16_checkers[] = {NULL}; | 670 | const struct decode_checker *kprobes_t16_checkers[] = {t16_stack_checker, NULL}; |
diff --git a/arch/arm/probes/kprobes/checkers-arm.c b/arch/arm/probes/kprobes/checkers-arm.c new file mode 100644 index 000000000000..f8176631d2a5 --- /dev/null +++ b/arch/arm/probes/kprobes/checkers-arm.c | |||
| @@ -0,0 +1,99 @@ | |||
| 1 | /* | ||
| 2 | * arch/arm/probes/kprobes/checkers-arm.c | ||
| 3 | * | ||
| 4 | * Copyright (C) 2014 Huawei 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 | #include <linux/kernel.h> | ||
| 17 | #include "../decode.h" | ||
| 18 | #include "../decode-arm.h" | ||
| 19 | #include "checkers.h" | ||
| 20 | |||
| 21 | static enum probes_insn __kprobes arm_check_stack(probes_opcode_t insn, | ||
| 22 | struct arch_probes_insn *asi, | ||
| 23 | const struct decode_header *h) | ||
| 24 | { | ||
| 25 | /* | ||
| 26 | * PROBES_LDRSTRD, PROBES_LDMSTM, PROBES_STORE, | ||
| 27 | * PROBES_STORE_EXTRA may get here. Simply mark all normal | ||
| 28 | * insns as STACK_USE_NONE. | ||
| 29 | */ | ||
| 30 | static const union decode_item table[] = { | ||
| 31 | /* | ||
| 32 | * 'STR{,D,B,H}, Rt, [Rn, Rm]' should be marked as UNKNOWN | ||
| 33 | * if Rn or Rm is SP. | ||
| 34 | * x | ||
| 35 | * STR (register) cccc 011x x0x0 xxxx xxxx xxxx xxxx xxxx | ||
| 36 | * STRB (register) cccc 011x x1x0 xxxx xxxx xxxx xxxx xxxx | ||
| 37 | */ | ||
| 38 | DECODE_OR (0x0e10000f, 0x0600000d), | ||
| 39 | DECODE_OR (0x0e1f0000, 0x060d0000), | ||
| 40 | |||
| 41 | /* | ||
| 42 | * x | ||
| 43 | * STRD (register) cccc 000x x0x0 xxxx xxxx xxxx 1111 xxxx | ||
| 44 | * STRH (register) cccc 000x x0x0 xxxx xxxx xxxx 1011 xxxx | ||
| 45 | */ | ||
| 46 | DECODE_OR (0x0e5000bf, 0x000000bd), | ||
| 47 | DECODE_CUSTOM (0x0e5f00b0, 0x000d00b0, STACK_USE_UNKNOWN), | ||
| 48 | |||
| 49 | /* | ||
| 50 | * For PROBES_LDMSTM, only stmdx sp, [...] need to examine | ||
| 51 | * | ||
| 52 | * Bit B/A (bit 24) encodes arithmetic operation order. 1 means | ||
| 53 | * before, 0 means after. | ||
| 54 | * Bit I/D (bit 23) encodes arithmetic operation. 1 means | ||
| 55 | * increment, 0 means decrement. | ||
| 56 | * | ||
| 57 | * So: | ||
| 58 | * B I | ||
| 59 | * / / | ||
| 60 | * A D | Rn | | ||
| 61 | * STMDX SP, [...] cccc 100x 00x0 xxxx xxxx xxxx xxxx xxxx | ||
| 62 | */ | ||
| 63 | DECODE_CUSTOM (0x0edf0000, 0x080d0000, STACK_USE_STMDX), | ||
| 64 | |||
| 65 | /* P U W | Rn | Rt | imm12 |*/ | ||
| 66 | /* STR (immediate) cccc 010x x0x0 1101 xxxx xxxx xxxx xxxx */ | ||
| 67 | /* STRB (immediate) cccc 010x x1x0 1101 xxxx xxxx xxxx xxxx */ | ||
| 68 | /* P U W | Rn | Rt |imm4| |imm4|*/ | ||
| 69 | /* STRD (immediate) cccc 000x x1x0 1101 xxxx xxxx 1111 xxxx */ | ||
| 70 | /* STRH (immediate) cccc 000x x1x0 1101 xxxx xxxx 1011 xxxx */ | ||
| 71 | /* | ||
| 72 | * index = (P == '1'); add = (U == '1'). | ||
| 73 | * Above insns with: | ||
| 74 | * index == 0 (str{,d,h} rx, [sp], #+/-imm) or | ||
| 75 | * add == 1 (str{,d,h} rx, [sp, #+<imm>]) | ||
| 76 | * should be STACK_USE_NONE. | ||
| 77 | * Only str{,b,d,h} rx,[sp,#-n] (P == 1 and U == 0) are | ||
| 78 | * required to be examined. | ||
| 79 | */ | ||
| 80 | /* STR{,B} Rt,[SP,#-n] cccc 0101 0xx0 1101 xxxx xxxx xxxx xxxx */ | ||
| 81 | DECODE_CUSTOM (0x0f9f0000, 0x050d0000, STACK_USE_FIXED_XXX), | ||
| 82 | |||
| 83 | /* STR{D,H} Rt,[SP,#-n] cccc 0001 01x0 1101 xxxx xxxx 1x11 xxxx */ | ||
| 84 | DECODE_CUSTOM (0x0fdf00b0, 0x014d00b0, STACK_USE_FIXED_X0X), | ||
| 85 | |||
| 86 | /* fall through */ | ||
| 87 | DECODE_CUSTOM (0, 0, STACK_USE_NONE), | ||
| 88 | DECODE_END | ||
| 89 | }; | ||
| 90 | |||
| 91 | return probes_decode_insn(insn, asi, table, false, false, stack_check_actions, NULL); | ||
| 92 | } | ||
| 93 | |||
| 94 | const struct decode_checker arm_stack_checker[NUM_PROBES_ARM_ACTIONS] = { | ||
| 95 | [PROBES_LDRSTRD] = {.checker = arm_check_stack}, | ||
| 96 | [PROBES_STORE_EXTRA] = {.checker = arm_check_stack}, | ||
| 97 | [PROBES_STORE] = {.checker = arm_check_stack}, | ||
| 98 | [PROBES_LDMSTM] = {.checker = arm_check_stack}, | ||
| 99 | }; | ||
diff --git a/arch/arm/probes/kprobes/checkers-common.c b/arch/arm/probes/kprobes/checkers-common.c new file mode 100644 index 000000000000..971119c29474 --- /dev/null +++ b/arch/arm/probes/kprobes/checkers-common.c | |||
| @@ -0,0 +1,101 @@ | |||
| 1 | /* | ||
| 2 | * arch/arm/probes/kprobes/checkers-common.c | ||
| 3 | * | ||
| 4 | * Copyright (C) 2014 Huawei 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 | #include <linux/kernel.h> | ||
| 17 | #include "../decode.h" | ||
| 18 | #include "../decode-arm.h" | ||
| 19 | #include "checkers.h" | ||
| 20 | |||
| 21 | enum probes_insn checker_stack_use_none(probes_opcode_t insn, | ||
| 22 | struct arch_probes_insn *asi, | ||
| 23 | const struct decode_header *h) | ||
| 24 | { | ||
| 25 | asi->stack_space = 0; | ||
| 26 | return INSN_GOOD_NO_SLOT; | ||
| 27 | } | ||
| 28 | |||
| 29 | enum probes_insn checker_stack_use_unknown(probes_opcode_t insn, | ||
| 30 | struct arch_probes_insn *asi, | ||
| 31 | const struct decode_header *h) | ||
| 32 | { | ||
| 33 | asi->stack_space = -1; | ||
| 34 | return INSN_GOOD_NO_SLOT; | ||
| 35 | } | ||
| 36 | |||
| 37 | #ifdef CONFIG_THUMB2_KERNEL | ||
| 38 | enum probes_insn checker_stack_use_imm_0xx(probes_opcode_t insn, | ||
| 39 | struct arch_probes_insn *asi, | ||
| 40 | const struct decode_header *h) | ||
| 41 | { | ||
| 42 | int imm = insn & 0xff; | ||
| 43 | asi->stack_space = imm; | ||
| 44 | return INSN_GOOD_NO_SLOT; | ||
| 45 | } | ||
| 46 | |||
| 47 | /* | ||
| 48 | * Different from other insn uses imm8, the real addressing offset of | ||
| 49 | * STRD in T32 encoding should be imm8 * 4. See ARMARM description. | ||
| 50 | */ | ||
| 51 | enum probes_insn checker_stack_use_t32strd(probes_opcode_t insn, | ||
| 52 | struct arch_probes_insn *asi, | ||
| 53 | const struct decode_header *h) | ||
| 54 | { | ||
| 55 | int imm = insn & 0xff; | ||
| 56 | asi->stack_space = imm << 2; | ||
| 57 | return INSN_GOOD_NO_SLOT; | ||
| 58 | } | ||
| 59 | #else | ||
| 60 | enum probes_insn checker_stack_use_imm_x0x(probes_opcode_t insn, | ||
| 61 | struct arch_probes_insn *asi, | ||
| 62 | const struct decode_header *h) | ||
| 63 | { | ||
| 64 | int imm = ((insn & 0xf00) >> 4) + (insn & 0xf); | ||
| 65 | asi->stack_space = imm; | ||
| 66 | return INSN_GOOD_NO_SLOT; | ||
| 67 | } | ||
| 68 | #endif | ||
| 69 | |||
| 70 | enum probes_insn checker_stack_use_imm_xxx(probes_opcode_t insn, | ||
| 71 | struct arch_probes_insn *asi, | ||
| 72 | const struct decode_header *h) | ||
| 73 | { | ||
| 74 | int imm = insn & 0xfff; | ||
| 75 | asi->stack_space = imm; | ||
| 76 | return INSN_GOOD_NO_SLOT; | ||
| 77 | } | ||
| 78 | |||
| 79 | enum probes_insn checker_stack_use_stmdx(probes_opcode_t insn, | ||
| 80 | struct arch_probes_insn *asi, | ||
| 81 | const struct decode_header *h) | ||
| 82 | { | ||
| 83 | unsigned int reglist = insn & 0xffff; | ||
| 84 | int pbit = insn & (1 << 24); | ||
| 85 | asi->stack_space = (hweight32(reglist) - (!pbit ? 1 : 0)) * 4; | ||
| 86 | |||
| 87 | return INSN_GOOD_NO_SLOT; | ||
| 88 | } | ||
| 89 | |||
| 90 | const union decode_action stack_check_actions[] = { | ||
| 91 | [STACK_USE_NONE] = {.decoder = checker_stack_use_none}, | ||
| 92 | [STACK_USE_UNKNOWN] = {.decoder = checker_stack_use_unknown}, | ||
| 93 | #ifdef CONFIG_THUMB2_KERNEL | ||
| 94 | [STACK_USE_FIXED_0XX] = {.decoder = checker_stack_use_imm_0xx}, | ||
| 95 | [STACK_USE_T32STRD] = {.decoder = checker_stack_use_t32strd}, | ||
| 96 | #else | ||
| 97 | [STACK_USE_FIXED_X0X] = {.decoder = checker_stack_use_imm_x0x}, | ||
| 98 | #endif | ||
| 99 | [STACK_USE_FIXED_XXX] = {.decoder = checker_stack_use_imm_xxx}, | ||
| 100 | [STACK_USE_STMDX] = {.decoder = checker_stack_use_stmdx}, | ||
| 101 | }; | ||
diff --git a/arch/arm/probes/kprobes/checkers-thumb.c b/arch/arm/probes/kprobes/checkers-thumb.c new file mode 100644 index 000000000000..d608e3b9017a --- /dev/null +++ b/arch/arm/probes/kprobes/checkers-thumb.c | |||
| @@ -0,0 +1,110 @@ | |||
| 1 | /* | ||
| 2 | * arch/arm/probes/kprobes/checkers-thumb.c | ||
| 3 | * | ||
| 4 | * Copyright (C) 2014 Huawei 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 | #include <linux/kernel.h> | ||
| 17 | #include "../decode.h" | ||
| 18 | #include "../decode-thumb.h" | ||
| 19 | #include "checkers.h" | ||
| 20 | |||
| 21 | static enum probes_insn __kprobes t32_check_stack(probes_opcode_t insn, | ||
| 22 | struct arch_probes_insn *asi, | ||
| 23 | const struct decode_header *h) | ||
| 24 | { | ||
| 25 | /* | ||
| 26 | * PROBES_T32_LDMSTM, PROBES_T32_LDRDSTRD and PROBES_T32_LDRSTR | ||
| 27 | * may get here. Simply mark all normal insns as STACK_USE_NONE. | ||
| 28 | */ | ||
| 29 | static const union decode_item table[] = { | ||
| 30 | |||
| 31 | /* | ||
| 32 | * First, filter out all ldr insns to make our life easier. | ||
| 33 | * Following load insns may come here: | ||
| 34 | * LDM, LDRD, LDR. | ||
| 35 | * In T32 encoding, bit 20 is enough for distinguishing | ||
| 36 | * load and store. All load insns have this bit set, when | ||
| 37 | * all store insns have this bit clear. | ||
| 38 | */ | ||
| 39 | DECODE_CUSTOM (0x00100000, 0x00100000, STACK_USE_NONE), | ||
| 40 | |||
| 41 | /* | ||
| 42 | * Mark all 'STR{,B,H}, Rt, [Rn, Rm]' as STACK_USE_UNKNOWN | ||
| 43 | * if Rn or Rm is SP. T32 doesn't encode STRD. | ||
| 44 | */ | ||
| 45 | /* xx | Rn | Rt | | Rm |*/ | ||
| 46 | /* STR (register) 1111 1000 0100 xxxx xxxx 0000 00xx xxxx */ | ||
| 47 | /* STRB (register) 1111 1000 0000 xxxx xxxx 0000 00xx xxxx */ | ||
| 48 | /* STRH (register) 1111 1000 0010 xxxx xxxx 0000 00xx xxxx */ | ||
| 49 | /* INVALID INSN 1111 1000 0110 xxxx xxxx 0000 00xx xxxx */ | ||
| 50 | /* By Introducing INVALID INSN, bit 21 and 22 can be ignored. */ | ||
| 51 | DECODE_OR (0xff9f0fc0, 0xf80d0000), | ||
| 52 | DECODE_CUSTOM (0xff900fcf, 0xf800000d, STACK_USE_UNKNOWN), | ||
| 53 | |||
| 54 | |||
| 55 | /* xx | Rn | Rt | PUW| imm8 |*/ | ||
| 56 | /* STR (imm 8) 1111 1000 0100 1101 xxxx 110x xxxx xxxx */ | ||
| 57 | /* STRB (imm 8) 1111 1000 0000 1101 xxxx 110x xxxx xxxx */ | ||
| 58 | /* STRH (imm 8) 1111 1000 0010 1101 xxxx 110x xxxx xxxx */ | ||
| 59 | /* INVALID INSN 1111 1000 0110 1101 xxxx 110x xxxx xxxx */ | ||
| 60 | /* Only consider U == 0 and P == 1: strx rx, [sp, #-<imm>] */ | ||
| 61 | DECODE_CUSTOM (0xff9f0e00, 0xf80d0c00, STACK_USE_FIXED_0XX), | ||
| 62 | |||
| 63 | /* For STR{,B,H} (imm 12), offset is always positive, so ignore them. */ | ||
| 64 | |||
| 65 | /* P U W | Rn | Rt | Rt2| imm8 |*/ | ||
| 66 | /* STRD (immediate) 1110 1001 01x0 1101 xxxx xxxx xxxx xxxx */ | ||
| 67 | /* | ||
| 68 | * Only consider U == 0 and P == 1. | ||
| 69 | * Also note that STRD in T32 encoding is special: | ||
| 70 | * imm = ZeroExtend(imm8:'00', 32) | ||
| 71 | */ | ||
| 72 | DECODE_CUSTOM (0xffdf0000, 0xe94d0000, STACK_USE_T32STRD), | ||
| 73 | |||
| 74 | /* | Rn | */ | ||
| 75 | /* STMDB 1110 1001 00x0 1101 xxxx xxxx xxxx xxxx */ | ||
| 76 | DECODE_CUSTOM (0xffdf0000, 0xe90d0000, STACK_USE_STMDX), | ||
| 77 | |||
| 78 | /* fall through */ | ||
| 79 | DECODE_CUSTOM (0, 0, STACK_USE_NONE), | ||
| 80 | DECODE_END | ||
| 81 | }; | ||
| 82 | |||
| 83 | return probes_decode_insn(insn, asi, table, false, false, stack_check_actions, NULL); | ||
| 84 | } | ||
| 85 | |||
| 86 | const struct decode_checker t32_stack_checker[NUM_PROBES_T32_ACTIONS] = { | ||
| 87 | [PROBES_T32_LDMSTM] = {.checker = t32_check_stack}, | ||
| 88 | [PROBES_T32_LDRDSTRD] = {.checker = t32_check_stack}, | ||
| 89 | [PROBES_T32_LDRSTR] = {.checker = t32_check_stack}, | ||
| 90 | }; | ||
| 91 | |||
| 92 | /* | ||
| 93 | * See following comments. This insn must be 'push'. | ||
| 94 | */ | ||
| 95 | static enum probes_insn __kprobes t16_check_stack(probes_opcode_t insn, | ||
| 96 | struct arch_probes_insn *asi, | ||
| 97 | const struct decode_header *h) | ||
| 98 | { | ||
| 99 | unsigned int reglist = insn & 0x1ff; | ||
| 100 | asi->stack_space = hweight32(reglist) * 4; | ||
| 101 | return INSN_GOOD; | ||
| 102 | } | ||
| 103 | |||
| 104 | /* | ||
| 105 | * T16 encoding is simple: only the 'push' insn can need extra stack space. | ||
| 106 | * Other insns, like str, can only use r0-r7 as Rn. | ||
| 107 | */ | ||
| 108 | const struct decode_checker t16_stack_checker[NUM_PROBES_T16_ACTIONS] = { | ||
| 109 | [PROBES_T16_PUSH] = {.checker = t16_check_stack}, | ||
| 110 | }; | ||
diff --git a/arch/arm/probes/kprobes/checkers.h b/arch/arm/probes/kprobes/checkers.h new file mode 100644 index 000000000000..bddfa0e82389 --- /dev/null +++ b/arch/arm/probes/kprobes/checkers.h | |||
| @@ -0,0 +1,54 @@ | |||
| 1 | /* | ||
| 2 | * arch/arm/probes/kprobes/checkers.h | ||
| 3 | * | ||
| 4 | * Copyright (C) 2014 Huawei 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 | #ifndef _ARM_KERNEL_PROBES_CHECKERS_H | ||
| 16 | #define _ARM_KERNEL_PROBES_CHECKERS_H | ||
| 17 | |||
| 18 | #include <linux/kernel.h> | ||
| 19 | #include <linux/types.h> | ||
| 20 | #include "../decode.h" | ||
| 21 | |||
| 22 | extern probes_check_t checker_stack_use_none; | ||
| 23 | extern probes_check_t checker_stack_use_unknown; | ||
| 24 | #ifdef CONFIG_THUMB2_KERNEL | ||
| 25 | extern probes_check_t checker_stack_use_imm_0xx; | ||
| 26 | #else | ||
| 27 | extern probes_check_t checker_stack_use_imm_x0x; | ||
| 28 | #endif | ||
| 29 | extern probes_check_t checker_stack_use_imm_xxx; | ||
| 30 | extern probes_check_t checker_stack_use_stmdx; | ||
| 31 | |||
| 32 | enum { | ||
| 33 | STACK_USE_NONE, | ||
| 34 | STACK_USE_UNKNOWN, | ||
| 35 | #ifdef CONFIG_THUMB2_KERNEL | ||
| 36 | STACK_USE_FIXED_0XX, | ||
| 37 | STACK_USE_T32STRD, | ||
| 38 | #else | ||
| 39 | STACK_USE_FIXED_X0X, | ||
| 40 | #endif | ||
| 41 | STACK_USE_FIXED_XXX, | ||
| 42 | STACK_USE_STMDX, | ||
| 43 | NUM_STACK_USE_TYPES | ||
| 44 | }; | ||
| 45 | |||
| 46 | extern const union decode_action stack_check_actions[]; | ||
| 47 | |||
| 48 | #ifndef CONFIG_THUMB2_KERNEL | ||
| 49 | extern const struct decode_checker arm_stack_checker[]; | ||
| 50 | #else | ||
| 51 | #endif | ||
| 52 | extern const struct decode_checker t32_stack_checker[]; | ||
| 53 | extern const struct decode_checker t16_stack_checker[]; | ||
| 54 | #endif | ||
