Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ARM: kprobes: check register usage for probed instruction.

This patch utilizes the previously introduced checker to check
register usage for probed ARM instruction and saves it in a mask.
A further patch will use such information to avoid simulation or
emulation.

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Reviewed-by: Jon Medhurst <tixy@linaro.org>
Signed-off-by: Jon Medhurst <tixy@linaro.org>

authored by

Wang Nan and committed by
Jon Medhurst
28a1899d 4cd872d9

+103 -1
+1
arch/arm/include/asm/probes.h
··· 41 41 probes_insn_singlestep_t *insn_singlestep; 42 42 probes_insn_fn_t *insn_fn; 43 43 int stack_space; 44 + unsigned long register_usage_flags; 44 45 }; 45 46 46 47 #endif /* __ASSEMBLY__ */
+7
arch/arm/probes/decode.c
··· 435 435 */ 436 436 asi->stack_space = 0; 437 437 438 + /* 439 + * Similarly to stack_space, register_usage_flags is filled by 440 + * checkers. Its default value is set to ~0, which is 'all 441 + * registers are used', to prevent any potential optimization. 442 + */ 443 + asi->register_usage_flags = ~0UL; 444 + 438 445 if (emulate) 439 446 insn = prepare_emulated_insn(insn, asi, thumb); 440 447
+1 -1
arch/arm/probes/kprobes/actions-arm.c
··· 341 341 [PROBES_LDMSTM] = {.decoder = kprobe_decode_ldmstm} 342 342 }; 343 343 344 - const struct decode_checker *kprobes_arm_checkers[] = {arm_stack_checker, NULL}; 344 + const struct decode_checker *kprobes_arm_checkers[] = {arm_stack_checker, arm_regs_checker, NULL};
+93
arch/arm/probes/kprobes/checkers-arm.c
··· 97 97 [PROBES_STORE] = {.checker = arm_check_stack}, 98 98 [PROBES_LDMSTM] = {.checker = arm_check_stack}, 99 99 }; 100 + 101 + static enum probes_insn __kprobes arm_check_regs_nouse(probes_opcode_t insn, 102 + struct arch_probes_insn *asi, 103 + const struct decode_header *h) 104 + { 105 + asi->register_usage_flags = 0; 106 + return INSN_GOOD; 107 + } 108 + 109 + static enum probes_insn arm_check_regs_normal(probes_opcode_t insn, 110 + struct arch_probes_insn *asi, 111 + const struct decode_header *h) 112 + { 113 + u32 regs = h->type_regs.bits >> DECODE_TYPE_BITS; 114 + int i; 115 + 116 + asi->register_usage_flags = 0; 117 + for (i = 0; i < 5; regs >>= 4, insn >>= 4, i++) 118 + if (regs & 0xf) 119 + asi->register_usage_flags |= 1 << (insn & 0xf); 120 + 121 + return INSN_GOOD; 122 + } 123 + 124 + 125 + static enum probes_insn arm_check_regs_ldmstm(probes_opcode_t insn, 126 + struct arch_probes_insn *asi, 127 + const struct decode_header *h) 128 + { 129 + unsigned int reglist = insn & 0xffff; 130 + unsigned int rn = (insn >> 16) & 0xf; 131 + asi->register_usage_flags = reglist | (1 << rn); 132 + return INSN_GOOD; 133 + } 134 + 135 + static enum probes_insn arm_check_regs_mov_ip_sp(probes_opcode_t insn, 136 + struct arch_probes_insn *asi, 137 + const struct decode_header *h) 138 + { 139 + /* Instruction is 'mov ip, sp' i.e. 'mov r12, r13' */ 140 + asi->register_usage_flags = (1 << 12) | (1<< 13); 141 + return INSN_GOOD; 142 + } 143 + 144 + /* 145 + * | Rn |Rt/d| | Rm | 146 + * LDRD (register) cccc 000x x0x0 xxxx xxxx xxxx 1101 xxxx 147 + * STRD (register) cccc 000x x0x0 xxxx xxxx xxxx 1111 xxxx 148 + * | Rn |Rt/d| |imm4L| 149 + * LDRD (immediate) cccc 000x x1x0 xxxx xxxx xxxx 1101 xxxx 150 + * STRD (immediate) cccc 000x x1x0 xxxx xxxx xxxx 1111 xxxx 151 + * 152 + * Such instructions access Rt/d and its next register, so different 153 + * from others, a specific checker is required to handle this extra 154 + * implicit register usage. 155 + */ 156 + static enum probes_insn arm_check_regs_ldrdstrd(probes_opcode_t insn, 157 + struct arch_probes_insn *asi, 158 + const struct decode_header *h) 159 + { 160 + int rdt = (insn >> 12) & 0xf; 161 + arm_check_regs_normal(insn, asi, h); 162 + asi->register_usage_flags |= 1 << (rdt + 1); 163 + return INSN_GOOD; 164 + } 165 + 166 + 167 + const struct decode_checker arm_regs_checker[NUM_PROBES_ARM_ACTIONS] = { 168 + [PROBES_MRS] = {.checker = arm_check_regs_normal}, 169 + [PROBES_SATURATING_ARITHMETIC] = {.checker = arm_check_regs_normal}, 170 + [PROBES_MUL1] = {.checker = arm_check_regs_normal}, 171 + [PROBES_MUL2] = {.checker = arm_check_regs_normal}, 172 + [PROBES_MUL_ADD_LONG] = {.checker = arm_check_regs_normal}, 173 + [PROBES_MUL_ADD] = {.checker = arm_check_regs_normal}, 174 + [PROBES_LOAD] = {.checker = arm_check_regs_normal}, 175 + [PROBES_LOAD_EXTRA] = {.checker = arm_check_regs_normal}, 176 + [PROBES_STORE] = {.checker = arm_check_regs_normal}, 177 + [PROBES_STORE_EXTRA] = {.checker = arm_check_regs_normal}, 178 + [PROBES_DATA_PROCESSING_REG] = {.checker = arm_check_regs_normal}, 179 + [PROBES_DATA_PROCESSING_IMM] = {.checker = arm_check_regs_normal}, 180 + [PROBES_SEV] = {.checker = arm_check_regs_nouse}, 181 + [PROBES_WFE] = {.checker = arm_check_regs_nouse}, 182 + [PROBES_SATURATE] = {.checker = arm_check_regs_normal}, 183 + [PROBES_REV] = {.checker = arm_check_regs_normal}, 184 + [PROBES_MMI] = {.checker = arm_check_regs_normal}, 185 + [PROBES_PACK] = {.checker = arm_check_regs_normal}, 186 + [PROBES_EXTEND] = {.checker = arm_check_regs_normal}, 187 + [PROBES_EXTEND_ADD] = {.checker = arm_check_regs_normal}, 188 + [PROBES_BITFIELD] = {.checker = arm_check_regs_normal}, 189 + [PROBES_LDMSTM] = {.checker = arm_check_regs_ldmstm}, 190 + [PROBES_MOV_IP_SP] = {.checker = arm_check_regs_mov_ip_sp}, 191 + [PROBES_LDRSTRD] = {.checker = arm_check_regs_ldrdstrd}, 192 + };
+1
arch/arm/probes/kprobes/checkers.h
··· 47 47 48 48 #ifndef CONFIG_THUMB2_KERNEL 49 49 extern const struct decode_checker arm_stack_checker[]; 50 + extern const struct decode_checker arm_regs_checker[]; 50 51 #else 51 52 #endif 52 53 extern const struct decode_checker t32_stack_checker[];