Merge branch 'tizen_2.4' into tizen_2.4_dev
[kernel/swap-modules.git] / fbiprobe / fbiprobe.c
1 /*
2  * @file fbiprobe/fbi_probe.c
3  *
4  * @author Alexander Aksenov <a.aksenov@samsung.com>
5  * @author Vitaliy Cherepanov <v.cherepanov@samsung.com>
6  *
7  * @section LICENSE
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22  *
23  * @section COPYRIGHT
24  *
25  * Copyright (C) Samsung Electronics, 2014
26  *
27  * 2014 Alexander Aksenov : FBI implement
28  * 2014 Vitaliy Cherepanov: FBI implement, portage
29  *
30  * @section DESCRIPTION
31  *
32  * Function body instrumetation
33  *
34  */
35
36 #include "fbiprobe.h"
37 #include "fbi_probe_module.h"
38 #include "fbi_msg.h"
39 #include "regs.h"
40
41 #include <us_manager/us_manager.h>
42 #include <us_manager/probes/probes.h>
43 #include <us_manager/probes/register_probes.h>
44
45 #include <uprobe/swap_uprobes.h>
46 #include <us_manager/sspt/ip.h>
47
48 #include <kprobe/swap_kprobes_deps.h>
49 #include <linux/module.h>
50
51 #include <linux/mm.h>
52 #include <linux/sched.h>
53 #include <linux/dcache.h>
54 #include <linux/mm_types.h>
55
56 #include <us_manager/sspt/sspt_page.h>
57 #include <us_manager/sspt/sspt_file.h>
58
59 #define DIRECT_ADDR (0xFF)
60 #define MAX_STRING_LEN (512)
61
62 /* on fails. return NULL, set size to 0 */
63 /* you shoud free allocated data buffer */
64 static char *fbi_probe_alloc_and_read_from_addr(const struct fbi_var_data *fbid,
65                                                 unsigned long addr,
66                                                 uint32_t *size)
67 {
68         uint8_t i, j;
69         char *buf = NULL;
70         struct fbi_step *step;
71
72         *size = 0;
73
74         /* get final variable address */
75         step = fbid->steps;
76         for (i = 0; i != fbid->steps_count; i++) {
77                 /* dereference */
78                 for (j = 0; j != step->ptr_order; j++) {
79                         unsigned long new_addr;
80                         /* equel to: addr = *addr */
81                         if (!read_proc_vm_atomic(current, addr, &new_addr,
82                                                  sizeof(new_addr))) {
83                                 print_warn("p = 0x%lx step #%d ptr_order #%d\n",
84                                            addr, i + 1, j + 1);
85                                 goto exit_fail;
86                         }
87                         addr = new_addr;
88                         print_debug("dereference addr = 0x%lx;\n", addr);
89                 }
90
91                 /* offset */
92                 addr += step->data_offset;
93                 print_debug("addr + offset = 0x%lx;\n", addr);
94                 step++;
95         }
96
97         /* calculate data size */
98         if (fbid->data_size == 0) {
99                 /*
100                  * that mean variable is string and
101                  * we need to calculate string length
102                  */
103
104                 *size = strnlen_user((const char __user *)addr, MAX_STRING_LEN);
105                 if (*size == 0) {
106                         print_warn("Cannot get string from 0x%lx\n", addr);
107                         goto exit_fail;
108                 }
109         } else {
110                 /* else use size from fbi struct */
111                 *size = fbid->data_size;
112         }
113
114         buf = kmalloc(*size, GFP_KERNEL);
115         if (buf == NULL) {
116                 print_warn("Not enough memory\n");
117                 goto exit_fail_size_0;
118         }
119
120         if (!read_proc_vm_atomic(current, addr, buf, *size)) {
121                 print_warn("Error reading data at 0x%lx, task %d\n",
122                            addr, current->pid);
123                 goto exit_fail_free_buf;
124         }
125
126         if (fbid->data_size == 0) {
127                 /*
128                  * that mean variable is string and
129                  * we need to add terminate '\0'
130                  */
131                 buf[*size - 1] = '\0';
132         }
133
134         return buf;
135
136 exit_fail_free_buf:
137         kfree(buf);
138         buf = NULL;
139 exit_fail_size_0:
140         *size = 0;
141 exit_fail:
142         return NULL;
143
144 }
145
146 static int fbi_probe_get_data_from_reg(const struct fbi_var_data *fbi_i,
147                                        struct pt_regs *regs)
148 {
149         unsigned long *reg_ptr;
150
151         reg_ptr = get_ptr_by_num(regs, fbi_i->reg_n);
152         if (reg_ptr == NULL) {
153                 print_err("fbi_probe_get_data_from_reg: Wrong register number!\n");
154                 return 0;
155         }
156
157         fbi_msg(fbi_i->var_id, fbi_i->data_size, (char *)reg_ptr);
158
159         return 0;
160 }
161
162 static int fbi_probe_get_data_from_ptrs(const struct fbi_var_data *fbi_i,
163                                         struct pt_regs *regs)
164 {
165         unsigned long *reg_ptr;
166         unsigned long addr;
167         uint32_t size = 0;
168         void *buf = NULL;
169
170         reg_ptr = get_ptr_by_num(regs, fbi_i->reg_n);
171         if (reg_ptr == NULL) {
172                 print_err("fbi_probe_get_data_from_ptrs: Wrong register number!\n");
173                 goto send_msg;
174         }
175
176         addr = *reg_ptr + fbi_i->reg_offset;
177         print_warn("reg = %p; off = 0x%llx; addr = 0x%lx!\n", reg_ptr,
178                    fbi_i->reg_offset, addr);
179
180         buf = fbi_probe_alloc_and_read_from_addr(fbi_i, addr, &size);
181
182 send_msg:
183         /* If buf is NULL size will be 0.
184          * That mean we cannot get data for this probe.
185          * But we should send probe message with packed data size 0
186          * as error message.
187          */
188         fbi_msg(fbi_i->var_id, size, buf);
189
190         if (buf != NULL)
191                 kfree(buf);
192         else
193                 print_err("cannot get data from ptrs\n");
194
195         return 0;
196 }
197
198 static struct vm_area_struct *find_vma_exe_by_dentry(struct mm_struct *mm,
199                                                      struct dentry *dentry)
200 {
201         struct vm_area_struct *vma;
202
203         /* FIXME: down_write(&mm->mmap_sem); up_write(&mm->mmap_sem); */
204         /* TODO FILTER vma */
205         for (vma = mm->mmap; vma; vma = vma->vm_next) {
206                 if (vma->vm_file &&
207                    (vma->vm_file->f_dentry == dentry))
208                         /* found */
209                         goto exit;
210         }
211
212         /* not found */
213         vma = NULL;
214 exit:
215         return vma;
216 }
217
218 static int fbi_probe_get_data_from_direct_addr(const struct fbi_var_data *fbi_i,
219                                                struct us_ip *ip,
220                                                struct pt_regs *regs)
221 {
222         struct vm_area_struct *vma;
223         unsigned long addr;
224         uint32_t size = 0;
225         char *buf;
226
227         /* register offset is global address */
228         vma = find_vma_exe_by_dentry(current->mm, ip->page->file->dentry);
229         if (vma == NULL) {
230                 print_warn("cannot locate dentry\n");
231                 goto exit;
232         }
233
234         addr = vma->vm_start + fbi_i->reg_offset;
235
236         print_debug("DIRECT_ADDR reg_offset = %llx\n", fbi_i->reg_offset);
237         print_debug("DIRECT_ADDR vm_start   = %lx\n", vma->vm_start);
238         print_debug("DIRECT_ADDR res_addr   = %lx\n", addr);
239
240         buf = fbi_probe_alloc_and_read_from_addr(fbi_i, addr, &size);
241         /* If buf is NULL size will be 0.
242          * That mean we cannot get data for this probe.
243          * But we should send probe message with packed data size 0
244          * as error message.
245          */
246         fbi_msg(fbi_i->var_id, size, buf);
247
248         if (buf != NULL) {
249                 kfree(buf);
250         } else {
251                 print_warn("get data by direct addr failed (0x%lx :0x%llx)\n",
252                            addr, fbi_i->reg_offset);
253         }
254 exit:
255         return 0;
256 }
257
258 static int fbi_probe_handler(struct uprobe *p, struct pt_regs *regs)
259 {
260         struct us_ip *ip = container_of(p, struct us_ip, uprobe);
261         struct fbi_info *fbi_i = &ip->desc->info.fbi_i;
262         struct fbi_var_data *fbi_d = NULL;
263         uint8_t i;
264
265         if (ip->desc->type != SWAP_FBIPROBE) {
266                 /* How this can occure? Doesn't matter, just print and go */
267                 print_err("Not FBI probe in FBI handler!\n");
268                 return 0;
269         }
270
271         for (i = 0; i != fbi_i->var_count; i++) {
272                 fbi_d = &fbi_i->vars[i];
273                 if (fbi_d->reg_n == DIRECT_ADDR) {
274                         if (0 != fbi_probe_get_data_from_direct_addr(fbi_d, ip,
275                                                                      regs))
276                                 print_err("fbi_probe_get_data_from_direct_addr error\n");
277                 } else if (fbi_d->steps_count == 0) {
278                         if (0 != fbi_probe_get_data_from_reg(fbi_d, regs))
279                                 print_err("fbi_probe_get_data_from_reg error\n");
280                 } else {
281                         if (0 != fbi_probe_get_data_from_ptrs(fbi_d, regs))
282                                 print_err("fbi_probe_get_data_from_ptrs error\n");
283                 }
284         }
285
286         return 0;
287 }
288
289 /* FBI probe interfaces */
290 void fbi_probe_cleanup(struct probe_info *probe_i)
291 {
292         uint8_t i;
293         struct fbi_info *fbi_i = &(probe_i->fbi_i);
294
295         for (i = 0; i != fbi_i->var_count; i++) {
296                 if (fbi_i->vars[i].steps != NULL) {
297                         if (fbi_i->vars[i].steps != NULL)
298                                 kfree(fbi_i->vars[i].steps);
299                         fbi_i->vars[i].steps = NULL;
300                         fbi_i->vars[i].steps_count = 0;
301                 }
302         }
303
304         kfree(fbi_i->vars);
305         fbi_i->vars = NULL;
306 }
307
308 void fbi_probe_init(struct us_ip *ip)
309 {
310         ip->uprobe.pre_handler = (uprobe_pre_handler_t)fbi_probe_handler;
311 }
312
313 void fbi_probe_uninit(struct us_ip *ip)
314 {
315         if (ip != NULL)
316                 fbi_probe_cleanup(&ip->desc->info);
317 }
318
319 static int fbi_probe_register_probe(struct us_ip *ip)
320 {
321         return swap_register_uprobe(&ip->uprobe);
322 }
323
324 static void fbi_probe_unregister_probe(struct us_ip *ip, int disarm)
325 {
326         __swap_unregister_uprobe(&ip->uprobe, disarm);
327 }
328
329 static struct uprobe *fbi_probe_get_uprobe(struct us_ip *ip)
330 {
331         return &ip->uprobe;
332 }
333
334 int fbi_probe_copy(struct probe_info *dest, const struct probe_info *source)
335 {
336         uint8_t steps_count;
337         size_t steps_size;
338         size_t vars_size;
339         struct fbi_var_data *vars;
340         struct fbi_step *steps_source;
341         struct fbi_step *steps_dest = NULL;
342         uint8_t i, n;
343         int ret = 0;
344
345         memcpy(dest, source, sizeof(*source));
346
347         vars_size = source->fbi_i.var_count * sizeof(*source->fbi_i.vars);
348         vars = kmalloc(vars_size, GFP_KERNEL);
349         if (vars == NULL)
350                 return -ENOMEM;
351
352         memcpy(vars, source->fbi_i.vars, vars_size);
353
354         for (i = 0; i != source->fbi_i.var_count; i++) {
355                 steps_dest = NULL;
356                 steps_count = vars[i].steps_count;
357                 steps_size = sizeof(*steps_source) * steps_count;
358                 steps_source = vars[i].steps;
359
360                 if (steps_size != 0 && steps_source != NULL) {
361                         steps_dest = kmalloc(steps_size, GFP_KERNEL);
362                         if (steps_dest == NULL) {
363                                 print_err("can not alloc data\n");
364                                 n = i;
365                                 ret = -ENOMEM;
366                                 goto err;
367                         }
368
369                         memcpy(steps_dest, steps_source, steps_size);
370                 }
371                 vars[i].steps = steps_dest;
372         }
373
374         dest->fbi_i.vars = vars;
375
376         return ret;
377 err:
378         for (i = 0; i < n; i++)
379                 kfree(vars[i].steps);
380         kfree(vars);
381         return ret;
382 }
383
384 /* Register */
385 static struct probe_iface fbi_probe_iface = {
386         .init = fbi_probe_init,
387         .uninit = fbi_probe_uninit,
388         .reg = fbi_probe_register_probe,
389         .unreg = fbi_probe_unregister_probe,
390         .get_uprobe = fbi_probe_get_uprobe,
391         .copy = fbi_probe_copy,
392         .cleanup = fbi_probe_cleanup
393 };
394
395 static int __init fbiprobe_module_init(void)
396 {
397         int ret = 0;
398         ret = swap_register_probe_type(SWAP_FBIPROBE, &fbi_probe_iface);
399         print_debug("Init done. Result=%d\n", ret);
400         return ret;
401 }
402
403 static void __exit fbiprobe_module_exit(void)
404 {
405         swap_unregister_probe_type(SWAP_FBIPROBE);
406 }
407
408 module_init(fbiprobe_module_init);
409 module_exit(fbiprobe_module_exit);
410
411 MODULE_LICENSE("GPL");
412 MODULE_DESCRIPTION("SWAP fbiprobe");
413 MODULE_AUTHOR("Alexander Aksenov <a.aksenov@samsung.com>; Vitaliy Cherepanov <v.cherepanov@samsung.com>");
414