Merge branch 'tizen_2.4' into tizen_2.4_dev
[kernel/swap-modules.git] / us_manager / sspt / sspt_proc.c
1 /*
2  *  Dynamic Binary Instrumentation Module based on KProbes
3  *  modules/driver/sspt/sspt_proc.c
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18  *
19  * Copyright (C) Samsung Electronics, 2013
20  *
21  * 2013         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
22  *
23  */
24
25 #include "sspt.h"
26 #include "sspt_proc.h"
27 #include "sspt_page.h"
28 #include "sspt_feature.h"
29 #include "sspt_filter.h"
30 #include "../pf/proc_filters.h"
31 #include <linux/module.h>
32 #include <linux/slab.h>
33 #include <linux/list.h>
34 #include <us_manager/us_slot_manager.h>
35
36 static LIST_HEAD(proc_probes_list);
37 static DEFINE_RWLOCK(sspt_proc_rwlock);
38
39
40 struct list_head *sspt_proc_list()
41 {
42         return &proc_probes_list;
43 }
44
45 /**
46  * @brief Global read lock for sspt_proc
47  *
48  * @return Void
49  */
50 void sspt_proc_read_lock(void)
51 {
52         read_lock(&sspt_proc_rwlock);
53 }
54
55 /**
56  * @brief Global read unlock for sspt_proc
57  *
58  * @return Void
59  */
60 void sspt_proc_read_unlock(void)
61 {
62         read_unlock(&sspt_proc_rwlock);
63 }
64
65 /**
66  * @brief Global write lock for sspt_proc
67  *
68  * @return Void
69  */
70 void sspt_proc_write_lock(void)
71 {
72         write_lock(&sspt_proc_rwlock);
73 }
74
75 /**
76  * @brief Global write unlock for sspt_proc
77  *
78  * @return Void
79  */
80 void sspt_proc_write_unlock(void)
81 {
82         write_unlock(&sspt_proc_rwlock);
83 }
84
85
86 /**
87  * @brief Create sspt_proc struct
88  *
89  * @param task Pointer to the task_struct struct
90  * @param priv Private data
91  * @return Pointer to the created sspt_proc struct
92  */
93 struct sspt_proc *sspt_proc_create(struct task_struct *task)
94 {
95         struct sspt_proc *proc = kzalloc(sizeof(*proc), GFP_ATOMIC);
96
97         if (proc) {
98                 proc->feature = sspt_create_feature();
99                 if (proc->feature == NULL) {
100                         kfree(proc);
101                         return NULL;
102                 }
103
104                 INIT_LIST_HEAD(&proc->list);
105                 proc->tgid = task->tgid;
106                 proc->task = task->group_leader;
107                 proc->sm = create_sm_us(task);
108                 INIT_LIST_HEAD(&proc->file_list);
109                 rwlock_init(&proc->filter_lock);
110                 INIT_LIST_HEAD(&proc->filter_list);
111                 atomic_set(&proc->usage, 1);
112
113                 get_task_struct(proc->task);
114
115                 /* add to list */
116                 list_add(&proc->list, &proc_probes_list);
117         }
118
119         return proc;
120 }
121
122 /**
123  * @brief Remove sspt_proc struct
124  *
125  * @param proc remove object
126  * @return Void
127  */
128
129 /* called with sspt_proc_write_lock() */
130 void sspt_proc_cleanup(struct sspt_proc *proc)
131 {
132         struct sspt_file *file, *n;
133
134         sspt_proc_del_all_filters(proc);
135
136         list_for_each_entry_safe(file, n, &proc->file_list, list) {
137                 list_del(&file->list);
138                 sspt_file_free(file);
139         }
140
141         sspt_destroy_feature(proc->feature);
142
143         free_sm_us(proc->sm);
144         sspt_proc_put(proc);
145 }
146
147 struct sspt_proc *sspt_proc_get(struct sspt_proc *proc)
148 {
149         atomic_inc(&proc->usage);
150
151         return proc;
152 }
153
154 void sspt_proc_put(struct sspt_proc *proc)
155 {
156         if (atomic_dec_and_test(&proc->usage)) {
157                 if (proc->__mm) {
158                         mmput(proc->__mm);
159                         proc->__mm = NULL;
160                 }
161                 if (proc->__task) {
162                         put_task_struct(proc->__task);
163                         proc->__task = NULL;
164                 }
165
166                 put_task_struct(proc->task);
167                 kfree(proc);
168         }
169 }
170
171 struct sspt_proc *sspt_proc_get_by_task(struct task_struct *task)
172 {
173         struct sspt_proc *proc;
174
175         sspt_proc_read_lock();
176         proc = sspt_proc_get_by_task_no_lock(task);
177         sspt_proc_read_unlock();
178
179         return proc;
180 }
181 EXPORT_SYMBOL_GPL(sspt_proc_get_by_task);
182
183 /**
184  * @brief Get sspt_proc by task
185  *
186  * @param task Pointer on the task_struct struct
187  * @return Pointer on the sspt_proc struct
188  */
189 struct sspt_proc *sspt_proc_get_by_task_no_lock(struct task_struct *task)
190 {
191         struct sspt_proc *proc, *tmp;
192
193         list_for_each_entry_safe(proc, tmp, &proc_probes_list, list) {
194                 if (proc->tgid == task->tgid)
195                         return proc;
196         }
197
198         return NULL;
199 }
200 EXPORT_SYMBOL_GPL(sspt_proc_get_by_task_no_lock);
201
202 /**
203  * @brief Call func() on each proc (no lock)
204  *
205  * @param func Callback
206  * @param data Data for callback
207  * @return Void
208  */
209 void on_each_proc_no_lock(void (*func)(struct sspt_proc *, void *), void *data)
210 {
211         struct sspt_proc *proc, *tmp;
212
213         list_for_each_entry_safe(proc, tmp, &proc_probes_list, list) {
214                 func(proc, data);
215         }
216 }
217
218 /**
219  * @brief Call func() on each proc
220  *
221  * @param func Callback
222  * @param data Data for callback
223  * @return Void
224  */
225 void on_each_proc(void (*func)(struct sspt_proc *, void *), void *data)
226 {
227         sspt_proc_read_lock();
228         on_each_proc_no_lock(func, data);
229         sspt_proc_read_unlock();
230 }
231 EXPORT_SYMBOL_GPL(on_each_proc);
232
233 /**
234  * @brief Get sspt_proc by task or create sspt_proc
235  *
236  * @param task Pointer on the task_struct struct
237  * @param priv Private data
238  * @return Pointer on the sspt_proc struct
239  */
240 struct sspt_proc *sspt_proc_get_by_task_or_new(struct task_struct *task)
241 {
242         struct sspt_proc *proc;
243
244         sspt_proc_write_lock();
245         proc = sspt_proc_get_by_task_no_lock(task);
246         if (proc == NULL)
247                 proc = sspt_proc_create(task);
248         sspt_proc_write_unlock();
249
250         return proc;
251 }
252
253 /**
254  * @brief Free all sspt_proc
255  *
256  * @return Pointer on the sspt_proc struct
257  */
258 void sspt_proc_free_all(void)
259 {
260         struct sspt_proc *proc, *n;
261
262         list_for_each_entry_safe(proc, n, &proc_probes_list, list) {
263                 list_del(&proc->list);
264                 sspt_proc_cleanup(proc);
265         }
266 }
267
268 static void sspt_proc_add_file(struct sspt_proc *proc, struct sspt_file *file)
269 {
270         list_add(&file->list, &proc->file_list);
271         file->proc = proc;
272 }
273
274 /**
275  * @brief Get sspt_file from sspt_proc by dentry or new
276  *
277  * @param proc Pointer on the sspt_proc struct
278  * @param dentry Dentry of file
279  * @return Pointer on the sspt_file struct
280  */
281 struct sspt_file *sspt_proc_find_file_or_new(struct sspt_proc *proc,
282                                              struct dentry *dentry)
283 {
284         struct sspt_file *file;
285
286         file = sspt_proc_find_file(proc, dentry);
287         if (file == NULL) {
288                 file = sspt_file_create(dentry, 10);
289                 if (file)
290                         sspt_proc_add_file(proc, file);
291         }
292
293         return file;
294 }
295
296 /**
297  * @brief Get sspt_file from sspt_proc by dentry
298  *
299  * @param proc Pointer on the sspt_proc struct
300  * @param dentry Dentry of file
301  * @return Pointer on the sspt_file struct
302  */
303 struct sspt_file *sspt_proc_find_file(struct sspt_proc *proc,
304                                       struct dentry *dentry)
305 {
306         struct sspt_file *file;
307
308         list_for_each_entry(file, &proc->file_list, list) {
309                 if (dentry == file->dentry)
310                         return file;
311         }
312
313         return NULL;
314 }
315
316 /**
317  * @brief Install probes on the page to monitored process
318  *
319  * @param proc Pointer on the sspt_proc struct
320  * @param page_addr Page address
321  * @return Void
322  */
323 void sspt_proc_install_page(struct sspt_proc *proc, unsigned long page_addr)
324 {
325         struct mm_struct *mm = proc->task->mm;
326         struct vm_area_struct *vma;
327
328         vma = find_vma_intersection(mm, page_addr, page_addr + 1);
329         if (vma && check_vma(vma)) {
330                 struct dentry *dentry = vma->vm_file->f_dentry;
331                 struct sspt_file *file = sspt_proc_find_file(proc, dentry);
332                 if (file) {
333                         struct sspt_page *page;
334
335                         sspt_file_set_mapping(file, vma);
336
337                         page = sspt_find_page_mapped(file, page_addr);
338                         if (page)
339                                 sspt_register_page(page, file);
340                 }
341         }
342 }
343
344 /**
345  * @brief Install probes to monitored process
346  *
347  * @param proc Pointer on the sspt_proc struct
348  * @return Void
349  */
350 void sspt_proc_install(struct sspt_proc *proc)
351 {
352         struct vm_area_struct *vma;
353         struct mm_struct *mm = proc->task->mm;
354
355         proc->first_install = 1;
356
357         for (vma = mm->mmap; vma; vma = vma->vm_next) {
358                 if (check_vma(vma)) {
359                         struct dentry *dentry = vma->vm_file->f_dentry;
360                         struct sspt_file *file =
361                                 sspt_proc_find_file(proc, dentry);
362                         if (file) {
363                                 sspt_file_set_mapping(file, vma);
364                                 sspt_file_install(file);
365                         }
366                 }
367         }
368 }
369
370 /**
371  * @brief Uninstall probes to monitored process
372  *
373  * @param proc Pointer on the sspt_proc struct
374  * @param task Pointer on the task_struct struct
375  * @param flag Action for probes
376  * @return Error code
377  */
378 int sspt_proc_uninstall(struct sspt_proc *proc,
379                         struct task_struct *task,
380                         enum US_FLAGS flag)
381 {
382         int err = 0;
383         struct sspt_file *file;
384
385         list_for_each_entry_rcu(file, &proc->file_list, list) {
386                 err = sspt_file_uninstall(file, task, flag);
387                 if (err != 0) {
388                         printk(KERN_INFO "ERROR sspt_proc_uninstall: err=%d\n",
389                                err);
390                         return err;
391                 }
392         }
393
394         return err;
395 }
396
397 static int intersection(unsigned long start_a, unsigned long end_a,
398                         unsigned long start_b, unsigned long end_b)
399 {
400         return start_a < start_b ?
401                         end_a > start_b :
402                         start_a < end_b;
403 }
404
405 /**
406  * @brief Get sspt_file list by region (remove sspt_file from sspt_proc list)
407  *
408  * @param proc Pointer on the sspt_proc struct
409  * @param head[out] Pointer on the head list
410  * @param start Region start
411  * @param len Region length
412  * @return Error code
413  */
414 int sspt_proc_get_files_by_region(struct sspt_proc *proc,
415                                   struct list_head *head,
416                                   unsigned long start, size_t len)
417 {
418         int ret = 0;
419         struct sspt_file *file, *n;
420         unsigned long end = start + len;
421
422         list_for_each_entry_safe(file, n, &proc->file_list, list) {
423                 if (intersection(file->vm_start, file->vm_end, start, end)) {
424                         ret = 1;
425                         list_move(&file->list, head);
426                 }
427         }
428
429         return ret;
430 }
431
432 /**
433  * @brief Insert sspt_file to sspt_proc list
434  *
435  * @param proc Pointer on the sspt_proc struct
436  * @param head Pointer on the head list
437  * @return Void
438  */
439 void sspt_proc_insert_files(struct sspt_proc *proc, struct list_head *head)
440 {
441         list_splice(head, &proc->file_list);
442 }
443
444 /**
445  * @brief Add sspt_filter to sspt_proc list
446  *
447  * @param proc Pointer to sspt_proc struct
448  * @param pfg Pointer to pf_group struct
449  * @return Void
450  */
451 void sspt_proc_add_filter(struct sspt_proc *proc, struct pf_group *pfg)
452 {
453         struct sspt_filter *f;
454
455         f = sspt_filter_create(proc, pfg);
456         if (f)
457                 list_add(&f->list, &proc->filter_list);
458 }
459
460 /**
461  * @brief Remove sspt_filter from sspt_proc list
462  *
463  * @param proc Pointer to sspt_proc struct
464  * @param pfg Pointer to pf_group struct
465  * @return Void
466  */
467 void sspt_proc_del_filter(struct sspt_proc *proc, struct pf_group *pfg)
468 {
469         struct sspt_filter *fl, *tmp;
470
471         write_lock(&proc->filter_lock);
472         list_for_each_entry_safe(fl, tmp, &proc->filter_list, list) {
473                 if (fl->pfg == pfg) {
474                         list_del(&fl->list);
475                         sspt_filter_free(fl);
476                 }
477         }
478         write_unlock(&proc->filter_lock);
479 }
480
481 /**
482  * @brief Remove all sspt_filters from sspt_proc list
483  *
484  * @param proc Pointer to sspt_proc struct
485  * @return Void
486  */
487 void sspt_proc_del_all_filters(struct sspt_proc *proc)
488 {
489         struct sspt_filter *fl, *tmp;
490
491         write_lock(&proc->filter_lock);
492         list_for_each_entry_safe(fl, tmp, &proc->filter_list, list) {
493                 list_del(&fl->list);
494                 sspt_filter_free(fl);
495         }
496         write_unlock(&proc->filter_lock);
497 }
498
499 /**
500  * @brief Check if sspt_filter is already in sspt_proc list
501  *
502  * @param proc Pointer to sspt_proc struct
503  * @param pfg Pointer to pf_group struct
504  * @return Boolean
505  */
506 bool sspt_proc_is_filter_new(struct sspt_proc *proc, struct pf_group *pfg)
507 {
508         struct sspt_filter *fl;
509
510         list_for_each_entry(fl, &proc->filter_list, list)
511                 if (fl->pfg == pfg)
512                         return false;
513
514         return true;
515 }
516
517 void sspt_proc_on_each_filter(struct sspt_proc *proc,
518                               void (*func)(struct sspt_filter *, void *),
519                               void *data)
520 {
521         struct sspt_filter *fl;
522
523         list_for_each_entry(fl, &proc->filter_list, list)
524                 func(fl, data);
525 }
526
527 void sspt_proc_on_each_ip(struct sspt_proc *proc,
528                           void (*func)(struct us_ip *, void *), void *data)
529 {
530         struct sspt_file *file;
531
532         list_for_each_entry(file, &proc->file_list, list)
533                 sspt_file_on_each_ip(file, func, data);
534 }
535
536 static void is_send_event(struct sspt_filter *f, void *data)
537 {
538         bool *is_send = (bool *)data;
539
540         if (!*is_send && f->pfg_is_inst)
541                 *is_send = !!pfg_msg_cb_get(f->pfg);
542 }
543
544 bool sspt_proc_is_send_event(struct sspt_proc *proc)
545 {
546         bool is_send = false;
547
548         /* FIXME: add read lock (deadlock in sampler) */
549         sspt_proc_on_each_filter(proc, is_send_event, (void *)&is_send);
550
551         return is_send;
552 }
553
554
555 static struct sspt_proc_cb *proc_cb;
556
557 int sspt_proc_cb_set(struct sspt_proc_cb *cb)
558 {
559         if (cb && proc_cb)
560                 return -EBUSY;
561
562         proc_cb = cb;
563
564         return 0;
565 }
566 EXPORT_SYMBOL_GPL(sspt_proc_cb_set);
567
568 void sspt_proc_priv_create(struct sspt_proc *proc)
569 {
570         if (proc_cb && proc_cb->priv_create)
571                 proc->private_data = proc_cb->priv_create(proc);
572 }
573
574 void sspt_proc_priv_destroy(struct sspt_proc *proc)
575 {
576         if (proc->first_install && proc_cb && proc_cb->priv_destroy)
577                 proc_cb->priv_destroy(proc, proc->private_data);
578 }