[FEATURE] Add web profiling 89/30389/10
authorRuslan Soloviev <r.soloviev@samsung.com>
Thu, 27 Nov 2014 07:12:42 +0000 (10:12 +0300)
committerDmitry Kovalenko <d.kovalenko@samsung.com>
Wed, 3 Dec 2014 14:52:07 +0000 (06:52 -0800)
Setup probes (probe type 3):
ewk_context_inspector_server_start
JSC::ProfileGenerator::willExecute
JSC::ProfileGenerator::didExecute

Change-Id: I65534ea544685b55d805df910d85b6a31eae2a93
Signed-off-by: Ruslan Soloviev <r.soloviev@samsung.com>
12 files changed:
Kbuild
build.sh
packaging/swap-modules.spec
parser/msg_cmd.c
parser/msg_cmd.h
parser/msg_parser.c
parser/swap_msg_parser.c
us_manager/probes/probes.h
webprobe/Kbuild [new file with mode: 0644]
webprobe/webprobe.c [new file with mode: 0644]
writer/swap_writer_module.c
writer/swap_writer_module.h

diff --git a/Kbuild b/Kbuild
index 40b8f27..54f3c3e 100644 (file)
--- a/Kbuild
+++ b/Kbuild
@@ -12,4 +12,5 @@ obj-m := buffer/ \
          sampler/ \
          energy/ \
          parser/ \
-         retprobe/
+         retprobe/ \
+         webprobe/
index e824400..3d21d97 100755 (executable)
--- a/build.sh
+++ b/build.sh
@@ -35,6 +35,7 @@ sampler_dir=${modules_dir}/sampler
 energy_dir=${modules_dir}/energy
 parser_dir=${modules_dir}/parser
 retprobe_dir=${modules_dir}/retprobe
+webprobe_dir=${modules_dir}/webprobe
 
 buffer_module_name=swap_buffer.ko
 driver_module_name=swap_driver.ko
@@ -49,6 +50,7 @@ energy_module_name=swap_energy.ko
 parser_module_name=swap_message_parser.ko
 ksyms_module_name=swap_ksyms.ko
 retprobe_module_name=swap_retprobe.ko
+webprobe_module_name=swap_webprobe.ko
 
 install_dir="/opt/swap/sdk"
 
@@ -72,7 +74,8 @@ ${sampler_dir}/${sampler_module_name} \
 ${energy_dir}/${energy_module_name} \
 ${parser_dir}/${parser_module_name} \
 ${ksyms_dir}/${ksyms_module_name} \
-${retprobe_dir}/${retprobe_module_name}"
+${retprobe_dir}/${retprobe_module_name} \
+${webprobe_dir}/${webprobe_module_name}"
 
 for m in ${modules} ; do
        ${cross_compile}strip -x -g $m
index 7d2ad40..9a2c030 100755 (executable)
@@ -53,6 +53,7 @@ install -m 666 sampler/swap_sampler.ko -t %{buildroot}/opt/swap/sdk
 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
 
 %files
 %defattr(-,root,root)
@@ -69,3 +70,4 @@ install -m 666 retprobe/swap_retprobe.ko -t %{buildroot}/opt/swap/sdk
 /opt/swap/sdk/swap_energy.ko
 /opt/swap/sdk/swap_message_parser.ko
 /opt/swap/sdk/swap_retprobe.ko
+/opt/swap/sdk/swap_webprobe.ko
index b516a21..fa890f9 100644 (file)
@@ -29,6 +29,7 @@
 
 
 #include <linux/errno.h>
+#include <linux/delay.h>
 #include <writer/swap_writer_module.h>
 #include "msg_parser.h"
 #include "msg_buf.h"
@@ -37,6 +38,8 @@
 #include "us_inst.h"
 #include <us_manager/us_manager.h>
 
+static int wrt_launcher_port = 0;
+
 static int set_config(struct conf_data *conf)
 {
        int ret;
@@ -237,6 +240,31 @@ free_us_inst:
        return ret;
 }
 
+void set_wrt_launcher_port(int port)
+{
+       wrt_launcher_port = port;
+}
+EXPORT_SYMBOL_GPL(set_wrt_launcher_port);
+
+#define GET_PORT_DELAY         100     /* msec */
+#define GET_PORT_TIMEOUT       10000   /* msec */
+
+int get_wrt_launcher_port(void)
+{
+       int port;
+       int timeout = GET_PORT_TIMEOUT;
+
+       do {
+               port = wrt_launcher_port;
+               timeout -= GET_PORT_DELAY;
+               mdelay(GET_PORT_DELAY);
+       } while (!port && timeout > 0);
+
+       set_wrt_launcher_port(0);
+
+       return port;
+}
+
 /**
  * @brief Initializes commands handling.
  *
index 16132ca..e444997 100644 (file)
@@ -41,5 +41,7 @@ int msg_stop(struct msg_buf *mb);
 int msg_config(struct msg_buf *mb);
 int msg_swap_inst_add(struct msg_buf *mb);
 int msg_swap_inst_remove(struct msg_buf *mb);
+int get_wrt_launcher_port(void);
+void set_wrt_launcher_port(int port);
 
 #endif /* _MSG_CMD_H */
index 63315a6..6e12886 100644 (file)
@@ -304,6 +304,21 @@ free_args:
 }
 
 /**
+ * @brief Gets webprobe 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_webprobe(struct msg_buf *mb, struct probe_info *pi)
+{
+       pi->probe_type = SWAP_WEBPROBE;
+       pi->size = 0;
+
+       return 0;
+}
+
+/**
  * @brief Retprobe data cleanup.
  *
  * @param pi Pointer to the probe_info comprising retprobe.
@@ -361,6 +376,10 @@ struct func_inst_data *create_func_inst_data(struct msg_buf *mb)
                if (get_retprobe(mb, &(fi->probe_i)) != 0)
                        goto free_func_inst;
                break;
+       case SWAP_WEBPROBE:
+               if (get_webprobe(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;
@@ -386,6 +405,8 @@ void destroy_func_inst_data(struct func_inst_data *fi)
        case SWAP_RETPROBE:
                put_retprobe(&(fi->probe_i));
                break;
+       case SWAP_WEBPROBE:
+               break;
        default:
                printk(KERN_WARNING "SWAP PARSER: Wrong probe type %d!\n",
                   fi->probe_i.probe_type);
index f1071e2..dca2999 100644 (file)
  * @brief Message IDs.
  */
 enum MSG_ID {
-       MSG_KEEP_ALIVE          = 0x0001,       /**< Keep alive message. */
-       MSG_START               = 0x0002,           /**< Start message. */
-       MSG_STOP                = 0x0003,           /**< Stop message. */
-       MSG_CONFIG              = 0x0004,           /**< Config message. */
-       MSG_SWAP_INST_ADD       = 0x0008,       /**< Swap inst add message. */
-       MSG_SWAP_INST_REMOVE    = 0x0009    /**< Swap inst remove message. */
+       MSG_KEEP_ALIVE          = 0x0001,       /**< Keep alive message. */
+       MSG_START               = 0x0002,       /**< Start message. */
+       MSG_STOP                = 0x0003,       /**< Stop message. */
+       MSG_CONFIG              = 0x0004,       /**< Config message. */
+       MSG_SWAP_INST_ADD       = 0x0008,       /**< Swap inst add message. */
+       MSG_SWAP_INST_REMOVE    = 0x0009,       /**< Swap inst remove message. */
+       MSG_WRT_LAUNCHER_PORT   = 0x8001        /**< WRT launcher port. */
 };
 
 /**
@@ -128,6 +129,18 @@ static int msg_handler(void __user *msg)
                print_parse_debug("MSG_SWAP_INST_REMOVE. size=%d\n", size);
                ret = msg_swap_inst_remove(&mb);
                break;
+       case MSG_WRT_LAUNCHER_PORT: {
+               /* TODO: discuss wrt-launcher port transfer */
+               int port;
+               print_parse_debug("MSG_WRT_LAUNCHER_PORT. size=%d\n", size);
+               port = get_wrt_launcher_port();
+               if (copy_to_user(payload, &port, sizeof(port))) {
+                       ret = -EIO;
+                       break;
+               }
+               ret = port ? 0 : -EINVAL;
+               break;
+       }
        default:
                print_err("incorrect message ID [%u]. size=%d\n", msg_id, size);
                ret = -EINVAL;
