[IMPROVE] add kprobe tests 41/69641/3
authorVyacheslav Cherkashin <v.cherkashin@samsung.com>
Mon, 16 May 2016 08:28:35 +0000 (11:28 +0300)
committerDmitry Kovalenko <d.kovalenko@samsung.com>
Wed, 18 May 2016 10:47:05 +0000 (03:47 -0700)
Change-Id: I8f89454a43ca725bfbad01163c224321c5937c3b
Signed-off-by: Vyacheslav Cherkashin <v.cherkashin@samsung.com>
tests/Kbuild [new file with mode: 0644]
tests/kprobe_tests/Kbuild [new file with mode: 0644]
tests/kprobe_tests/kp_tests_module.c [new file with mode: 0644]
tests/kprobe_tests/run_kp_tests.sh [new file with mode: 0644]

diff --git a/tests/Kbuild b/tests/Kbuild
new file mode 100644 (file)
index 0000000..9817995
--- /dev/null
@@ -0,0 +1,3 @@
+EXTRA_CFLAGS := $(extra_cflags)
+
+obj-m := kprobe_tests/
diff --git a/tests/kprobe_tests/Kbuild b/tests/kprobe_tests/Kbuild
new file mode 100644 (file)
index 0000000..7ffd593
--- /dev/null
@@ -0,0 +1,4 @@
+EXTRA_CFLAGS := $(extra_cflags)
+
+obj-m := swap_kp_tests.o
+swap_kp_tests-y := kp_tests_module.o
diff --git a/tests/kprobe_tests/kp_tests_module.c b/tests/kprobe_tests/kp_tests_module.c
new file mode 100644 (file)
index 0000000..816d92e
--- /dev/null
@@ -0,0 +1,488 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) Samsung Electronics, 2016
+ *
+ * 2016         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/kthread.h>
+#include <ksyms/ksyms.h>
+#include <kprobe/swap_kprobes.h>
+#include <master/swap_initializer.h>
+
+
+static struct task_struct *cur_task;
+
+
+
+/*
+ ******************************************************************************
+ *                                    log                                     *
+ ******************************************************************************
+ */
+static long write_to_stdout(const char *buf, size_t len)
+{
+       static asmlinkage long (*sys_write)(unsigned int, const char __user *, size_t) = NULL;
+       long ret = -ESRCH;
+
+       if (sys_write == NULL)
+               sys_write = (void *)swap_ksyms("sys_write");
+
+       if (sys_write) {
+               mm_segment_t fs = get_fs();
+               set_fs(get_ds());
+               ret = sys_write(1, buf, len);
+               set_fs(fs);
+       }
+
+       return ret;
+}
+
+static void olog(const char *fmt, ...)
+{
+       char buf[256];
+       va_list args;
+
+       va_start(args, fmt);
+       vsnprintf(buf, sizeof(buf), fmt, args);
+       va_end(args);
+
+       printk("%s", buf);
+       write_to_stdout(buf, strlen(buf));
+}
+
+
+
+
+static struct kprobe *kp_create(char *name,
+                               int (*pre_h)(struct kprobe *, struct pt_regs *))
+{
+       struct kprobe *p;
+
+       p = kzalloc(sizeof(*p), GFP_KERNEL);
+       if (p) {
+               p->symbol_name = name;
+               p->pre_handler = pre_h;
+       }
+
+       return p;
+}
+
+static void kp_free(struct kprobe *p)
+{
+       memset(p, 0x10, sizeof(*p));
+}
+
+#define kp_reg(ptr, name, handler) \
+       do { \
+               ptr = kp_create(name, handler); \
+               swap_register_kprobe(ptr); \
+       } while (0)
+
+#define kp_unreg(ptr) \
+       do { \
+               swap_unregister_kprobe(ptr); \
+               kp_free(ptr); \
+               ptr = NULL; \
+       } while (0)
+
+
+noinline char *my_kstrdup(const char *s, gfp_t gfp)
+{
+       return kstrdup(s, gfp);
+}
+
+noinline void my_kfree(const void *data)
+{
+       kfree(data);
+}
+
+
+
+
+/*
+ ******************************************************************************
+ *                                 recursion                                  *
+ ******************************************************************************
+ */
+static int kstrdup_cnt;
+static int kfree_cnt;
+
+static struct kprobe *kp_kstrdup;
+static int kstrdup_h(struct kprobe *kp, struct pt_regs *regs)
+{
+       char *str;
+
+       str = my_kstrdup("from_kfree_h", GFP_ATOMIC);
+       my_kfree(str);
+
+       ++kstrdup_cnt;
+
+       return 0;
+}
+
+static struct kprobe *kp_kfree;
+static int kfree_h(struct kprobe *kp, struct pt_regs *regs)
+{
+       ++kfree_cnt;
+
+       return 0;
+}
+
+static void run_test_recursion(void)
+{
+       char *str;
+
+       str = my_kstrdup("test_string_0", GFP_KERNEL);
+       my_kfree(str);
+
+       str = my_kstrdup("test_string_1", GFP_KERNEL);
+       my_kfree(str);
+}
+
+static void do_test_recursion(void)
+{
+       kp_reg(kp_kfree, "my_kfree", kfree_h);
+       kp_reg(kp_kstrdup, "my_kstrdup", kstrdup_h);
+
+       run_test_recursion();
+
+       kp_unreg(kp_kstrdup);
+       kp_unreg(kp_kfree);
+}
+
+
+static void test_recursion(void)
+{
+       olog("Recursion:\n");
+
+       kstrdup_cnt = 0;
+       kfree_cnt = 0;
+
+       do_test_recursion();
+
+       if (kstrdup_cnt == 2 && kfree_cnt == 2) {
+               olog("    OK\n");
+       } else {
+               olog("    ERROR: kstrdup_cnt=%d kfree_cnt=%d\n",
+                      kstrdup_cnt, kfree_cnt);
+       }
+}
+
+
+
+
+/*
+ ******************************************************************************
+ *            recursion and multiple handlers (Aggregate probe)               *
+ ******************************************************************************
+ */
+static int kfree2_cnt;
+
+static struct kprobe *kp_kfree2;
+static int kfree2_h(struct kprobe *kp, struct pt_regs *regs)
+{
+       if (current != cur_task || in_interrupt())
+               return 0;
+
+       ++kfree2_cnt;
+       return 0;
+}
+
+static void pre_test_recursion_and_mh(void)
+{
+       kstrdup_cnt = 0;
+       kfree_cnt = 0;
+       kfree2_cnt = 0;
+}
+
+static void post_test_recursion_and_mh(void)
+{
+       if (kstrdup_cnt == 2 && kfree_cnt == 2 && kfree2_cnt == 2) {
+               olog("    OK\n");
+       } else {
+               olog("    ERROR: kstrdup_cnt=%d kfree_cnt=%d kfree2_cnt=%d\n",
+                    kstrdup_cnt, kfree_cnt, kfree2_cnt);
+       }
+}
+
+static void test_recursion_and_multiple_handlers(void)
+{
+       olog("Recursion and multiple handlers:\n");
+
+       pre_test_recursion_and_mh();
+
+       kp_reg(kp_kfree2, "my_kfree", kfree2_h);
+       do_test_recursion();
+       kp_unreg(kp_kfree2);
+
+       post_test_recursion_and_mh();
+}
+
+static void test_recursion_and_multiple_handlers2(void)
+{
+       olog("Recursion and multiple handlers [II]:\n");
+
+       pre_test_recursion_and_mh();
+
+       kp_reg(kp_kfree, "my_kfree", kfree_h);
+       kp_reg(kp_kstrdup, "my_kstrdup", kstrdup_h);
+       kp_reg(kp_kfree2, "my_kfree", kfree2_h);
+
+       run_test_recursion();
+
+       kp_unreg(kp_kstrdup);
+       kp_unreg(kp_kfree);
+       kp_unreg(kp_kfree2);
+
+       post_test_recursion_and_mh();
+}
+
+
+
+
+/*
+ ******************************************************************************
+ *                        swap_unregister_kprobe(), sync                      *
+ ******************************************************************************
+ */
+
+static const char task_name[] = "my_task";
+
+static int is_my_task(void)
+{
+       return !strcmp(task_name, current->comm);
+}
+
+static int find_module_cnt;
+
+static struct kprobe *kp_find_module;
+static int find_module_h(struct kprobe *kp, struct pt_regs *regs)
+{
+       if (is_my_task()) {
+               might_sleep();
+               ++find_module_cnt;
+
+               /* sleep 0.5 sec */
+               msleep(500);
+               schedule();
+
+               ++find_module_cnt;
+       }
+
+       return 0;
+}
+
+static int kthread_my_fn(void *data)
+{
+       find_module("o_lo_lo");
+       find_module("o_lo_lo");
+
+       while (!kthread_should_stop()) {
+               set_current_state(TASK_INTERRUPTIBLE);
+               schedule();
+       }
+
+       return 0;
+}
+
+
+static void do_test_sync_unreg(unsigned int ms)
+{
+       struct task_struct *task;
+
+       kp_reg(kp_find_module, "find_module", find_module_h);
+
+       task = kthread_run(kthread_my_fn, NULL, task_name);
+       if (IS_ERR(task)) {
+               olog("ERROR: kthread_run()\n");
+               goto unreg;
+       }
+
+       /* waiting for kthread_my_fn() call */
+       msleep(ms);
+unreg:
+       kp_unreg(kp_find_module);
+       if (!IS_ERR(task))
+               kthread_stop(task);
+}
+
+static void test_sync_unreg(void)
+{
+       olog("Unreg kp:\n");
+
+       find_module_cnt = 0;
+
+       do_test_sync_unreg(200);
+
+       if (find_module_cnt == 2) {
+               olog("    OK\n");
+       } else {
+               olog("    ERROR: find_module_cnt=%d\n", find_module_cnt);
+       }
+}
+
+
+
+/*
+ ******************************************************************************
+ *             swap_unregister_kprobe(), sync and multiple handlers           *
+ ******************************************************************************
+ */
+static int find_module2_cnt;
+
+static struct kprobe *kp_find_module2;
+static int find_module2_h(struct kprobe *kp, struct pt_regs *regs)
+{
+       if (is_my_task()) {
+               ++find_module2_cnt;
+
+               /* sleep 0.5 sec */
+               msleep(500);
+
+               ++find_module2_cnt;
+       }
+
+       return 0;
+}
+
+static void pre_test_sync_unreg_and_mh(void)
+{
+       find_module_cnt = 0;
+       find_module2_cnt = 0;
+}
+
+static void post_test_sync_unreg_and_mh(int cnt, int cnt2)
+{
+       if (find_module_cnt == cnt && find_module2_cnt == cnt2) {
+               olog("    OK\n");
+       } else {
+               olog("    ERROR: find_module_cnt=%d find_module2_cnt=%d\n",
+                    find_module_cnt, find_module2_cnt);
+       }
+}
+
+static void do_test_sync_unreg_and_mh(unsigned int ms)
+{
+       struct task_struct *task;
+
+       kp_reg(kp_find_module, "find_module", find_module_h);
+       kp_reg(kp_find_module2, "find_module", find_module2_h);
+
+       task = kthread_run(kthread_my_fn, NULL, task_name);
+       if (IS_ERR(task)) {
+               olog("ERROR: kthread_run()\n");
+               goto unreg;
+       }
+
+       /* waiting for kthread_my_fn() call */
+       msleep(ms);
+unreg:
+       kp_unreg(kp_find_module2);
+       kp_unreg(kp_find_module);
+       if (!IS_ERR(task))
+               kthread_stop(task);
+}
+
+static void test_sync_unreg_and_multiple_handlers(void)
+{
+       olog("Unreg kp and multiple handlers:\n");
+
+       pre_test_sync_unreg_and_mh();
+
+       do_test_sync_unreg_and_mh(700);
+
+       post_test_sync_unreg_and_mh(2, 2);
+}
+
+static void do_test_sync_unreg_and_mh2(unsigned int ms)
+{
+       struct task_struct *task;
+
+       kp_reg(kp_find_module, "find_module", find_module_h);
+       kp_reg(kp_find_module2, "find_module", find_module2_h);
+
+       task = kthread_run(kthread_my_fn, NULL, task_name);
+       if (IS_ERR(task)) {
+               olog("ERROR: kthread_run()\n");
+               goto unreg;
+       }
+
+       /* waiting for kthread_my_fn() call */
+       msleep(ms);
+unreg:
+       kp_unreg(kp_find_module);
+       kp_unreg(kp_find_module2);
+       if (!IS_ERR(task))
+               kthread_stop(task);
+}
+
+static void test_sync_unreg_and_multiple_handlers2(void)
+{
+       olog("Unreg kp and multiple handlers [II]:\n");
+
+       pre_test_sync_unreg_and_mh();
+
+       do_test_sync_unreg_and_mh2(700);
+
+       post_test_sync_unreg_and_mh(2, 2);
+}
+
+
+static void print_mod_info(void)
+{
+       struct module *mod = THIS_MODULE;
+
+       printk("### MOD_INFO:\n");
+       printk("    core: %p..%p\n", mod->module_init, mod->module_init + mod->init_text_size);
+       printk("    init: %p..%p\n", mod->module_core, mod->module_core + mod->core_text_size);
+       printk("\n");
+}
+
+static int test_init(void)
+{
+       cur_task = current;
+
+       print_mod_info();
+
+       olog("### Begin tests ###\n");
+       test_recursion();
+       test_recursion_and_multiple_handlers();
+       test_recursion_and_multiple_handlers2();
+       // add 3
+
+       test_sync_unreg();
+       test_sync_unreg_and_multiple_handlers();
+       test_sync_unreg_and_multiple_handlers2();
+       olog("### End tests ###\n");
+
+       return -1;
+}
+
+static void test_exit(void)
+{
+}
+
+
+SWAP_LIGHT_INIT_MODULE(NULL, test_init, test_exit, NULL, NULL);
+
+MODULE_LICENSE("GPL");
diff --git a/tests/kprobe_tests/run_kp_tests.sh b/tests/kprobe_tests/run_kp_tests.sh
new file mode 100644 (file)
index 0000000..d912090
--- /dev/null
@@ -0,0 +1,11 @@
+
+cd /opt/swap/sdk
+
+insmod swap_master.ko
+echo 1 > /sys/kernel/debug/swap/enable
+insmod swap_kprobe.ko
+
+insmod swap_kp_tests.ko 2>/dev/null
+
+rmmod swap_kprobe
+rmmod swap_master