[ktap] [PATCH 8/8] Add ffi test cases and script

  • From: Yicheng Qin <qycqycqycqycqyc@xxxxxxxxx>
  • To: ktap@xxxxxxxxxxxxx
  • Date: Tue, 26 Nov 2013 14:52:36 -0500

Test cases include cparser ability, ffi.current function, 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       |  48 ++++++++
 test/ffi/cparser_test.c | 304 ++++++++++++++++++++++++++++++++++++++++++++++++
 test/ffi/current.kp     |   2 +
 test/ffi/funct.c        |  40 +++++++
 test/ffi/halt.kp        |   3 +
 test/ffi/kfunct.kp      |   8 ++
 test/ffi/ufunct.kp      |  24 ++++
 test/run_test.sh        |   2 +
 8 files changed, 431 insertions(+)
 create mode 100644 test/ffi/Makefile
 create mode 100644 test/ffi/cparser_test.c
 create mode 100644 test/ffi/current.kp
 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..70ef523
--- /dev/null
+++ b/test/ffi/Makefile
@@ -0,0 +1,48 @@
+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 now -----------"
+       ./cparser_test
+       @echo "------------ Test ffi.current now ------------"
+       ../../ktap current.kp
+       @echo "------------ Test ffi module now ------------"
+       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..c10271f
--- /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 = 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 = 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 = 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(id_to_csym(lookup_csymbol_id_by_name("foo")));
+       fcs_bar = csym_func(id_to_csym(lookup_csymbol_id_by_name("bar")));
+
+       assert(csymf_arg_ids(fcs_foo)[0] == csymf_ret_id(fcs_bar));
+       assert(csymf_arg(fcs_foo, 0) == 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/current.kp b/test/ffi/current.kp
new file mode 100644
index 0000000..1fa7836
--- /dev/null
+++ b/test/ffi/current.kp
@@ -0,0 +1,2 @@
+curr = ffi.current()
+print("current task pointer:", curr)
diff --git a/test/ffi/funct.c b/test/ffi/funct.c
new file mode 100644
index 0000000..2003a1d
--- /dev/null
+++ b/test/ffi/funct.c
@@ -0,0 +1,40 @@
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+static int __init funct_init(void)
+{
+       printk("Hello World!\n");
+       return 0;
+}
+
+void funct_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 void __exit funct_exit(void)
+{
+       printk("Goodbye!\n");
+}
+
+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 c41b1f7..5f85ed7 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.3.4 (Apple Git-47)


Other related posts: