Rework webprobe module
[kernel/swap-modules.git] / webprobe / webprobe.c
1 /**
2  * webprobe/webprobe.c
3  * @author Ruslan Soloviev
4  *
5  * @section LICENSE
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, see <http://www.gnu.org/licenses/>.
19  *
20  * @section COPYRIGHT
21  *
22  * Copyright (C) Samsung Electronics, 2014
23  *
24  * @section DESCRIPTION
25  *
26  * Web application profiling
27  */
28
29 #include <linux/module.h>
30 #include <linux/slab.h>
31 #include <us_manager/us_manager.h>
32 #include <us_manager/pf/pf_group.h>
33 #include <us_manager/probes/probe_info_new.h>
34 #include <uprobe/swap_uprobes.h>
35 #include <parser/msg_cmd.h>
36 #include <master/swap_initializer.h>
37
38 #include "webprobe.h"
39 #include "webprobe_debugfs.h"
40 #include "web_msg.h"
41
42 struct web_prof_data {
43         struct dentry *app_dentry;
44         struct dentry *lib_dentry;
45         struct pf_group *pfg;
46         u64 inspserver_addr;
47         u64 tick_addr;
48         bool enable;
49 };
50
51 static DEFINE_MUTEX(web_mutex);
52 static const char *CHROMIUM_EWK = "/usr/lib/libchromium-ewk.so";
53 static struct web_prof_data *web_data;
54
55 /* function tick handler */
56 static int tick_handler(struct uprobe *p, struct pt_regs *regs);
57 static struct probe_desc pin_tick_handler = MAKE_UPROBE(tick_handler);
58 static struct probe_new tick_probe = {
59         .desc = &pin_tick_handler
60 };
61
62 /* function inspector port */
63 static int insport_rhandler(struct uretprobe_instance *ri,
64                             struct pt_regs *regs);
65 static struct probe_desc pin_insport_rhandler =
66                                 MAKE_URPROBE(NULL, insport_rhandler, 0);
67 static struct probe_new insport_probe = {
68         .desc = &pin_insport_rhandler
69 };
70
71 static int insport_rhandler(struct uretprobe_instance *ri,
72                             struct pt_regs *regs)
73 {
74         set_wrt_launcher_port((int)regs_return_value(regs));
75
76         return 0;
77 }
78
79 static int tick_handler(struct uprobe *p, struct pt_regs *regs)
80 {
81         web_sample_msg(regs);
82
83         return 0;
84 }
85
86 u64 *web_prof_addr_ptr(enum web_prof_addr_t type)
87 {
88         u64 *addr_ptr;
89
90         mutex_lock(&web_mutex);
91         switch (type) {
92         case INSPSERVER_START:
93                 addr_ptr = &web_data->inspserver_addr;
94                 break;
95         case TICK_PROBE:
96                 addr_ptr = &web_data->tick_addr;
97                 break;
98         default:
99                 pr_err("ERROR: WEB_PROF_ADDR_PTR_TYPE=0x%x\n", type);
100                 addr_ptr = NULL;
101         }
102         mutex_unlock(&web_mutex);
103
104         return addr_ptr;
105 }
106
107 int web_prof_data_set(char *app_path, char *app_id)
108 {
109         int ret = 0;
110
111         mutex_lock(&web_mutex);
112         web_data->app_dentry = dentry_by_path(app_path);
113         if (!web_data->app_dentry) {
114                 ret = -EFAULT;
115                 goto out;
116         }
117
118         web_data->lib_dentry = dentry_by_path(CHROMIUM_EWK);
119         if (!web_data->lib_dentry) {
120                 ret = -EFAULT;
121                 goto out;
122         }
123
124         if (web_data->pfg)
125                 put_pf_group(web_data->pfg);
126
127         web_data->pfg = get_pf_group_by_comm(app_id, web_data->app_dentry);
128         if (!web_data->pfg) {
129                 ret = -EFAULT;
130                 goto out;
131         }
132
133 out:
134         mutex_unlock(&web_mutex);
135
136         return 0;
137 }
138
139 bool web_prof_enabled(void)
140 {
141         bool ret;
142
143         mutex_lock(&web_mutex);
144         ret = web_data->enable;
145         mutex_unlock(&web_mutex);
146
147         return ret;
148 }
149
150 static void __web_prof_disable(struct web_prof_data *data)
151 {
152         pin_unregister(&tick_probe, data->pfg, data->lib_dentry);
153         pin_unregister(&insport_probe, data->pfg, data->lib_dentry);
154 }
155
156 static int __web_prof_enable(struct web_prof_data *data)
157 {
158         int ret;
159
160         tick_probe.offset = data->tick_addr;
161         ret = pin_register(&tick_probe, data->pfg, data->lib_dentry);
162         if (ret)
163                 goto fail0;
164
165         insport_probe.offset = data->inspserver_addr;
166         ret = pin_register(&insport_probe, data->pfg, data->lib_dentry);
167         if (ret)
168                 goto fail1;
169
170         return 0;
171
172 fail1:
173         pin_unregister(&tick_probe, data->pfg, data->lib_dentry);
174 fail0:
175         return ret;
176 }
177
178 int web_prof_enable(void)
179 {
180         int ret = 0;
181
182         mutex_lock(&web_mutex);
183         if (web_data->enable) {
184                 pr_err("ERROR: Web profiling is already enabled\n");
185                 ret = -EBUSY;
186                 goto out;
187         }
188
189         if (!web_data->inspserver_addr) {
190                 pr_err("bad inspserver addr 0x%llx\n",
191                        web_data->inspserver_addr);
192                 goto out;
193         }
194
195         if (!web_data->tick_addr) {
196                 pr_err("bad tick addr 0x%llx\n", web_data->tick_addr);
197                 goto out;
198         }
199
200         ret = __web_prof_enable(web_data);
201         if (ret) {
202                 pr_err("failed to enable Web profiling\n");
203                 goto out;
204         }
205
206         web_data->enable = true;
207
208 out:
209         mutex_unlock(&web_mutex);
210
211         return ret;
212 }
213
214 int web_prof_disable(void)
215 {
216         int ret = 0;
217
218         mutex_lock(&web_mutex);
219         if (!web_data->enable) {
220                 pr_err("ERROR: Web profiling is already disabled\n");
221                 ret = -EBUSY;
222                 goto out;
223         }
224
225         __web_prof_disable(web_data);
226         web_data->enable = false;
227
228 out:
229         mutex_unlock(&web_mutex);
230         return ret;
231 }
232
233 static int webprobe_module_init(void)
234 {
235         mutex_lock(&web_mutex);
236         web_data = kzalloc(sizeof(*web_data), GFP_KERNEL);
237         if (!web_data)
238                 return -ENOMEM;
239
240         web_data->enable = false;
241         mutex_unlock(&web_mutex);
242
243         return 0;
244 }
245
246 static void webprobe_module_exit(void)
247 {
248         mutex_lock(&web_mutex);
249         if (web_data->enable)
250                 __web_prof_disable(web_data);
251
252         if (web_data->pfg)
253                 put_pf_group(web_data->pfg);
254
255         kfree(web_data);
256         web_data = NULL;
257         mutex_unlock(&web_mutex);
258 }
259
260 SWAP_LIGHT_INIT_MODULE(NULL, webprobe_module_init, webprobe_module_exit,
261                        webprobe_debugfs_init, webprobe_debugfs_exit);
262
263 MODULE_LICENSE("GPL");
264 MODULE_DESCRIPTION("SWAP webprobe");
265 MODULE_AUTHOR("Ruslan Soloviev <r.soloviev@samsung.com>"
266               "Anastasia Lyupa <a.lyupa@samsung.com>");