[IMPROVE] Ksyms: Implement searching symbols 42/14942/9
authorAlexander Aksenov <a.aksenov@samsung.com>
Tue, 14 Jan 2014 07:20:53 +0000 (11:20 +0400)
committerDmitry Kovalenko <d.kovalenko@samsung.com>
Tue, 25 Mar 2014 07:23:11 +0000 (00:23 -0700)
with kallsyms_on_each_symbol()

Change-Id: I6e2211b6beca9d3b4b3ba4799009a87acf88c01b
Signed-off-by: Alexander Aksenov <a.aksenov@samsung.com>
Kbuild
ksyms/Kbuild
ksyms/ksyms.c
ksyms/ksyms.h
ksyms/no_ksyms.c [new file with mode: 0644]
start.sh
stop.sh

diff --git a/Kbuild b/Kbuild
index 7deb5d8..e334a39 100644 (file)
--- a/Kbuild
+++ b/Kbuild
@@ -1,6 +1,7 @@
 EXTRA_CFLAGS := $(extra_cflags)
 
 obj-m := buffer/ \
+         ksyms/ \
          driver/ \
          writer/ \
          kprobe/ \
index 317f398..70bb2c9 100644 (file)
@@ -1,4 +1,9 @@
-ifneq ($(CONFIG_KALLSYMS),y)
-       obj-m := swap_ksyms.o
+EXTRA_CFLAGS := $(extra_cflags)
+
+obj-m := swap_ksyms.o
+
+ifeq ($(CONFIG_KALLSYMS),y)
        swap_ksyms-y := ksyms.o
-endif
\ No newline at end of file
+else
+       swap_ksyms-y := no_ksyms.o
+endif
index 6cf9ada..dca39eb 100644 (file)
  * 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, 2013
+ * Copyright (C) Samsung Electronics, 2014
  *
- * 2013         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ * 2014         Alexander Aksenov <a.aksenov@samsung.com>
  *
  */
 
+
 #include "ksyms.h"
+#include <linux/kallsyms.h>
 #include <linux/module.h>