index 4ba8111..d83f1cb 100644 (file)
@@ -37,6 +37,7 @@
  */
 enum probe_t {
        SWAP_RETPROBE = 0,          /* Retprobe */
+       SWAP_WEBPROBE = 3,          /* Webprobe */
        SWAP_PROBE_MAX_VAL          /* Probes max value. */
 };
 
diff --git a/webprobe/Kbuild b/webprobe/Kbuild
new file mode 100644 (file)
index 0000000..c79cb10
--- /dev/null
@@ -0,0 +1,4 @@
+EXTRA_CFLAGS := $(extra_cflags)
+
+obj-m := swap_webprobe.o
+swap_webprobe-y := webprobe.o
diff --git a/webprobe/webprobe.c b/webprobe/webprobe.c
new file mode 100644 (file)
index 0000000..d4bc268
--- /dev/null
@@ -0,0 +1,168 @@
+/**
+ * webprobe/webprobe.c
+ * @author Ruslan Soloviev
+ *
+ * @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, 2014
+ *
+ * @section DESCRIPTION
+ *
+ * Web application profiling
+ */
+
+
+#include <us_manager/us_manager.h>
+#include <us_manager/sspt/ip.h>
+#include <us_manager/probes/register_probes.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>
+
+static int webprobe_copy(struct probe_info *dest,
+                        const struct probe_info *source)
+{
+       memcpy(dest, source, sizeof(*source));
+
+       return 0;
+}
+
+static void webprobe_cleanup(struct probe_info *probe_i)
+{
+}
+
+static struct uprobe *webprobe_get_uprobe(struct us_ip *ip)
+{
+       return &ip->retprobe.up;
+}
+
+static int webprobe_register_probe(struct us_ip *ip)
+{
+       return swap_register_uretprobe(&ip->retprobe);
+}
+
+static void webprobe_unregister_probe(struct us_ip *ip, int disarm)
+{
+       __swap_unregister_uretprobe(&ip->retprobe, disarm);
+}
+
+static int entry_web_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);
+       }
+
+       return 0;
+}
+
+static int exit_web_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);
+       }
+
+       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;
+}
+
+#define WEB_FUNC_INSPSERVSTART         0
+#define WEB_FUNC_WILLEXECUTE           1
+#define WEB_FUNC_DIDEXECUTE            2
+
+static void webprobe_init(struct us_ip *ip)
+{
+       static int fcnt = 0;
+
+       switch(fcnt++) {
+       case WEB_FUNC_INSPSERVSTART:
+               ip->retprobe.entry_handler = NULL;
+               ip->retprobe.handler = ret_web_handler;
+               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;
+               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;
+               printk("SWAP_WEBPROBE: web function didExecute\n");
+               /* FIXME: probes can be set more than once */
+               fcnt = 0;
+               break;
+       default:
+               printk("SWAP_WEBPROBE: web functions more than necessary\n");
+       }
+
+       ip->retprobe.maxactive = 0;
+}
+
+static void webprobe_uninit(struct us_ip *ip)
+{
+       webprobe_cleanup(&ip->probe_i);
+}
+
+
+static struct probe_iface webprobe_iface = {
+       .init = webprobe_init,
+       .uninit = webprobe_uninit,
+       .reg = webprobe_register_probe,
+       .unreg = webprobe_unregister_probe,
+       .get_uprobe = webprobe_get_uprobe,
+       .copy = webprobe_copy,
+       .cleanup = webprobe_cleanup
+};
+
+static int __init webprobe_module_init(void)
+{
+       return swap_register_probe_type(SWAP_WEBPROBE, &webprobe_iface);
+}
+
+static void __exit webprobe_module_exit(void)
+{
+       swap_unregister_probe_type(SWAP_WEBPROBE);
+}
+
+module_init(webprobe_module_init);
+module_exit(webprobe_module_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("SWAP webprobe");
+MODULE_AUTHOR("Ruslan Soloviev <r.soloviev@samsung.com>");
index 00e35c7..4162628 100644 (file)
@@ -70,7 +70,9 @@ enum MSG_ID {
        MSG_CONTEXT_SWITCH_EXIT         = 0x0011,   /**< Context switch exit */
        MSG_PROC_MAP                    = 0x0012,       /**< Process map */
        MSG_PROC_UNMAP                  = 0x0013,       /**< Process unmap */
-       MSG_PROC_COMM                   = 0x0014        /**< Process comm */
+       MSG_PROC_COMM                   = 0x0014,       /**< Process comm */
+       MSG_WEB_FUNCTION_ENTRY          = 0x0015,   /**< Web function entry */
+       MSG_WEB_FUNCTION_EXIT           = 0x0016    /**< Web function exit */
 };
 
 static char *cpu_buf[NR_CPUS];
@@ -1240,6 +1242,7 @@ static int pack_custom_event(char *buf, int len, const char *fmt, va_list args)
        enum { max_str_len = 512 };
        const char *p;
        char *buf_orig = buf;
+       int len_s = 0;
 
        for (p = fmt; *p != '\0'; p++) {
                char ch = *p;
@@ -1252,6 +1255,13 @@ static int pack_custom_event(char *buf, int len, const char *fmt, va_list args)
                len -= 1;
 
                switch (ch) {
+               case '*': /* string length (without '\0') */
+                       /* usage: '*s' or '*S' */
+                       /* will not pack to buffer */
+                       len_s = va_arg(args, int);
+                       buf -= 1;
+                       len += 1;
+                       break;
                case 'b': /* 1 byte(bool) */
                        if (len < 1)
                                return -ENOMEM;
@@ -1292,11 +1302,14 @@ static int pack_custom_event(char *buf, int len, const char *fmt, va_list args)
                case 's': /* userspace string with '\0' terminating byte */
                {
                        const char __user *str;
-                       int len_s, n;
+                       int n;
 
                        str = va_arg(args, const char __user *);
                        /* strnlen_user includes '\0' in its return value */
-                       len_s = strnlen_user(str, max_str_len);
+                       if (len_s == 0)
+                               len_s = strnlen_user(str, max_str_len);
+                       else
+                               len_s++; /* + '\0' */
                        if (len < len_s)
                                return -ENOMEM;
                        /* strncpy_from_user returns the length of the copied
@@ -1308,15 +1321,16 @@ static int pack_custom_event(char *buf, int len, const char *fmt, va_list args)
 
                        buf += n + 1;
                        len -= n + 1;
+                       len_s = 0;
                        break;
                }
                case 'S': /* kernelspace string with '\0' terminating byte */
                {
                        const char *str;
-                       int len_s;
 
                        str = va_arg(args, const char *);
-                       len_s = strnlen(str, max_str_len);
+                       if (len_s == 0)
+                               len_s = strnlen(str, max_str_len);
                        if (len < len_s + 1) /* + '\0' */
                                return -ENOMEM;
                        strncpy(buf, str, len_s);
@@ -1324,6 +1338,7 @@ static int pack_custom_event(char *buf, int len, const char *fmt, va_list args)
 
                        buf += len_s + 1;
                        len -= len_s + 1;
+                       len_s = 0;
                        break;
                }
                case 'a': /* userspace byte array (len + ptr) */
@@ -1374,6 +1389,18 @@ static int pack_custom_event(char *buf, int len, const char *fmt, va_list args)
        return buf - buf_orig;
 }
 
+static int pack_custom_args(char *buf, int len, const char *fmt, ...)
+{
+       va_list vargs;
+       int ret;
+
+       va_start(vargs, fmt);
+       ret = pack_custom_event(buf, len, fmt, vargs);
+       va_end(vargs);
+
+       return ret;
+}
+
 enum { max_custom_event_size = 2048 };
 
 /**
@@ -1455,6 +1482,115 @@ put_buf:
 }
 EXPORT_SYMBOL_GPL(custom_exit_event);
 
+
+
+
+/* ============================================================================
+ * =                              WEB APP EVENT                               =
+ * ============================================================================
+ */
+
+/* TODO: develop method for obtaining this data during build... */
+/* location: webkit2-efl-123997_0.11.113/Source/WTF/wtf/text/StringImpl.h:70 */
+struct MStringImpl {
+       unsigned m_refCount;
+       unsigned m_length;
+       union {
+               const unsigned char *m_data8;
+               const unsigned short *m_data16;
+       };
+       union {
+               void* m_buffer;
+               struct MStringImpl *m_substringBuffer;
+               unsigned short *m_copyData16;
+       };
+       unsigned m_hashAndFlags;
+};
+
+/* location: webkit2-efl-123997_0.11.113/Source/JavaScriptCore/profiler/
+ * CallIdentifier.h:36
+ */
+struct MCallIdentifier {
+       struct MStringImpl *m_name;
+       struct MStringImpl *m_url;
+       unsigned m_lineNumber;
+};
+
+int entry_web_event(unsigned long func_addr, struct pt_regs *regs)
+{
+       char *buf, *payload;
+       int ret, t;
+       struct MCallIdentifier *callIdentifier;
+       struct {
+               const char *str;
+               int len;
+       } m_name, m_url;
+
+       if (!check_event(current))
+               return 0;
+
+       callIdentifier = (void *)swap_get_uarg(regs, 2);
+
+       if (!(!get_user(t, (int *)&callIdentifier->m_name) &&
+             !get_user(m_name.str, &((struct MStringImpl *)t)->m_data8) &&
+             !get_user(m_name.len, &((struct MStringImpl *)t)->m_length) &&
+             !get_user(t, (int *)&callIdentifier->m_url) &&
+             !get_user(m_url.str, &((struct MStringImpl *)t)->m_data8) &&
+             !get_user(m_url.len, &((struct MStringImpl *)t)->m_length))) {
+               printk("SWAP_WRITER: cannot read user memory\n");
+               return 0;
+       }
+
+       buf = get_current_buf();
+       payload = pack_basic_msg_fmt(buf, MSG_WEB_FUNCTION_ENTRY);
+       payload = pack_msg_func_entry(payload, "ssd", func_addr, regs, PT_US,
+                                     PST_NONE);
+       payload += pack_custom_args(payload, 1024, "*s*sd", m_name.len,
+                                   m_name.str, m_url.len, m_url.str,
+                                   callIdentifier->m_lineNumber);
+       set_len_msg(buf, payload);
+       ret = write_to_buffer(buf);
+       put_current_buf();
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(entry_web_event);
+
+int exit_web_event(unsigned long func_addr, struct pt_regs *regs)
+{
+       char *buf, *payload;
+       int ret, t;
+       struct MCallIdentifier *callIdentifier;
+       struct {
+               const char *str;
+               int len;
+       } m_name;
+
+       if (!check_event(current))
+               return 0;
+
+       callIdentifier = (void *)swap_get_uarg(regs, 2);
+
+       if (!(!get_user(t, (int *)&callIdentifier->m_name) &&
+             !get_user(m_name.str, &((struct MStringImpl *)t)->m_data8) &&
+             !get_user(m_name.len, &((struct MStringImpl *)t)->m_length))) {
+               printk("SWAP_WRITER: cannot read user memory\n");
+               return 0;
+       }
+
+       buf = get_current_buf();
+       payload = pack_basic_msg_fmt(buf, MSG_WEB_FUNCTION_EXIT);
+       payload = pack_msg_func_entry(payload, "s", func_addr, regs, PT_US,
+                                     PST_NONE);
+       payload += pack_custom_args(payload, 1024, "*s", m_name.len, m_name.str);
+       set_len_msg(buf, payload);
+       ret = write_to_buffer(buf);
+       put_current_buf();
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(exit_web_event);
+
 static int __init swap_writer_module_init(void)
 {
        int ret;
index c975a8e..38f2288 100644 (file)
@@ -80,6 +80,9 @@ int entry_event(const char *fmt, unsigned long func_addr, struct pt_regs *regs,
 int exit_event(char ret_type, struct pt_regs *regs, int pt, int sub_type,
               unsigned long func_addr, unsigned long ret_addr);
 
+int entry_web_event(unsigned long func_addr, struct pt_regs *regs);
+int exit_web_event(unsigned long func_addr, struct pt_regs *regs);
+
 int switch_entry(struct pt_regs *regs);
 int switch_exit(struct pt_regs *regs);