Merge branch 'tizen_2.4' into tizen_2.4_dev
[kernel/swap-modules.git] / wsp / wsp.c
1 /*
2  * This program is free software; you can redistribute it and/or modify
3  * it under the terms of the GNU General Public License as published by
4  * the Free Software Foundation; either version 2 of the License, or
5  * (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software
14  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15  *
16  * Copyright (C) Samsung Electronics, 2015
17  *
18  * 2015         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
19  *
20  */
21
22
23 #include <uprobe/swap_uaccess.h>
24 #include <us_manager/sspt/sspt.h>
25 #include <us_manager/probes/probe_info_new.h>
26 #include "wsp.h"
27 #include "wsp_res.h"
28 #include "wsp_msg.h"
29
30
31 struct wsp_probe {
32         const char *name;
33         struct probe_new probe;
34 };
35
36 struct wsp_bin {
37         const char *name;
38         unsigned long cnt;
39         struct wsp_probe *probe_array;
40 };
41
42
43 /* TODO: configure this from outside (using debugfs) */
44 static const char webapp_path[] = "/usr/bin/wrt_launchpad_daemon";
45 static const char ewebkit_path[] = "/usr/lib/libewebkit2.so";
46
47
48 #define WSP_PROBE_MAKE(__name, __desc)  \
49 {                                       \
50         .name = __name,                 \
51         .probe.offset = 0,              \
52         .probe.desc = __desc            \
53 }
54
55
56 static void do_res_processing_begin(void *data, void *ptr, enum wsp_res_t type)
57 {
58         struct wsp_res **save_res = (struct wsp_res **)data;
59         struct wsp_res *res;
60
61         res = wsp_res_find(ptr, type);
62
63         /* save res pointer */
64         *save_res = res;
65         if (res) {
66                 wsp_msg(WSP_RES_PROC_BEGIN, res->id, NULL);
67                 wsp_res_stat_set_next(res, WRS_ADD_DATA);
68         }
69 }
70
71 static void do_res_processing_end(struct wsp_res *res)
72 {
73         wsp_msg(WSP_RES_PROC_END, res->id, NULL);
74 }
75
76 static void do_res_finish(struct wsp_res *res)
77 {
78         wsp_msg(WSP_RES_LOAD_END, res->id, NULL);
79         wsp_res_stat_set_next(res, WRS_FINISH);
80         wsp_res_del(res);
81 }
82
83
84 /*
85  * soup_req
86  */
87 static int soup_req_handle(struct uprobe *p, struct pt_regs *regs)
88 {
89         enum { max_str_len = 512 };
90         const char __user *user_s;
91         const char *path;
92         struct wsp_res *res;
93
94         res = wsp_res_last();
95         if (res == NULL) {
96                 pr_err("last wsp_res is not found\n");
97                 return 0;
98         }
99
100         user_s = (const char __user *)swap_get_uarg(regs, 1);
101         path = strdup_from_user(user_s, GFP_ATOMIC);
102         if (path == NULL) {
103                 pr_warn("soup_req_handle: invalid path\n");
104                 return 0;
105         }
106
107         wsp_msg(WSP_RES_LOAD_BEGIN, res->id, path);
108         wsp_res_stat_set_next(res, WRS_SOUP_REQ);
109         kfree(path);
110
111         return 0;
112 }
113
114 static struct probe_desc soup_req = MAKE_UPROBE(soup_req_handle);
115
116
117 /*
118  * main_res_req
119  */
120 static int mres_req_handle(struct uprobe *p, struct pt_regs *regs)
121 {
122         void *ptr = (void *)swap_get_uarg(regs, 0);
123         struct wsp_res *res;
124
125         res = wsp_res_new(ptr, WR_MAIN);
126         if (res)
127                 wsp_res_stat_set_next(res, WRS_WILL_REQ);
128
129         return 0;
130 }
131
132 static struct probe_desc mres_req = MAKE_UPROBE(mres_req_handle);
133
134
135 /*
136  * main_res_add_data
137  */
138
139 static int mres_adata_eh(struct uretprobe_instance *ri, struct pt_regs *regs)
140 {
141         void *ptr = (void *)swap_get_uarg(regs, 0);
142
143         do_res_processing_begin(ri->data, ptr, WR_MAIN);
144
145         return 0;
146 }
147
148 static int mres_adata_rh(struct uretprobe_instance *ri, struct pt_regs *regs)
149 {
150         struct wsp_res *res = *(struct wsp_res **)ri->data;
151
152         if (res)
153                 do_res_processing_end(res);
154
155         return 0;
156 }
157
158 static struct probe_desc mres_adata =
159                 MAKE_URPROBE(mres_adata_eh, mres_adata_rh,
160                              sizeof(struct wsp_res *));
161
162
163 /*
164  * main_res_finish
165  */
166 static int mres_finish_handle(struct uprobe *p, struct pt_regs *regs)
167 {
168         void *ptr = (void *)swap_get_uarg(regs, 0);
169         struct wsp_res *res;
170
171         res = wsp_res_find(ptr, WR_MAIN);
172         if (res) {
173                 wsp_current_set_stat(TDS_FINISH_MAIN_LOAD);
174                 do_res_finish(res);
175         }
176
177         return 0;
178 }
179
180 static struct probe_desc mres_finish = MAKE_UPROBE(mres_finish_handle);
181
182
183 /*
184  * res_request
185  */
186 static int res_request_handle(struct uprobe *p, struct pt_regs *regs)
187 {
188         void *ptr = (void *)swap_get_uarg(regs, 0);
189         struct wsp_res *res;
190
191         res = wsp_res_last();
192         if (res) {
193                 if (res->type == WR_MAIN && res->stat == WRS_WILL_REQ)
194                         /* skip */
195                         return 0;
196         }
197
198         res = wsp_res_new(ptr, WR_ANY);
199         if (res)
200                 wsp_res_stat_set_next(res, WRS_WILL_REQ);
201
202         return 0;
203 }
204
205 static struct probe_desc res_request = MAKE_UPROBE(res_request_handle);
206
207
208 /*
209  * res_finish
210  */
211 static int res_finish_ehandle(struct uretprobe_instance *ri,
212                               struct pt_regs *regs)
213 {
214         void *ptr = (void *)swap_get_uarg(regs, 0);
215
216         do_res_processing_begin(ri->data, ptr, WR_ANY);
217
218         return 0;
219 }
220
221 static int res_finish_rhandle(struct uretprobe_instance *ri,
222                               struct pt_regs *regs)
223 {
224         struct wsp_res *res = *(struct wsp_res **)ri->data;
225
226         if (res) {
227                 do_res_processing_end(res);
228                 do_res_finish(res);
229         }
230
231         return 0;
232 }
233
234 static struct probe_desc res_finish =
235                 MAKE_URPROBE(res_finish_ehandle, res_finish_rhandle,
236                              sizeof(struct wsp_res *));
237
238
239 /*
240  * redraw
241  */
242 static int redraw_eh(struct uretprobe_instance *ri, struct pt_regs *regs)
243 {
244         enum tdata_stat stat;
245
246         stat = wsp_current_get_stat();
247
248         if (stat == TDS_FINISH_MAIN_LOAD)
249                 wsp_msg(WSP_DRAW_BEGIN, 0, NULL);
250
251         return 0;
252 }
253
254 static int redraw_rh(struct uretprobe_instance *ri, struct pt_regs *regs)
255 {
256         if (wsp_current_get_stat() == TDS_FINISH_MAIN_LOAD) {
257                 wsp_current_set_stat(TDS_DRAW);
258                 wsp_msg(WSP_DRAW_END, 0, NULL);
259         }
260
261         return 0;
262 }
263
264 static struct probe_desc redraw = MAKE_URPROBE(redraw_eh, redraw_rh, 0);
265
266
267 static struct wsp_probe ewebkit_probe_array[] = {
268         /* plt */
269         /* soup_requester_request@plt */
270         WSP_PROBE_MAKE("soup_requester_request@plt", &soup_req),
271
272         /* main_res */
273         /* WebCore::MainResourceLoader::willSendRequest(WebCore::ResourceRequest&, WebCore::ResourceResponse const&) */
274         WSP_PROBE_MAKE("_ZN7WebCore18MainResourceLoader15willSendRequestERNS_15ResourceRequestERKNS_16ResourceResponseE", &mres_req),
275         /* WebCore::MainResourceLoader::addData(char const*, int, bool) */
276         WSP_PROBE_MAKE("_ZN7WebCore18MainResourceLoader7addDataEPKcib", &mres_adata),
277         /* WebCore::MainResourceLoader::didFinishLoading(double) */
278         WSP_PROBE_MAKE("_ZN7WebCore18MainResourceLoader16didFinishLoadingEd", &mres_finish),
279
280
281         /* res */
282         /* WebCore::ResourceLoader::willSendRequest(WebCore::ResourceRequest&, WebCore::ResourceResponse const&) */
283         WSP_PROBE_MAKE("_ZN7WebCore14ResourceLoader15willSendRequestERNS_15ResourceRequestERKNS_16ResourceResponseE", &res_request),
284         /* WebCore::ResourceLoader::didFinishLoading(WebCore::ResourceHandle*, double) */
285         WSP_PROBE_MAKE("_ZN7WebCore14ResourceLoader16didFinishLoadingEPNS_14ResourceHandleEd", &res_finish),
286
287
288         /* redraw */
289         /* WebKit::LayerTreeCoordinator::flushPendingLayerChanges() */
290         WSP_PROBE_MAKE("_ZN6WebKit20LayerTreeCoordinator24flushPendingLayerChangesEv", &redraw),
291 };
292
293 enum {
294         ewebkit_probes_cnt =
295                 sizeof(ewebkit_probe_array) / sizeof(struct wsp_probe)
296 };
297
298 static struct wsp_bin ewebkit = {
299         .name = ewebkit_path,
300         .cnt = ewebkit_probes_cnt,
301         .probe_array = ewebkit_probe_array
302 };
303
304
305 /* check ewebkit_probe_array on init address */
306 static bool wsp_is_addr_init(void)
307 {
308         int i;
309
310         for (i = 0; i < ewebkit_probes_cnt; ++i)
311                 if (ewebkit_probe_array[i].probe.offset == 0)
312                         return false;
313
314         return true;
315 }
316
317
318 static int wsp_probe_register(struct pf_group *pfg, struct dentry *dentry,
319                               struct wsp_probe *wsp_probe)
320 {
321         struct probe_new *probe_new = &wsp_probe->probe;
322
323         return pin_register(probe_new, pfg, dentry);
324 }
325
326 static void wsp_probe_unregister(struct pf_group *pfg, struct dentry *dentry,
327                                  struct wsp_probe *wsp_probe)
328 {
329         struct probe_new *probe_new = &wsp_probe->probe;
330
331         pin_unregister(probe_new, pfg, dentry);
332 }
333
334
335
336
337 static int wsp_bin_register(struct pf_group *pfg, struct wsp_bin *bin)
338 {
339         int i, ret;
340         struct dentry *dentry;
341
342         dentry = dentry_by_path(bin->name);
343         if (dentry == NULL) {
344                 pr_err("dentry not found (path='%s'\n", bin->name);
345                 return -EINVAL;
346         }
347
348         for (i = 0; i < bin->cnt; ++i) {
349                 struct wsp_probe *p = &bin->probe_array[i];
350
351                 ret = wsp_probe_register(pfg, dentry, p);
352                 if (ret) {
353                         pr_err("ERROR: wsp_probe_register, addr=%lx ret=%d\n",
354                                p->probe.offset, ret);
355                         return ret;
356                 }
357         }
358
359         return 0;
360 }
361
362 static void wsp_bin_unregister(struct pf_group *pfg, struct wsp_bin *bin)
363 {
364         int i;
365         struct dentry *dentry;
366
367         dentry = dentry_by_path(bin->name);
368         for (i = 0; i < bin->cnt; ++i)
369                 wsp_probe_unregister(pfg, dentry, &bin->probe_array[i]);
370 }
371
372
373 static struct pf_group *g_pfg;
374
375 static int wsp_app_register(void)
376 {
377         struct dentry *dentry;
378
379         dentry = dentry_by_path(webapp_path);
380         if (dentry == NULL) {
381                 pr_err("dentry not found (path='%s'\n", webapp_path);
382                 return -EINVAL;
383         }
384
385         g_pfg = get_pf_group_by_dentry(dentry, (void *)dentry);
386         if (g_pfg == NULL) {
387                 pr_err("g_pfg is NULL (by dentry=%p)\n", dentry);
388                 return -ENOMEM;
389         }
390
391         return wsp_bin_register(g_pfg, &ewebkit);
392 }
393
394 static void wsp_app_unregister(void)
395 {
396         wsp_bin_unregister(g_pfg, &ewebkit);
397         put_pf_group(g_pfg);
398 }
399
400
401 static int do_wsp_on(void)
402 {
403         int ret;
404
405         ret = wsp_res_init();
406         if (ret)
407                 return ret;
408
409         ret = wsp_app_register();
410         if (ret)
411                 wsp_res_exit();
412
413         return ret;
414 }
415
416 static void do_wsp_off(void)
417 {
418         wsp_app_unregister();
419         wsp_res_exit();
420 }
421
422
423 static enum wsp_mode g_mode = WSP_OFF;
424 static DEFINE_MUTEX(g_mode_mutex);
425
426 int wsp_set_addr(const char *name, unsigned long offset)
427 {
428         int i, ret = 0;
429
430         if (mutex_trylock(&g_mode_mutex) == 0)
431                 return -EBUSY;
432
433         for (i = 0; i < ewebkit_probes_cnt; ++i) {
434                 if (0 == strcmp(name, ewebkit_probe_array[i].name)) {
435                         ewebkit_probe_array[i].probe.offset = offset;
436                         goto unlock;
437                 }
438         }
439
440         ret = -EINVAL;
441
442 unlock:
443         mutex_unlock(&g_mode_mutex);
444         return ret;
445 }
446
447 int wsp_set_mode(enum wsp_mode mode)
448 {
449         int ret = 0;
450
451         mutex_lock(&g_mode_mutex);
452         switch (mode) {
453         case WSP_ON:
454                 if (g_mode == WSP_ON) {
455                         ret = -EBUSY;
456                         goto unlock;
457                 }
458
459                 ret = wsp_is_addr_init() ? do_wsp_on() : -EPERM;
460                 break;
461         case WSP_OFF:
462                 if (g_mode == WSP_OFF) {
463                         ret = -EBUSY;
464                         goto unlock;
465                 }
466
467                 do_wsp_off();
468                 break;
469         default:
470                 ret = -EINVAL;
471                 break;
472         }
473
474 unlock:
475         if (ret == 0)
476                 g_mode = mode;
477
478         mutex_unlock(&g_mode_mutex);
479         return ret;
480 }
481
482 enum wsp_mode wsp_get_mode(void)
483 {
484         return g_mode;
485 }
486
487 int wsp_init(void)
488 {
489         return 0;
490 }
491
492 void wsp_exit(void)
493 {
494         wsp_set_mode(WSP_OFF);
495 }