2011-08-28 16:18:43 +01:00
/*
* arch / arm / kernel / kprobes - test . h
*
* Copyright ( C ) 2011 Jon Medhurst < tixy @ yxit . co . uk > .
*
* 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 .
*/
# define VERBOSE 0 /* Set to '1' for more logging of test cases */
# ifdef CONFIG_THUMB2_KERNEL
# define NORMAL_ISA "16"
# else
# define NORMAL_ISA "32"
# endif
/* Flags used in kprobe_test_flags */
# define TEST_FLAG_NO_ITBLOCK (1<<0)
# define TEST_FLAG_FULL_ITBLOCK (1<<1)
# define TEST_FLAG_NARROW_INSTR (1<<2)
extern int kprobe_test_flags ;
extern int kprobe_test_cc_position ;
# define TEST_MEMORY_SIZE 256
/*
* Test case structures .
*
* The arguments given to test cases can be one of three types .
*
* ARG_TYPE_REG
* Load a register with the given value .
*
* ARG_TYPE_PTR
* Load a register with a pointer into the stack buffer ( SP + given value ) .
*
* ARG_TYPE_MEM
* Store the given value into the stack buffer at [ SP + index ] .
*
*/
# define ARG_TYPE_END 0
# define ARG_TYPE_REG 1
# define ARG_TYPE_PTR 2
# define ARG_TYPE_MEM 3
# define ARG_FLAG_UNSUPPORTED 0x01
# define ARG_FLAG_SUPPORTED 0x02
# define ARG_FLAG_THUMB 0x10 /* Must be 16 so TEST_ISA can be used */
# define ARG_FLAG_ARM 0x20 /* Must be 32 so TEST_ISA can be used */
struct test_arg {
u8 type ; /* ARG_TYPE_x */
u8 _padding [ 7 ] ;
} ;
struct test_arg_regptr {
u8 type ; /* ARG_TYPE_REG or ARG_TYPE_PTR */
u8 reg ;
u8 _padding [ 2 ] ;
u32 val ;
} ;
struct test_arg_mem {
u8 type ; /* ARG_TYPE_MEM */
u8 index ;
u8 _padding [ 2 ] ;
u32 val ;
} ;
struct test_arg_end {
u8 type ; /* ARG_TYPE_END */
u8 flags ; /* ARG_FLAG_x */
u16 code_offset ;
u16 branch_offset ;
u16 end_offset ;
} ;
/*
* Building blocks for test cases .
*
* Each test case is wrapped between TESTCASE_START and TESTCASE_END .
*
* To specify arguments for a test case the TEST_ARG_ { REG , PTR , MEM } macros are
* used followed by a terminating TEST_ARG_END .
*
* After this , the instruction to be tested is defined with TEST_INSTRUCTION .
* Or for branches , TEST_BRANCH_B and TEST_BRANCH_F ( branch forwards / backwards ) .
*
* Some specific test cases may make use of other custom constructs .
*/
# if VERBOSE
# define verbose(fmt, ...) pr_info(fmt, ##__VA_ARGS__)
# else
# define verbose(fmt, ...)
# endif
# define TEST_GROUP(title) \
verbose ( " \n " ) ; \
verbose ( title " \n " ) ; \
verbose ( " --------------------------------------------------------- \n " ) ;
# define TESTCASE_START(title) \
__asm__ __volatile__ ( \
" bl __kprobes_test_case_start \n \t " \
/* don't use .asciz here as 'title' may be */ \
/* multiple strings to be concatenated. */ \
" .ascii " # title " \n \t " \
" .byte 0 \n \t " \
" .align 2 \n \t "
# define TEST_ARG_REG(reg, val) \
" .byte " __stringify ( ARG_TYPE_REG ) " \n \t " \
" .byte " # reg " \n \t " \
" .short 0 \n \t " \
" .word " # val " \n \t "
# define TEST_ARG_PTR(reg, val) \
" .byte " __stringify ( ARG_TYPE_PTR ) " \n \t " \
" .byte " # reg " \n \t " \
" .short 0 \n \t " \
" .word " # val " \n \t "
# define TEST_ARG_MEM(index, val) \
" .byte " __stringify ( ARG_TYPE_MEM ) " \n \t " \
" .byte " # index " \n \t " \
" .short 0 \n \t " \
" .word " # val " \n \t "
# define TEST_ARG_END(flags) \
" .byte " __stringify ( ARG_TYPE_END ) " \n \t " \
" .byte " TEST_ISA flags " \n \t " \
" .short 50f-0f \n \t " \
" .short 2f-0f \n \t " \
" .short 99f-0f \n \t " \
" .code " TEST_ISA " \n \t " \
" 0: \n \t "
# define TEST_INSTRUCTION(instruction) \
" 50: nop \n \t " \
" 1: " instruction " \n \t " \
" nop \n \t "
2011-11-24 13:01:08 +01:00
# define TEST_BRANCH_F(instruction) \
2011-08-28 16:18:43 +01:00
TEST_INSTRUCTION ( instruction ) \
" b 99f \n \t " \
2011-11-24 13:01:08 +01:00
" 2: nop \n \t "
# define TEST_BRANCH_B(instruction) \
" b 50f \n \t " \
" b 99f \n \t " \
" 2: nop \n \t " \
" b 99f \n \t " \
TEST_INSTRUCTION ( instruction )
# define TEST_BRANCH_FX(instruction, codex) \
TEST_INSTRUCTION ( instruction ) \
" b 99f \n \t " \
codex " \n \t " \
2011-08-28 16:18:43 +01:00
" b 99f \n \t " \
" 2: nop \n \t "
2011-11-24 13:01:08 +01:00
# define TEST_BRANCH_BX(instruction, codex) \
2011-08-28 16:18:43 +01:00
" b 50f \n \t " \
" b 99f \n \t " \
" 2: nop \n \t " \
" b 99f \n \t " \
2011-11-24 13:01:08 +01:00
codex " \n \t " \
2011-08-28 16:18:43 +01:00
TEST_INSTRUCTION ( instruction )
# define TESTCASE_END \
" 2: \n \t " \
" 99: \n \t " \
" bl __kprobes_test_case_end_ " TEST_ISA " \n \t " \
" .code " NORMAL_ISA " \n \t " \
: : \
: " r0 " , " r1 " , " r2 " , " r3 " , " ip " , " lr " , " memory " , " cc " \
) ;
/*
* Macros to define test cases .
*
* Those of the form TEST_ { R , P , M } * can be used to define test cases
* which take combinations of the three basic types of arguments . E . g .
*
* TEST_R One register argument
* TEST_RR Two register arguments
* TEST_RPR A register , a pointer , then a register argument
*
* For testing instructions which may branch , there are macros TEST_BF_ *
* and TEST_BB_ * for branching forwards and backwards .
*
* TEST_SUPPORTED and TEST_UNSUPPORTED don ' t cause the code to be executed ,
* the just verify that a kprobe is or is not allowed on the given instruction .
*/
# define TEST(code) \
TESTCASE_START ( code ) \
TEST_ARG_END ( " " ) \
TEST_INSTRUCTION ( code ) \
TESTCASE_END
# define TEST_UNSUPPORTED(code) \
TESTCASE_START ( code ) \
TEST_ARG_END ( " | " __stringify ( ARG_FLAG_UNSUPPORTED ) ) \
TEST_INSTRUCTION ( code ) \
TESTCASE_END
# define TEST_SUPPORTED(code) \
TESTCASE_START ( code ) \
TEST_ARG_END ( " | " __stringify ( ARG_FLAG_SUPPORTED ) ) \
TEST_INSTRUCTION ( code ) \
TESTCASE_END
# define TEST_R(code1, reg, val, code2) \
TESTCASE_START ( code1 # reg code2 ) \
TEST_ARG_REG ( reg , val ) \
TEST_ARG_END ( " " ) \
TEST_INSTRUCTION ( code1 # reg code2 ) \
TESTCASE_END
# define TEST_RR(code1, reg1, val1, code2, reg2, val2, code3) \
TESTCASE_START ( code1 # reg1 code2 # reg2 code3 ) \
TEST_ARG_REG ( reg1 , val1 ) \
TEST_ARG_REG ( reg2 , val2 ) \
TEST_ARG_END ( " " ) \
TEST_INSTRUCTION ( code1 # reg1 code2 # reg2 code3 ) \
TESTCASE_END
# define TEST_RRR(code1, reg1, val1, code2, reg2, val2, code3, reg3, val3, code4)\
TESTCASE_START ( code1 # reg1 code2 # reg2 code3 # reg3 code4 ) \
TEST_ARG_REG ( reg1 , val1 ) \
TEST_ARG_REG ( reg2 , val2 ) \
TEST_ARG_REG ( reg3 , val3 ) \
TEST_ARG_END ( " " ) \
TEST_INSTRUCTION ( code1 # reg1 code2 # reg2 code3 # reg3 code4 ) \
TESTCASE_END
# define TEST_RRRR(code1, reg1, val1, code2, reg2, val2, code3, reg3, val3, code4, reg4, val4) \
TESTCASE_START ( code1 # reg1 code2 # reg2 code3 # reg3 code4 # reg4 ) \
TEST_ARG_REG ( reg1 , val1 ) \
TEST_ARG_REG ( reg2 , val2 ) \
TEST_ARG_REG ( reg3 , val3 ) \
TEST_ARG_REG ( reg4 , val4 ) \
TEST_ARG_END ( " " ) \
TEST_INSTRUCTION ( code1 # reg1 code2 # reg2 code3 # reg3 code4 # reg4 ) \
TESTCASE_END
# define TEST_P(code1, reg1, val1, code2) \
TESTCASE_START ( code1 # reg1 code2 ) \
TEST_ARG_PTR ( reg1 , val1 ) \
TEST_ARG_END ( " " ) \
TEST_INSTRUCTION ( code1 # reg1 code2 ) \
TESTCASE_END
# define TEST_PR(code1, reg1, val1, code2, reg2, val2, code3) \
TESTCASE_START ( code1 # reg1 code2 # reg2 code3 ) \
TEST_ARG_PTR ( reg1 , val1 ) \
TEST_ARG_REG ( reg2 , val2 ) \
TEST_ARG_END ( " " ) \
TEST_INSTRUCTION ( code1 # reg1 code2 # reg2 code3 ) \
TESTCASE_END
# define TEST_RP(code1, reg1, val1, code2, reg2, val2, code3) \
TESTCASE_START ( code1 # reg1 code2 # reg2 code3 ) \
TEST_ARG_REG ( reg1 , val1 ) \
TEST_ARG_PTR ( reg2 , val2 ) \
TEST_ARG_END ( " " ) \
TEST_INSTRUCTION ( code1 # reg1 code2 # reg2 code3 ) \
TESTCASE_END
# define TEST_PRR(code1, reg1, val1, code2, reg2, val2, code3, reg3, val3, code4)\
TESTCASE_START ( code1 # reg1 code2 # reg2 code3 # reg3 code4 ) \
TEST_ARG_PTR ( reg1 , val1 ) \
TEST_ARG_REG ( reg2 , val2 ) \
TEST_ARG_REG ( reg3 , val3 ) \
TEST_ARG_END ( " " ) \
TEST_INSTRUCTION ( code1 # reg1 code2 # reg2 code3 # reg3 code4 ) \
TESTCASE_END
# define TEST_RPR(code1, reg1, val1, code2, reg2, val2, code3, reg3, val3, code4)\
TESTCASE_START ( code1 # reg1 code2 # reg2 code3 # reg3 code4 ) \
TEST_ARG_REG ( reg1 , val1 ) \
TEST_ARG_PTR ( reg2 , val2 ) \
TEST_ARG_REG ( reg3 , val3 ) \
TEST_ARG_END ( " " ) \
TEST_INSTRUCTION ( code1 # reg1 code2 # reg2 code3 # reg3 code4 ) \
TESTCASE_END
# define TEST_RRP(code1, reg1, val1, code2, reg2, val2, code3, reg3, val3, code4)\
TESTCASE_START ( code1 # reg1 code2 # reg2 code3 # reg3 code4 ) \
TEST_ARG_REG ( reg1 , val1 ) \
TEST_ARG_REG ( reg2 , val2 ) \
TEST_ARG_PTR ( reg3 , val3 ) \
TEST_ARG_END ( " " ) \
TEST_INSTRUCTION ( code1 # reg1 code2 # reg2 code3 # reg3 code4 ) \
TESTCASE_END
# define TEST_BF_P(code1, reg1, val1, code2) \
TESTCASE_START ( code1 # reg1 code2 ) \
TEST_ARG_PTR ( reg1 , val1 ) \
TEST_ARG_END ( " " ) \
2011-11-24 13:01:08 +01:00
TEST_BRANCH_F ( code1 # reg1 code2 ) \
2011-08-28 16:18:43 +01:00
TESTCASE_END
2011-11-24 13:01:08 +01:00
# define TEST_BF(code) \
2011-08-28 16:18:43 +01:00
TESTCASE_START ( code ) \
TEST_ARG_END ( " " ) \
2011-11-24 13:01:08 +01:00
TEST_BRANCH_F ( code ) \
2011-08-28 16:18:43 +01:00
TESTCASE_END
2011-11-24 13:01:08 +01:00
# define TEST_BB(code) \
2011-08-28 16:18:43 +01:00
TESTCASE_START ( code ) \
TEST_ARG_END ( " " ) \
2011-11-24 13:01:08 +01:00
TEST_BRANCH_B ( code ) \
2011-08-28 16:18:43 +01:00
TESTCASE_END
2011-11-24 13:01:08 +01:00
# define TEST_BF_R(code1, reg, val, code2) \
TESTCASE_START ( code1 # reg code2 ) \
TEST_ARG_REG ( reg , val ) \
TEST_ARG_END ( " " ) \
TEST_BRANCH_F ( code1 # reg code2 ) \
2011-08-28 16:18:43 +01:00
TESTCASE_END
2011-11-24 13:01:08 +01:00
# define TEST_BB_R(code1, reg, val, code2) \
TESTCASE_START ( code1 # reg code2 ) \
TEST_ARG_REG ( reg , val ) \
TEST_ARG_END ( " " ) \
TEST_BRANCH_B ( code1 # reg code2 ) \
2011-08-28 16:18:43 +01:00
TESTCASE_END
# define TEST_BF_RR(code1, reg1, val1, code2, reg2, val2, code3) \
TESTCASE_START ( code1 # reg1 code2 # reg2 code3 ) \
TEST_ARG_REG ( reg1 , val1 ) \
TEST_ARG_REG ( reg2 , val2 ) \
TEST_ARG_END ( " " ) \
2011-11-24 13:01:08 +01:00
TEST_BRANCH_F ( code1 # reg1 code2 # reg2 code3 ) \
TESTCASE_END
# define TEST_BF_X(code, codex) \
TESTCASE_START ( code ) \
TEST_ARG_END ( " " ) \
TEST_BRANCH_FX ( code , codex ) \
TESTCASE_END
# define TEST_BB_X(code, codex) \
TESTCASE_START ( code ) \
TEST_ARG_END ( " " ) \
TEST_BRANCH_BX ( code , codex ) \
TESTCASE_END
# define TEST_BF_RX(code1, reg, val, code2, codex) \
TESTCASE_START ( code1 # reg code2 ) \
TEST_ARG_REG ( reg , val ) \
TEST_ARG_END ( " " ) \
TEST_BRANCH_FX ( code1 # reg code2 , codex ) \
2011-08-28 16:18:43 +01:00
TESTCASE_END
# define TEST_X(code, codex) \
TESTCASE_START ( code ) \
TEST_ARG_END ( " " ) \
TEST_INSTRUCTION ( code ) \
" b 99f \n \t " \
" " codex " \n \t " \
TESTCASE_END
# define TEST_RX(code1, reg, val, code2, codex) \
TESTCASE_START ( code1 # reg code2 ) \
TEST_ARG_REG ( reg , val ) \
TEST_ARG_END ( " " ) \
TEST_INSTRUCTION ( code1 __stringify ( reg ) code2 ) \
" b 99f \n \t " \
" " codex " \n \t " \
TESTCASE_END
# define TEST_RRX(code1, reg1, val1, code2, reg2, val2, code3, codex) \
TESTCASE_START ( code1 # reg1 code2 # reg2 code3 ) \
TEST_ARG_REG ( reg1 , val1 ) \
TEST_ARG_REG ( reg2 , val2 ) \
TEST_ARG_END ( " " ) \
TEST_INSTRUCTION ( code1 __stringify ( reg1 ) code2 __stringify ( reg2 ) code3 ) \
" b 99f \n \t " \
" " codex " \n \t " \
TESTCASE_END
2011-11-24 13:01:08 +01:00
/*
* Macros for defining space directives spread over multiple lines .
* These are required so the compiler guesses better the length of inline asm
* code and will spill the literal pool early enough to avoid generating PC
* relative loads with out of range offsets .
*/
# define TWICE(x) x x
# define SPACE_0x8 TWICE(".space 4\n\t")
# define SPACE_0x10 TWICE(SPACE_0x8)
# define SPACE_0x20 TWICE(SPACE_0x10)
# define SPACE_0x40 TWICE(SPACE_0x20)
# define SPACE_0x80 TWICE(SPACE_0x40)
# define SPACE_0x100 TWICE(SPACE_0x80)
# define SPACE_0x200 TWICE(SPACE_0x100)
# define SPACE_0x400 TWICE(SPACE_0x200)
# define SPACE_0x800 TWICE(SPACE_0x400)
# define SPACE_0x1000 TWICE(SPACE_0x800)
2011-08-28 16:18:43 +01:00
/* Various values used in test cases... */
# define N(val) (val ^ 0xffffffff)
# define VAL1 0x12345678
# define VAL2 N(VAL1)
# define VAL3 0xa5f801
# define VAL4 N(VAL3)
# define VALM 0x456789ab
# define VALR 0xdeaddead
# define HH1 0x0123fecb
# define HH2 0xa9874567
2011-08-27 12:40:30 +01:00
# ifdef CONFIG_THUMB2_KERNEL
void kprobe_thumb16_test_cases ( void ) ;
void kprobe_thumb32_test_cases ( void ) ;
2011-08-27 12:41:05 +01:00
# else
void kprobe_arm_test_cases ( void ) ;
2011-08-27 12:40:30 +01:00
# endif