GOT patcher: make common code general
authorAlexander Aksenov <a.aksenov@samsung.com>
Wed, 9 Nov 2016 09:36:18 +0000 (12:36 +0300)
committerAlexander Aksenov <a.aksenov@samsung.com>
Wed, 9 Nov 2016 13:35:15 +0000 (16:35 +0300)
Change-Id: I3d9f62333b0201d22f7f79608104923b0a1dcd8b
Signed-off-by: Alexander Aksenov <a.aksenov@samsung.com>
got_patcher/gt_debugfs.c
got_patcher/gt_module.c

index e114ea2..415f9d9 100644 (file)
@@ -31,103 +31,130 @@ static const char GT_MINIMAL_INIT[] = "minimal_init_off";
 static struct dentry *gt_root;
 
 
-/* ===========================================================================
- * =                              TARGETS                                    =
- * ===========================================================================
- */
+/* Type for function that handles string grabbed from userspace */
+typedef int (*sh_t)(char *);
 
-static ssize_t handler_path_write(struct file *file, const char __user *buf,
-                                 size_t len, loff_t *ppos)
+/* Type for function that handles unsigned long grabbed from userspace */
+typedef int (*ulh_t)(unsigned long);
+
+/* Type for function that handles pid grabbed from userspace */
+typedef int (*ph_t)(pid_t);
+
+
+static ssize_t get_string_and_call(const char __user *buf, size_t len,
+                                  sh_t cb)
 {
+       char *string;
        ssize_t ret;
-       char *path;
 
-       path = kmalloc(len, GFP_KERNEL);
-       if (path == NULL) {
+       string = kmalloc(len, GFP_KERNEL);
+       if (string == NULL) {
                ret = -ENOMEM;
-               goto handler_path_write_out;
+               goto get_string_write_out;
        }
 
-       if (copy_from_user(path, buf, len)) {
+       if (copy_from_user(string, buf, len)) {
                ret = -EINVAL;
-               goto handler_path_write_out;
+               goto get_string_write_out;
        }
 
-       path[len - 1] = '\0';
-       ret = gtm_set_handler_path(path);
+       string[len - 1] = '\0';
+
+       ret = cb(string);
 
-handler_path_write_out:
-       kfree(path);
+get_string_write_out:
+       kfree(string);
 
        return ret == 0 ? len : ret;
 }
 
-static ssize_t handler_fixup_off_write(struct file *file,
-                                      const char __user *buf, size_t len,
-                                      loff_t *ppos)
+static ssize_t get_ul_and_call(const char __user *buf, size_t len, ulh_t cb)
 {
        ssize_t ret;
-       char *off;
-       unsigned long offset;
+       char *ulstring;
+       unsigned long ul;
 
-       off = kmalloc(len, GFP_KERNEL);
-       if (off == NULL) {
+       ulstring = kmalloc(len, GFP_KERNEL);
+       if (ulstring == NULL) {
                ret = -ENOMEM;
-               goto handler_fixup_off_write_out;
+               goto get_ul_write_out;
        }
 
-       if (copy_from_user(off, buf, len)) {
+       if (copy_from_user(ulstring, buf, len)) {
                ret = -EINVAL;
-               goto handler_fixup_off_write_out;
+               goto get_ul_write_out;
        }
 
-       off[len - 1] = '\0';
+       ulstring[len - 1] = '\0';
 
-       ret = kstrtoul(off, 16, &offset);
+       ret = kstrtoul(ulstring, 16, &ul);
        if (ret != 0)
-               goto handler_fixup_off_write_out;
+               goto get_ul_write_out;
 
-       ret = gtm_set_handler_fixup_off(offset);
+       ret = cb(ul);
 
-handler_fixup_off_write_out:
-       kfree(off);
+get_ul_write_out:
+       kfree(ulstring);
 
        return ret == 0 ? len : ret;
 }
 
-static ssize_t handler_reloc_off_write(struct file *file,
-                                      const char __user *buf, size_t len,
-                                      loff_t *ppos)
+static ssize_t get_pid_and_call(const char __user *buf, size_t len, ph_t cb)
 {
        ssize_t ret;
-       char *off;
-       unsigned long offset;
+       char *pidstring;
+       pid_t pid;
 
-       off = kmalloc(len, GFP_KERNEL);
-       if (off == NULL) {
+       pidstring = kmalloc(len, GFP_KERNEL);
+       if (pidstring == NULL) {
                ret = -ENOMEM;
-               goto handler_reloc_off_write_out;
+               goto get_pid_write_out;
        }
 
-       if (copy_from_user(off, buf, len)) {
+       if (copy_from_user(pidstring, buf, len)) {
                ret = -EINVAL;
-               goto handler_reloc_off_write_out;
+               goto get_pid_write_out;
        }
 
-       off[len - 1] = '\0';
+       pidstring[len - 1] = '\0';
 
-       ret = kstrtoul(off, 16, &offset);
+       ret = kstrtoul(pidstring, 10, (unsigned long *)&pid);
        if (ret != 0)
-               goto handler_reloc_off_write_out;
+               goto get_pid_write_out;
 
-       ret = gtm_set_handler_reloc_off(offset);
+       ret = cb(pid);
 
-handler_reloc_off_write_out:
-       kfree(off);
+get_pid_write_out:
+       kfree(pidstring);
 
        return ret == 0 ? len : ret;
 }
 
+/* ===========================================================================
+ * =                              TARGETS                                    =
+ * ===========================================================================
+ */
+
+static ssize_t handler_path_write(struct file *file, const char __user *buf,
+                                 size_t len, loff_t *ppos)
+{
+       return get_string_and_call(buf, len, gtm_set_handler_path);
+}
+
+static ssize_t handler_fixup_off_write(struct file *file,
+                                      const char __user *buf, size_t len,
+                                      loff_t *ppos)
+{
+       return get_ul_and_call(buf, len, gtm_set_handler_fixup_off);
+}
+
+static ssize_t handler_reloc_off_write(struct file *file,
+                                      const char __user *buf, size_t len,
+                                      loff_t *ppos)
+{
+       return get_ul_and_call(buf, len, gtm_set_handler_reloc_off);
+}
+
 static const struct file_operations handler_path_fops = {
        .owner = THIS_MODULE,
        .write = handler_path_write,
@@ -151,117 +178,25 @@ static const struct file_operations handler_reloc_off_fops = {
 static ssize_t by_path_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 target_path_add_write_out;
-       }
-
-       if (copy_from_user(path, buf, len)) {
-               ret = -EINVAL;
-               goto target_path_add_write_out;
-       }
-
-       path[len - 1] = '\0';
-       ret = gtm_add_by_path(path);
-
-target_path_add_write_out:
-       kfree(path);
-
-       return ret == 0 ? len : ret;
+       return get_string_and_call(buf, len, gtm_add_by_path);
 }
 
 static ssize_t by_path_del_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 target_path_del_write_out;
-       }
-
-       if (copy_from_user(path, buf, len)) {
-               ret = -EINVAL;
-               goto target_path_del_write_out;
-       }
-
-       path[len - 1] = '\0';
-       ret = gtm_del_by_path(path);
-
-target_path_del_write_out:
-       kfree(path);
-
-       return ret == 0 ? len : ret;
+       return get_string_and_call(buf, len, gtm_del_by_path);
 }
 
 static ssize_t by_pid_add_write(struct file *file, const char __user *buf,
                                size_t len, loff_t *ppos)
 {
-       ssize_t ret;
-       unsigned long pid;
-       char *pid_str;
-
-       pid_str = kmalloc(len, GFP_KERNEL);
-       if (pid_str == NULL) {
-               ret = -ENOMEM;
-               goto target_pid_add_write_out;
-       }
-
-       if (copy_from_user(pid_str, buf, len)) {
-               ret = -EINVAL;
-               goto target_pid_add_write_out;
-       }
-
-       pid_str[len - 1] = '\0';
-
-       ret = kstrtoul(pid_str, 10, &pid);
-       if (ret != 0)
-               goto target_pid_add_write_out;
-
-       ret = gtm_add_by_pid(pid);
-
-target_pid_add_write_out:
-       kfree(pid_str);
-
-       return ret == 0 ? len : ret;
+       return get_pid_and_call(buf, len, gtm_add_by_pid);
 }
 
 static ssize_t by_pid_del_write(struct file *file, const char __user *buf,
                                size_t len, loff_t *ppos)
 {
-       ssize_t ret;
-       unsigned long pid;
-       char *pid_str;
-
-       pid_str = kmalloc(len, GFP_KERNEL);
-       if (pid_str == NULL) {
-               ret = -ENOMEM;
-               goto target_pid_del_write_out;
-       }
-
-       if (copy_from_user(pid_str, buf, len)) {
-               ret = -EINVAL;
-               goto target_pid_del_write_out;
-       }
-
-       pid_str[len - 1] = '\0';
-
-       ret = kstrtoul(pid_str, 10, &pid);
-       if (ret != 0)
-               goto target_pid_del_write_out;
-
-       ret = gtm_del_by_pid(pid);
-
-target_pid_del_write_out:
-       kfree(pid_str);
-
-       return ret == 0 ? len : ret;
+       return get_pid_and_call(buf, len, gtm_del_by_pid);
 }
 
 static ssize_t del_all_write(struct file *file, const char __user *buf,
@@ -378,92 +313,19 @@ static const struct file_operations enable_fops = {
 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';
-
-       ret = gtm_set_linker_path(path);
-
-linker_path_write_out:
-       kfree(path);
-
-       return ret == 0 ? len : ret;
+       return get_string_and_call(buf, len, gtm_set_linker_path);
 }
 
 static ssize_t fixup_off_write(struct file *file, const char __user *buf,
                               size_t len, loff_t *ppos)
 {
-       ssize_t ret;
-       char *off;
-       unsigned long offset;
-
-       off = kmalloc(len, GFP_KERNEL);
-       if (off == NULL) {
-               ret = -ENOMEM;
-               goto fixup_off_write_out;
-       }
-
-       if (copy_from_user(off, buf, len)) {
-               ret = -EINVAL;
-               goto fixup_off_write_out;
-       }
-
-       off[len - 1] = '\0';
-
-       ret = kstrtoul(off, 16, &offset);
-       if (ret != 0)
-               goto fixup_off_write_out;
-
-       ret = gtm_set_fixup_off(offset);
-
-fixup_off_write_out:
-       kfree(off);
-
-       return ret == 0 ? len : ret;
+       return get_ul_and_call(buf, len, gtm_set_fixup_off);
 }
 
 static ssize_t reloc_off_write(struct file *file, const char __user *buf,
                               size_t len, loff_t *ppos)
 {
-       ssize_t ret;
-       char *off;
-       unsigned long offset;
-
-       off = kmalloc(len, GFP_KERNEL);
-       if (off == NULL) {
-               ret = -ENOMEM;
-               goto reloc_off_write_out;
-       }
-
-       if (copy_from_user(off, buf, len)) {
-               ret = -EINVAL;
-               goto reloc_off_write_out;
-       }
-
-       off[len - 1] = '\0';
-
-       ret = kstrtoul(off, 16, &offset);
-       if (ret != 0)
-               goto reloc_off_write_out;
-
-       ret = gtm_set_reloc_off(offset);
-
-reloc_off_write_out:
-       kfree(off);
-
-       return ret == 0 ? len : ret;
+       return get_ul_and_call(buf, len, gtm_set_reloc_off);
 }
 
 static const struct file_operations linker_path_fops = {
@@ -491,62 +353,13 @@ static const struct file_operations reloc_off_fops = {
 static ssize_t pthread_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 pthread_path_write_out;
-       }
-
-       if (copy_from_user(path, buf, len)) {
-               ret = -EINVAL;
-               goto pthread_path_write_out;
-       }
-
-       path[len - 1] = '\0';
-
-       ret = gtm_set_pthread_path(path);
-
-pthread_path_write_out:
-       kfree(path);
-
-       return ret == 0 ? len : ret;
+       return get_string_and_call(buf, len, gtm_set_pthread_path);
 }
 
 static ssize_t init_off_write(struct file *file, const char __user *buf,
                              size_t len, loff_t *ppos)
 {
-       ssize_t ret;
-       char *off;
-       unsigned long offset;
-
-       off = kmalloc(len, GFP_KERNEL);
-       if (off == NULL) {
-               ret = -ENOMEM;
-               goto init_off_write_out;
-       }
-
-       if (copy_from_user(off, buf, len)) {
-               ret = -EINVAL;
-               goto init_off_write_out;
-       }
-
-       off[len - 1] = '\0';
-
-       ret = kstrtoul(off, 16, &offset);
-       if (ret != 0) {
-               ret = -EINVAL;
-               goto init_off_write_out;
-       }
-
-       ret = gtm_set_init_off(offset);
-
-init_off_write_out:
-       kfree(off);
-
-       return ret == 0 ? len : ret;
+       return get_ul_and_call(buf, len, gtm_set_init_off);
 }
 
 static const struct file_operations pthread_path_fops = {
index f737499..194beba 100644 (file)
@@ -42,6 +42,9 @@ struct bin_data_t {
 typedef unsigned long (*rh_t)(struct uretprobe_instance *, struct pt_regs *,
                              struct hd_t *);
 
+/* Typedef for compare function that removes data from list */
+typedef bool (*cf_t)(struct l_probe_el*, void *);
+
 static LIST_HEAD(_reg_probes);
 static LIST_HEAD(_unreg_probes);
 static DEFINE_MUTEX(_linker_probes_lock);
@@ -152,6 +155,33 @@ static inline void _set_in_handler(bool is_in_handler)
        *(bool *)swap_ktd(&gt_ktd, current) = is_in_handler;
 }
 
+static inline bool _check_by_dentry(struct l_probe_el *l_probe, void *data)
+{
+       struct dentry *dentry = (struct dentry *)data;
+
+       if (l_probe->task_id == GT_SET_BY_DENTRY &&
+           l_probe->dentry == dentry)
+               return true;
+
+       return false;
+}
+
+static inline bool _check_by_pid(struct l_probe_el *l_probe, void *data)
+{
+       pid_t tgid = *(pid_t *)data;
+
+       if (l_probe->task_id == GT_SET_BY_PID &&
+           l_probe->tgid == tgid)
+               return true;
+
+       return false;
+}
+
+static inline bool _del_all(struct l_probe_el *l_probe, void *data)
+{
+       return true;
+}
+
 /* ===========================================================================
  * =                            LINKER HANDLERS                              =
  * ===========================================================================
@@ -614,6 +644,56 @@ static char *_add_separator(char *dest)
        return (dest + 1);
 }
 
+static int _add_to_list(struct l_probe_el *l_probe)
+{
+       int ret = 0;
+
+       _lock_probes_list();
+       if (_is_enable()) {
+               ret = _register_probe_el_no_lock(l_probe);
+               if (ret == 0)
+                       list_add_tail(&l_probe->list, &_reg_probes);
+       } else {
+               list_add_tail(&l_probe->list, &_unreg_probes);
+       }
+
+       _unlock_probes_list();
+
+       return ret;
+}
+
+static int _remove_from_list(cf_t cb, void *data)
+{
+       struct l_probe_el *l_probe, *n;
+       int ret = 0;
+
+       _lock_probes_list();
+
+       list_for_each_entry_safe(l_probe, n, &_reg_probes, list) {
+               if (cb(l_probe, data)) {
+                       ret = _unregister_probe_el_no_lock(l_probe);
+                       if (ret == 0) {
+                               list_del(&l_probe->list);
+                               _destroy_linker_probe_el_no_lock(l_probe);
+                       }
+                       goto remove_from_list_unlock;
+               }
+       }
+
+       list_for_each_entry_safe(l_probe, n, &_unreg_probes, list) {
+               if (cb(l_probe, data)) {
+                       list_del(&l_probe->list);
+                       _destroy_linker_probe_el_no_lock(l_probe);
+                       goto remove_from_list_unlock;
+               }
+       }
+
+remove_from_list_unlock:
+       _unlock_probes_list();
+
+       return ret;
+}
+
 
 
 
@@ -704,22 +784,13 @@ int gtm_add_by_path(char *path)
        l_probe->task_id = GT_SET_BY_DENTRY;
        l_probe->dentry = dentry;
 
-       _lock_probes_list();
-       if (_is_enable()) {
-               ret = _register_probe_el_no_lock(l_probe);
-               if (ret == 0)
-                       list_add_tail(&l_probe->list, &_reg_probes);
-               else
-                       goto add_by_path_unlock;
-       } else {
-               list_add_tail(&l_probe->list, &_unreg_probes);
-       }
-       _unlock_probes_list();
+       ret = _add_to_list(l_probe);
+       if (ret != 0)
+               goto add_by_path_free;
 
        return 0;
 
-add_by_path_unlock:
-       _unlock_probes_list();
+add_by_path_free:
        kfree(l_probe);
 
 add_by_path_put_pfg:
@@ -752,22 +823,13 @@ int gtm_add_by_pid(pid_t pid)
        l_probe->task_id = GT_SET_BY_PID;
        l_probe->tgid = pid;
 
-       _lock_probes_list();
-       if (_is_enable()) {
-               ret = _register_probe_el_no_lock(l_probe);
-               if (ret == 0)
-                       list_add_tail(&l_probe->list, &_reg_probes);
-               else
-                       goto add_by_pid_unlock;
-       } else {
-               list_add_tail(&l_probe->list, &_unreg_probes);
-       }
-       _unlock_probes_list();
+       ret = _add_to_list(l_probe);
+       if (ret != 0)
+               goto add_by_pid_free;
 
        return 0;
 
-add_by_pid_unlock:
-       _unlock_probes_list();
+add_by_pid_free:
        kfree(l_probe);
 
 add_by_pid_put_pfg:
@@ -778,7 +840,6 @@ add_by_pid_put_pfg:
 
 int gtm_del_by_path(char *path)
 {
-       struct l_probe_el *l_probe, *n;
        struct dentry *dentry;
        int ret = 0;
 
@@ -786,91 +847,25 @@ int gtm_del_by_path(char *path)
        if (dentry == NULL)
                return -EINVAL;
 
-       _lock_probes_list();
-
-       list_for_each_entry_safe(l_probe, n, &_reg_probes, list) {
-               if (l_probe->task_id == GT_SET_BY_DENTRY &&
-                   l_probe->dentry == dentry) {
-                       ret = _unregister_probe_el_no_lock(l_probe);
-                       if (ret != 0)
-                               goto del_by_path_unlock;
-                       list_del(&l_probe->list);
-                       _destroy_linker_probe_el_no_lock(l_probe);
-                       goto del_by_path_unlock;
-               }
-       }
-
-       list_for_each_entry_safe(l_probe, n, &_unreg_probes, list) {
-               if (l_probe->task_id == GT_SET_BY_DENTRY &&
-                   l_probe->dentry == dentry) {
-                       list_del(&l_probe->list);
-                       _destroy_linker_probe_el_no_lock(l_probe);
-                       goto del_by_path_unlock;
-               }
-       }
-
-del_by_path_unlock:
-       _unlock_probes_list();
+       ret = _remove_from_list(_check_by_dentry, dentry);
 
        return ret;
 }
 
 int gtm_del_by_pid(pid_t pid)
 {
-       struct l_probe_el *l_probe, *n;
        int ret = 0;
 
-       _lock_probes_list();
-
-       list_for_each_entry_safe(l_probe, n, &_reg_probes, list) {
-               if (l_probe->task_id == GT_SET_BY_PID &&
-                   l_probe->tgid == pid) {
-                       ret = _unregister_probe_el_no_lock(l_probe);
-                       if (ret != 0)
-                               goto del_by_pid_unlock;
-                       list_del(&l_probe->list);
-                       _destroy_linker_probe_el_no_lock(l_probe);
-                       goto del_by_pid_unlock;
-               }
-       }
-
-       list_for_each_entry_safe(l_probe, n, &_unreg_probes, list) {
-               if (l_probe->task_id == GT_SET_BY_PID &&
-                   l_probe->tgid == pid) {
-                       list_del(&l_probe->list);
-                       _destroy_linker_probe_el_no_lock(l_probe);
-                       goto del_by_pid_unlock;
-               }
-       }
-
-del_by_pid_unlock:
-       _unlock_probes_list();
+       ret = _remove_from_list(_check_by_pid, &pid);
 
        return ret;
 }
 
 int gtm_del_all(void)
 {
-       struct l_probe_el *l_probe, *n;
        int ret = 0;
 
-       _lock_probes_list();
-
-       list_for_each_entry_safe(l_probe, n, &_reg_probes, list) {
-               ret = _unregister_probe_el_no_lock(l_probe);
-               if (ret != 0)
-                       goto del_all_fail;
-               list_del(&l_probe->list);
-               _destroy_linker_probe_el_no_lock(l_probe);
-       }
-
-       list_for_each_entry_safe(l_probe, n, &_unreg_probes, list) {
-               list_del(&l_probe->list);
-               _destroy_linker_probe_el_no_lock(l_probe);
-       }
-
-del_all_fail:
-       _unlock_probes_list();
+       ret = _remove_from_list(_del_all, NULL);
 
        return ret;
 }