-#include <linux/types.h>
-#include <linux/vmalloc.h>
-#include <linux/semaphore.h>
-#include <linux/fs.h>
-#include <linux/slab.h>
-#include <asm/fcntl.h>
-
-
-#ifndef CONFIG_KALLSYMS
-
-#define KSYMS_ERR(format, args...) \
-       do { \
-               char *f = __FILE__; \
-               char *n = strrchr(f, '/'); \
-               printk("%s:%u \'%s\' ERROR: " format "\n" , (n) ? n+1 : f, __LINE__, __FUNCTION__, ##args); \
-       } while(0)
-
-
-struct sys_map_item {
-       struct list_head list;
+#include <linux/percpu.h>
 
+struct symbol_data {
+       const char *name;
+       size_t len;
        unsigned long addr;
-       char *name;
 };
 
-static char* sm_path = NULL;
-module_param(sm_path, charp, 0);
-
-LIST_HEAD(smi_list);
-static struct file *file = NULL;
-
-static int cnt_init_sm = 0;
-DEFINE_SEMAPHORE(cnt_init_sm_lock);
-
-static int file_open(void)
+static int symbol_cb(void *data, const char *sym, struct module *mod,
+                    unsigned long addr)
 {
-       struct file *f = filp_open(sm_path, O_RDONLY, 0);
+       struct symbol_data *sym_data_p = (struct symbol_data *)data;
 
-       if (IS_ERR(f)) {
-               KSYMS_ERR("cannot open file \'%s\'", sm_path);
-               return PTR_ERR(f);
+       /* We expect that real symbol name should have at least the same length as
+        * symbol name we are looking for. */
+       if (strncmp(sym_data_p->name, sym, sym_data_p->len) == 0) {
+               sym_data_p->addr = addr;
+               /* Return != 0 to stop loop over the symbols */
+               return 1;
        }
 
-       file = f;
-
        return 0;
 }
 
-static void file_close(void)
-{
-       if (file) {
-               int ret = filp_close(file, NULL);
-               file = NULL;
-
-               if (ret) {
-                       KSYMS_ERR("while closing file \'%s\' err=%d", sm_path, ret);
-               }
-       }
-}
-
-static int file_check(void)
-{
-       int ret = file_open();
-       if (ret == 0) {
-               file_close();
-       }
-
-       return ret;
-}
-
-static long file_size(struct file *file)
-{
-       struct kstat st;
-       if (vfs_getattr(file->f_path.mnt, file->f_path.dentry, &st)) {
-               return -1;
-       }
-
-       if (!S_ISREG(st.mode)) {
-               return -1;
-       }
-
-       if (st.size != (long)st.size) {
-               return -1;
-       }
-
-       return st.size;
-}
-
-static struct sys_map_item *create_smi(unsigned long addr, const char *name)
+unsigned long swap_ksyms_substr(const char *name)
 {
-       struct sys_map_item *smi = kmalloc(sizeof(*smi), GFP_KERNEL);
-
-       if (smi == NULL) {
-               KSYMS_ERR("not enough memory");
-               return NULL;
-       }
-
-       smi->name = kmalloc(strlen(name) + 1, GFP_KERNEL);
-       if (smi->name == NULL) {
-               kfree(smi);
-               KSYMS_ERR("not enough memory");
-               return NULL;
-       }
-
-       INIT_LIST_HEAD(&smi->list);
-       smi->addr = addr;
-       strcpy(smi->name, name);
-
-       return smi;
-}
-
-static void free_smi(struct sys_map_item *smi)
-{
-       kfree(smi->name);
-       kfree(smi);
-}
-
-static void add_smi(const struct sys_map_item *smi)
-{
-       list_add_tail(&smi->list, &smi_list);
-}
-
-static int is_endline(char c)
-{
-       return c == '\n' || c == '\r' || c == '\0';
-}
-
-static int is_symbol_attr(char c)
-{
-       return c == 't' || c == 'T';
-}
-
-static struct sys_map_item *get_sys_map_item(char *begin, char *end)
-{
-       struct sys_map_item *smi = NULL;
-       int n, len = end - begin;
-       unsigned long addr;
-       char attr, name[128], *line;
-
-       line = kmalloc(len + 1, GFP_KERNEL);
-       memcpy(line, begin, len);
-       line[len] = '\0';
-
-       n = sscanf(line, "%x %c %127s", &addr, &attr, &name);
-       name[127] = '\0';
-
-       if (n != 3) {
-               KSYMS_ERR("parsing line: \"%s\"", line);
-               attr = '\0';
-       }
-
-       kfree(line);
-
-       if (is_symbol_attr(attr)) {
-               smi = create_smi(addr, name);
-       }
+       struct symbol_data sym_data = {
+               .name = name,
+               .len = strlen(name),
+               .addr = 0
+       };
+       kallsyms_on_each_symbol(symbol_cb, (void *)&sym_data);
 
-       return smi;
+       return sym_data.addr;
 }
-
-
-static void parsing(char *buf, int size)
-{
-       struct sys_map_item *smi;
-       char *start, *end, *c;
-
-       start = buf;
-       end = buf + size;
-
-       for (c = start; c < end; ++c) {
-               if (is_endline(*c)) {
-                       smi = get_sys_map_item(start, c);
-                       if (smi) {
-                               add_smi(smi);
-                       }
-
-                       for (start = c; c < end; ++c) {
-                               if (!is_endline(*c)) {
-                                       start = c;
-                                       break;
-                               }
-                       }
-               }
-       }
-}
-
-static int create_sys_map(void)
-{
-       char *data;
-       long size;
-       int ret = file_open();
-
-       if (ret) {
-               return ret;
-       }
-
-       size = file_size(file);
-       if (size < 0) {
-               KSYMS_ERR("cannot get file size");
-               ret = size;
-               goto close;
-       }
-
-       data = vmalloc(size);
-       if (data == NULL) {
-               KSYMS_ERR("not enough memory");
-               ret = -1;
-               goto close;
-       }
-
-       if (kernel_read(file, 0, data, size) != size) {
-               KSYMS_ERR("reading file %s", sm_path);
-               ret = -1;
-               goto free;
-       }
-
-       parsing(data, size);
-
-free:
-       vfree(data);
-
-close:
-       file_close();
-
-       return 0;
-}
-
-static void free_sys_map(void)
-{
-       struct sys_map_item *smi, *n;
-       list_for_each_entry_safe(smi, n, &smi_list, list) {
-               list_del(&smi->list);
-               free_smi(smi);
-       }
-}
-
-int swap_get_ksyms(void)
-{
-       int ret = 0;
-
-       down(&cnt_init_sm_lock);
-       if (cnt_init_sm == 0) {
-               ret = create_sys_map();
-       }
-
-       ++cnt_init_sm;
-       up(&cnt_init_sm_lock);
-
-       return ret;
-}
-EXPORT_SYMBOL_GPL(swap_get_ksyms);
-
-void swap_put_ksyms(void)
-{
-       down(&cnt_init_sm_lock);
-       --cnt_init_sm;
-       if (cnt_init_sm == 0)  {
-               free_sys_map();
-       }
-
-       if (cnt_init_sm < 0) {
-               KSYMS_ERR("cnt_init_sm=%d", cnt_init_sm);
-               cnt_init_sm = 0;
-       }
-
-       up(&cnt_init_sm_lock);
-}
-EXPORT_SYMBOL_GPL(swap_put_ksyms);
-
-unsigned long swap_ksyms(const char *name)
-{
-       struct sys_map_item *smi;
-
-       list_for_each_entry(smi, &smi_list, list) {
-               if (strcmp(name, smi->name) == 0) {
-                       return smi->addr;
-               }
-       }
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(swap_ksyms);
+EXPORT_SYMBOL_GPL(swap_ksyms_substr);
 
 int __init swap_ksyms_init(void)
 {
-       int ret = 0;
-
-       if (sm_path == NULL) {
-               KSYMS_ERR("sm_path=NULL");
-               return -EINVAL;
-       }
-
-       ret = file_check();
-       if (ret) {
-               return -EINVAL;
-       }
-
-       // TODO: calling func 'swap_get_ksyms' in module used func 'swap_ksyms'
-       swap_get_ksyms();
+       printk("SWAP_KSYMS: Module initialized\n");
 
        return 0;
 }
 
 void __exit swap_ksyms_exit(void)
 {
-       down(&cnt_init_sm_lock);
-
-       if (cnt_init_sm > 0)  {
-               free_sys_map();
-       }
-
-       up(&cnt_init_sm_lock);
+       printk("SWAP_KSYMS: Module uninitialized\n");
 }
 
 module_init(swap_ksyms_init);
@@ -345,4 +82,3 @@ MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("SWAP ksyms module");
 MODULE_AUTHOR("Vyacheslav Cherkashin <v.cherkashin@samaung.com>");
 
-#endif /*CONFIG_KALLSYMS*/
index 7719e2e..723bb08 100644 (file)
@@ -58,4 +58,6 @@ unsigned long swap_ksyms(const char *name);
 
 #endif /*CONFIG_KALLSYMS*/
 
+unsigned long swap_ksyms_substr(const char *name);
+
 #endif /*__KSYMS_H__*/
diff --git a/ksyms/no_ksyms.c b/ksyms/no_ksyms.c
new file mode 100644 (file)
index 0000000..a91eeb8
--- /dev/null
@@ -0,0 +1,358 @@
+/*
+ *  Dynamic Binary Instrumentation Module based on KProbes
+ *  modules/ksyms/no_ksyms.c
+ *
+ * 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, 2013
+ *
+ * 2013         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ */
+
+#include "ksyms.h"
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/vmalloc.h>
+#include <linux/semaphore.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <asm/fcntl.h>
+
+
+#define KSYMS_ERR(format, args...) \
+       do { \
+               char *f = __FILE__; \
+               char *n = strrchr(f, '/'); \
+               printk("%s:%u \'%s\' ERROR: " format "\n" , (n) ? n+1 : f, __LINE__, __FUNCTION__, ##args); \
+       } while(0)
+
+
+struct sys_map_item {
+       struct list_head list;
+
+       unsigned long addr;
+       char *name;
+};
+
+static char* sm_path = NULL;
+module_param(sm_path, charp, 0);
+
+LIST_HEAD(smi_list);
+static struct file *file = NULL;
+
+static int cnt_init_sm = 0;
+DEFINE_SEMAPHORE(cnt_init_sm_lock);
+
+static int file_open(void)
+{
+       struct file *f = filp_open(sm_path, O_RDONLY, 0);
+
+       if (IS_ERR(f)) {
+               KSYMS_ERR("cannot open file \'%s\'", sm_path);
+               return PTR_ERR(f);
+       }
+
+       file = f;
+
+       return 0;
+}
+
+static void file_close(void)
+{
+       if (file) {
+               int ret = filp_close(file, NULL);
+               file = NULL;
+
+               if (ret) {
+                       KSYMS_ERR("while closing file \'%s\' err=%d", sm_path, ret);
+               }
+       }
+}
+
+static int file_check(void)
+{
+       int ret = file_open();
+       if (ret == 0) {
+               file_close();
+       }
+
+       return ret;
+}
+
+static long file_size(struct file *file)
+{
+       struct kstat st;
+       if (vfs_getattr(file->f_path.mnt, file->f_path.dentry, &st)) {
+               return -1;
+       }
+
+       if (!S_ISREG(st.mode)) {
+               return -1;
+       }
+
+       if (st.size != (long)st.size) {
+               return -1;
+       }
+
+       return st.size;
+}
+
+static struct sys_map_item *create_smi(unsigned long addr, const char *name)
+{
+       struct sys_map_item *smi = kmalloc(sizeof(*smi), GFP_KERNEL);
+
+       if (smi == NULL) {
+               KSYMS_ERR("not enough memory");
+               return NULL;
+       }
+
+       smi->name = kmalloc(strlen(name) + 1, GFP_KERNEL);
+       if (smi->name == NULL) {
+               kfree(smi);
+               KSYMS_ERR("not enough memory");
+               return NULL;
+       }
+
+       INIT_LIST_HEAD(&smi->list);
+       smi->addr = addr;
+       strcpy(smi->name, name);
+
+       return smi;
+}
+
+static void free_smi(struct sys_map_item *smi)
+{
+       kfree(smi->name);
+       kfree(smi);
+}
+
+static void add_smi(const struct sys_map_item *smi)
+{
+       list_add_tail(&smi->list, &smi_list);
+}
+
+static int is_endline(char c)
+{
+       return c == '\n' || c == '\r' || c == '\0';
+}
+
+static int is_symbol_attr(char c)
+{
+       return c == 't' || c == 'T';
+}
+
+static struct sys_map_item *get_sys_map_item(char *begin, char *end)
+{
+       struct sys_map_item *smi = NULL;
+       int n, len = end - begin;
+       unsigned long addr;
+       char attr, name[128], *line;
+
+       line = kmalloc(len + 1, GFP_KERNEL);
+       memcpy(line, begin, len);
+       line[len] = '\0';
+
+       n = sscanf(line, "%x %c %127s", &addr, &attr, &name);
+       name[127] = '\0';
+
+       if (n != 3) {
+               KSYMS_ERR("parsing line: \"%s\"", line);
+               attr = '\0';
+       }
+
+       kfree(line);
+
+       if (is_symbol_attr(attr)) {
+               smi = create_smi(addr, name);
+       }
+
+       return smi;
+}
+
+
+static void parsing(char *buf, int size)
+{
+       struct sys_map_item *smi;
+       char *start, *end, *c;
+
+       start = buf;
+       end = buf + size;
+
+       for (c = start; c < end; ++c) {
+               if (is_endline(*c)) {
+                       smi = get_sys_map_item(start, c);
+                       if (smi) {
+                               add_smi(smi);
+                       }
+
+                       for (start = c; c < end; ++c) {
+                               if (!is_endline(*c)) {
+                                       start = c;
+                                       break;
+                               }
+                       }
+               }
+       }
+}
+
+static int create_sys_map(void)
+{
+       char *data;
+       long size;
+       int ret = file_open();
+
+       if (ret) {
+               return ret;
+       }
+
+       size = file_size(file);
+       if (size < 0) {
+               KSYMS_ERR("cannot get file size");
+               ret = size;
+               goto close;
+       }
+
+       data = vmalloc(size);
+       if (data == NULL) {
+               KSYMS_ERR("not enough memory");
+               ret = -1;
+               goto close;
+       }
+
+       if (kernel_read(file, 0, data, size) != size) {
+               KSYMS_ERR("reading file %s", sm_path);
+               ret = -1;
+               goto free;
+       }
+
+       parsing(data, size);
+
+free:
+       vfree(data);
+
+close:
+       file_close();
+
+       return 0;
+}
+
+static void free_sys_map(void)
+{
+       struct sys_map_item *smi, *n;
+       list_for_each_entry_safe(smi, n, &smi_list, list) {
+               list_del(&smi->list);
+               free_smi(smi);
+       }
+}
+
+int swap_get_ksyms(void)
+{
+       int ret = 0;
+
+       down(&cnt_init_sm_lock);
+       if (cnt_init_sm == 0) {
+               ret = create_sys_map();
+       }
+
+       ++cnt_init_sm;
+       up(&cnt_init_sm_lock);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(swap_get_ksyms);
+
+void swap_put_ksyms(void)
+{
+       down(&cnt_init_sm_lock);
+       --cnt_init_sm;
+       if (cnt_init_sm == 0)  {
+               free_sys_map();
+       }
+
+       if (cnt_init_sm < 0) {
+               KSYMS_ERR("cnt_init_sm=%d", cnt_init_sm);
+               cnt_init_sm = 0;
+       }
+
+       up(&cnt_init_sm_lock);
+}
+EXPORT_SYMBOL_GPL(swap_put_ksyms);
+
+unsigned long swap_ksyms(const char *name)
+{
+       struct sys_map_item *smi;
+
+       list_for_each_entry(smi, &smi_list, list) {
+               if (strcmp(name, smi->name) == 0) {
+                       return smi->addr;
+               }
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(swap_ksyms);
+
+unsigned long swap_ksyms_substr(const char *name)
+{
+       struct sys_map_item *smi;
+       size_t len = strlen(name);
+
+       list_for_each_entry(smi, &smi_list, list) {
+               if (strncmp(name, smi->name, len) == 0)
+                       return smi->addr;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(swap_ksyms_substr);
+
+int __init swap_ksyms_init(void)
+{
+       int ret = 0;
+
+       if (sm_path == NULL) {
+               KSYMS_ERR("sm_path=NULL");
+               return -EINVAL;
+       }
+
+       ret = file_check();
+       if (ret) {
+               return -EINVAL;
+       }
+
+       // TODO: calling func 'swap_get_ksyms' in module used func 'swap_ksyms'
+       swap_get_ksyms();
+
+       return 0;
+}
+
+void __exit swap_ksyms_exit(void)
+{
+       down(&cnt_init_sm_lock);
+
+       if (cnt_init_sm > 0)  {
+               free_sys_map();
+       }
+
+       up(&cnt_init_sm_lock);
+}
+
+module_init(swap_ksyms_init);
+module_exit(swap_ksyms_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("SWAP ksyms module");
+MODULE_AUTHOR("Vyacheslav Cherkashin <v.cherkashin@samaung.com>");
index 5d0e6c9..41864b3 100755 (executable)
--- a/start.sh
+++ b/start.sh
@@ -1,6 +1,7 @@
 #!/bin/sh
 
 insmod swap_buffer.ko || exit 1  # buffer is loaded
+insmod swap_ksyms.ko || exit 1
 insmod swap_driver.ko || exit 1  # driver is loaded
 insmod swap_writer.ko || exit 1
 insmod swap_kprobe.ko || exit 1  # kprobe is loaded
diff --git a/stop.sh b/stop.sh
index 12d1406..dcb4706 100755 (executable)
--- a/stop.sh
+++ b/stop.sh
@@ -10,6 +10,7 @@ rmmod swap_ks_manager
 rmmod swap_kprobe
 rmmod swap_writer
 rmmod swap_driver
+rmmod swap_ksyms
 rmmod swap_buffer