forked from mirrors/linux
		
	ARM: kprobes: collects stack consumption for store instructions
This patch uses the previously introduced checker functionality on store instructions to record their stack consumption information to arch_probes_insn. Signed-off-by: Wang Nan <wangnan0@huawei.com> Reviewed-by: Jon Medhurst <tixy@linaro.org> Signed-off-by: Jon Medhurst <tixy@linaro.org>
This commit is contained in:
		
							parent
							
								
									83803d97da
								
							
						
					
					
						commit
						6624cf651f
					
				
					 9 changed files with 383 additions and 6 deletions
				
			
		| 
						 | 
					@ -38,6 +38,7 @@ struct arch_probes_insn {
 | 
				
			||||||
	probes_check_cc			*insn_check_cc;
 | 
						probes_check_cc			*insn_check_cc;
 | 
				
			||||||
	probes_insn_singlestep_t	*insn_singlestep;
 | 
						probes_insn_singlestep_t	*insn_singlestep;
 | 
				
			||||||
	probes_insn_fn_t		*insn_fn;
 | 
						probes_insn_fn_t		*insn_fn;
 | 
				
			||||||
 | 
						int				stack_space;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -425,6 +425,16 @@ probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi,
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	probes_opcode_t origin_insn = insn;
 | 
						probes_opcode_t origin_insn = insn;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * stack_space is initialized to 0 here. Checker functions
 | 
				
			||||||
 | 
						 * should update is value if they find this is a stack store
 | 
				
			||||||
 | 
						 * instruction: positive value means bytes of stack usage,
 | 
				
			||||||
 | 
						 * negitive value means unable to determine stack usage
 | 
				
			||||||
 | 
						 * statically. For instruction doesn't store to stack, checker
 | 
				
			||||||
 | 
						 * do nothing with it.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						asi->stack_space = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (emulate)
 | 
						if (emulate)
 | 
				
			||||||
		insn = prepare_emulated_insn(insn, asi, thumb);
 | 
							insn = prepare_emulated_insn(insn, asi, thumb);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,11 +1,11 @@
 | 
				
			||||||
obj-$(CONFIG_KPROBES)		+= core.o actions-common.o
 | 
					obj-$(CONFIG_KPROBES)		+= core.o actions-common.o checkers-common.o
 | 
				
			||||||
obj-$(CONFIG_ARM_KPROBES_TEST)	+= test-kprobes.o
 | 
					obj-$(CONFIG_ARM_KPROBES_TEST)	+= test-kprobes.o
 | 
				
			||||||
test-kprobes-objs		:= test-core.o
 | 
					test-kprobes-objs		:= test-core.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ifdef CONFIG_THUMB2_KERNEL
 | 
					ifdef CONFIG_THUMB2_KERNEL
 | 
				
			||||||
obj-$(CONFIG_KPROBES)		+= actions-thumb.o
 | 
					obj-$(CONFIG_KPROBES)		+= actions-thumb.o checkers-thumb.o
 | 
				
			||||||
test-kprobes-objs		+= test-thumb.o
 | 
					test-kprobes-objs		+= test-thumb.o
 | 
				
			||||||
else
 | 
					else
 | 
				
			||||||
obj-$(CONFIG_KPROBES)		+= actions-arm.o
 | 
					obj-$(CONFIG_KPROBES)		+= actions-arm.o checkers-arm.o
 | 
				
			||||||
test-kprobes-objs		+= test-arm.o
 | 
					test-kprobes-objs		+= test-arm.o
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -64,6 +64,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "../decode-arm.h"
 | 
					#include "../decode-arm.h"
 | 
				
			||||||
#include "core.h"
 | 
					#include "core.h"
 | 
				
			||||||
 | 
					#include "checkers.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if  __LINUX_ARM_ARCH__ >= 6
 | 
					#if  __LINUX_ARM_ARCH__ >= 6
 | 
				
			||||||
#define BLX(reg)	"blx	"reg"		\n\t"
 | 
					#define BLX(reg)	"blx	"reg"		\n\t"
 | 
				
			||||||
| 
						 | 
					@ -340,4 +341,4 @@ const union decode_action kprobes_arm_actions[NUM_PROBES_ARM_ACTIONS] = {
 | 
				
			||||||
	[PROBES_LDMSTM] = {.decoder = kprobe_decode_ldmstm}
 | 
						[PROBES_LDMSTM] = {.decoder = kprobe_decode_ldmstm}
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const struct decode_checker *kprobes_arm_checkers[] = {NULL};
 | 
					const struct decode_checker *kprobes_arm_checkers[] = {arm_stack_checker, NULL};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -15,6 +15,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "../decode-thumb.h"
 | 
					#include "../decode-thumb.h"
 | 
				
			||||||
#include "core.h"
 | 
					#include "core.h"
 | 
				
			||||||
 | 
					#include "checkers.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* These emulation encodings are functionally equivalent... */
 | 
					/* These emulation encodings are functionally equivalent... */
 | 
				
			||||||
#define t32_emulate_rd8rn16rm0ra12_noflags \
 | 
					#define t32_emulate_rd8rn16rm0ra12_noflags \
 | 
				
			||||||
| 
						 | 
					@ -665,5 +666,5 @@ const union decode_action kprobes_t32_actions[NUM_PROBES_T32_ACTIONS] = {
 | 
				
			||||||
		.handler = t32_emulate_rdlo12rdhi8rn16rm0_noflags},
 | 
							.handler = t32_emulate_rdlo12rdhi8rn16rm0_noflags},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const struct decode_checker *kprobes_t32_checkers[] = {NULL};
 | 
					const struct decode_checker *kprobes_t32_checkers[] = {t32_stack_checker, NULL};
 | 
				
			||||||
const struct decode_checker *kprobes_t16_checkers[] = {NULL};
 | 
					const struct decode_checker *kprobes_t16_checkers[] = {t16_stack_checker, NULL};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										99
									
								
								arch/arm/probes/kprobes/checkers-arm.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								arch/arm/probes/kprobes/checkers-arm.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,99 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * arch/arm/probes/kprobes/checkers-arm.c
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright (C) 2014 Huawei Inc.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This program is free software; you can redistribute it and/or modify
 | 
				
			||||||
 | 
					 * it under the terms of the GNU General Public License version 2 as
 | 
				
			||||||
 | 
					 * published by the Free Software Foundation.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This program is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
				
			||||||
 | 
					 * General Public License for more details.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <linux/kernel.h>
 | 
				
			||||||
 | 
					#include "../decode.h"
 | 
				
			||||||
 | 
					#include "../decode-arm.h"
 | 
				
			||||||
 | 
					#include "checkers.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static enum probes_insn __kprobes arm_check_stack(probes_opcode_t insn,
 | 
				
			||||||
 | 
							struct arch_probes_insn *asi,
 | 
				
			||||||
 | 
							const struct decode_header *h)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * PROBES_LDRSTRD, PROBES_LDMSTM, PROBES_STORE,
 | 
				
			||||||
 | 
						 * PROBES_STORE_EXTRA may get here. Simply mark all normal
 | 
				
			||||||
 | 
						 * insns as STACK_USE_NONE.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						static const union decode_item table[] = {
 | 
				
			||||||
 | 
							/*
 | 
				
			||||||
 | 
							 * 'STR{,D,B,H}, Rt, [Rn, Rm]' should be marked as UNKNOWN
 | 
				
			||||||
 | 
							 * if Rn or Rm is SP.
 | 
				
			||||||
 | 
							 *                                 x
 | 
				
			||||||
 | 
							 * STR (register)	cccc 011x x0x0 xxxx xxxx xxxx xxxx xxxx
 | 
				
			||||||
 | 
							 * STRB (register)	cccc 011x x1x0 xxxx xxxx xxxx xxxx xxxx
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							DECODE_OR	(0x0e10000f, 0x0600000d),
 | 
				
			||||||
 | 
							DECODE_OR	(0x0e1f0000, 0x060d0000),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/*
 | 
				
			||||||
 | 
							 *                                                     x
 | 
				
			||||||
 | 
							 * STRD (register)	cccc 000x x0x0 xxxx xxxx xxxx 1111 xxxx
 | 
				
			||||||
 | 
							 * STRH (register)	cccc 000x x0x0 xxxx xxxx xxxx 1011 xxxx
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							DECODE_OR	(0x0e5000bf, 0x000000bd),
 | 
				
			||||||
 | 
							DECODE_CUSTOM	(0x0e5f00b0, 0x000d00b0, STACK_USE_UNKNOWN),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/*
 | 
				
			||||||
 | 
							 * For PROBES_LDMSTM, only stmdx sp, [...] need to examine
 | 
				
			||||||
 | 
							 *
 | 
				
			||||||
 | 
							 * Bit B/A (bit 24) encodes arithmetic operation order. 1 means
 | 
				
			||||||
 | 
							 * before, 0 means after.
 | 
				
			||||||
 | 
							 * Bit I/D (bit 23) encodes arithmetic operation. 1 means
 | 
				
			||||||
 | 
							 * increment, 0 means decrement.
 | 
				
			||||||
 | 
							 *
 | 
				
			||||||
 | 
							 * So:
 | 
				
			||||||
 | 
							 *                              B I
 | 
				
			||||||
 | 
							 *                              / /
 | 
				
			||||||
 | 
							 *                              A D   | Rn |
 | 
				
			||||||
 | 
							 * STMDX SP, [...]	cccc 100x 00x0 xxxx xxxx xxxx xxxx xxxx
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							DECODE_CUSTOM	(0x0edf0000, 0x080d0000, STACK_USE_STMDX),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/*                              P U W | Rn | Rt |     imm12    |*/
 | 
				
			||||||
 | 
							/* STR (immediate)	cccc 010x x0x0 1101 xxxx xxxx xxxx xxxx */
 | 
				
			||||||
 | 
							/* STRB (immediate)	cccc 010x x1x0 1101 xxxx xxxx xxxx xxxx */
 | 
				
			||||||
 | 
							/*                              P U W | Rn | Rt |imm4|    |imm4|*/
 | 
				
			||||||
 | 
							/* STRD (immediate)	cccc 000x x1x0 1101 xxxx xxxx 1111 xxxx */
 | 
				
			||||||
 | 
							/* STRH (immediate)	cccc 000x x1x0 1101 xxxx xxxx 1011 xxxx */
 | 
				
			||||||
 | 
							/*
 | 
				
			||||||
 | 
							 * index = (P == '1'); add = (U == '1').
 | 
				
			||||||
 | 
							 * Above insns with:
 | 
				
			||||||
 | 
							 *    index == 0 (str{,d,h} rx, [sp], #+/-imm) or
 | 
				
			||||||
 | 
							 *    add == 1 (str{,d,h} rx, [sp, #+<imm>])
 | 
				
			||||||
 | 
							 * should be STACK_USE_NONE.
 | 
				
			||||||
 | 
							 * Only str{,b,d,h} rx,[sp,#-n] (P == 1 and U == 0) are
 | 
				
			||||||
 | 
							 * required to be examined.
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							/* STR{,B} Rt,[SP,#-n]	cccc 0101 0xx0 1101 xxxx xxxx xxxx xxxx */
 | 
				
			||||||
 | 
							DECODE_CUSTOM	(0x0f9f0000, 0x050d0000, STACK_USE_FIXED_XXX),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* STR{D,H} Rt,[SP,#-n]	cccc 0001 01x0 1101 xxxx xxxx 1x11 xxxx */
 | 
				
			||||||
 | 
							DECODE_CUSTOM	(0x0fdf00b0, 0x014d00b0, STACK_USE_FIXED_X0X),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* fall through */
 | 
				
			||||||
 | 
							DECODE_CUSTOM	(0, 0, STACK_USE_NONE),
 | 
				
			||||||
 | 
							DECODE_END
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return probes_decode_insn(insn, asi, table, false, false, stack_check_actions, NULL);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const struct decode_checker arm_stack_checker[NUM_PROBES_ARM_ACTIONS] = {
 | 
				
			||||||
 | 
						[PROBES_LDRSTRD] = {.checker = arm_check_stack},
 | 
				
			||||||
 | 
						[PROBES_STORE_EXTRA] = {.checker = arm_check_stack},
 | 
				
			||||||
 | 
						[PROBES_STORE] = {.checker = arm_check_stack},
 | 
				
			||||||
 | 
						[PROBES_LDMSTM] = {.checker = arm_check_stack},
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
							
								
								
									
										101
									
								
								arch/arm/probes/kprobes/checkers-common.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								arch/arm/probes/kprobes/checkers-common.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,101 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * arch/arm/probes/kprobes/checkers-common.c
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright (C) 2014 Huawei Inc.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This program is free software; you can redistribute it and/or modify
 | 
				
			||||||
 | 
					 * it under the terms of the GNU General Public License version 2 as
 | 
				
			||||||
 | 
					 * published by the Free Software Foundation.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This program is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
				
			||||||
 | 
					 * General Public License for more details.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <linux/kernel.h>
 | 
				
			||||||
 | 
					#include "../decode.h"
 | 
				
			||||||
 | 
					#include "../decode-arm.h"
 | 
				
			||||||
 | 
					#include "checkers.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum probes_insn checker_stack_use_none(probes_opcode_t insn,
 | 
				
			||||||
 | 
							struct arch_probes_insn *asi,
 | 
				
			||||||
 | 
							const struct decode_header *h)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						asi->stack_space = 0;
 | 
				
			||||||
 | 
						return INSN_GOOD_NO_SLOT;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum probes_insn checker_stack_use_unknown(probes_opcode_t insn,
 | 
				
			||||||
 | 
							struct arch_probes_insn *asi,
 | 
				
			||||||
 | 
							const struct decode_header *h)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						asi->stack_space = -1;
 | 
				
			||||||
 | 
						return INSN_GOOD_NO_SLOT;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_THUMB2_KERNEL
 | 
				
			||||||
 | 
					enum probes_insn checker_stack_use_imm_0xx(probes_opcode_t insn,
 | 
				
			||||||
 | 
							struct arch_probes_insn *asi,
 | 
				
			||||||
 | 
							const struct decode_header *h)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int imm = insn & 0xff;
 | 
				
			||||||
 | 
						asi->stack_space = imm;
 | 
				
			||||||
 | 
						return INSN_GOOD_NO_SLOT;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Different from other insn uses imm8, the real addressing offset of
 | 
				
			||||||
 | 
					 * STRD in T32 encoding should be imm8 * 4. See ARMARM description.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					enum probes_insn checker_stack_use_t32strd(probes_opcode_t insn,
 | 
				
			||||||
 | 
							struct arch_probes_insn *asi,
 | 
				
			||||||
 | 
							const struct decode_header *h)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int imm = insn & 0xff;
 | 
				
			||||||
 | 
						asi->stack_space = imm << 2;
 | 
				
			||||||
 | 
						return INSN_GOOD_NO_SLOT;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					enum probes_insn checker_stack_use_imm_x0x(probes_opcode_t insn,
 | 
				
			||||||
 | 
							struct arch_probes_insn *asi,
 | 
				
			||||||
 | 
							const struct decode_header *h)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int imm = ((insn & 0xf00) >> 4) + (insn & 0xf);
 | 
				
			||||||
 | 
						asi->stack_space = imm;
 | 
				
			||||||
 | 
						return INSN_GOOD_NO_SLOT;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum probes_insn checker_stack_use_imm_xxx(probes_opcode_t insn,
 | 
				
			||||||
 | 
							struct arch_probes_insn *asi,
 | 
				
			||||||
 | 
							const struct decode_header *h)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int imm = insn & 0xfff;
 | 
				
			||||||
 | 
						asi->stack_space = imm;
 | 
				
			||||||
 | 
						return INSN_GOOD_NO_SLOT;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum probes_insn checker_stack_use_stmdx(probes_opcode_t insn,
 | 
				
			||||||
 | 
							struct arch_probes_insn *asi,
 | 
				
			||||||
 | 
							const struct decode_header *h)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						unsigned int reglist = insn & 0xffff;
 | 
				
			||||||
 | 
						int pbit = insn & (1 << 24);
 | 
				
			||||||
 | 
						asi->stack_space = (hweight32(reglist) - (!pbit ? 1 : 0)) * 4;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return INSN_GOOD_NO_SLOT;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const union decode_action stack_check_actions[] = {
 | 
				
			||||||
 | 
						[STACK_USE_NONE] = {.decoder = checker_stack_use_none},
 | 
				
			||||||
 | 
						[STACK_USE_UNKNOWN] = {.decoder = checker_stack_use_unknown},
 | 
				
			||||||
 | 
					#ifdef CONFIG_THUMB2_KERNEL
 | 
				
			||||||
 | 
						[STACK_USE_FIXED_0XX] = {.decoder = checker_stack_use_imm_0xx},
 | 
				
			||||||
 | 
						[STACK_USE_T32STRD] = {.decoder = checker_stack_use_t32strd},
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
						[STACK_USE_FIXED_X0X] = {.decoder = checker_stack_use_imm_x0x},
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						[STACK_USE_FIXED_XXX] = {.decoder = checker_stack_use_imm_xxx},
 | 
				
			||||||
 | 
						[STACK_USE_STMDX] = {.decoder = checker_stack_use_stmdx},
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
							
								
								
									
										110
									
								
								arch/arm/probes/kprobes/checkers-thumb.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								arch/arm/probes/kprobes/checkers-thumb.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,110 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * arch/arm/probes/kprobes/checkers-thumb.c
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright (C) 2014 Huawei Inc.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This program is free software; you can redistribute it and/or modify
 | 
				
			||||||
 | 
					 * it under the terms of the GNU General Public License version 2 as
 | 
				
			||||||
 | 
					 * published by the Free Software Foundation.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This program is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
				
			||||||
 | 
					 * General Public License for more details.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <linux/kernel.h>
 | 
				
			||||||
 | 
					#include "../decode.h"
 | 
				
			||||||
 | 
					#include "../decode-thumb.h"
 | 
				
			||||||
 | 
					#include "checkers.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static enum probes_insn __kprobes t32_check_stack(probes_opcode_t insn,
 | 
				
			||||||
 | 
							struct arch_probes_insn *asi,
 | 
				
			||||||
 | 
							const struct decode_header *h)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * PROBES_T32_LDMSTM, PROBES_T32_LDRDSTRD and PROBES_T32_LDRSTR
 | 
				
			||||||
 | 
						 * may get here. Simply mark all normal insns as STACK_USE_NONE.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						static const union decode_item table[] = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/*
 | 
				
			||||||
 | 
							 * First, filter out all ldr insns to make our life easier.
 | 
				
			||||||
 | 
							 * Following load insns may come here:
 | 
				
			||||||
 | 
							 * LDM, LDRD, LDR.
 | 
				
			||||||
 | 
							 * In T32 encoding, bit 20 is enough for distinguishing
 | 
				
			||||||
 | 
							 * load and store. All load insns have this bit set, when
 | 
				
			||||||
 | 
							 * all store insns have this bit clear.
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							DECODE_CUSTOM	(0x00100000, 0x00100000, STACK_USE_NONE),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/*
 | 
				
			||||||
 | 
							 * Mark all 'STR{,B,H}, Rt, [Rn, Rm]' as STACK_USE_UNKNOWN
 | 
				
			||||||
 | 
							 * if Rn or Rm is SP. T32 doesn't encode STRD.
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							/*                                 xx | Rn | Rt |         | Rm |*/
 | 
				
			||||||
 | 
							/* STR (register)	1111 1000 0100 xxxx xxxx 0000 00xx xxxx */
 | 
				
			||||||
 | 
							/* STRB (register)	1111 1000 0000 xxxx xxxx 0000 00xx xxxx */
 | 
				
			||||||
 | 
							/* STRH (register)	1111 1000 0010 xxxx xxxx 0000 00xx xxxx */
 | 
				
			||||||
 | 
							/* INVALID INSN		1111 1000 0110 xxxx xxxx 0000 00xx xxxx */
 | 
				
			||||||
 | 
							/* By Introducing INVALID INSN, bit 21 and 22 can be ignored. */
 | 
				
			||||||
 | 
							DECODE_OR	(0xff9f0fc0, 0xf80d0000),
 | 
				
			||||||
 | 
							DECODE_CUSTOM	(0xff900fcf, 0xf800000d, STACK_USE_UNKNOWN),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/*                                 xx | Rn | Rt | PUW|   imm8  |*/
 | 
				
			||||||
 | 
							/* STR (imm 8)		1111 1000 0100 1101 xxxx 110x xxxx xxxx */
 | 
				
			||||||
 | 
							/* STRB (imm 8)		1111 1000 0000 1101 xxxx 110x xxxx xxxx */
 | 
				
			||||||
 | 
							/* STRH (imm 8)		1111 1000 0010 1101 xxxx 110x xxxx xxxx */
 | 
				
			||||||
 | 
							/* INVALID INSN		1111 1000 0110 1101 xxxx 110x xxxx xxxx */
 | 
				
			||||||
 | 
							/* Only consider U == 0 and P == 1: strx rx, [sp, #-<imm>] */
 | 
				
			||||||
 | 
							DECODE_CUSTOM	(0xff9f0e00, 0xf80d0c00, STACK_USE_FIXED_0XX),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* For STR{,B,H} (imm 12), offset is always positive, so ignore them. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/*                              P U W | Rn | Rt | Rt2|   imm8  |*/
 | 
				
			||||||
 | 
							/* STRD (immediate)	1110 1001 01x0 1101 xxxx xxxx xxxx xxxx */
 | 
				
			||||||
 | 
							/*
 | 
				
			||||||
 | 
							 * Only consider U == 0 and P == 1.
 | 
				
			||||||
 | 
							 * Also note that STRD in T32 encoding is special:
 | 
				
			||||||
 | 
							 * imm = ZeroExtend(imm8:'00', 32)
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							DECODE_CUSTOM	(0xffdf0000, 0xe94d0000, STACK_USE_T32STRD),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/*                                    | Rn | */
 | 
				
			||||||
 | 
							/* STMDB		1110 1001 00x0 1101 xxxx xxxx xxxx xxxx */
 | 
				
			||||||
 | 
							DECODE_CUSTOM	(0xffdf0000, 0xe90d0000, STACK_USE_STMDX),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* fall through */
 | 
				
			||||||
 | 
							DECODE_CUSTOM	(0, 0, STACK_USE_NONE),
 | 
				
			||||||
 | 
							DECODE_END
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return probes_decode_insn(insn, asi, table, false, false, stack_check_actions, NULL);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const struct decode_checker t32_stack_checker[NUM_PROBES_T32_ACTIONS] = {
 | 
				
			||||||
 | 
						[PROBES_T32_LDMSTM] = {.checker = t32_check_stack},
 | 
				
			||||||
 | 
						[PROBES_T32_LDRDSTRD] = {.checker = t32_check_stack},
 | 
				
			||||||
 | 
						[PROBES_T32_LDRSTR] = {.checker = t32_check_stack},
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * See following comments. This insn must be 'push'.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static enum probes_insn __kprobes t16_check_stack(probes_opcode_t insn,
 | 
				
			||||||
 | 
							struct arch_probes_insn *asi,
 | 
				
			||||||
 | 
							const struct decode_header *h)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						unsigned int reglist = insn & 0x1ff;
 | 
				
			||||||
 | 
						asi->stack_space = hweight32(reglist) * 4;
 | 
				
			||||||
 | 
						return INSN_GOOD;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * T16 encoding is simple: only the 'push' insn can need extra stack space.
 | 
				
			||||||
 | 
					 * Other insns, like str, can only use r0-r7 as Rn.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					const struct decode_checker t16_stack_checker[NUM_PROBES_T16_ACTIONS] = {
 | 
				
			||||||
 | 
						[PROBES_T16_PUSH] = {.checker = t16_check_stack},
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
							
								
								
									
										54
									
								
								arch/arm/probes/kprobes/checkers.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								arch/arm/probes/kprobes/checkers.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,54 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * arch/arm/probes/kprobes/checkers.h
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright (C) 2014 Huawei Inc.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This program is free software; you can redistribute it and/or modify
 | 
				
			||||||
 | 
					 * it under the terms of the GNU General Public License version 2 as
 | 
				
			||||||
 | 
					 * published by the Free Software Foundation.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This program is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
				
			||||||
 | 
					 * General Public License for more details.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#ifndef _ARM_KERNEL_PROBES_CHECKERS_H
 | 
				
			||||||
 | 
					#define _ARM_KERNEL_PROBES_CHECKERS_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <linux/kernel.h>
 | 
				
			||||||
 | 
					#include <linux/types.h>
 | 
				
			||||||
 | 
					#include "../decode.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern probes_check_t checker_stack_use_none;
 | 
				
			||||||
 | 
					extern probes_check_t checker_stack_use_unknown;
 | 
				
			||||||
 | 
					#ifdef CONFIG_THUMB2_KERNEL
 | 
				
			||||||
 | 
					extern probes_check_t checker_stack_use_imm_0xx;
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					extern probes_check_t checker_stack_use_imm_x0x;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					extern probes_check_t checker_stack_use_imm_xxx;
 | 
				
			||||||
 | 
					extern probes_check_t checker_stack_use_stmdx;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum {
 | 
				
			||||||
 | 
						STACK_USE_NONE,
 | 
				
			||||||
 | 
						STACK_USE_UNKNOWN,
 | 
				
			||||||
 | 
					#ifdef CONFIG_THUMB2_KERNEL
 | 
				
			||||||
 | 
						STACK_USE_FIXED_0XX,
 | 
				
			||||||
 | 
						STACK_USE_T32STRD,
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
						STACK_USE_FIXED_X0X,
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						STACK_USE_FIXED_XXX,
 | 
				
			||||||
 | 
						STACK_USE_STMDX,
 | 
				
			||||||
 | 
						NUM_STACK_USE_TYPES
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern const union decode_action stack_check_actions[];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef CONFIG_THUMB2_KERNEL
 | 
				
			||||||
 | 
					extern const struct decode_checker arm_stack_checker[];
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					extern const struct decode_checker t32_stack_checker[];
 | 
				
			||||||
 | 
					extern const struct decode_checker t16_stack_checker[];
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
		Loading…
	
		Reference in a new issue