21dcde1ee27afb6a24e19e2ca1c4584afe60fece
[kernel/swap-modules.git] / us_manager / sspt / sspt_page.c
1 /*
2  *  Dynamic Binary Instrumentation Module based on KProbes
3  *  modules/driver/sspt/sspt_page.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_page.h"
27 #include "sspt_file.h"
28 #include "ip.h"
29 #include <linux/slab.h>
30 #include <linux/list.h>
31
32 struct sspt_page *sspt_page_create(unsigned long offset)
33 {
34         struct sspt_page *obj = kmalloc(sizeof(*obj), GFP_ATOMIC);
35         if (obj) {
36                 INIT_LIST_HEAD(&obj->ip_list);
37                 obj->offset = offset;
38                 obj->install = 0;
39                 spin_lock_init(&obj->lock);
40                 obj->file = NULL;
41                 INIT_HLIST_NODE(&obj->hlist);
42         }
43
44         return obj;
45 }
46
47 void sspt_page_free(struct sspt_page *page)
48 {
49         struct us_ip *ip, *n;
50
51         list_for_each_entry_safe(ip, n, &page->ip_list, list) {
52                 list_del(&ip->list);
53                 free_ip(ip);
54         }
55
56         kfree(page);
57 }
58
59 static void sspt_list_add_ip(struct sspt_page *page, struct us_ip *ip)
60 {
61         list_add(&ip->list, &page->ip_list);
62         ip->page = page;
63 }
64
65 static void sspt_list_del_ip(struct us_ip *ip)
66 {
67         list_del(&ip->list);
68 }
69
70 void sspt_add_ip(struct sspt_page *page, struct us_ip *ip)
71 {
72         struct us_ip *ip_tmp;
73
74         ip->offset &= ~PAGE_MASK;
75
76         list_for_each_entry(ip_tmp, &page->ip_list, list) {
77                 if (ip_tmp->offset == ip->offset) {
78                         /* TODO: process second instanse of probe */
79                         return;
80                 }
81         }
82
83         sspt_list_add_ip(page, ip);
84 }
85
86 void sspt_del_ip(struct us_ip *ip)
87 {
88         sspt_list_del_ip(ip);
89         free_ip(ip);
90 }
91
92 struct us_ip *sspt_find_ip(struct sspt_page *page, unsigned long offset)
93 {
94         struct us_ip *ip;
95
96         list_for_each_entry(ip, &page->ip_list, list) {
97                 if (ip->offset == offset) {
98                         return ip;
99                 }
100         }
101
102         return NULL;
103 }
104
105 void sspt_set_all_ip_addr(struct sspt_page *page, const struct sspt_file *file)
106 {
107         struct us_ip *ip;
108         unsigned long addr;
109
110         list_for_each_entry(ip, &page->ip_list, list) {
111                 addr = file->vm_start + page->offset + ip->offset;
112                 ip->retprobe.up.kp.addr = ip->jprobe.up.kp.addr = (kprobe_opcode_t *)addr;
113         }
114 }
115
116 int sspt_register_page(struct sspt_page *page, struct sspt_file *file)
117 {
118         int err = 0;
119         struct us_ip *ip, *n;
120
121         spin_lock(&page->lock);
122
123         if (sspt_page_is_installed(page)) {
124                 struct task_struct *task = page->file->proc->task;
125
126                 printk("page %lx in %s task[tgid=%u, pid=%u] already installed\n",
127                                 page->offset, file->dentry->d_iname, task->tgid, task->pid);
128                 goto unlock;
129         }
130
131         sspt_page_assert_install(page);
132         sspt_set_all_ip_addr(page, file);
133
134         list_for_each_entry_safe(ip, n, &page->ip_list, list) {
135                 err = sspt_register_usprobe(ip);
136                 if (err == -ENOEXEC) {
137                         list_del(&ip->list);
138                         free_ip(ip);
139                         continue;
140                 } else if (err) {
141                         printk("Failed to install probe\n");
142                 }
143         }
144 unlock:
145         sspt_page_install(page);
146         spin_unlock(&page->lock);
147
148         return 0;
149 }
150
151 int sspt_unregister_page(struct sspt_page *page,
152                          enum US_FLAGS flag,
153                          struct task_struct *task)
154 {
155         int err = 0;
156         struct us_ip *ip;
157
158         spin_lock(&page->lock);
159         if (!sspt_page_is_installed(page)) {
160                 spin_unlock(&page->lock);
161                 return 0;
162         }
163
164         list_for_each_entry(ip, &page->ip_list, list) {
165                 err = sspt_unregister_usprobe(task, ip, flag);
166                 if (err != 0) {
167                         //TODO: ERROR
168                         break;
169                 }
170         }
171
172         if (flag != US_DISARM) {
173                 sspt_page_uninstall(page);
174         }
175         spin_unlock(&page->lock);
176
177         return err;
178 }