[FEATURE] Preload: Implement 60/33660/7
authorAlexander Aksenov <a.aksenov@samsung.com>
Wed, 4 Jun 2014 08:07:14 +0000 (12:07 +0400)
committerAlexander Aksenov <a.aksenov@samsung.com>
Tue, 24 Feb 2015 08:28:41 +0000 (11:28 +0300)
Change-Id: Ida266d6bc3af76bbf046434da99bc7fa3a256d49
Signed-off-by: Vasiliy Ulyanov <v.ulyanov@samsung.com>
Signed-off-by: Alexander Aksenov <a.aksenov@samsung.com>
23 files changed:
Kbuild
build.sh
packaging/swap-modules.spec
parser/msg_parser.c
preload/Kbuild [new file with mode: 0644]
preload/preload.h [new file with mode: 0644]
preload/preload_control.c [new file with mode: 0644]
preload/preload_control.h [new file with mode: 0644]
preload/preload_debugfs.c [new file with mode: 0644]
preload/preload_debugfs.h [new file with mode: 0644]
preload/preload_module.c [new file with mode: 0644]
preload/preload_module.h [new file with mode: 0644]
preload/preload_patcher.c [new file with mode: 0644]
preload/preload_patcher.h [new file with mode: 0644]
preload/preload_pd.c [new file with mode: 0644]
preload/preload_pd.h [new file with mode: 0644]
preload/preload_probe.c [new file with mode: 0644]
preload/preload_probe.h [new file with mode: 0644]
preload/preload_storage.c [new file with mode: 0644]
preload/preload_storage.h [new file with mode: 0644]
preload/preload_threads.c [new file with mode: 0644]
preload/preload_threads.h [new file with mode: 0644]
us_manager/probes/probes.h

diff --git a/Kbuild b/Kbuild
index 0fa4d0c..ea8a582 100644 (file)
--- a/Kbuild
+++ b/Kbuild
@@ -14,4 +14,5 @@ obj-m := buffer/ \
          parser/ \
          retprobe/ \
          webprobe/ \
-         task_data/
+         task_data/ \
+         preload/
index 8fcaeef..d4194b2 100755 (executable)
--- a/build.sh
+++ b/build.sh
@@ -37,6 +37,7 @@ parser_dir=${modules_dir}/parser
 retprobe_dir=${modules_dir}/retprobe
 webprobe_dir=${modules_dir}/webprobe
 task_data_dir=${modules_dir}/task_data
+preload_dir=${modules_dir}/preload
 
 buffer_module_name=swap_buffer.ko
 driver_module_name=swap_driver.ko
@@ -53,6 +54,7 @@ ksyms_module_name=swap_ksyms.ko
 retprobe_module_name=swap_retprobe.ko
 webprobe_module_name=swap_webprobe.ko
 task_data_module_name=swap_task_data.ko
+preload_module_name=swap_preload.ko
 
 install_dir="/opt/swap/sdk"
 
@@ -77,9 +79,11 @@ ${energy_dir}/${energy_module_name} \
 ${parser_dir}/${parser_module_name} \
 ${ksyms_dir}/${ksyms_module_name} \
 ${retprobe_dir}/${retprobe_module_name} \
-${webprobe_dir}/${webprobe_module_name}"
+${webprobe_dir}/${webprobe_module_name} \
+${task_data_dir}/${task_data_module_name} \
+${preload_dir}/${preload_module_name}"
 
 for m in ${modules} ; do
        ${cross_compile}strip -x -g $m
-#      sdb -e push $m ${install_dir}
+#      sdb -e push $m ${install_dir}
 done
index bf45366..5cbc90d 100755 (executable)
@@ -44,6 +44,8 @@ install -m 666 energy/swap_energy.ko -t %{buildroot}/opt/swap/sdk
 install -m 666 parser/swap_message_parser.ko -t %{buildroot}/opt/swap/sdk
 install -m 666 retprobe/swap_retprobe.ko -t %{buildroot}/opt/swap/sdk
 install -m 666 webprobe/swap_webprobe.ko -t %{buildroot}/opt/swap/sdk
+install -m 666 task_data/swap_task_data.ko -t %{buildroot}/opt/swap/sdk
+install -m 666 preload/swap_preload.ko -t %{buildroot}/opt/swap/sdk
 
 %files
 %defattr(-,root,root)
@@ -61,3 +63,5 @@ install -m 666 webprobe/swap_webprobe.ko -t %{buildroot}/opt/swap/sdk
 /opt/swap/sdk/swap_message_parser.ko
 /opt/swap/sdk/swap_retprobe.ko
 /opt/swap/sdk/swap_webprobe.ko
+/opt/swap/sdk/swap_task_data.ko
+/opt/swap/sdk/swap_preload.ko
index 6e12886..359fb1e 100644 (file)
@@ -329,6 +329,97 @@ void put_retprobe(struct probe_info *pi)
        put_string(pi->rp_i.args);
 }
 
+/**
+ * @brief Gets preload data and puts it to the probe_info struct.
+ *
+ * @param mb Pointer to the message buffer.
+ * @param pi Pointer to the probe_info struct.
+ * @return 0 on success, error code on error.
+ */
+int get_preload_probe(struct msg_buf *mb, struct probe_info *pi)
+{
+       u64 handler;
+       u8 type;
+
+       print_parse_debug("funct handler:");
+       if (get_u64(mb, &handler)) {
+               print_err("failed to read function handler\n");
+               return -EINVAL;
+       }
+
+       print_parse_debug("collect events type:");
+       if (get_u8(mb, &type)) {
+               print_err("failed to read collect events type\n");
+               return -EINVAL;
+       }
+
+       pi->probe_type = SWAP_PRELOAD_PROBE;
+       pi->size = sizeof(pi->pl_i) + sizeof(pi->probe_type) + sizeof(pi->size);
+       pi->pl_i.handler = handler;
+       pi->pl_i.type = type;
+
+       return 0;
+}
+
+/**
+ * @brief Preload probe data cleanup.
+ *
+ * @param pi Pointer to the probe_info comprising retprobe.
+ * @return Void.
+ */
+void put_preload_probe(struct probe_info *pi)
+{
+}
+
+/**
+ * @brief Gets preload get_caller and puts it to the probe_info struct.
+ *
+ * @param mb Pointer to the message buffer.
+ * @param pi Pointer to the probe_info struct.
+ * @return 0 on success, error code on error.
+ */
+int get_get_caller_probe(struct msg_buf *mb, struct probe_info *pi)
+{
+       pi->probe_type = SWAP_GET_CALLER;
+       pi->size = sizeof(pi->gc_i);
+
+       return 0;
+}
+
+/**
+ * @brief Preload get_caller probe data cleanup.
+ *
+ * @param pi Pointer to the probe_info comprising retprobe.
+ * @return Void.
+ */
+void put_get_caller_probe(struct probe_info *pi)
+{
+}
+
+/**
+ * @brief Gets preload get_call_type and puts it to the probe_info struct.
+ *
+ * @param mb Pointer to the message buffer.
+ * @param pi Pointer to the probe_info struct.
+ * @return 0 on success, error code on error.
+ */
+int get_get_call_type_probe(struct msg_buf *mb, struct probe_info *pi)
+{
+       pi->probe_type = SWAP_GET_CALL_TYPE;
+       pi->size = sizeof(pi->gct_i);
+
+       return 0;
+}
+
+/**
+ * @brief Preload get_call type probe data cleanup.
+ *
+ * @param pi Pointer to the probe_info comprising retprobe.
+ * @return Void.
+ */
+void put_get_call_type_probe(struct probe_info *pi)
+{
+}
 
 
 
@@ -380,6 +471,18 @@ struct func_inst_data *create_func_inst_data(struct msg_buf *mb)
                if (get_webprobe(mb, &(fi->probe_i)) != 0)
                        goto free_func_inst;
                break;
+       case SWAP_PRELOAD_PROBE:
+               if (get_preload_probe(mb, &(fi->probe_i)) != 0)
+                       goto free_func_inst;
+               break;
+       case SWAP_GET_CALLER:
+               if (get_get_caller_probe(mb, &(fi->probe_i)) != 0)
+                       goto free_func_inst;
+               break;
+       case SWAP_GET_CALL_TYPE:
+               if (get_get_call_type_probe(mb, &(fi->probe_i)) != 0)
+                       goto free_func_inst;
+               break;
        default:
                printk(KERN_WARNING "SWAP PARSER: Wrong probe type %d!\n", type);
                goto free_func_inst;
@@ -407,6 +510,15 @@ void destroy_func_inst_data(struct func_inst_data *fi)
                break;
        case SWAP_WEBPROBE:
                break;
+       case SWAP_PRELOAD_PROBE:
+               put_preload_probe(&(fi->probe_i));
+               break;
+       case SWAP_GET_CALLER:
+               put_get_caller_probe(&(fi->probe_i));
+               break;
+       case SWAP_GET_CALL_TYPE:
+               put_get_call_type_probe(&(fi->probe_i));
+               break;
        default:
                printk(KERN_WARNING "SWAP PARSER: Wrong probe type %d!\n",
                   fi->probe_i.probe_type);
