EXTRA_CFLAGS := $(extra_cflags)
obj-m := swap_webprobe.o
-swap_webprobe-y := webprobe.o
+swap_webprobe-y := webprobe.o \
+ webprobe_debugfs.o \
+ webprobe_prof.o
#include <us_manager/us_manager.h>
#include <us_manager/sspt/ip.h>
#include <us_manager/probes/register_probes.h>
+#include <us_manager/sspt/sspt.h>
#include <writer/swap_writer_module.h>
#include <uprobe/swap_uprobes.h>
#include <parser/msg_cmd.h>
#include <linux/module.h>
#include <linux/slab.h>
+#include <master/swap_initializer.h>
+
+#include "webprobe_debugfs.h"
+#include "webprobe_prof.h"
+
+
+static unsigned long inspserver_addr_local;
+static unsigned long willexecute_addr_local;
+static unsigned long didexecute_addr_local;
static int webprobe_copy(struct probe_info *dest,
const struct probe_info *source)
static void webprobe_unregister_probe(struct us_ip *ip, int disarm)
{
+ if (ip->orig_addr == inspserver_addr_local)
+ web_func_inst_remove(web_prof_addr(INSPSERVER_START));
+ else if (ip->orig_addr == willexecute_addr_local)
+ web_func_inst_remove(web_prof_addr(WILL_EXECUTE));
+ else if (ip->orig_addr == didexecute_addr_local)
+ web_func_inst_remove(web_prof_addr(DID_EXECUTE));
+
__swap_unregister_uretprobe(&ip->retprobe, disarm);
}
-static int entry_web_handler(struct uretprobe_instance *ri, struct pt_regs *regs)
+static int web_entry_handler(struct uretprobe_instance *ri,
+ struct pt_regs *regs)
{
struct uretprobe *rp = ri->rp;
-
- if (rp && get_quiet() == QT_OFF) {
- struct us_ip *ip = container_of(rp, struct us_ip, retprobe);
- unsigned long addr = (unsigned long)ip->orig_addr;
-
- entry_web_event(addr, regs);
+ struct us_ip *ip;
+ unsigned long vaddr, page_vaddr;
+ struct vm_area_struct *vma;
+
+ if (rp == NULL)
+ return 0;
+
+ ip = container_of(rp, struct us_ip, retprobe);
+ vaddr = (unsigned long)ip->orig_addr;
+ page_vaddr = vaddr & PAGE_MASK;
+
+ vma = find_vma_intersection(current->mm, page_vaddr, page_vaddr + 1);
+ if (vma && check_vma(vma)) {
+ unsigned long addr = vaddr - vma->vm_start;
+ struct dentry *d = vma->vm_file->f_dentry;
+
+ if (addr == web_prof_addr(WILL_EXECUTE) &&
+ d == web_prof_lib_dentry()) {
+ willexecute_addr_local = ip->orig_addr;
+ return entry_web_event(addr, regs);
+ } else if (addr == web_prof_addr(DID_EXECUTE) &&
+ d == web_prof_lib_dentry()) {
+ didexecute_addr_local = ip->orig_addr;
+ return exit_web_event(addr, regs);
+ }
}
return 0;
}
-static int exit_web_handler(struct uretprobe_instance *ri, struct pt_regs *regs)
+
+static int web_ret_handler(struct uretprobe_instance *ri, struct pt_regs *regs)
{
struct uretprobe *rp = ri->rp;
-
- if (rp && get_quiet() == QT_OFF) {
- struct us_ip *ip = container_of(rp, struct us_ip, retprobe);
- unsigned long addr = (unsigned long)ip->orig_addr;
-
- exit_web_event(addr, regs);
+ struct us_ip *ip;
+ unsigned long vaddr, page_vaddr;
+ struct vm_area_struct *vma;
+
+ if (rp == NULL)
+ return 0;
+
+ ip = container_of(rp, struct us_ip, retprobe);
+ vaddr = (unsigned long)ip->orig_addr;
+ page_vaddr = vaddr & PAGE_MASK;
+
+ vma = find_vma_intersection(current->mm, page_vaddr, page_vaddr + 1);
+ if (vma && check_vma(vma)) {
+ unsigned long addr = vaddr - vma->vm_start;
+ struct dentry *d = vma->vm_file->f_dentry;
+
+ if (addr == web_prof_addr(INSPSERVER_START) &&
+ d == web_prof_lib_dentry()) {
+ inspserver_addr_local = ip->orig_addr;
+ set_wrt_launcher_port((int)regs_return_value(regs));
+ }
}
return 0;
}
-static int ret_web_handler(struct uretprobe_instance *ri, struct pt_regs *regs)
-{
- set_wrt_launcher_port((int)regs_return_value(regs));
-
- return 0;
-}
-
static void webprobe_init(struct us_ip *ip)
{
- enum {
- web_func_inspservstart,
- web_func_willexecute,
- web_func_didexecute
- };
- static int fnum = web_func_inspservstart;
-
- /* FIXME: probes can be set more than once */
- switch(fnum) {
- case web_func_inspservstart:
- ip->retprobe.entry_handler = NULL;
- ip->retprobe.handler = ret_web_handler;
- fnum = web_func_willexecute;
- printk("SWAP_WEBPROBE: web function ewk_view_inspector_server_start\n");
- break;
- case web_func_willexecute:
- /* TODO: use uprobe instead of uretprobe */
- ip->retprobe.entry_handler = entry_web_handler;
- ip->retprobe.handler = NULL;
- fnum = web_func_didexecute;
- printk("SWAP_WEBPROBE: web function willExecute\n");
- break;
- case web_func_didexecute:
- /* TODO: use uprobe instead of uretprobe */
- ip->retprobe.entry_handler = exit_web_handler;
- ip->retprobe.handler = NULL;
- fnum = web_func_inspservstart;
- printk("SWAP_WEBPROBE: web function didExecute\n");
- break;
- default:
- printk("SWAP_WEBPROBE: web functions more than necessary\n");
- }
-
+ ip->retprobe.entry_handler = web_entry_handler;
+ ip->retprobe.handler = web_ret_handler;
ip->retprobe.maxactive = 0;
}
.cleanup = webprobe_cleanup
};
-static int __init webprobe_module_init(void)
+static int webprobe_module_init(void)
{
- return swap_register_probe_type(SWAP_WEBPROBE, &webprobe_iface);
+ int ret = 0;
+
+ ret = swap_register_probe_type(SWAP_WEBPROBE, &webprobe_iface);
+ if (ret)
+ pr_err("Cannot register probe type SWAP_WEBPROBE\n");
+
+ return ret;
}
-static void __exit webprobe_module_exit(void)
+static void webprobe_module_exit(void)
{
swap_unregister_probe_type(SWAP_WEBPROBE);
}
-module_init(webprobe_module_init);
-module_exit(webprobe_module_exit);
+SWAP_LIGHT_INIT_MODULE(NULL, webprobe_module_init, webprobe_module_exit,
+ webprobe_debugfs_init, webprobe_debugfs_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("SWAP webprobe");
-MODULE_AUTHOR("Ruslan Soloviev <r.soloviev@samsung.com>");
+MODULE_AUTHOR("Ruslan Soloviev <r.soloviev@samsung.com>"
+ "Anastasia Lyupa <a.lyupa@samsung.com>");
--- /dev/null
+/**
+ * webprobe/webprobe_debugfs.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, 2015
+ *
+ * 2015 Anastasia Lyupa <a.lyupa@samsung.com>
+ *
+ */
+
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/debugfs.h>
+#include <linux/uaccess.h>
+
+#include <master/swap_debugfs.h>
+#include <master/swap_initializer.h>
+
+#include "webprobe_debugfs.h"
+#include "webprobe_prof.h"
+
+static const char ENABLED_FILE[] = "enabled";
+static const char APP_INFO_FILE[] = "app_info";
+static const char INSPSERVER_START_FILE[] = "inspector_server_start";
+static const char WILL_EXECUTE_FILE[] = "will_execute";
+static const char DID_EXECUTE_FILE[] = "did_execute";
+
+enum { max_count = 256 };
+static char app_info[max_count];
+
+/* ============================================================================
+ * === DEBUGFS FOR WEBPROBE INSTRUMENTATION ===
+ * ============================================================================
+ */
+
+static ssize_t read_enabled(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ char buf[2];
+
+ buf[0] = web_prof_enabled() == PROF_ON ? '1' : '0';
+ buf[1] = '\n';
+
+ return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
+}
+
+static ssize_t write_enabled(struct file *file, const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ int ret = 0;
+ char buf[32];
+ size_t buf_size;
+
+ buf_size = min(count, (sizeof(buf) - 1));
+ if (copy_from_user(buf, user_buf, buf_size))
+ return -EFAULT;
+
+ buf[buf_size] = '\0';
+ switch (buf[0]) {
+ case '1':
+ ret = web_prof_enable();
+ break;
+ case '0':
+ ret = web_prof_disable();
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (ret)
+ return ret;
+
+ return count;
+}
+
+static const struct file_operations fops_enabled = {
+ .write = write_enabled,
+ .read = read_enabled,
+ .open = swap_init_simple_open,
+ .release = swap_init_simple_release,
+};
+
+static ssize_t write_app_info(struct file *file, const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ int ret;
+ char *buf, *path, *id;
+ int n;
+
+ if (count > max_count)
+ return -ENOMEM;
+
+ buf = kmalloc(count + 1, GFP_KERNEL);
+ if (buf == NULL)
+ return -ENOMEM;
+
+ if (copy_from_user(buf, user_buf, count)) {
+ ret = -EFAULT;
+ goto free_buf;
+ }
+
+ buf[count] = '\0';
+
+ path = kmalloc(count, GFP_KERNEL);
+ if (path == NULL) {
+ ret = -ENOMEM;
+ goto free_buf;
+ }
+
+ id = kmalloc(count, GFP_KERNEL);
+ if (id == NULL) {
+ ret = -ENOMEM;
+ goto free_path;
+ }
+
+ n = sscanf(buf, "%s %s", path, id);
+
+ if (n != 2) {
+ ret = -EINVAL;
+ goto free_app_info;
+ }
+
+ web_prof_data_set(path, id);
+ sprintf(app_info, "%s\n", buf);
+
+free_app_info:
+ kfree(id);
+free_path:
+ kfree(path);
+free_buf:
+ kfree(buf);
+
+ return ret ? ret : count;
+}
+
+static ssize_t read_app_info(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ return simple_read_from_buffer(userbuf, count, ppos, app_info,
+ sizeof(app_info) - 1);
+}
+
+static const struct file_operations fops_app_info = {
+ .write = write_app_info,
+ .read = read_app_info,
+ .open = swap_init_simple_open,
+ .release = swap_init_simple_release,
+};
+
+
+/* ============================================================================
+ * === INIT/EXIT ===
+ * ============================================================================
+ */
+
+static struct dentry *webprobe_dir;
+
+void webprobe_debugfs_exit(void)
+{
+ web_prof_exit();
+
+ debugfs_remove_recursive(webprobe_dir);
+
+ webprobe_dir = NULL;
+}
+
+int webprobe_debugfs_init(void)
+{
+ struct dentry *dentry;
+
+ if (web_prof_init())
+ goto fail;
+
+ dentry = swap_debugfs_getdir();
+ if (dentry == NULL)
+ return -ENOENT;
+
+ webprobe_dir = debugfs_create_dir("webprobe", dentry);
+ if (webprobe_dir == NULL)
+ return -ENOMEM;
+
+ dentry = debugfs_create_file(ENABLED_FILE, 0600, webprobe_dir, NULL,
+ &fops_enabled);
+
+ dentry = debugfs_create_file(APP_INFO_FILE, 0600, webprobe_dir,
+ NULL, &fops_app_info);
+ if (dentry == NULL)
+ goto fail;
+
+ dentry = debugfs_create_x64(INSPSERVER_START_FILE, 0600, webprobe_dir,
+ web_prof_addr_ptr(INSPSERVER_START));
+ if (dentry == NULL)
+ goto fail;
+
+ dentry = debugfs_create_x64(WILL_EXECUTE_FILE, 0600, webprobe_dir,
+ web_prof_addr_ptr(WILL_EXECUTE));
+ if (dentry == NULL)
+ goto fail;
+
+ dentry = debugfs_create_x64(DID_EXECUTE_FILE, 0600, webprobe_dir,
+ web_prof_addr_ptr(DID_EXECUTE));
+ if (dentry == NULL)
+ goto fail;
+
+ return 0;
+
+fail:
+ webprobe_debugfs_exit();
+ return -ENOMEM;
+}
--- /dev/null
+#ifndef _WEBPROBE_DEBUGFS_H
+#define _WEBPROBE_DEBUGFS_H
+
+/**
+ * @file webprobe/webprobe_debugfs.h
+ * @author Anastasia Lyupa <a.lyupa@samsung.com>
+ *
+ * @section LICENSE
+ * 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.
+ *
+ * @section COPYRIGHT
+ * Copyright (C) Samsung Electronics, 2015
+ *
+ * @section DESCRIPTION
+ * Debugfs for webprobe
+ */
+
+
+int webprobe_debugfs_init(void);
+void webprobe_debugfs_exit(void);
+
+
+#endif /* _WEBPROBE_DEBUGFS_H */
--- /dev/null
+/**
+ * webprobe/webprobe_prof.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, 2015
+ *
+ * 2015 Anastasia Lyupa <a.lyupa@samsung.com>
+ *
+ */
+
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/version.h>
+#include <linux/namei.h>
+
+#include <us_manager/pf/pf_group.h>
+#include <us_manager/probes/probes.h>
+
+#include "webprobe_prof.h"
+
+
+static DEFINE_MUTEX(mutex_enable);
+
+struct web_prof_data {
+ struct dentry *app_dentry;
+ struct dentry *lib_dentry;
+ struct pf_group *pfg;
+ unsigned long inspserver_addr;
+ unsigned long willexecute_addr;
+ unsigned long didexecute_addr;
+ enum web_prof_state_t enabled;
+};
+
+static const char *LIBEWEBKIT2_PATH = "/usr/lib/libewebkit2.so.0";
+static struct web_prof_data *web_data;
+
+static struct dentry *dentry_by_path(const char *path)
+{
+ struct dentry *dentry;
+ struct path st_path;
+ if (kern_path(path, LOOKUP_FOLLOW, &st_path) != 0) {
+ pr_err("failed to lookup dentry for path %s!\n", path);
+ return NULL;
+ }
+ dentry = st_path.dentry;
+ path_put(&st_path);
+
+ return dentry;
+}
+
+u64 *web_prof_addr_ptr(enum web_prof_addr_t type)
+{
+ u64 *addr_ptr;
+
+ switch (type) {
+ case INSPSERVER_START:
+ addr_ptr = (u64 *)&web_data->inspserver_addr;
+ break;
+ case WILL_EXECUTE:
+ addr_ptr = (u64 *)&web_data->willexecute_addr;
+ break;
+ case DID_EXECUTE:
+ addr_ptr = (u64 *)&web_data->didexecute_addr;
+ break;
+ default:
+ pr_err("ERROR: WEB_PROF_ADDR_PTR_TYPE=0x%x\n", type);
+ addr_ptr = NULL;
+ }
+
+ return addr_ptr;
+}
+
+unsigned long web_prof_addr(enum web_prof_addr_t type)
+{
+ unsigned long addr;
+
+ switch (type) {
+ case INSPSERVER_START:
+ addr = web_data->inspserver_addr;
+ break;
+ case WILL_EXECUTE:
+ addr = web_data->willexecute_addr;
+ break;
+ case DID_EXECUTE:
+ addr = web_data->didexecute_addr;
+ break;
+ default:
+ pr_err("ERROR: WEB_PROF_ADDR_TYPE=0x%x\n", type);
+ addr = 0;
+ }
+
+ return addr;
+}
+
+static int web_func_inst_add(unsigned long addr)
+{
+ int ret;
+ struct probe_info probe;
+
+ probe.probe_type = SWAP_WEBPROBE;
+ probe.size = 0;
+
+ ret = pf_register_probe(web_data->pfg, web_data->lib_dentry,
+ addr, &probe);
+
+ return ret;
+}
+
+int web_func_inst_remove(unsigned long addr)
+{
+ int ret;
+
+ /* FIXME: check that address needs removing */
+ ret = pf_unregister_probe(web_data->pfg, web_data->lib_dentry,
+ addr);
+
+ return ret;
+}
+
+int web_prof_data_set(char *app_path, char *app_id)
+{
+ web_data->app_dentry = dentry_by_path(app_path);
+ if (web_data->app_dentry == NULL)
+ return -EFAULT;
+
+ web_data->lib_dentry = dentry_by_path(LIBEWEBKIT2_PATH);
+ if (web_data->lib_dentry == NULL)
+ return -EFAULT;
+
+ web_data->pfg = get_pf_group_by_comm(app_id, web_data->app_dentry);
+ if (web_data->pfg == NULL)
+ return -EFAULT;
+
+ return 0;
+}
+
+struct dentry *web_prof_lib_dentry(void)
+{
+ return web_data->lib_dentry;
+}
+
+enum web_prof_state_t web_prof_enabled(void)
+{
+ return web_data->enabled;
+}
+
+int web_prof_enable(void)
+{
+ int ret = 0;
+
+ mutex_lock(&mutex_enable);
+ if (web_data->enabled == PROF_OFF) {
+ web_data->enabled = PROF_ON;
+
+ if ((web_data->inspserver_addr == 0) ||
+ (web_data->willexecute_addr == 0) ||
+ (web_data->didexecute_addr == 0)) {
+ pr_err("ERROR: Can't enable web profiling\n");
+ ret = -EFAULT;
+ } else {
+ web_func_inst_add(web_data->inspserver_addr);
+ web_func_inst_add(web_data->willexecute_addr);
+ web_func_inst_add(web_data->didexecute_addr);
+ }
+ } else {
+ pr_err("ERROR: Web profiling is already enabled\n");
+ }
+ mutex_unlock(&mutex_enable);
+
+ return ret;
+}
+
+int web_prof_disable(void)
+{
+ int ret = 0;
+
+ mutex_lock(&mutex_enable);
+ if (web_data->enabled == PROF_ON) {
+ web_data->enabled = PROF_OFF;
+
+ if ((web_data->inspserver_addr == 0) ||
+ (web_data->willexecute_addr == 0) ||
+ (web_data->didexecute_addr == 0)) {
+ pr_err("ERROR: Can't disable web profiling\n");
+ ret = -EFAULT;
+ } else {
+ web_func_inst_remove(web_data->inspserver_addr);
+ web_func_inst_remove(web_data->willexecute_addr);
+ web_func_inst_remove(web_data->didexecute_addr);
+ }
+ } else {
+ pr_err("ERROR: Web profiling is already disabled\n");
+ }
+ mutex_unlock(&mutex_enable);
+
+ return ret;
+}
+
+int web_prof_init(void)
+{
+ web_data = kmalloc(sizeof(*web_data), GFP_KERNEL);
+ if (web_data == NULL)
+ return -ENOMEM;
+
+ memset(web_data, 0, sizeof(struct web_prof_data));
+
+ web_data->enabled = PROF_OFF;
+
+ return 0;
+}
+
+
+void web_prof_exit(void)
+{
+ kfree(web_data);
+}
--- /dev/null
+#ifndef _WEBPROBE_PROF_H
+#define _WEBPROBE_PROF_H
+
+/**
+ * @file webprobe/webprobe_prof.h
+ * @author Anastasia Lyupa <a.lyupa@samsung.com>
+ *
+ * @section LICENSE
+ * 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.
+ *
+ * @section COPYRIGHT
+ * Copyright (C) Samsung Electronics, 2015
+ *
+ * @section DESCRIPTION
+ * Profiling for webprobe
+ */
+
+
+enum web_prof_addr_t {
+ INSPSERVER_START = 1,
+ WILL_EXECUTE = 2,
+ DID_EXECUTE = 3
+};
+
+enum web_prof_state_t {
+ PROF_OFF,
+ PROF_ON
+};
+
+int web_prof_init(void);
+void web_prof_exit(void);
+int web_prof_enable(void);
+int web_prof_disable(void);
+enum web_prof_state_t web_prof_enabled(void);
+int web_func_inst_remove(unsigned long addr);
+u64 *web_prof_addr_ptr(enum web_prof_addr_t type);
+unsigned long web_prof_addr(enum web_prof_addr_t type);
+int web_prof_data_set(char *app_path, char *app_id);
+struct dentry *web_prof_lib_dentry(void);
+
+#endif /* _WEBPROBE_PROF_H */