From: Yicheng Qin <qycqycqycqycqyc@xxxxxxxxx> Test cases include: * cparser ability * C function call on user-defined kernel functions * C function call on native kernel functions Signed-off-by: Yicheng Qin <qycqycqycqycqyc@xxxxxxxxx> Signed-off-by: Qingping Hou <qingping.hou@xxxxxxxxx> --- test/ffi/Makefile | 46 ++++++++ test/ffi/cparser_test.c | 304 ++++++++++++++++++++++++++++++++++++++++++++++++ test/ffi/funct.c | 46 ++++++++ test/ffi/halt.kp | 3 + test/ffi/kfunct.kp | 8 ++ test/ffi/ufunct.kp | 24 ++++ test/run_test.sh | 2 + 7 files changed, 433 insertions(+) create mode 100644 test/ffi/Makefile create mode 100644 test/ffi/cparser_test.c create mode 100644 test/ffi/funct.c create mode 100644 test/ffi/halt.kp create mode 100644 test/ffi/kfunct.kp create mode 100644 test/ffi/ufunct.kp diff --git a/test/ffi/Makefile b/test/ffi/Makefile new file mode 100644 index 0000000..cd17ff7 --- /dev/null +++ b/test/ffi/Makefile @@ -0,0 +1,46 @@ +obj-m += funct.o + +all: funct_mod cparser_test + +funct_mod: + make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules + +INC=../../include +U_DIR=../../userspace +INTP=../../interpreter +U_FFI_DIR=$(U_DIR)/ffi +CPARSER_FILES=cparser.o ctype.o ffi_type.o +KTAPC_CFLAGS = -Wall -O2 + +cparser.o: $(U_FFI_DIR)/cparser.c $(INC)/* + $(CC) -DCONFIG_KTAP_FFI -o $@ -c $< + +ctype.o: $(U_FFI_DIR)/ctype.c $(INC)/* + $(CC) -DCONFIG_KTAP_FFI -o $@ -c $< + +ffi_type.o: $(INTP)/ffi/ffi_type.c $(INC)/* + $(CC) -DCONFIG_KTAP_FFI -o $@ -c $< + +cparser_test: cparser_test.c $(CPARSER_FILES) $(INC)/* + $(CC) -DCONFIG_KTAP_FFI -I$(INC) -I$(U_DIR) $(KTAPC_CFLAGS) \ + -o $@ $< $(CPARSER_FILES) + +load: + insmod funct.ko + +unload: + rmmod funct + +test: all + @echo "------------ test cparser -----------" + ./cparser_test + @echo "------------ test ffi module ------------" + rmmod funct > /dev/null 2>&1 || true + insmod funct.ko + ../../ktap ufunct.kp + ../../ktap kfunct.kp + rmmod funct.ko + +clean: + make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean + rm -rf cparser_test diff --git a/test/ffi/cparser_test.c b/test/ffi/cparser_test.c new file mode 100644 index 0000000..a4f203a --- /dev/null +++ b/test/ffi/cparser_test.c @@ -0,0 +1,304 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> + +#include "ktap_types.h" +#include "ktap_opcodes.h" +#include "../../userspace/ktapc.h" +#include "cparser.h" + +void ffi_cparser_init(void); +void ffi_cparser_free(void); +int ffi_cdef(char *s); + +static cp_csymbol_state *csym_state; + +#define cs_nr (csym_state->cs_nr) +#define cs_arr_size (csym_state->cs_arr_size) +#define cs_arr (csym_state->cs_arr) + + +#define DO_TEST(name) do { \ + int ret; \ + printf("[*] start "#name" test...\n"); \ + ret = test_##name(); \ + if (ret) \ + fprintf(stderr, "[!] "#name" test failed.\n"); \ + else \ + printf("[*] "#name" test passed.\n"); \ +} while (0) + +#define assert_csym_arr_type(cs_arr, n, t) do { \ + csymbol *ncs; \ + ncs = &cs_arr[n]; \ + assert(ncs->type == t); \ +} while (0) + +#define assert_arg_type(fcs, n, t) do { \ + csymbol *ncs; \ + ncs = &cs_arr[fcs->arg_ids[n]]; \ + assert(ncs->type == t); \ +} while (0) + + + + +/* mock find_kernel_symbol */ +unsigned long find_kernel_symbol(const char *symbol) +{ + return 0xdeadbeef; +} + +int lookup_csymbol_id_by_name(char *name) +{ + int i; + + for (i = 0; i < cs_nr; i++) { + if (!strcmp(name, cs_arr[i].name)) { + return i; + } + } + + return -1; +} + +int test_func_sched_clock() +{ + int idx; + csymbol *cs; + csymbol_func *fcs; + + ffi_cdef("unsigned long long sched_clock();"); + + csym_state = ctype_get_csym_state(); + assert(cs_arr); + + idx = lookup_csymbol_id_by_name("sched_clock"); + assert(idx >= 0); + cs = &cs_arr[idx]; + assert(cs->type == FFI_FUNC); + + fcs = csym_func(cs); + + /* check return type */ + cs = &cs_arr[fcs->ret_id]; + assert(cs->type == FFI_UINT64); + + /* check arguments */ + assert(fcs->arg_nr == 0); + + return 0; +} + +int test_func_funct_module() +{ + int idx; + csymbol *cs; + csymbol_func *fcs; + + ffi_cdef("void funct_void();"); + ffi_cdef("int funct_int1(unsigned char a, char b, unsigned short c, " + "short d);"); + ffi_cdef("long long funct_int2(unsigned int a, int b, " + "unsigned long c, long d, unsigned long long e, " + "long long f, long long g);"); + ffi_cdef("void *funct_pointer1(char *a);"); + + csym_state = ctype_get_csym_state(); + assert(cs_arr); + + /* check funct_void function */ + idx = lookup_csymbol_id_by_name("funct_void"); + assert(idx >= 0); + cs = &cs_arr[idx]; + assert(cs->type == FFI_FUNC); + fcs = csym_func(cs); + + /* check return type */ + cs = &cs_arr[fcs->ret_id]; + assert(cs->type == FFI_VOID); + + /* check arguments */ + assert(fcs->arg_nr == 0); + + + + /* check funct_int1 function */ + idx = lookup_csymbol_id_by_name("funct_int1"); + assert(idx >= 0); + cs = &cs_arr[idx]; + assert(cs); + assert(cs->type == FFI_FUNC); + fcs = csym_func(cs); + + /* check return type */ + cs = &cs_arr[fcs->ret_id]; + assert(cs->type == FFI_INT32); + + /* check arguments */ + assert(fcs->arg_nr == 4); + assert_arg_type(fcs, 0, FFI_UINT8); + assert_arg_type(fcs, 1, FFI_INT8); + assert_arg_type(fcs, 2, FFI_UINT16); + assert_arg_type(fcs, 3, FFI_INT16); + + + + /* check funct_int2 function */ + idx = lookup_csymbol_id_by_name("funct_int2"); + assert(idx >= 0); + cs = &cs_arr[idx]; + assert(cs); + assert(cs->type == FFI_FUNC); + fcs = csym_func(cs); + + /* check return type */ + cs = &cs_arr[fcs->ret_id]; + assert(cs->type == FFI_INT64); + + /* check arguments */ + assert(fcs->arg_nr == 7); + assert_arg_type(fcs, 0, FFI_UINT32); + assert_arg_type(fcs, 1, FFI_INT32); + assert_arg_type(fcs, 2, FFI_UINT64); + assert_arg_type(fcs, 3, FFI_INT64); + assert_arg_type(fcs, 4, FFI_UINT64); + assert_arg_type(fcs, 5, FFI_INT64); + assert_arg_type(fcs, 6, FFI_INT64); + + + + /* check funct_pointer1 function */ + idx = lookup_csymbol_id_by_name("funct_pointer1"); + assert(idx >= 0); + cs = &cs_arr[idx]; + assert(cs); + assert(cs->type == FFI_FUNC); + fcs = csym_func(cs); + + /* check return type */ + cs = &cs_arr[fcs->ret_id]; + assert(cs->type == FFI_PTR); + + /* check arguments */ + assert(fcs->arg_nr == 1); + assert_arg_type(fcs, 0, FFI_PTR); + /*@TODO check pointer dereference type 18.11 2013 (houqp)*/ + + return 0; +} + +int test_struct_timespec() +{ + int idx; + csymbol *cs; + csymbol_struct *stcs; + + ffi_cdef("struct timespec { long ts_sec; long ts_nsec; };"); + + csym_state = ctype_get_csym_state(); + assert(cs_arr); + + idx = lookup_csymbol_id_by_name("struct timespec"); + assert(idx >= 0); + cs = &cs_arr[idx]; + assert(cs); + assert(cs->type == FFI_STRUCT); + + stcs = csym_struct(cs); + assert(stcs->memb_nr == 2); + + return 0; +} + +int test_func_time_to_tm() +{ + int idx; + csymbol *cs, *arg_cs; + csymbol_struct *stcs; + csymbol_func *fcs; + + ffi_cdef("typedef long time_t;"); + ffi_cdef("struct tm { " + "int tm_sec;" + "int tm_min;" + "int tm_hour;" + "int tm_mday;" + "int tm_mon;" + "long tm_year;" + "int tm_wday;" + "int tm_yday;" + "};"); + ffi_cdef("void time_to_tm(time_t totalsecs, int offset, struct tm *result);"); + + csym_state = ctype_get_csym_state(); + assert(cs_arr); + + idx = lookup_csymbol_id_by_name("struct tm"); + assert(idx >= 0); + cs = cp_id_to_csym(idx); + assert(cs); + assert(cs->type == FFI_STRUCT); + + stcs = csym_struct(cs); + assert(stcs->memb_nr == 8); + + + idx = lookup_csymbol_id_by_name("time_to_tm"); + assert(idx >= 0); + cs = cp_id_to_csym(idx); + assert(cs); + assert(cs->type == FFI_FUNC); + + fcs = csym_func(cs); + assert(csymf_arg_nr(fcs) == 3); + /* check first argument */ + assert_arg_type(fcs, 0, FFI_INT64); + + /* check second argument */ + assert_arg_type(fcs, 1, FFI_INT32); + /* check third argument */ + assert_arg_type(fcs, 2, FFI_PTR); + arg_cs = cp_csymf_arg(fcs, 2); + assert(!strcmp(csym_name(arg_cs), "struct tm *")); + assert(csym_ptr_deref_id(arg_cs) == + lookup_csymbol_id_by_name("struct tm")); + + return 0; +} + +int test_pointer_symbols() +{ + csymbol_func *fcs_foo, *fcs_bar; + + /* int pointer symbol should be resolved to the same id */ + ffi_cdef("void foo(int *a);"); + ffi_cdef("int *bar(void);"); + + csym_state = ctype_get_csym_state(); + assert(cs_arr); + + fcs_foo = csym_func(cp_id_to_csym(lookup_csymbol_id_by_name("foo"))); + fcs_bar = csym_func(cp_id_to_csym(lookup_csymbol_id_by_name("bar"))); + + assert(csymf_arg_ids(fcs_foo)[0] == csymf_ret_id(fcs_bar)); + assert(cp_csymf_arg(fcs_foo, 0) == cp_csymf_ret(fcs_bar)); + + return 0; +} + +int main (int argc, char *argv[]) +{ + ffi_cparser_init(); + + DO_TEST(func_sched_clock); + DO_TEST(func_funct_module); + DO_TEST(struct_timespec); + DO_TEST(func_time_to_tm); + DO_TEST(pointer_symbols); + + ffi_cparser_free(); + + return 0; +} diff --git a/test/ffi/funct.c b/test/ffi/funct.c new file mode 100644 index 0000000..789188f --- /dev/null +++ b/test/ffi/funct.c @@ -0,0 +1,46 @@ +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> + +void funct_void(void) +{ +} +EXPORT_SYMBOL(funct_void); + +int funct_int1(unsigned char a, char b, unsigned short c, short d) +{ + return a + b + c + d; +} +EXPORT_SYMBOL(funct_int1); + +long long funct_int2(unsigned int a, int b, unsigned long c, long d, + unsigned long long e, long long f, long long g) +{ + return a + b + c + d + e + f + g; +} +EXPORT_SYMBOL(funct_int2); + +void *funct_pointer1(char *a) { + return a; +} +EXPORT_SYMBOL(funct_pointer1); + + + +static int __init funct_init(void) +{ + printk("Hello World!\n"); + return 0; +} + +static void __exit funct_exit(void) +{ + printk("Goodbye!\n"); +} + + +MODULE_DESCRIPTION("ktap test module"); +MODULE_LICENSE("GPL"); + +module_init(funct_init); +module_exit(funct_exit); diff --git a/test/ffi/halt.kp b/test/ffi/halt.kp new file mode 100644 index 0000000..7bfae9a --- /dev/null +++ b/test/ffi/halt.kp @@ -0,0 +1,3 @@ +cdef("void kernel_halt(void);") + +C.kernel_halt() diff --git a/test/ffi/kfunct.kp b/test/ffi/kfunct.kp new file mode 100644 index 0000000..dc6aa74 --- /dev/null +++ b/test/ffi/kfunct.kp @@ -0,0 +1,8 @@ +cdef("unsigned long long sched_clock();") + + +print("start of user script...") + +print("[*] try a registered C function...") +ret = C.sched_clock() +print("C function returned, value: ", ret) diff --git a/test/ffi/ufunct.kp b/test/ffi/ufunct.kp new file mode 100644 index 0000000..adbe3fe --- /dev/null +++ b/test/ffi/ufunct.kp @@ -0,0 +1,24 @@ +cdef("void funct_void();") +cdef("int funct_int1(unsigned char a, char b, unsigned short c, short d);") +cdef("long long funct_int2(unsigned int a, int b, unsigned long c, long d, unsigned long long e, long long f, long long g);") +cdef("void *funct_pointer1(char *a);") + + +print("start of user script...") + +print("[*] try funct_void...") +ret = C.funct_void() +print("C function returned, value: ", ret, ", should be nil") + +print("[*] try funct_int1...") +ret = C.funct_int1(1111, 1111, 1111, 1111) +print("C function returned, value: ", ret, ", should be 2396") + +print("[*] try funct_int2...") +ret = C.funct_int2(90, 7800, 560000, 34000000, 1200000000, 900000000000, 78000000000000) +print("C function returned, value: ", ret, ", should be 78901234567890") + +print("[*] try funct_pointer1...") +ret = C.funct_pointer1("") +print("C function returned, value: ", ret, + ", should be around 0xffff8800--------") diff --git a/test/run_test.sh b/test/run_test.sh index 71e96b6..3375c36 100644 --- a/test/run_test.sh +++ b/test/run_test.sh @@ -51,6 +51,8 @@ sleep 1 pkill ktap sleep 1 +cd ffi && make test && cd - + ##################################################### rmmod ktapvm if test $? -ne 0; then -- 1.8.1.2