diff --git a/preload/Kbuild b/preload/Kbuild
new file mode 100644 (file)
index 0000000..6d6cf84
--- /dev/null
@@ -0,0 +1,11 @@
+EXTRA_CFLAGS := $(extra_cflags)
+
+obj-m := swap_preload.o
+swap_preload-y := preload_module.o \
+                  preload_debugfs.o \
+                  preload_storage.o \
+                  preload_probe.o \
+                  preload_control.o \
+                  preload_threads.o \
+                  preload_patcher.o \
+                  preload_pd.o
diff --git a/preload/preload.h b/preload/preload.h
new file mode 100644 (file)
index 0000000..7034222
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef __PRELOAD__
+#define __PRELOAD__
+
+#define PRELOAD_PREFIX "SWAP_PRELOAD: "
+#define PRELOAD_MAX_ATTEMPTS 10
+#define PRELOAD_DEFAULT_PERMS (S_IRUSR | S_IWUSR) /* u+rw */
+
+#endif /* __PRELOAD__ */
diff --git a/preload/preload_control.c b/preload/preload_control.c
new file mode 100644 (file)
index 0000000..61ede6f
--- /dev/null
@@ -0,0 +1,285 @@
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/limits.h>
+
+#include <us_manager/sspt/ip.h>
+
+#include "preload.h"
+
+#include "preload_control.h"
+#include "preload_probe.h"
+#include "preload_module.h"
+
+
+#define DEFAULT_SLOTS_COUNT 5
+#define DEFAULT_SLOTS_STEP 2
+
+struct bin_desc {
+       struct dentry *dentry;
+       char *filename;
+};
+
+static struct bin_desc *target_binaries = NULL;
+static unsigned int target_binaries_cnt = 0;
+static unsigned int target_binaries_slots = 0;
+
+static DEFINE_MUTEX(__target_binaries_mutex);
+
+
+static inline void __target_binaries_lock(void)
+{
+       mutex_lock(&__target_binaries_mutex);
+}
+
+static inline void __target_binaries_unlock(void)
+{
+       mutex_unlock(&__target_binaries_mutex);
+}
+
+static inline struct task_struct *__get_task_struct(void)
+{
+       return current;
+}
+
+static int __alloc_target_binaries_no_lock(unsigned int cnt)
+{
+       target_binaries = kmalloc(sizeof(*target_binaries) * cnt, GFP_KERNEL);
+       if (target_binaries == NULL)
+               return -ENOMEM;
+
+       target_binaries_slots = cnt;
+
+       return 0;
+}
+
+static int __alloc_target_binaries(unsigned int cnt)
+{
+       int ret;
+
+       __target_binaries_lock();
+       ret = __alloc_target_binaries_no_lock(cnt);
+       __target_binaries_unlock();
+
+       return ret;
+}
+
+static void __free_target_binaries(void)
+{
+       int i;
+
+       __target_binaries_lock();
+
+       for (i = 0; i < target_binaries_cnt; i++) {
+               put_dentry(target_binaries[i].dentry);
+               kfree(target_binaries[i].filename);
+       }
+
+       kfree(target_binaries);
+       target_binaries_cnt = 0;
+       target_binaries_slots = 0;
+
+       __target_binaries_unlock();
+}
+
+static int __grow_target_binaries(void)
+{
+       struct bin_desc *tmp = target_binaries;
+       int i, ret;
+
+       __target_binaries_lock();
+
+       ret = __alloc_target_binaries_no_lock(target_binaries_slots + DEFAULT_SLOTS_STEP);
+       if (ret != 0)
+               return ret;
+
+       target_binaries_slots += DEFAULT_SLOTS_STEP;
+
+       for (i = 0; i < target_binaries_cnt; i++) {
+               target_binaries[i].dentry = tmp[i].dentry;
+               target_binaries[i].filename = tmp[i].filename;
+       }
+
+       __target_binaries_unlock();
+
+       kfree(tmp);
+
+       return 0;
+}
+
+static bool __check_dentry_already_exist(struct dentry *dentry)
+{
+       int i;
+       bool ret = false;
+
+       __target_binaries_lock();
+
+       for (i = 0; i < target_binaries_cnt; i++) {
+               if (target_binaries[i].dentry == dentry) {
+                       ret = true;
+                       goto check_dentry_unlock;
+               }
+       }
+
+check_dentry_unlock:
+       __target_binaries_unlock();
+
+       return ret;
+}
+
+static int __add_target_binary(struct dentry *dentry, char *filename)
+{
+       int ret;
+       size_t len;
+
+       if (__check_dentry_already_exist(dentry)) {
+               printk(PRELOAD_PREFIX "Binary already exist\n");
+               return EALREADY;
+       }
+
+
+       if (target_binaries_slots == target_binaries_cnt) {
+               ret = __grow_target_binaries();
+               if (ret != 0)
+                       return ret;
+       }
+
+       /* Filename should be < PATH_MAX */
+       len = strnlen(filename, PATH_MAX);
+       if (len == PATH_MAX)
+               return -EINVAL;
+
+       __target_binaries_lock();
+
+       target_binaries[target_binaries_cnt].dentry = dentry;
+       target_binaries[target_binaries_cnt].filename = kmalloc(len + 1, GFP_KERNEL);
+       memcpy(target_binaries[target_binaries_cnt].filename, filename, len + 1);
+       ++target_binaries_cnt;
+
+       __target_binaries_unlock();
+
+       return 0;
+}
+
+static char *__get_binary_name(struct bin_desc *bin)
+{
+       return bin->filename;
+}
+
+static struct dentry *__get_caller_dentry(struct task_struct *task,
+                                         unsigned long caller)
+{
+       struct vm_area_struct *vma = NULL;
+
+       if (unlikely(task->mm == NULL))
+               goto get_caller_dentry_fail;
+
+       vma = find_vma_intersection(task->mm, caller, caller + 1);
+       if (unlikely(vma == NULL || vma->vm_file == NULL))
+               goto get_caller_dentry_fail;
+
+       return vma->vm_file->f_dentry;
+
+get_caller_dentry_fail:
+
+       return NULL;
+}
+
+static bool __check_if_instrumented(struct task_struct *task,
+                                   struct dentry *dentry)
+{
+       int i;
+
+       for (i = 0; i < target_binaries_cnt; i++)
+               if (target_binaries[i].dentry == dentry)
+                       return true;
+
+       return false;
+}
+
+static bool __is_instrumented(void *caller)
+{
+       struct task_struct *task = __get_task_struct();
+       struct dentry *caller_dentry = __get_caller_dentry(task,
+                                                          (unsigned long) caller);
+
+       if (caller_dentry == NULL)
+               return false;
+
+       return __check_if_instrumented(task, caller_dentry);
+}
+
+
+
+enum preload_call_type preload_control_call_type(struct us_ip *ip, void *caller)
+{
+       if (__is_instrumented(caller))
+               return INTERNAL_CALL;
+
+       if (ip->probe_i.pl_i.type & SWAP_PRELOAD_ALWAYS)
+               return EXTERNAL_CALL;
+
+       return NOT_INSTRUMENTED;
+}
+
+int preload_control_add_instrumented_binary(char *filename)
+{
+       struct dentry *dentry = get_dentry(filename);
+       int res = 0;
+
+       if (dentry == NULL)
+               return -EINVAL;
+
+       res = __add_target_binary(dentry, filename);
+       if (res != 0)
+               put_dentry(dentry);
+
+       return res > 0 ? 0 : res;
+}
+
+int preload_control_clean_instrumented_bins(void)
+{
+       __free_target_binaries();
+       return __alloc_target_binaries(DEFAULT_SLOTS_COUNT);
+}
+
+unsigned int preload_control_get_bin_names(char ***filenames_p)
+{
+       int i;
+       unsigned int ret = 0;
+
+       __target_binaries_lock();
+
+       *filenames_p = kmalloc(sizeof(**filenames_p) * target_binaries_cnt,
+                          GFP_KERNEL);
+       if (*filenames_p == NULL)
+               goto get_binaries_names_out;
+
+       for (i = 0; i < target_binaries_cnt; i++)
+               (*filenames_p)[i] = __get_binary_name(&target_binaries[i]);
+
+       ret = target_binaries_cnt;
+
+get_binaries_names_out:
+       __target_binaries_unlock();
+
+       return ret;
+}
+
+void preload_control_release_bin_names(char ***filenames_p)
+{
+       kfree(*filenames_p);
+}
+
+int preload_control_init(void)
+{
+       return __alloc_target_binaries(DEFAULT_SLOTS_COUNT);
+}
+
+void preload_control_exit(void)
+{
+       __free_target_binaries();
+}
+
+#undef DEFAULT_SLOTS_STEP
+#undef DEFAULT_SLOTS_COUNT
diff --git a/preload/preload_control.h b/preload/preload_control.h
new file mode 100644 (file)
index 0000000..170adb6
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef __PRELOAD_CONTROL_H__
+#define __PRELOAD_CONTROL_H__
+
+enum preload_call_type {
+       NOT_INSTRUMENTED,
+       EXTERNAL_CALL,
+       INTERNAL_CALL
+};
+
+int preload_control_init(void);
+void preload_control_exit(void);
+
+enum preload_call_type preload_control_call_type(struct us_ip *ip, void *caller);
+int preload_control_add_instrumented_binary(char *filename);
+int preload_control_clean_instrumented_bins(void);
+
+unsigned int preload_control_get_bin_names(char ***filenames_p);
+void preload_control_release_bin_names(char ***filenames_p);
+
+#endif /* __PRELOAD_CONTROL_H__ */
diff --git a/preload/preload_debugfs.c b/preload/preload_debugfs.c
new file mode 100644 (file)
index 0000000..d9b4d18
--- /dev/null
@@ -0,0 +1,493 @@
+#include <linux/kernel.h>
+#include <linux/debugfs.h>
+#include <linux/err.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/limits.h>
+#include <asm/uaccess.h>
+#include <driver/swap_debugfs.h>
+#include "preload.h"
+#include "preload_debugfs.h"
+#include "preload_module.h"
+#include "preload_control.h"
+#include "preload_patcher.h"
+#include "preload_storage.h"
+
+static const char PRELOAD_FOLDER[] = "preload";
+static const char PRELOAD_LOADER[] = "loader";
+static const char PRELOAD_LOADER_OFFSET[] = "loader_offset";
+static const char PRELOAD_LOADER_PATH[] = "loader_path";
+static const char PRELOAD_BINARIES[] = "target_binaries";
+static const char PRELOAD_BINARIES_LIST[] = "bins_list";
+static const char PRELOAD_BINARIES_ADD[] = "bins_add";
+static const char PRELOAD_BINARIES_REMOVE[] = "bins_remove";
+static const char PRELOAD_CALLER[] = "caller";
+static const char PRELOAD_HANDLERS_PATH[] = "handlers_path";
+static const char PRELOAD_LINKER_DATA[] = "linker";
+static const char PRELOAD_LINKER_PATH[] = "linker_path";
+static const char PRELOAD_LINKER_R_DEBUG_OFFSET[] = "r_debug_offset";
+
+struct loader_info {
+       char *path;
+       unsigned long offset;
+       struct dentry *dentry;
+};
+
+static struct dentry *preload_root;
+static struct loader_info __loader_info = {
+       .path = NULL,
+       .offset = 0,
+       .dentry = NULL
+};
+
+static unsigned long r_debug_offset = 0;
+static DEFINE_MUTEX(__dentry_lock);
+
+static inline void dentry_lock(void)
+{
+       mutex_lock(&__dentry_lock);
+}
+
+static inline void dentry_unlock(void)
+{
+       mutex_unlock(&__dentry_lock);
+}
+
+
+static void set_loader_file(char *path)
+{
+       __loader_info.path = path;
+       dentry_lock();
+       __loader_info.dentry = get_dentry(__loader_info.path);
+       dentry_unlock();
+}
+
+struct dentry *preload_debugfs_get_loader_dentry(void)
+{
+       struct dentry *dentry;
+
+       dentry_lock();
+       dentry = __loader_info.dentry;
+       dentry_unlock();
+
+       return dentry;
+}
+
+unsigned long preload_debugfs_get_loader_offset(void)
+{
+       /* TODO Think about sync */
+       return __loader_info.offset;
+}
+
+static void clean_loader_info(void)
+{
+       if (__loader_info.path != NULL)
+               kfree(__loader_info.path);
+
+       dentry_lock();
+       if (__loader_info.dentry != NULL)
+               put_dentry(__loader_info.dentry);
+       dentry_unlock();
+}
+
+struct dentry *debugfs_create_ptr(const char *name, mode_t mode,
+                                 struct dentry *parent,
+                                 unsigned long *value)
+{
+       struct dentry *dentry;
+
+#if BITS_PER_LONG == 32
+       dentry = debugfs_create_x32(name, mode, parent, (u32 *)value);
+#elif BITS_PER_LONG == 64
+       dentry = debugfs_create_x64(name, mode, parent, (u64 *)value);
+#else
+#error Unsupported BITS_PER_LONG value
+#endif
+
+       return dentry;
+}
+
+
+/* ===========================================================================
+ * =                              LOADER PATH                                =
+ * ===========================================================================
+ */
+
+static ssize_t loader_path_write(struct file *file, const char __user *buf,
+                           size_t len, loff_t *ppos)
+{
+       ssize_t ret;
+       char *path;
+
+       if (preload_module_is_running())
+               return -EBUSY;
+
+       clean_loader_info();
+
+       path = kmalloc(len, GFP_KERNEL);
+       if (path == NULL) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       if (copy_from_user(path, buf, len)) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       path[len - 1] = '\0';
+       set_loader_file(path);
+       ret = len;
+
+out:
+       return ret;
+}
+
+
+static const struct file_operations loader_path_file_ops = {
+       .owner = THIS_MODULE,
+       .write = loader_path_write,
+};
+
+
+/* ===========================================================================
+ * =                                BIN PATH                                 =
+ * ===========================================================================
+ */
+
+static ssize_t bin_add_write(struct file *file, const char __user *buf,
+                          size_t len, loff_t *ppos)
+{
+       ssize_t ret;
+       char *path;
+
+       path = kmalloc(len, GFP_KERNEL);
+       if (path == NULL) {
+               ret = -ENOMEM;
+               goto bin_add_write_out;
+       }
+
+       if (copy_from_user(path, buf, len)) {
+               ret = -EINVAL;
+               goto bin_add_write_out;
+       }
+
+       path[len - 1] = '\0';
+
+       if (preload_control_add_instrumented_binary(path) != 0) {
+               printk(PRELOAD_PREFIX "Cannot add binary %s\n", path);
+               ret = -EINVAL;
+               goto bin_add_write_out;
+       }
+
+       ret = len;
+
+bin_add_write_out:
+       kfree(path);
+
+       return ret;
+}
+
+static ssize_t bin_remove_write(struct file *file, const char __user *buf,
+                             size_t len, loff_t *ppos)
+{
+       ssize_t ret;
+
+       ret = preload_control_clean_instrumented_bins();
+       if (ret != 0) {
+               printk(PRELOAD_PREFIX "Error during clean!\n");
+               ret = -EINVAL;
+               goto bin_remove_write_out;
+       }
+
+       ret = len;
+
+bin_remove_write_out:
+       return ret;
+}
+
+static ssize_t bin_list_read(struct file *file, char __user *usr_buf,
+                                size_t count, loff_t *ppos)
+{
+       unsigned int i;
+       unsigned int files_cnt = 0;
+       ssize_t len = 0, tmp, ret = 0;
+       char **filenames = NULL;
+       char *buf = NULL;
+       char *ptr = NULL;
+
+       files_cnt = preload_control_get_bin_names(&filenames);
+
+       if (files_cnt == 0) {
+               printk(PRELOAD_PREFIX "Cannot read binaries names!\n");
+               ret = 0;
+               goto bin_list_read_out;
+       }
+
+       for (i = 0; i < files_cnt; i++)
+               len += strlen(filenames[i]);
+
+       buf = kmalloc(len + files_cnt, GFP_KERNEL);
+       if (buf == NULL) {
+               ret = 0;
+               goto bin_list_read_fail;
+       }
+
+       ptr = buf;
+
+       for (i = 0; i < files_cnt; i++) {
+               tmp = strlen(filenames[i]);
+               memcpy(ptr, filenames[i], tmp);
+               ptr += tmp;
+               *ptr = '\n';
+               ptr += 1;
+       }
+
+       preload_control_release_bin_names(&filenames);
+
+       return simple_read_from_buffer(usr_buf, count, ppos, buf, len);
+
+bin_list_read_fail:
+       preload_control_release_bin_names(&filenames);
+
+bin_list_read_out:
+       return ret;
+}
+
+static const struct file_operations bin_list_file_ops = {
+       .owner = THIS_MODULE,
+       .read = bin_list_read
+};
+
+static const struct file_operations bin_add_file_ops = {
+       .owner = THIS_MODULE,
+       .write = bin_add_write,
+};
+
+static const struct file_operations bin_remove_file_ops = {
+       .owner = THIS_MODULE,
+       .write = bin_remove_write,
+};
+
+
+/* ===========================================================================
+ * =                            LINKER PATH                                  =
+ * ===========================================================================
+ */
+
+
+static ssize_t linker_path_write(struct file *file, const char __user *buf,
+                                 size_t len, loff_t *ppos)
+{
+       ssize_t ret;
+       char *path;
+
+       path = kmalloc(len, GFP_KERNEL);
+       if (path == NULL) {
+               ret = -ENOMEM;
+               goto linker_path_write_out;
+       }
+
+       if (copy_from_user(path, buf, len)) {
+               ret = -EINVAL;
+               goto linker_path_write_out;
+       }
+
+       path[len - 1] = '\0';
+
+       if (preload_storage_set_linker_info(path) != 0) {
+               printk(PRELOAD_PREFIX "Cannot set linker path %s\n", path);
+               ret = -EINVAL;
+               goto linker_path_write_out;
+       }
+
+       ret = len;
+
+linker_path_write_out:
+       kfree(path);
+
+       return ret;
+}
+
+static const struct file_operations linker_path_file_ops = {
+       .owner = THIS_MODULE,
+       .write = linker_path_write,
+};
+
+
+/* ===========================================================================
+ * =                           HANDLERS PATH                                 =
+ * ===========================================================================
+ */
+
+
+static ssize_t handlers_path_write(struct file *file, const char __user *buf,
+                                  size_t len, loff_t *ppos)
+{
+       ssize_t ret;
+       char *path;
+
+       path = kmalloc(len, GFP_KERNEL);
+       if (path == NULL) {
+               ret = -ENOMEM;
+               goto handlers_path_write_out;
+       }
+
+       if (copy_from_user(path, buf, len)) {
+               ret = -EINVAL;
+               goto handlers_path_write_out;
+       }
+
+       path[len - 1] = '\0';
+
+       if (preload_storage_set_handlers_info(path) != 0) {
+               printk(PRELOAD_PREFIX "Cannot set handler path %s\n", path);
+               ret = -EINVAL;
+               goto handlers_path_write_out;
+       }
+
+       ret = len;
+
+handlers_path_write_out:
+       kfree(path);
+
+       return ret;
+}
+
+static const struct file_operations handlers_path_file_ops = {
+       .owner = THIS_MODULE,
+       .write = handlers_path_write,
+};
+
+
+
+
+unsigned long preload_debugfs_r_debug_offset(void)
+{
+       return r_debug_offset;
+}
+
+int preload_debugfs_init(void)
+{
+       struct dentry *swap_dentry, *root, *loader, *open_p, *lib_path,
+                 *bin_path, *bin_list, *bin_add, *bin_remove,
+                 *linker_dir, *linker_path, *linker_offset, *handlers_path;
+       int ret;
+
+       ret = -ENODEV;
+       if (!debugfs_initialized())
+               goto fail;
+
+       ret = -ENOENT;
+       swap_dentry = get_swap_debugfs_dir();
+       if (!swap_dentry)
+               goto fail;
+
+       ret = -ENOMEM;
+       root = debugfs_create_dir(PRELOAD_FOLDER, swap_dentry);
+       if (IS_ERR_OR_NULL(root))
+               goto fail;
+
+       preload_root = root;
+
+       loader = debugfs_create_dir(PRELOAD_LOADER, root);
+       if (IS_ERR_OR_NULL(root)) {
+               ret = -ENOMEM;
+               goto remove;
+       }
+
+       open_p = debugfs_create_ptr(PRELOAD_LOADER_OFFSET, PRELOAD_DEFAULT_PERMS,
+                                   loader, &__loader_info.offset);
+       if (IS_ERR_OR_NULL(open_p)) {
+               ret = -ENOMEM;
+               goto remove;
+       }
+
+       lib_path = debugfs_create_file(PRELOAD_LOADER_PATH, PRELOAD_DEFAULT_PERMS,
+                                      loader, NULL, &loader_path_file_ops);
+       if (IS_ERR_OR_NULL(lib_path)) {
+               ret = -ENOMEM;
+               goto remove;
+       }
+
+       bin_path = debugfs_create_dir(PRELOAD_BINARIES, root);
+       if (IS_ERR_OR_NULL(bin_path)) {
+               ret = -ENOMEM;
+               goto remove;
+       }
+
+       bin_list = debugfs_create_file(PRELOAD_BINARIES_LIST, PRELOAD_DEFAULT_PERMS,
+                                      bin_path, NULL, &bin_list_file_ops);
+       if (IS_ERR_OR_NULL(bin_list)) {
+               ret = -ENOMEM;
+               goto remove;
+       }
+
+       bin_add = debugfs_create_file(PRELOAD_BINARIES_ADD, PRELOAD_DEFAULT_PERMS,
+                                      bin_path, NULL, &bin_add_file_ops);
+       if (IS_ERR_OR_NULL(bin_add)) {
+               ret = -ENOMEM;
+               goto remove;
+       }
+
+       bin_remove = debugfs_create_file(PRELOAD_BINARIES_REMOVE,
+                                        PRELOAD_DEFAULT_PERMS, bin_path, NULL,
+                                        &bin_remove_file_ops);
+       if (IS_ERR_OR_NULL(bin_remove)) {
+               ret = -ENOMEM;
+               goto remove;
+       }
+
+       linker_dir = debugfs_create_dir(PRELOAD_LINKER_DATA, root);
+       if (IS_ERR_OR_NULL(linker_dir)) {
+               ret = -ENOMEM;
+               goto remove;
+       }
+
+       linker_path = debugfs_create_file(PRELOAD_LINKER_PATH,
+                                         PRELOAD_DEFAULT_PERMS, linker_dir, NULL,
+                                         &linker_path_file_ops);
+       if (IS_ERR_OR_NULL(linker_path)) {
+               ret = -ENOMEM;
+               goto remove;
+       }
+
+       linker_offset = debugfs_create_ptr(PRELOAD_LINKER_R_DEBUG_OFFSET,
+                                          PRELOAD_DEFAULT_PERMS, linker_dir,
+                                          &r_debug_offset);
+       if (IS_ERR_OR_NULL(linker_offset)) {
+               ret = -ENOMEM;
+               goto remove;
+       }
+
+       handlers_path = debugfs_create_file(PRELOAD_HANDLERS_PATH,
+                                           PRELOAD_DEFAULT_PERMS, root, NULL,
+                                           &handlers_path_file_ops);
+       if (IS_ERR_OR_NULL(handlers_path)) {
+               ret = -ENOMEM;
+               goto remove;
+       }
+
+       return 0;
+
+remove:
+
+       debugfs_remove_recursive(root);
+
+fail:
+       printk(PRELOAD_PREFIX "Debugfs initialization failure: %d\n", ret);
+
+       return ret;
+}
+
+void preload_debugfs_exit(void)
+{
+       if (preload_root)
+               debugfs_remove_recursive(preload_root);
+       preload_root = NULL;
+
+       preload_module_set_not_ready();
+       clean_loader_info();
+}
diff --git a/preload/preload_debugfs.h b/preload/preload_debugfs.h
new file mode 100644 (file)
index 0000000..d2c457b
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef __PRELOAD_DEBUGFS_H__
+#define __PRELOAD_DEBUGFS_H__
+
+struct dentry;
+
+int preload_debugfs_init(void);
+void preload_debugfs_exit(void);
+
+struct dentry *preload_debugfs_get_loader_dentry(void);
+unsigned long preload_debugfs_get_loader_offset(void);
+
+struct dentry *preload_debugfs_create_new_thread(unsigned long tid);
+
+unsigned long preload_debugfs_r_debug_offset(void);
+
+#endif /* __PRELOAD_DEBUGFS_H__ */
diff --git a/preload/preload_module.c b/preload/preload_module.c
new file mode 100644 (file)
index 0000000..f3c7e71
--- /dev/null
@@ -0,0 +1,805 @@
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/dcache.h>
+#include <linux/namei.h>
+#include <linux/slab.h>
+#include <linux/mman.h>
+#include <linux/mm.h>
+#include <linux/err.h>
+#include <kprobe/swap_kprobes.h>
+#include <us_manager/us_manager_common.h>
+#include <us_manager/sspt/sspt_page.h>
+#include <us_manager/sspt/sspt_file.h>
+#include <us_manager/sspt/sspt_proc.h>
+#include <us_manager/sspt/ip.h>
+#include <writer/kernel_operations.h>
+#include <task_data/task_data.h>
+#include "preload.h"
+#include "preload_probe.h"
+#include "preload_debugfs.h"
+#include "preload_module.h"
+#include "preload_storage.h"
+#include "preload_control.h"
+#include "preload_threads.h"
+#include "preload_patcher.h"
+#include "preload_pd.h"
+
+#define page_to_proc(page) ((page)->file->proc)
+#define page_to_dentry(page) ((page)->file->dentry)
+#define ip_to_proc(ip) page_to_proc((ip)->page)
+
+struct us_priv {
+       struct pt_regs regs;
+       unsigned long arg0;
+       unsigned long arg1;
+       unsigned long raddr;
+       unsigned long origin;
+};
+
+static int get_put_counter;
+
+enum preload_status_t {
+       SWAP_PRELOAD_NOT_READY = 0,
+       SWAP_PRELOAD_READY = 1,
+       SWAP_PRELOAD_RUNNING = 2
+};
+
+enum {
+       /* task preload flags */
+       HANDLER_RUNNING = 0x1
+};
+
+static enum preload_status_t __preload_status = SWAP_PRELOAD_NOT_READY;
+
+static inline struct process_data *__get_process_data(struct uretprobe *rp)
+{
+    struct process_data *pd;
+    struct us_ip *ip = to_us_ip(rp);
+
+    pd = ip_to_proc(ip)->private_data;
+
+    return pd;
+}
+
+static struct dentry *__get_dentry(struct dentry *dentry)
+{
+       get_put_counter++;
+       return dget(dentry);
+}
+
+
+
+bool preload_module_is_running(void)
+{
+       if (__preload_status == SWAP_PRELOAD_RUNNING)
+               return true;
+
+       return false;
+}
+
+bool preload_module_is_ready(void)
+{
+       if (__preload_status == SWAP_PRELOAD_READY)
+               return true;
+
+       return false;
+}
+
+bool preload_module_is_not_ready(void)
+{
+       if (__preload_status == SWAP_PRELOAD_NOT_READY)
+               return true;
+
+       return false;
+}
+
+void preload_module_set_ready(void)
+{
+       __preload_status = SWAP_PRELOAD_READY;
+}
+
+void preload_module_set_running(void)
+{
+       __preload_status = SWAP_PRELOAD_RUNNING;
+}
+
+void preload_module_set_not_ready(void)
+{
+       __preload_status = SWAP_PRELOAD_NOT_READY;
+}
+
+struct dentry *get_dentry(const char *filepath)
+{
+       struct path path;
+       struct dentry *dentry = NULL;
+
+       if (kern_path(filepath, LOOKUP_FOLLOW, &path) == 0) {
+               dentry = __get_dentry(path.dentry);
+               path_put(&path);
+       }
+
+       return dentry;
+}
+
+void put_dentry(struct dentry *dentry)
+{
+       get_put_counter--;
+       dput(dentry);
+}
+
+static inline unsigned long get_preload_flags(struct task_struct *task)
+{
+       unsigned long flags;
+       int ok;
+
+       flags = (unsigned long)swap_task_data_get(task, &ok);
+       WARN(!ok, "Preload flags(%08lx) seem corrupted", flags);
+
+       return (ok ? flags: 0);
+}
+
+static inline void set_preload_flags(struct task_struct *task,
+                                    unsigned long flags)
+{
+       swap_task_data_set(task, (void *)flags, 0);
+}
+
+static inline void __prepare_ujump(struct uretprobe_instance *ri,
+                                  struct pt_regs *regs,
+                                  unsigned long vaddr)
+{
+       ri->rp->up.kp.ss_addr[smp_processor_id()] = (kprobe_opcode_t *)vaddr;
+}
+
+static inline int __push(struct pt_regs *regs, void *buf, size_t len)
+{
+       unsigned long sp = swap_get_stack_ptr(regs) - len;
+
+       sp = PTR_ALIGN(sp, sizeof(unsigned long));
+       if (copy_to_user((void __user *)sp, buf, len))
+               return -EIO;
+       swap_set_stack_ptr(regs, sp);
+
+       return 0;
+}
+
+static inline void __save_uregs(struct uretprobe_instance *ri,
+                               struct pt_regs *regs)
+{
+       struct us_priv *priv = (struct us_priv *)ri->data;
+
+       memcpy(ri->data, regs, sizeof(*regs));
+       priv->arg0 = swap_get_arg(regs, 0);
+       priv->arg1 = swap_get_arg(regs, 1);
+       priv->raddr = swap_get_ret_addr(regs);
+}
+
+static inline void __restore_uregs(struct uretprobe_instance *ri,
+                                  struct pt_regs *regs)
+{
+       struct us_priv *priv = (struct us_priv *)ri->data;
+
+       memcpy(regs, ri->data, sizeof(*regs));
+       swap_set_arg(regs, 0, priv->arg0);
+       swap_set_arg(regs, 1, priv->arg1);
+       swap_set_ret_addr(regs, priv->raddr);
+#ifndef CONFIG_ARM
+       /* need to do it only on x86 */
+       regs->EREG(ip) -= 1;
+#endif /* !CONFIG_ARM */
+       /* we have just restored the registers => no need to do it in
+        * trampoline_uprobe_handler */
+       ri->ret_addr = NULL;
+}
+
+static inline void print_regs(const char *prefix, struct pt_regs *regs,
+                             struct uretprobe_instance *ri)
+{
+#ifdef CONFIG_ARM
+       printk(PRELOAD_PREFIX "%s[%d/%d] (%d) %s addr(%08lx), "
+              "r0(%08lx), r1(%08lx), r2(%08lx), r3(%08lx), "
+              "r4(%08lx), r5(%08lx), r6(%08lx), r7(%08lx), "
+              "sp(%08lx), lr(%08lx), pc(%08lx)\n",
+              current->comm, current->tgid, current->pid,
+              (int)preload_pd_get_state(__get_process_data(ri->rp)),
+              prefix, (unsigned long)ri->rp->up.kp.addr,
+              regs->ARM_r0, regs->ARM_r1, regs->ARM_r2, regs->ARM_r3,
+              regs->ARM_r4, regs->ARM_r5, regs->ARM_r6, regs->ARM_r7,
+              regs->ARM_sp, regs->ARM_lr, regs->ARM_pc);
+#else /* !CONFIG_ARM */
+       printk(PRELOAD_PREFIX "%s[%d/%d] (%d) %s addr(%08lx), "
+              "ip(%08lx), arg0(%08lx), arg1(%08lx), raddr(%08lx)\n",
+              current->comm, current->tgid, current->pid,
+              (int)preload_pd_get_state(__get_process_data(ri->rp)),
+              prefix, (unsigned long)ri->rp->up.kp.addr,
+              regs->EREG(ip), swap_get_arg(regs, 0), swap_get_arg(regs, 1),
+              swap_get_ret_addr(regs));
+#endif /* CONFIG_ARM */
+}
+
+static inline unsigned long __get_r_debug_off(struct vm_area_struct *linker_vma)
+{
+       unsigned long start_addr;
+       unsigned long offset = preload_debugfs_r_debug_offset();
+
+       if (linker_vma == NULL)
+               return 0;
+
+       start_addr = linker_vma->vm_start;
+
+       return (offset ? start_addr + offset : 0);
+}
+
+static struct vm_area_struct *__get_linker_vma(struct task_struct *task)
+{
+       struct vm_area_struct *vma = NULL;
+       struct bin_info *ld_info;
+
+       ld_info = preload_storage_get_linker_info();
+
+       for (vma = task->mm->mmap; vma; vma = vma->vm_next) {
+               if (vma->vm_file && vma->vm_flags & VM_EXEC
+                   && vma->vm_file->f_dentry == ld_info->dentry) {
+                               preload_storage_put_linker_info(ld_info);
+                               return vma;
+               }
+       }
+
+       preload_storage_put_linker_info(ld_info);
+       return NULL;
+}
+
+static struct vm_area_struct *__get_libc_vma(struct task_struct *task)
+{
+       struct vm_area_struct *vma = NULL;
+       struct dentry *libc_dentry;
+
+       libc_dentry = get_dentry("/lib/libc.so.6");
+
+       for (vma = task->mm->mmap; vma; vma = vma->vm_next) {
+               if (vma->vm_file && vma->vm_flags & VM_EXEC
+                   && vma->vm_file->f_dentry == libc_dentry) {
+                               put_dentry(libc_dentry);
+                               return vma;
+               }
+       }
+
+       put_dentry(libc_dentry);
+       return NULL;
+}
+
+static inline struct vm_area_struct *__get_vma_by_addr(struct task_struct *task,
+                                                       unsigned long caller_addr)
+{
+       struct vm_area_struct *vma = NULL;
+
+       if (task->mm == NULL)
+               return NULL;
+       vma = find_vma_intersection(task->mm, caller_addr, caller_addr + 1);
+
+       return vma;
+}
+
+static inline bool __is_probe_non_block(struct us_ip *ip)
+{
+       if (!(ip->probe_i.pl_i.type & (0x1 << 1)))
+               return true;
+
+       return false;
+}
+
+static inline bool __is_handlers_call(struct vm_area_struct *caller)
+{
+       /* TODO Optimize using start/stop callbacks */
+
+       struct bin_info *hi = preload_storage_get_handlers_info();
+       bool res = false;
+
+       if (hi == NULL) {
+               printk(PRELOAD_PREFIX "Cannot get handlers dentry!\n");
+               goto is_handlers_call_out;
+       }
+
+       if (caller == NULL || caller->vm_file == NULL ||
+               caller->vm_file->f_dentry == NULL) {
+               goto is_handlers_call_out;
+       }
+
+       if (hi->dentry == caller->vm_file->f_dentry)
+               res = true;
+
+is_handlers_call_out:
+
+       preload_storage_put_handlers_info(hi);
+
+       return res;
+}
+
+
+
+
+
+static bool __is_proc_mmap_mappable(struct task_struct *task)
+{
+       struct vm_area_struct *linker_vma = __get_linker_vma(task);
+       unsigned long r_debug_addr;
+       unsigned int state;
+       int ret;
+
+       if (linker_vma == NULL)
+               return false;
+
+       r_debug_addr = __get_r_debug_off(linker_vma);
+       if (r_debug_addr == 0)
+               return false;
+
+       ret = preload_patcher_get_ui((void *)r_debug_addr + sizeof(int) +
+                                sizeof(void *) + sizeof(unsigned long),
+                                &state, task);
+       if (ret != sizeof(state))
+               return false;
+
+       return ( state == 0 ? true : false );
+}
+
+static bool __not_system_caller(struct task_struct *task,
+                                struct vm_area_struct *caller)
+{
+       struct vm_area_struct *linker_vma = __get_linker_vma(task);
+       struct vm_area_struct *libc_vma = __get_libc_vma(task);
+
+       if (linker_vma == NULL || libc_vma == NULL || caller == NULL ||
+           caller == linker_vma || caller == libc_vma)
+               return false;
+
+       return true;
+}
+
+static bool __should_we_preload_handlers(struct task_struct *task,
+                                        struct pt_regs *regs)
+{
+       unsigned long caller_addr = get_regs_ret_func(regs);
+    struct vm_area_struct *cvma = __get_vma_by_addr(current, caller_addr);
+
+       if (!__is_proc_mmap_mappable(task) ||
+           !__not_system_caller(task, cvma))
+               return false;
+
+       return true;
+}
+
+
+
+static int preload_us_entry(struct uretprobe_instance *ri, struct pt_regs *regs)
+{
+       struct process_data *pd = __get_process_data(ri->rp);
+       struct us_ip *ip = container_of(ri->rp, struct us_ip, retprobe);
+       struct us_priv *priv = (struct us_priv *)ri->data;
+       unsigned long flags = get_preload_flags(current);
+       unsigned long offset = ip->probe_i.pl_i.handler;
+       unsigned long vaddr = 0;
+       char __user *path = NULL;
+
+       if ((flags & HANDLER_RUNNING) ||
+           preload_threads_check_disabled_probe(current, ip->orig_addr))
+               goto out_set_origin;
+
+       switch (preload_pd_get_state(pd)) {
+       case NOT_LOADED:
+               /* if linker is still doing its work, we do nothing */
+               if (!__should_we_preload_handlers(current, regs))
+                       goto out_set_origin;
+
+               /* jump to loader code if ready */
+               vaddr = preload_pd_get_loader_base(pd) + preload_debugfs_get_loader_offset();
+               if (vaddr) {
+                       /* save original regs state */
+                       __save_uregs(ri, regs);
+                       print_regs("ORIG", regs, ri);
+
+                       path = preload_pd_get_path(pd);
+
+                       /* set dlopen args: filename, flags */
+                       swap_set_arg(regs, 0, (unsigned long)path/*swap_get_stack_ptr(regs)*/);
+                       swap_set_arg(regs, 1, 2 /* RTLD_NOW */);
+
+                       /* do the jump to dlopen */
+                       __prepare_ujump(ri, regs, vaddr);
+                       /* set new state */
+                       preload_pd_set_state(pd, LOADING);
+               }
+               break;
+       case LOADING:
+               /* handlers have not yet been loaded... just ignore */
+               break;
+       case LOADED:
+               /* jump to preloaded handler */
+               vaddr = preload_pd_get_handlers_base(pd) + offset;
+               if (vaddr) {
+                       unsigned long disable_addr;
+                       unsigned long caddr = get_regs_ret_func(regs);
+                       struct vm_area_struct *cvma = __get_vma_by_addr(current, caddr);
+                       enum preload_call_type ct;
+
+                       disable_addr = __is_probe_non_block(ip) ? ip->orig_addr : 0;
+                       ct = preload_control_call_type(ip, (void *)caddr);
+
+                       /* jump only if caller is instumented and it is not a system lib -
+                        * this leads to some errors */
+                       if (__not_system_caller(current, cvma) && ct &&
+                           !__is_handlers_call(cvma)) {
+                               if (preload_threads_set_data(current,
+                                                            caddr, ct,
+                                                            disable_addr) != 0)
+                                       printk(PRELOAD_PREFIX "Error! Failed to set caller 0x%lx"
+                                              " for %d/%d\n", caddr, current->tgid,
+                                                              current->pid);
+                               /* args are not changed */
+                               __prepare_ujump(ri, regs, vaddr);
+                               if (disable_addr == 0)
+                                       set_preload_flags(current, HANDLER_RUNNING);
+                       }
+               }
+               break;
+       case FAILED:
+       case ERROR:
+       default:
+               /* do nothing */
+               break;
+       }
+
+out_set_origin:
+       priv->origin = vaddr;
+       return 0;
+}
+
+static int preload_us_ret(struct uretprobe_instance *ri, struct pt_regs *regs)
+{
+       struct process_data *pd = __get_process_data(ri->rp);
+       struct us_ip *ip = container_of(ri->rp, struct us_ip, retprobe);
+       struct us_priv *priv = (struct us_priv *)ri->data;
+       unsigned long flags = get_preload_flags(current);
+       unsigned long offset = ip->probe_i.pl_i.handler;
+       unsigned long vaddr = 0;
+
+       switch (preload_pd_get_state(pd)) {
+       case NOT_LOADED:
+               /* loader has not yet been mapped... just ignore */
+               break;
+       case LOADING:
+               /* check if preloading has been completed */
+               vaddr = preload_pd_get_loader_base(pd) + preload_debugfs_get_loader_offset();
+               if (vaddr && (priv->origin == vaddr)) {
+                       preload_pd_set_handle(pd, (void __user *)regs_return_value(regs));
+
+                       /* restore original regs state */
+                       __restore_uregs(ri, regs);
+                       print_regs("REST", regs, ri);
+                       /* check if preloading done */
+
+                       if (preload_pd_get_handle(pd)) {
+                               preload_pd_set_state(pd, LOADED);
+                               preload_pd_put_path(pd);
+                       } else {
+                               preload_pd_dec_attempts(pd);
+                               preload_pd_set_state(pd, FAILED);
+                               preload_pd_put_path(pd);
+                       }
+               }
+               break;
+       case LOADED:
+               if ((flags & HANDLER_RUNNING) ||
+                   preload_threads_check_disabled_probe(current, ip->orig_addr)) {
+                       bool non_blk_probe = __is_probe_non_block(ip);
+
+                       /* drop the flag if the handler has completed */
+                       vaddr = preload_pd_get_handlers_base(pd) + offset;
+                       if (vaddr && (priv->origin == vaddr)) {
+                               if (preload_threads_put_data(current) != 0)
+                                       printk(PRELOAD_PREFIX "Error! Failed to put caller slot"
+                                              " for %d/%d\n", current->tgid, current->pid);
+                               if (!non_blk_probe) {
+                                       flags &= ~HANDLER_RUNNING;
+                                       set_preload_flags(current, flags);
+                               }
+                       }
+               }
+               break;
+       case FAILED:
+               if (preload_pd_get_attempts(pd)) {
+                       preload_pd_set_state(pd, NOT_LOADED);
+                       preload_pd_put_path(pd);
+               }
+               break;
+       case ERROR:
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+enum mmap_type_t {
+       MMAP_LOADER,
+       MMAP_HANDLERS,
+       MMAP_SKIP
+};
+
+struct mmap_priv {
+       enum mmap_type_t type;
+};
+
+static inline bool check_prot(unsigned long prot)
+{
+       return !!((prot & PROT_READ) && (prot & PROT_EXEC));
+}
+
+static int mmap_entry_handler(struct kretprobe_instance *ri,
+                             struct pt_regs *regs)
+{
+       struct file *file = (struct file *)swap_get_karg(regs, 0);
+       unsigned long prot = swap_get_karg(regs, 3);
+       struct mmap_priv *priv = (struct mmap_priv *)ri->data;
+       struct dentry *dentry, *loader_dentry;
+       struct bin_info *hi;
+
+       priv->type = MMAP_SKIP;
+       if (!check_prot(prot))
+               return 0;
+
+       if (!file)
+               return 0;
+       dentry = file->f_dentry;
+       if (dentry == NULL)
+               return 0;
+
+       hi = preload_storage_get_handlers_info();
+       loader_dentry = preload_debugfs_get_loader_dentry();
+       if (dentry == loader_dentry)
+               priv->type = MMAP_LOADER;
+       else if (hi->dentry != NULL && dentry == hi->dentry) 
+               priv->type = MMAP_HANDLERS;
+
+       if (hi != NULL)
+               preload_storage_put_handlers_info(hi);
+
+       return 0;
+}
+
+static int mmap_ret_handler(struct kretprobe_instance *ri,
+                           struct pt_regs *regs)
+{
+       struct mmap_priv *priv = (struct mmap_priv *)ri->data;
+       struct task_struct *task = current->group_leader;
+       struct sspt_proc *proc;
+       unsigned long vaddr;
+
+       if (!task->mm)
+               return 0;
+
+       vaddr = (unsigned long)regs_return_value(regs);
+       if (IS_ERR_VALUE(vaddr))
+               return 0;
+
+       proc = sspt_proc_get_by_task(task);
+       if (!proc)
+               return 0;
+
+       switch (priv->type) {
+       case MMAP_LOADER:
+               preload_pd_set_loader_base(proc->private_data, vaddr);
+               break;
+       case MMAP_HANDLERS:
+               preload_pd_set_handlers_base(proc->private_data, vaddr);
+               break;
+       case MMAP_SKIP:
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+
+static int get_caller_handler(struct kprobe *p, struct pt_regs *regs)
+{
+       unsigned long caller;
+       int ret;
+
+       ret = preload_threads_get_caller(current, &caller);
+       if (ret != 0) {
+               caller = 0xbadbeef;
+               printk(PRELOAD_PREFIX "Error! Cannot get caller address for %d/%d\n",
+                      current->tgid, current->pid);
+       }
+
+       swap_put_uarg(regs, 0, caller);
+
+       return 0;
+}
+
+static int get_call_type_handler(struct kprobe *p, struct pt_regs *regs)
+{
+       unsigned char call_type;
+       int ret;
+
+       ret = preload_threads_get_call_type(current, &call_type);
+       if (ret != 0) {
+               call_type = 0xff;
+               printk(PRELOAD_PREFIX "Error! Cannot get call type for %d/%d\n",
+                      current->tgid, current->pid);
+       }
+
+       swap_put_uarg(regs, 0, call_type);
+
+       return 0;
+}
+
+
+
+
+int preload_module_get_caller_init(struct us_ip *ip)
+{
+       struct uprobe *up = &ip->uprobe;
+
+       up->kp.pre_handler = get_caller_handler;
+
+       return 0;
+}
+
+void preload_module_get_caller_exit(struct us_ip *ip)
+{
+}
+
+int preload_module_get_call_type_init(struct us_ip *ip)
+{
+       struct uprobe *up = &ip->uprobe;
+
+       up->kp.pre_handler = get_call_type_handler;
+
+       return 0;
+}
+
+void preload_module_get_call_type_exit(struct us_ip *ip)
+{
+}
+
+
+static struct kretprobe mmap_rp = {
+       .kp.symbol_name = "do_mmap_pgoff",
+       .data_size = sizeof(struct mmap_priv),
+       .entry_handler = mmap_entry_handler,
+       .handler = mmap_ret_handler
+};
+
+int preload_module_uprobe_init(struct us_ip *ip)
+{
+       struct uretprobe *rp = &ip->retprobe;
+       struct sspt_proc *proc = page_to_proc(ip->page);
+       int ret;
+
+       if (proc->private_data == NULL) {
+               ret = preload_pd_create_pd(&(proc->private_data), proc->task);
+               if (ret != 0)
+                       return ret;
+       }
+
+       preload_pd_inc_refs(proc->private_data);
+
+       rp->entry_handler = preload_us_entry;
+       rp->handler = preload_us_ret;
+       /* FIXME actually additional data_size is needed only when we jump
+        * to dlopen */
+       rp->data_size = sizeof(struct us_priv);
+
+       ret = swap_register_kretprobe(&mmap_rp);
+       if (ret == 0) {
+               return -EFAULT; /* failed to get THIS_MODULE */
+       }
+
+       return 0;
+}
+
+void preload_module_uprobe_exit(struct us_ip *ip)
+{
+       struct sspt_proc *proc = ip_to_proc(ip);
+
+       preload_pd_dec_refs(proc->private_data);
+
+       swap_unregister_kretprobe(&mmap_rp);
+}
+
+int preload_set(void)
+{
+       if (preload_module_is_running())
+               return -EBUSY;
+
+       return 0;
+}
+
+void preload_unset(void)
+{
+       swap_unregister_kretprobe(&mmap_rp);
+       /*module_put(THIS_MODULE);*/
+       preload_module_set_not_ready();
+
+}
+
+static int __init preload_module_init(void)
+{
+       int ret;
+
+       ret = preload_debugfs_init();
+       if (ret)
+               goto out_err;
+
+       ret = preload_storage_init();
+       if (ret)
+               goto exit_debugfs;
+
+       ret = preload_pd_init();
+       if (ret)
+               goto exit_storage;
+
+       /* TODO do not forget to remove set (it is just for debugging) */
+       ret = preload_set();
+       if (ret)
+               goto exit_pd;
+
+       ret = preload_control_init();
+       if (ret)
+               goto exit_set;
+
+       ret = preload_threads_init();
+       if (ret)
+               goto exit_control;
+
+       ret = register_preload_probes();
+       if (ret)
+               goto exit_threads;
+
+       return 0;
+
+exit_threads:
+       preload_threads_exit();
+
+exit_control:
+       preload_control_exit();
+
+exit_set:
+       preload_unset();
+
+exit_pd:
+       preload_pd_uninit();
+
+exit_storage:
+       preload_storage_exit();
+
+exit_debugfs:
+       preload_debugfs_exit();
+
+out_err:
+       return ret;
+}
+
+static void __exit preload_module_exit(void)
+{
+       unregister_preload_probes();
+       preload_threads_exit();
+       preload_control_exit();
+       preload_unset();
+       preload_pd_uninit();
+       preload_storage_exit();
+       preload_debugfs_exit();
+
+       WARN(get_put_counter, "Bad GET/PUT balance: %d\n", get_put_counter);
+}
+
+module_init(preload_module_init);
+module_exit(preload_module_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("SWAP Preload Module");
+MODULE_AUTHOR("Vasiliy Ulyanov <v.ulyanov@samsung.com>"
+              "Alexander Aksenov <a.aksenov@samsung.com>");
diff --git a/preload/preload_module.h b/preload/preload_module.h
new file mode 100644 (file)
index 0000000..cc33f53
--- /dev/null
@@ -0,0 +1,28 @@
+#ifndef __PRELOAD_MODULE_H__
+#define __PRELOAD_MODULE_H__
+
+#include <linux/types.h>
+
+struct us_ip;
+struct dentry;
+
+bool preload_module_is_ready(void);
+bool preload_module_is_running(void);
+bool preload_module_is_not_ready(void);
+void preload_module_set_ready(void);
+void preload_module_set_running(void);
+void preload_module_set_not_ready(void);
+
+int preload_module_uprobe_init(struct us_ip *ip);
+void preload_module_uprobe_exit(struct us_ip *ip);
+
+int preload_module_get_caller_init(struct us_ip *ip);
+void preload_module_get_caller_exit(struct us_ip *ip);
+int preload_module_get_call_type_init(struct us_ip *ip);
+void preload_module_get_call_type_exit(struct us_ip *ip);
+
+struct dentry *get_dentry(const char *filepath);
+void put_dentry(struct dentry *dentry);
+
+
+#endif /* __PRELOAD_MODULE_H__ */
diff --git a/preload/preload_patcher.c b/preload/preload_patcher.c
new file mode 100644 (file)
index 0000000..d2457b7
--- /dev/null
@@ -0,0 +1,76 @@
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm_types.h>
+#include <linux/mm.h>
+
+#include <kprobe/swap_kprobes_deps.h>
+
+#include "preload_patcher.h"
+#include "preload_debugfs.h"
+#include "preload_storage.h"
+
+
+static inline bool check_vma(struct vm_area_struct *vma, struct dentry *dentry)
+{
+       struct file *file = vma->vm_file;
+
+       return (file && (vma->vm_flags & VM_EXEC) && (file->f_dentry == dentry));
+}
+
+
+static inline int __patch_proc_mem(struct task_struct *task, unsigned long addr,
+                                  void *buf, int size)
+{
+       return write_proc_vm_atomic(task, addr, buf, size);
+}
+
+static inline int __read_proc_mem(struct task_struct *task, unsigned long addr,
+                                 void *value, size_t value_size)
+{
+       return read_proc_vm_atomic(task, addr, value, value_size);
+}
+
+
+
+
+int preload_patcher_patch_proc(void *addr, unsigned long val,
+                              struct task_struct *task)
+{
+       return __patch_proc_mem(task, (unsigned long)addr, &val, sizeof(val));
+}
+
+int preload_patcher_write_string(void *addr, char *string, size_t len,
+                                struct task_struct *task)
+{
+       return __patch_proc_mem(task, (unsigned long)addr, string, len);
+}
+
+int preload_patcher_get_ul(void *addr, unsigned long *val,
+                          struct task_struct *task)
+{
+       return __read_proc_mem(task, (unsigned long)addr, val, sizeof(*val));
+}
+
+int preload_patcher_get_ui(void *addr, unsigned int *val,
+                          struct task_struct *task)
+{
+       return __read_proc_mem(task, (unsigned long)addr, val, sizeof(*val));
+}
+
+int preload_patcher_null_mem(void *addr, int size, struct task_struct *task)
+{
+       char *buf;
+       int ret;
+
+       buf = kmalloc(size, GFP_KERNEL);
+       if (buf == NULL)
+               return -ENOMEM;
+
+       memset(buf, 0, size);
+
+       ret = __patch_proc_mem(task, (unsigned long)addr, buf, size);
+
+       kfree(buf);
+
+       return ret;
+}
diff --git a/preload/preload_patcher.h b/preload/preload_patcher.h
new file mode 100644 (file)
index 0000000..492a2c0
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef __PRELOAD_PATCHER_H__
+#define __PRELOAD_PATCHER_H__
+
+struct task_struct;
+
+int preload_patcher_patch_proc(void *addr, unsigned long val,
+                               struct task_struct *task);
+int preload_patcher_write_string(void *addr, char *string, size_t len,
+                                 struct task_struct *task);
+int preload_patcher_get_ul(void *addr, unsigned long *val,
+                           struct task_struct *task);
+int preload_patcher_null_mem(void *addr, int size, struct task_struct *task);
+int preload_patcher_get_ui(void *addr, unsigned int *val,
+                           struct task_struct *task);
+
+
+
+#endif /* __PRELOAD_PATCHER_H__ */
diff --git a/preload/preload_pd.c b/preload/preload_pd.c
new file mode 100644 (file)
index 0000000..628f434
--- /dev/null
@@ -0,0 +1,416 @@
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/dcache.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/hardirq.h>
+#include <us_manager/us_manager_common.h>
+#include "preload_pd.h"
+#include "preload_threads.h"
+#include "preload_debugfs.h"
+#include "preload_storage.h"
+#include "preload_patcher.h"
+#include "preload.h"
+
+struct process_data {
+    char is_mapped;
+       enum preload_state_t state;
+       unsigned long loader_base;
+       unsigned long handlers_base;
+       unsigned long data_page;
+       void __user *handle;
+       long attempts;
+       long refcount;
+};
+
+static struct bin_info *handlers_info;
+
+
+
+static inline bool check_vma(struct vm_area_struct *vma, struct dentry *dentry)
+{
+       struct file *file = vma->vm_file;
+
+       return (file && (vma->vm_flags & VM_EXEC) && (file->f_dentry == dentry));
+}
+
+static inline enum preload_state_t __get_state(struct process_data *pd)
+{
+       return pd->state;
+}
+
+static inline void __set_state(struct process_data *pd,
+                                  enum preload_state_t state)
+{
+       pd->state = state;
+}
+
+static inline unsigned long __get_loader_base(struct process_data *pd)
+{
+       return pd->loader_base;
+}
+
+static inline void __set_loader_base(struct process_data *pd,
+                                    unsigned long addr)
+{
+       pd->loader_base = addr;
+}
+
+static inline unsigned long __get_handlers_base(struct process_data *pd)
+{
+       return pd->handlers_base;
+}
+
+static inline void __set_handlers_base(struct process_data *pd,
+                                      unsigned long addr)
+{
+       pd->handlers_base = addr;
+}
+
+static inline char __user *__get_path(struct process_data *pd)
+{
+       return (char *)pd->data_page;
+}
+
+static inline unsigned long __get_data_page(struct process_data *pd)
+{
+       return pd->data_page;
+}
+
+static inline void __set_data_page(struct process_data *pd, unsigned long page)
+{
+       pd->data_page = page;
+}
+
+static inline void *__get_handle(struct process_data *pd)
+{
+       return pd->handle;
+}
+
+static inline void __set_handle(struct process_data *pd, void __user *handle)
+{
+       pd->handle = handle;
+}
+
+static inline long __get_attempts(struct process_data *pd)
+{
+       return pd->attempts;
+}
+
+static inline void __set_attempts(struct process_data *pd, long attempts)
+{
+       pd->attempts = attempts;
+}
+
+static inline long __get_refcount(struct process_data *pd)
+{
+       return pd->refcount;
+}
+
+static inline void __set_refcount(struct process_data *pd, long refcount)
+{
+       pd->refcount = refcount;
+}
+
+
+
+
+static unsigned long __find_dentry_base(struct mm_struct *mm,
+                                       struct dentry *dentry)
+{
+       struct vm_area_struct *vma;
+
+       for (vma = mm->mmap; vma; vma = vma->vm_next) {
+               if (check_vma(vma, dentry))
+                       return vma->vm_start;
+       }
+
+       return 0;
+}
+
+static unsigned long find_dentry_base(struct task_struct *task,
+                                     struct dentry *dentry)
+{
+       struct mm_struct *mm = task->mm;
+       unsigned long addr;
+
+#ifdef CONFIG_ARM
+       down_read(&mm->mmap_sem);
+#endif /* CONFIG_ARM */
+       addr = __find_dentry_base(mm, dentry);
+#ifdef CONFIG_ARM
+       up_read(&mm->mmap_sem);
+#endif /* CONFIG_ARM */
+
+       return addr;
+}
+
+static int __pd_create_on_demand(void)
+{
+       if (handlers_info == NULL) {
+               handlers_info = preload_storage_get_handlers_info();
+               if (handlers_info == NULL)
+                       return -EINVAL;
+       }
+
+       return 0;
+}
+
+
+
+enum preload_state_t preload_pd_get_state(struct process_data *pd)
+{
+       if (pd == NULL)
+               return 0;
+
+       return __get_state(pd);
+}
+
+void preload_pd_set_state(struct process_data *pd, enum preload_state_t state)
+{
+       if (pd == NULL) {
+               printk(PRELOAD_PREFIX "%d: No process data! Current %d %s\n", __LINE__,
+               current->tgid, current->comm);
+               return;
+       }
+
+       __set_state(pd, state);
+}
+
+unsigned long preload_pd_get_loader_base(struct process_data *pd)
+{
+       if (pd == NULL)
+               return ERROR;
+
+       return __get_loader_base(pd);
+}
+
+void preload_pd_set_loader_base(struct process_data *pd, unsigned long vaddr)
+{
+       if (pd == NULL) {
+               printk(PRELOAD_PREFIX "%d: No process data! Current %d %s\n", __LINE__,
+               current->tgid, current->comm);
+               return;
+       }
+
+       __set_loader_base(pd, vaddr);
+}
+
+unsigned long preload_pd_get_handlers_base(struct process_data *pd)
+{
+       if (pd == NULL)
+               return 0;
+
+       return __get_handlers_base(pd);
+}
+
+void preload_pd_set_handlers_base(struct process_data *pd, unsigned long vaddr)
+{
+       if (pd == NULL) {
+               printk(PRELOAD_PREFIX "%d: No process data! Current %d %s\n", __LINE__,
+               current->tgid, current->comm);
+               return;
+       }
+
+       __set_handlers_base(pd, vaddr);
+}
+
+void preload_pd_put_path(struct process_data *pd)
+{
+       if (pd == NULL) {
+               printk(PRELOAD_PREFIX "%d: No process data! Current %d %s\n", __LINE__,
+               current->tgid, current->comm);
+               return;
+       }
+
+       if (__get_data_page(pd) == 0)
+               return;
+
+       __set_data_page(pd, 0);
+}
+
+char __user *preload_pd_get_path(struct process_data *pd)
+{
+       /* This function should be called only for current */
+
+       struct task_struct *task = current;
+       unsigned long page = __get_data_page(pd);
+       int ret;
+
+       if (pd == NULL || page == 0)
+               return NULL;
+
+    if (pd->is_mapped == 1)
+               return __get_path(pd);
+
+       ret = preload_patcher_write_string((void *)page, handlers_info->path,
+                                          strnlen(handlers_info->path, PATH_MAX),
+                                          task);
+       if (ret <= 0) {
+               printk(KERN_ERR PRELOAD_PREFIX "Cannot copy string to user!\n");
+        goto get_path_failed;
+       }
+
+    pd->is_mapped = 1;
+
+       return __get_path(pd);
+
+get_path_failed:
+
+    return NULL;
+}
+
+
+
+void *preload_pd_get_handle(struct process_data *pd)
+{
+       if (pd == NULL)
+               return NULL;
+
+       return __get_handle(pd);
+}
+
+void preload_pd_set_handle(struct process_data *pd, void __user *handle)
+{
+       if (pd == NULL) {
+               printk(PRELOAD_PREFIX "%d: No process data! Current %d %s\n", __LINE__,
+               current->tgid, current->comm);
+               return;
+       }
+
+       __set_handle(pd, handle);
+}
+
+long preload_pd_get_attempts(struct process_data *pd)
+{
+       if (pd == NULL)
+               return -EINVAL;
+
+       return __get_attempts(pd);
+}
+
+void preload_pd_dec_attempts(struct process_data *pd)
+{
+       long attempts;
+
+       if (pd == NULL) {
+               printk(PRELOAD_PREFIX "%d: No process data! Current %d %s\n", __LINE__,
+               current->tgid, current->comm);
+               return;
+       }
+
+       attempts = __get_attempts(pd);
+       attempts--;
+       __set_attempts(pd, attempts);
+}
+
+void preload_pd_inc_refs(struct process_data *pd)
+{
+       long refs;
+
+       if (pd == NULL) {
+               printk(PRELOAD_PREFIX "%d: No process data! Current %d %s\n", __LINE__,
+               current->tgid, current->comm);
+               return;
+       }
+
+       refs = __get_refcount(pd);
+       refs++;
+       __set_refcount(pd, refs);
+}
+
+void preload_pd_dec_refs(struct process_data *pd)
+{
+       long refs;
+
+       if (pd == NULL) {
+               printk(PRELOAD_PREFIX "%d: No process data! Current %d %s\n", __LINE__,
+               current->tgid, current->comm);
+               return;
+       }
+
+       refs = __get_refcount(pd);
+       refs--;
+       __set_refcount(pd, refs);
+}
+
+long preload_pd_get_refs(struct process_data *pd)
+{
+       if (pd == NULL)
+               return -EINVAL;
+
+       return __get_refcount(pd);
+}
+
+int preload_pd_create_pd(void** target_place, struct task_struct *task)
+{
+    struct process_data *pd;
+    unsigned long page = 0;
+       unsigned long base;
+       struct dentry *dentry;
+       int ret;
+
+       ret = __pd_create_on_demand();
+       if (ret)
+               goto create_pd_exit;
+
+       pd = kzalloc(sizeof(*pd), GFP_ATOMIC);
+       if (pd == NULL) {
+               ret = -ENOMEM;
+               goto create_pd_exit;
+       }
+
+       ret = 0;
+
+       /* 1. check if loader is already mapped */
+       dentry = preload_debugfs_get_loader_dentry();
+       base = find_dentry_base(task, dentry);
+       if (base)
+               __set_loader_base(pd, base);
+
+       /* 2. check if handlers are already mapped */
+       base = find_dentry_base(task, handlers_info->dentry);
+       if (base) {
+               __set_handlers_base(pd, base);
+               __set_state(pd, LOADED);
+       }
+
+       /* 3. map page to store path */
+#ifdef CONFIG_ARM
+       down_write(&current->mm->mmap_sem);
+#endif
+
+       page = swap_do_mmap(NULL, 0, PAGE_SIZE, PROT_READ,
+                           MAP_ANONYMOUS | MAP_PRIVATE, 0);
+#ifdef CONFIG_ARM
+       up_write(&current->mm->mmap_sem);
+#endif
+       if (IS_ERR((void *)page)) {
+               printk(KERN_ERR PRELOAD_PREFIX "Cannot alloc page for %u\n", task->tgid);
+               ret = -ENOMEM;
+               goto create_pd_exit;
+       }
+
+       pd->is_mapped = 0;
+
+       __set_data_page(pd, page);
+       __set_attempts(pd, PRELOAD_MAX_ATTEMPTS);
+
+       *target_place = pd;
+
+create_pd_exit:
+       return ret;
+}
+
+int preload_pd_init(void)
+{
+       return 0;
+}
+
+void preload_pd_uninit(void)
+{
+       if (handlers_info)
+               preload_storage_put_handlers_info(handlers_info);
+       handlers_info = NULL;
+}
diff --git a/preload/preload_pd.h b/preload/preload_pd.h
new file mode 100644 (file)
index 0000000..46473cc
--- /dev/null
@@ -0,0 +1,66 @@
+#ifndef __PRELOAD_PD_H__
+#define __PRELOAD_PD_H__
+
+struct process_data;
+struct task_struct;
+
+/* process preload states */
+enum preload_state_t {
+       NOT_LOADED,
+       LOADING,
+       LOADED,
+       FAILED,
+    ERROR
+};
+
+//enum preload_state_t preload_pd_get_state(struct task_struct *task);
+//void preload_pd_set_state(struct task_struct *task, enum preload_state_t state);
+//unsigned long preload_pd_get_loader_base(struct task_struct *task);
+//void preload_pd_set_loader_base(struct task_struct *task, unsigned long vaddr);
+//unsigned long preload_pd_get_handlers_base(struct task_struct *task);
+//void preload_pd_set_handlers_base(struct task_struct *task,
+//                                  unsigned long vaddr);
+////unsigned long preload_pd_get_flags(struct task_struct *task);
+////void preload_pd_set_flags(struct task_struct *task, unsigned long flags);
+//void *preload_pd_get_handle(struct task_struct *task);
+//void preload_pd_set_handle(struct task_struct *task, void __user *handle);
+//
+//long preload_pd_get_attempts(struct task_struct *task);
+//void preload_pd_dec_attempts(struct task_struct *task);
+//
+//void preload_pd_inc_refs(struct task_struct *task);
+//void preload_pd_dec_refs(struct task_struct *task);
+//long preload_pd_get_refs(struct task_struct *task);
+//
+//char __user *preload_pd_get_path(void);
+//void preload_pd_put_path(struct task_struct *task);
+//
+//int preload_pd_create_pd(struct process_data **pd_pp, struct task_struct *task);
+
+
+enum preload_state_t preload_pd_get_state(struct process_data *pd);
+void preload_pd_set_state(struct process_data *pd, enum preload_state_t state);
+unsigned long preload_pd_get_loader_base(struct process_data *pd);
+void preload_pd_set_loader_base(struct process_data *pd, unsigned long vaddr);
+unsigned long preload_pd_get_handlers_base(struct process_data *pd);
+void preload_pd_set_handlers_base(struct process_data *pd, unsigned long vaddr);
+void *preload_pd_get_handle(struct process_data *pd);
+void preload_pd_set_handle(struct process_data *pd, void __user *handle);
+
+long preload_pd_get_attempts(struct process_data *pd);
+void preload_pd_dec_attempts(struct process_data *pd);
+
+void preload_pd_inc_refs(struct process_data *pd);
+void preload_pd_dec_refs(struct process_data *pd);
+long preload_pd_get_refs(struct process_data *pd);
+
+char __user *preload_pd_get_path(struct process_data *pd);
+void preload_pd_put_path(struct process_data *pd);
+
+int preload_pd_create_pd(void **target_place, struct task_struct *task);
+
+int preload_pd_init(void);
+void preload_pd_uninit(void);
+
+
+#endif /* __PRELOAD_PD_H__*/
diff --git a/preload/preload_probe.c b/preload/preload_probe.c
new file mode 100644 (file)
index 0000000..d773251
--- /dev/null
@@ -0,0 +1,238 @@
+/*
+ *  SWAP uprobe manager
+ *  modules/us_manager/probes/preload_probe.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, 2014
+ *
+ * 2014         Alexander Aksenov: Preload implement
+ *
+ */
+
+#include <linux/module.h>
+#include <us_manager/us_manager.h>
+#include <us_manager/probes/register_probes.h>
+#include <us_manager/sspt/sspt_page.h>
+#include <writer/swap_writer_module.h>
+#include <uprobe/swap_uprobes.h>
+#include <us_manager/sspt/ip.h>
+#include "preload_probe.h"
+#include "preload.h"
+#include "preload_module.h"
+#include "preload_debugfs.h"
+
+static unsigned long long probes_count = 0;
+
+static int preload_info_copy(struct probe_info *dest,
+                             const struct probe_info *source)
+{
+       memcpy(dest, source, sizeof(*source));
+
+       return 0;
+}
+
+static void preload_info_cleanup(struct probe_info *probe_i)
+{
+}
+
+static struct uprobe *preload_get_uprobe(struct us_ip *ip)
+{
+       return &ip->retprobe.up;
+}
+
+/* We count all preload probes to know current state of the preload module:
+ * if there are registered probes, than it is currently running, if there is no
+ * probes, module is just ready to be used.
+ *
+ * If there was no registered probes and now they're appeared, change state to
+ * 'running'.
+ */
+static inline void inc_probes(void)
+{
+       if (probes_count == 0)
+               preload_module_set_running();
+
+       probes_count++;
+}
+
+/* If there were probes, but now there's no of them, change state to 'ready'.
+ */
+static inline void dec_probes(void)
+{
+       if (unlikely(probes_count == 0))
+               printk(KERN_ERR PRELOAD_PREFIX "Trying to remove probe when there is no one!\n");
+
+       probes_count--;
+       if (probes_count == 0)
+               preload_module_set_ready();
+}
+
+/* Checks if preload can be in 'ready' state. It is so, if loader's dentry and
+ * offset are specified.
+ */
+static inline bool can_be_ready(void)
+{
+       struct dentry *dentry = preload_debugfs_get_loader_dentry();
+       unsigned long offset = preload_debugfs_get_loader_offset();
+
+       if (dentry != NULL && offset != 0)
+               return true;
+
+       return false;
+}
+
+/* Registers probe if preload is 'running' or 'ready'.
+ */
+static int preload_register_probe(struct us_ip *ip)
+{
+       if (preload_module_is_not_ready()) {
+               if (can_be_ready()) {
+                       preload_module_set_ready();
+               } else {
+                       printk(PRELOAD_PREFIX "Module is not initialized!\n");
+                       return -EINVAL;
+               }
+       }
+
+       inc_probes();
+
+       return swap_register_uretprobe(&ip->retprobe);
+}
+
+static void preload_unregister_probe(struct us_ip *ip, int disarm)
+{
+       __swap_unregister_uretprobe(&ip->retprobe, disarm);
+
+       dec_probes();
+}
+
+static void preload_init(struct us_ip *ip)
+{
+       preload_module_uprobe_init(ip);
+}
+
+static void preload_uninit(struct us_ip *ip)
+{
+       preload_module_uprobe_exit(ip);
+
+       preload_info_cleanup(&ip->probe_i);
+}
+
+static struct probe_iface preload_iface = {
+       .init = preload_init,
+       .uninit = preload_uninit,
+       .reg = preload_register_probe,
+       .unreg = preload_unregister_probe,
+       .get_uprobe = preload_get_uprobe,
+       .copy = preload_info_copy,
+       .cleanup = preload_info_cleanup
+};
+
+static int get_caller_info_copy(struct probe_info *dest,
+                               const struct probe_info *source)
+{
+       memcpy(dest, source, sizeof(*source));
+
+       return 0;
+}
+
+static void get_caller_info_cleanup(struct probe_info *probe_i)
+{
+}
+
+static struct uprobe *get_caller_get_uprobe(struct us_ip *ip)
+{
+       return &ip->uprobe;
+}
+
+static int get_caller_register_probe(struct us_ip *ip)
+{
+       return swap_register_uprobe(&ip->uprobe);
+}
+
+static void get_caller_unregister_probe(struct us_ip *ip, int disarm)
+{
+       __swap_unregister_uprobe(&ip->uprobe, disarm);
+}
+
+static void get_caller_init(struct us_ip *ip)
+{
+       preload_module_get_caller_init(ip);
+}
+
+static void get_caller_uninit(struct us_ip *ip)
+{
+       preload_module_get_caller_exit(ip);
+
+       get_caller_info_cleanup(&ip->probe_i);
+}
+
+static struct probe_iface get_caller_iface = {
+       .init = get_caller_init,
+       .uninit = get_caller_uninit,
+       .reg = get_caller_register_probe,
+       .unreg = get_caller_unregister_probe,
+       .get_uprobe = get_caller_get_uprobe,
+       .copy = get_caller_info_copy,
+       .cleanup = get_caller_info_cleanup
+};
+
+static void get_call_type_init(struct us_ip *ip)
+{
+       preload_module_get_call_type_init(ip);
+}
+
+static void get_call_type_uninit(struct us_ip *ip)
+{
+       preload_module_get_call_type_exit(ip);
+
+       get_caller_info_cleanup(&ip->probe_i);
+}
+
+static struct probe_iface get_call_type_iface = {
+       .init = get_call_type_init,
+       .uninit = get_call_type_uninit,
+       .reg = get_caller_register_probe,
+       .unreg = get_caller_unregister_probe,
+       .get_uprobe = get_caller_get_uprobe,
+       .copy = get_caller_info_copy,
+       .cleanup = get_caller_info_cleanup
+};
+
+
+
+int register_preload_probes(void)
+{
+       int ret;
+
+       ret = swap_register_probe_type(SWAP_PRELOAD_PROBE, &preload_iface);
+       if (ret != 0)
+               return ret;
+
+       ret = swap_register_probe_type(SWAP_GET_CALLER, &get_caller_iface);
+       if (ret != 0)
+               return ret;
+
+       ret = swap_register_probe_type(SWAP_GET_CALL_TYPE, &get_call_type_iface);
+       return ret;
+}
+
+void unregister_preload_probes(void)
+{
+       swap_unregister_probe_type(SWAP_PRELOAD_PROBE);
+       swap_unregister_probe_type(SWAP_GET_CALLER);
+       swap_unregister_probe_type(SWAP_GET_CALL_TYPE);
+}
diff --git a/preload/preload_probe.h b/preload/preload_probe.h
new file mode 100644 (file)
index 0000000..7b7a32a
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ *  SWAP uprobe manager
+ *  modules/us_manager/probes/preload_probe.h
+ *
+ * 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, 2014
+ *
+ * 2014         Alexander Aksenov: FBI implement
+ *
+ */
+
+#ifndef __PRELOAD_PROBE_H__
+#define __PRELOAD_PROBE_H__
+
+/* Probe type, specifies when probe should be ran. */
+enum preload_probe_type_t {
+       SWAP_PRELOAD_INTERNAL_CALL = 0,     /* Run probe only when it is called from
+                                              target binaries. */
+       SWAP_PRELOAD_ALWAYS = 1,            /* Run probe always. */
+       SWAP_PRELOAD_DISABLE_HANDLING = 2   /* Disable handlers execution. */
+};
+
+/* Preload probe info. */
+struct preload_info {
+       unsigned long handler;              /* Handler offset in probe library. */
+       enum preload_probe_type_t type;     /* Preload probe type. */
+};
+
+/* Get caller probe info */
+struct get_caller_info {
+};
+
+/* Get call type probe info */
+struct get_call_type_info {
+};
+
+int register_preload_probes(void);
+void unregister_preload_probes(void);
+
+#endif /* __URETPROBE_H__ */
diff --git a/preload/preload_storage.c b/preload/preload_storage.c
new file mode 100644 (file)
index 0000000..c19853b
--- /dev/null
@@ -0,0 +1,165 @@
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <ks_features/ks_map.h>
+#include <linux/fs.h>
+#include "preload.h"
+#include "preload_module.h"
+#include "preload_storage.h"
+
+static struct bin_info __handlers_info = { NULL, NULL };
+static struct bin_info __linker_info = { NULL, NULL };
+
+static inline struct bin_info *__get_handlers_info(void)
+{
+       return &__handlers_info;
+}
+
+static inline bool __check_handlers_info(void)
+{
+       return (__handlers_info.dentry != NULL); /* TODO */
+}
+
+static inline int __init_handlers_info(char *path)
+{
+       struct dentry *dentry;
+       size_t len = strnlen(path, PATH_MAX);
+       int ret = 0;
+
+       __handlers_info.path = kmalloc(len + 1, GFP_KERNEL);
+       if (__handlers_info.path == NULL) {
+               ret = -ENOMEM;
+               goto init_handlers_fail;
+       }
+
+       dentry = get_dentry(path);
+       if (!dentry) {
+               ret = -ENOENT;
+               goto init_handlers_fail_free;
+       }
+
+       strncpy(__handlers_info.path, path, len);
+       __handlers_info.path[len] = '\0';
+       __handlers_info.dentry = dentry;
+
+       return ret;
+
+init_handlers_fail_free:
+       kfree(__handlers_info.path);
+
+init_handlers_fail:
+       return ret;
+}
+
+static inline void __drop_handlers_info(void)
+{
+       __handlers_info.path = NULL;
+       if (__handlers_info.dentry)
+               put_dentry(__handlers_info.dentry);
+       __handlers_info.dentry = NULL;
+       kfree(__handlers_info.path);
+}
+
+static inline struct bin_info *__get_linker_info(void)
+{
+       return &__linker_info;
+}
+
+static inline bool __check_linker_info(void)
+{
+       return (__linker_info.dentry != NULL); /* TODO */
+}
+
+static inline int __init_linker_info(char *path)
+{
+       struct dentry *dentry;
+       size_t len = strnlen(path, PATH_MAX);
+       int ret = 0;
+
+
+       __linker_info.path = kmalloc(len + 1, GFP_KERNEL);
+       if (__linker_info.path == NULL) {
+               ret = -ENOMEM;
+               goto init_linker_fail;
+       }
+
+       dentry = get_dentry(path);
+       if (!dentry) {
+               ret = -ENOENT;
+               goto init_linker_fail_free;
+       }
+
+       strncpy(__linker_info.path, path, len);
+       __linker_info.path[len] = '\0';
+       __linker_info.dentry = dentry;
+
+       return ret;
+
+init_linker_fail_free:
+       kfree(__linker_info.path);
+
+init_linker_fail:
+
+       return ret;
+}
+
+static inline void __drop_linker_info(void)
+{
+       __linker_info.path = NULL;
+       if (__linker_info.dentry)
+               put_dentry(__linker_info.dentry);
+       __linker_info.dentry = NULL;
+       kfree(__linker_info.path);
+}
+
+
+
+
+int preload_storage_set_handlers_info(char *path)
+{
+       return __init_handlers_info(path);
+}
+
+struct bin_info *preload_storage_get_handlers_info(void)
+{
+       struct bin_info *info = __get_handlers_info();
+
+       if (__check_handlers_info())
+               return info;
+
+       return NULL;
+}
+
+void preload_storage_put_handlers_info(struct bin_info *info)
+{
+}
+
+int preload_storage_set_linker_info(char *path)
+{
+       return __init_linker_info(path);
+}
+
+struct bin_info *preload_storage_get_linker_info(void)
+{
+       struct bin_info *info = __get_linker_info();
+
+       if (__check_linker_info())
+               return info;
+
+       return NULL;
+}
+
+void preload_storage_put_linker_info(struct bin_info *info)
+{
+}
+
+int preload_storage_init(void)
+{
+       return 0;
+}
+
+void preload_storage_exit(void)
+{
+       __drop_handlers_info();
+       __drop_linker_info();
+}
diff --git a/preload/preload_storage.h b/preload/preload_storage.h
new file mode 100644 (file)
index 0000000..86c7919
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef __PRELOAD_STORAGE_H__
+#define __PRELOAD_STORAGE_H__
+
+struct bin_info {
+       char *path;
+       /* ghot */
+       struct dentry *dentry;
+};
+
+int preload_storage_set_handlers_info(char *path);
+struct bin_info *preload_storage_get_handlers_info(void);
+void preload_storage_put_handlers_info(struct bin_info *info);
+
+int preload_storage_set_linker_info(char *path);
+struct bin_info *preload_storage_get_linker_info(void);
+void preload_storage_put_linker_info(struct bin_info *info);
+
+int preload_storage_init(void);
+void preload_storage_exit(void);
+
+#endif /* __PRELOAD_HANDLERS_H__ */
diff --git a/preload/preload_threads.c b/preload/preload_threads.c
new file mode 100644 (file)
index 0000000..e6b706d
--- /dev/null
@@ -0,0 +1,362 @@
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/list.h>
+#include "preload.h"
+#include "preload_threads.h"
+#include "preload_debugfs.h"
+#include "preload_patcher.h"
+#include "preload_pd.h"
+
+enum {
+       DEFAULT_SLOTS_CNT = 10,
+};
+
+struct thread_slot {
+       struct list_head list;
+       struct task_struct *task;
+       struct list_head disabled_addrs;          /* No use for spinlock - called only
+                                                in one thread */
+       unsigned long caller;
+       unsigned char call_type;
+};
+
+struct disabled_addr {
+       struct list_head list;
+       unsigned long addr;
+};
+
+static LIST_HEAD(thread_slot_list);
+static spinlock_t slock;
+static unsigned long sflags;
+
+
+static inline void __lock_init(void)
+{
+       spin_lock_init(&slock);
+}
+
+static inline void __lock(void)
+{
+       spin_lock_irqsave(&slock, sflags);
+}
+
+static inline void __unlock(void)
+{
+       spin_unlock_irqrestore(&slock, sflags);
+}
+
+
+
+/* Checks slot for task */
+static inline bool __is_slot_for_task(struct thread_slot *slot,
+                                     struct task_struct *task)
+{
+       if (slot->task == task)
+               return true;
+
+       return false;
+}
+
+/* Checks slot if it is free */
+static inline bool __is_slot_free(struct thread_slot *slot)
+{
+       if (slot->task == NULL)
+               return true;
+
+       return false;
+}
+
+static inline bool __is_addr_found(struct disabled_addr *da,
+                                  unsigned long addr)
+{
+       if (da->addr == addr)
+               return true;
+
+       return false;
+}
+
+static inline void __remove_from_disable_list(struct disabled_addr *da)
+{
+       list_del(&da->list);
+       kfree(da);
+}
+
+static inline void __remove_whole_disable_list(struct thread_slot *slot)
+{
+       struct disabled_addr *da, *n;
+
+       list_for_each_entry_safe(da, n, &slot->disabled_addrs, list)
+               __remove_from_disable_list(da);
+}
+
+static inline void __init_slot(struct thread_slot *slot)
+{
+       slot->task = NULL;
+       slot->caller = 0;
+       slot->call_type = 0;
+       INIT_LIST_HEAD(&slot->disabled_addrs);
+}
+
+static inline void __reinit_slot(struct thread_slot *slot)
+{
+       __remove_whole_disable_list(slot);
+       __init_slot(slot);
+}
+
+static inline void __set_slot(struct thread_slot *slot,
+                             struct task_struct *task, unsigned long caller,
+                             unsigned char call_type)
+{
+       slot->task = task;
+       slot->caller = caller;
+       slot->call_type = call_type;
+}
+
+static inline int __add_to_disable_list(struct thread_slot *slot,
+                                       unsigned long disable_addr)
+{
+       struct disabled_addr *da = kmalloc(sizeof(*da), GFP_KERNEL);
+
+       if (da == NULL)
+               return -ENOMEM;
+
+       INIT_LIST_HEAD(&da->list);
+       da->addr = disable_addr;
+       list_add_tail(&da->list, &slot->disabled_addrs);
+
+       return 0;
+}
+
+static inline struct disabled_addr *__find_disabled_addr(struct thread_slot *slot,
+                                                        unsigned long addr)
+{
+       struct disabled_addr *da;
+
+       list_for_each_entry(da, &slot->disabled_addrs, list)
+               if (__is_addr_found(da, addr))
+                       return da;
+
+       return NULL;
+}
+
+/* Adds a new slot */
+static inline struct thread_slot *__grow_slot(void)
+{
+       struct thread_slot *tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
+
+       if (tmp == NULL)
+               return NULL;
+
+       INIT_LIST_HEAD(&tmp->list);
+       __init_slot(tmp);
+       list_add_tail(&tmp->list, &thread_slot_list);
+
+       return tmp;
+}
+
+/* Free slot */
+static void __clean_slot(struct thread_slot *slot)
+{
+       list_del(&slot->list);
+       kfree(slot);
+}
+
+/* Free all slots. This and all the previous slot functions should be called
+   in locks. */
+static void __clean_all(void)
+{
+       struct thread_slot *slot, *n;
+
+       list_for_each_entry_safe(slot, n, &thread_slot_list, list)
+               __clean_slot(slot);
+}
+
+static inline struct thread_slot *__get_task_slot(struct task_struct *task)
+{
+       struct thread_slot *slot;
+
+       list_for_each_entry(slot, &thread_slot_list, list)
+               if (__is_slot_for_task(slot, task))
+                       return slot;
+
+       return NULL;
+}
+
+
+
+
+int preload_threads_set_data(struct task_struct *task, unsigned long caller,
+                            unsigned char call_type, unsigned long disable_addr)
+{
+       struct thread_slot *slot;
+       int ret = 0;
+
+       __lock();
+
+       list_for_each_entry(slot, &thread_slot_list, list) {
+               if (__is_slot_free(slot)) {
+                       __set_slot(slot, task, caller, call_type);
+                       if ((disable_addr != 0) && 
+                           (__add_to_disable_list(slot, disable_addr) != 0)) {
+                               printk(PRELOAD_PREFIX "Cannot alloc memory!\n");
+                               ret = -ENOMEM;
+                       }
+                       goto set_data_done;
+               }
+       }
+
+       /* If there is no empty slots - grow */
+       slot = __grow_slot();
+       if (slot == NULL) {
+               ret = -ENOMEM;
+               goto set_data_done;
+       }
+
+       __set_slot(slot, task, caller, call_type);
+
+set_data_done:
+       __unlock();
+
+       return ret;
+}
+
+int preload_threads_get_caller(struct task_struct *task, unsigned long *caller)
+{
+       struct thread_slot *slot;
+       int ret = 0;
+
+       __lock();
+
+       slot = __get_task_slot(task);
+       if (slot != NULL) {
+                       *caller = slot->caller;
+                       goto get_caller_done;
+       }
+
+       /* If we're here - slot was not found */
+       ret = -EINVAL;
+
+get_caller_done:
+       __unlock();
+
+       return ret;
+}
+
+int preload_threads_get_call_type(struct task_struct *task,
+                                 unsigned char *call_type)
+{
+       struct thread_slot *slot;
+       int ret = 0;
+
+       __lock();
+
+       slot = __get_task_slot(task);
+       if (slot != NULL) {
+               *call_type = slot->call_type;
+               goto get_call_type_done;
+       }
+
+       /* If we're here - slot was not found */
+       ret = -EINVAL;
+
+get_call_type_done:
+       __unlock();
+
+       return ret;
+}
+
+bool preload_threads_check_disabled_probe(struct task_struct *task,
+                                         unsigned long addr)
+{
+       struct thread_slot *slot;
+       bool ret = false;
+
+       __lock();
+
+       slot = __get_task_slot(task);
+       if (slot != NULL)
+               ret = __find_disabled_addr(slot, addr) == NULL ? false : true;
+
+       __unlock();
+
+       return ret;
+}
+
+void preload_threads_enable_probe(struct task_struct *task, unsigned long addr)
+{
+       struct thread_slot *slot;
+       struct disabled_addr *da;
+
+       __lock();
+
+       slot = __get_task_slot(task);
+       if (slot == NULL) {
+               printk(PRELOAD_PREFIX "Error! Slot not found!\n");
+               goto enable_probe_failed;
+       }
+
+       da = __find_disabled_addr(slot, addr);
+       if (da != NULL)
+               __remove_from_disable_list(da);
+
+enable_probe_failed:
+
+       __unlock();
+}
+
+int preload_threads_put_data(struct task_struct *task)
+{
+       struct thread_slot *slot;
+       int ret = 0;
+
+       __lock();
+
+       slot = __get_task_slot(task);
+       if (slot != NULL) {
+               __reinit_slot(slot);
+               goto put_data_done;
+       }
+
+put_data_done:
+       __unlock();
+
+       return ret;
+}
+
+/* Allocates slots */
+int preload_threads_init(void)
+{
+       int i, ret = 0;
+
+       __lock_init();
+
+       __lock();
+
+       for (i = 0; i < DEFAULT_SLOTS_CNT; i++) {
+               if (__grow_slot() == NULL) {
+                       ret = -ENOMEM;
+                       goto init_failed;
+               }
+       }
+
+       __unlock();
+
+       return 0;
+
+init_failed:
+
+       __clean_all();
+       __unlock();
+
+       return ret;
+}
+
+/* Cleans slots */
+void preload_threads_exit(void)
+{
+       __lock();
+       __clean_all();
+       __unlock();
+}
diff --git a/preload/preload_threads.h b/preload/preload_threads.h
new file mode 100644 (file)
index 0000000..8d28c56
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef __PRELOAD_THREADS_H__
+#define __PRELOAD_THREADS_H__
+
+struct task_struct;
+
+int preload_threads_set_data(struct task_struct *task, unsigned long caller,
+                            unsigned char call_type, unsigned long disable_addr);
+int preload_threads_get_caller(struct task_struct *task, unsigned long *caller);
+int preload_threads_get_call_type(struct task_struct *task,
+                                 unsigned char *call_type);
+bool preload_threads_check_disabled_probe(struct task_struct *task,
+                                         unsigned long addr);
+void preload_threads_enable_probe(struct task_struct *task, unsigned long addr);
+int preload_threads_put_data(struct task_struct *task);
+int preload_threads_init(void);
+void preload_threads_exit(void);
+
+#endif /* __PRELOAD_THREADS_H__ */
index d83f1cb..13c3c4f 100644 (file)
@@ -28,6 +28,7 @@
 
 #include <linux/types.h>
 
+#include <preload/preload_probe.h>   /* TODO Remove */
 #include <retprobe/retprobe.h>       /* TODO Remove */
 
 
  */
 enum probe_t {
        SWAP_RETPROBE = 0,          /* Retprobe */
+       SWAP_PRELOAD_PROBE = 2,     /* Preload probe */
        SWAP_WEBPROBE = 3,          /* Webprobe */
+       SWAP_GET_CALLER = 4,        /* Get caller probe. Supports preload */
+       SWAP_GET_CALL_TYPE = 5,     /* Get call type probe. Supports preload */
        SWAP_PROBE_MAX_VAL          /* Probes max value. */
 };
 
@@ -48,6 +52,9 @@ struct probe_info {
        /* Union of all SWAP supported probe types */
        union {
                struct retprobe_info rp_i;
+               struct preload_info pl_i;
+               struct get_caller_info gc_i;
+               struct get_call_type_info gct_i;
        };
 };