ba3fd6678273f3580e744ccfb67be89910b0911a
[profile/mobile/platform/kernel/linux-3.10-sc7730.git] / kernel / swap / preload / preload_debugfs.c
1 #include <linux/kernel.h>
2 #include <linux/debugfs.h>
3 #include <linux/err.h>
4 #include <linux/fs.h>
5 #include <linux/module.h>
6 #include <linux/slab.h>
7 #include <linux/spinlock.h>
8 #include <linux/limits.h>
9 #include <asm/uaccess.h>
10 #include <master/swap_debugfs.h>
11 #include "preload.h"
12 #include "preload_debugfs.h"
13 #include "preload_module.h"
14 #include "preload_control.h"
15 #include "preload_storage.h"
16
17 static const char PRELOAD_FOLDER[] = "preload";
18 static const char PRELOAD_LOADER[] = "loader";
19 static const char PRELOAD_LOADER_OFFSET[] = "loader_offset";
20 static const char PRELOAD_LOADER_PATH[] = "loader_path";
21 static const char PRELOAD_BINARIES[] = "target_binaries";
22 static const char PRELOAD_BINARIES_LIST[] = "bins_list";
23 static const char PRELOAD_BINARIES_ADD[] = "bins_add";
24 static const char PRELOAD_BINARIES_REMOVE[] = "bins_remove";
25 static const char PRELOAD_CALLER[] = "caller";
26 static const char PRELOAD_HANDLERS_PATH[] = "handlers_path";
27 static const char PRELOAD_LINKER_DATA[] = "linker";
28 static const char PRELOAD_LINKER_PATH[] = "linker_path";
29 static const char PRELOAD_LINKER_R_DEBUG_OFFSET[] = "r_debug_offset";
30
31 struct loader_info {
32         char *path;
33         unsigned long offset;
34         struct dentry *dentry;
35 };
36
37 static struct dentry *preload_root;
38 static struct loader_info __loader_info;
39
40 static unsigned long r_debug_offset = 0;
41 static DEFINE_SPINLOCK(__dentry_lock);
42
43 static inline void dentry_lock(void)
44 {
45         spin_lock(&__dentry_lock);
46 }
47
48 static inline void dentry_unlock(void)
49 {
50         spin_unlock(&__dentry_lock);
51 }
52
53
54 static void set_loader_file(char *path)
55 {
56         __loader_info.path = path;
57         dentry_lock();
58         __loader_info.dentry = get_dentry(__loader_info.path);
59         dentry_unlock();
60 }
61
62 struct dentry *preload_debugfs_get_loader_dentry(void)
63 {
64         struct dentry *dentry;
65
66         dentry_lock();
67         dentry = __loader_info.dentry;
68         dentry_unlock();
69
70         return dentry;
71 }
72
73 unsigned long preload_debugfs_get_loader_offset(void)
74 {
75         /* TODO Think about sync */
76         return __loader_info.offset;
77 }
78
79 static void clean_loader_info(void)
80 {
81         if (__loader_info.path != NULL)
82                 kfree(__loader_info.path);
83         __loader_info.path = NULL;
84
85         dentry_lock();
86         if (__loader_info.dentry != NULL)
87                 put_dentry(__loader_info.dentry);
88
89         __loader_info.dentry = NULL;
90         __loader_info.offset = 0;
91
92         dentry_unlock();
93 }
94
95 struct dentry *debugfs_create_ptr(const char *name, mode_t mode,
96                                   struct dentry *parent,
97                                   unsigned long *value)
98 {
99         struct dentry *dentry;
100
101 #if BITS_PER_LONG == 32
102         dentry = debugfs_create_x32(name, mode, parent, (u32 *)value);
103 #elif BITS_PER_LONG == 64
104         dentry = debugfs_create_x64(name, mode, parent, (u64 *)value);
105 #else
106 #error Unsupported BITS_PER_LONG value
107 #endif
108
109         return dentry;
110 }
111
112
113 /* ===========================================================================
114  * =                              LOADER PATH                                =
115  * ===========================================================================
116  */
117
118 static ssize_t loader_path_write(struct file *file, const char __user *buf,
119                                  size_t len, loff_t *ppos)
120 {
121         ssize_t ret;
122         char *path;
123
124         if (preload_module_is_running())
125                 return -EBUSY;
126
127         clean_loader_info();
128
129         path = kmalloc(len, GFP_KERNEL);
130         if (path == NULL) {
131                 return -ENOMEM;
132         }
133
134         if (copy_from_user(path, buf, len)) {
135                 ret = -EINVAL;
136                 goto err;
137         }
138
139         path[len - 1] = '\0';
140         set_loader_file(path);
141         ret = len;
142
143         return ret;
144 err:
145         kfree(path);
146         return ret;
147 }
148
149
150 static const struct file_operations loader_path_file_ops = {
151         .owner = THIS_MODULE,
152         .write = loader_path_write,
153 };
154
155
156 /* ===========================================================================
157  * =                                BIN PATH                                 =
158  * ===========================================================================
159  */
160
161 static ssize_t bin_add_write(struct file *file, const char __user *buf,
162                            size_t len, loff_t *ppos)
163 {
164         ssize_t ret;
165         char *path;
166
167         path = kmalloc(len, GFP_KERNEL);
168         if (path == NULL) {
169                 ret = -ENOMEM;
170                 goto bin_add_write_out;
171         }
172
173         if (copy_from_user(path, buf, len)) {
174                 ret = -EINVAL;
175                 goto bin_add_write_out;
176         }
177
178         path[len - 1] = '\0';
179
180         if (preload_control_add_instrumented_binary(path) != 0) {
181                 printk(PRELOAD_PREFIX "Cannot add binary %s\n", path);
182                 ret = -EINVAL;
183                 goto bin_add_write_out;
184         }
185
186         ret = len;
187
188 bin_add_write_out:
189         kfree(path);
190
191         return ret;
192 }
193
194 static ssize_t bin_remove_write(struct file *file, const char __user *buf,
195                               size_t len, loff_t *ppos)
196 {
197         ssize_t ret;
198
199         ret = preload_control_clean_instrumented_bins();
200         if (ret != 0) {
201                 printk(PRELOAD_PREFIX "Error during clean!\n");
202                 ret = -EINVAL;
203                 goto bin_remove_write_out;
204         }
205
206         ret = len;
207
208 bin_remove_write_out:
209         return ret;
210 }
211
212 static ssize_t bin_list_read(struct file *file, char __user *usr_buf,
213                                  size_t count, loff_t *ppos)
214 {
215         unsigned int i;
216         unsigned int files_cnt = 0;
217         ssize_t len = 0, tmp, ret = 0;
218         char **filenames = NULL;
219         char *buf = NULL;
220         char *ptr = NULL;
221
222         files_cnt = preload_control_get_bin_names(&filenames);
223
224         if (files_cnt == 0) {
225                 printk(PRELOAD_PREFIX "Cannot read binaries names!\n");
226                 ret = 0;
227                 goto bin_list_read_out;
228         }
229
230         for (i = 0; i < files_cnt; i++)
231                 len += strlen(filenames[i]);
232
233         buf = kmalloc(len + files_cnt, GFP_KERNEL);
234         if (buf == NULL) {
235                 ret = 0;
236                 goto bin_list_read_fail;
237         }
238
239         ptr = buf;
240
241         for (i = 0; i < files_cnt; i++) {
242                 tmp = strlen(filenames[i]);
243                 memcpy(ptr, filenames[i], tmp);
244                 ptr += tmp;
245                 *ptr = '\n';
246                 ptr += 1;
247         }
248
249         preload_control_release_bin_names(&filenames);
250
251         return simple_read_from_buffer(usr_buf, count, ppos, buf, len);
252
253 bin_list_read_fail:
254         preload_control_release_bin_names(&filenames);
255
256 bin_list_read_out:
257         return ret;
258 }
259
260 static const struct file_operations bin_list_file_ops = {
261         .owner = THIS_MODULE,
262         .read = bin_list_read
263 };
264
265 static const struct file_operations bin_add_file_ops = {
266         .owner = THIS_MODULE,
267         .write = bin_add_write,
268 };
269
270 static const struct file_operations bin_remove_file_ops = {
271         .owner = THIS_MODULE,
272         .write = bin_remove_write,
273 };
274
275
276 /* ===========================================================================
277  * =                            LINKER PATH                                  =
278  * ===========================================================================
279  */
280
281
282 static ssize_t linker_path_write(struct file *file, const char __user *buf,
283                                   size_t len, loff_t *ppos)
284 {
285         ssize_t ret;
286         char *path;
287
288         path = kmalloc(len, GFP_KERNEL);
289         if (path == NULL) {
290                 ret = -ENOMEM;
291                 goto linker_path_write_out;
292         }
293
294         if (copy_from_user(path, buf, len)) {
295                 ret = -EINVAL;
296                 goto linker_path_write_out;
297         }
298
299         path[len - 1] = '\0';
300
301         if (preload_storage_set_linker_info(path) != 0) {
302                 printk(PRELOAD_PREFIX "Cannot set linker path %s\n", path);
303                 ret = -EINVAL;
304                 goto linker_path_write_out;
305         }
306
307         ret = len;
308
309 linker_path_write_out:
310         kfree(path);
311
312         return ret;
313 }
314
315 static const struct file_operations linker_path_file_ops = {
316         .owner = THIS_MODULE,
317         .write = linker_path_write,
318 };
319
320
321 /* ===========================================================================
322  * =                           HANDLERS PATH                                 =
323  * ===========================================================================
324  */
325
326
327 static ssize_t handlers_path_write(struct file *file, const char __user *buf,
328                                    size_t len, loff_t *ppos)
329 {
330         ssize_t ret;
331         char *path;
332
333         path = kmalloc(len, GFP_KERNEL);
334         if (path == NULL) {
335                 ret = -ENOMEM;
336                 goto handlers_path_write_out;
337         }
338
339         if (copy_from_user(path, buf, len)) {
340                 ret = -EINVAL;
341                 goto handlers_path_write_out;
342         }
343
344         path[len - 1] = '\0';
345
346         if (preload_storage_set_handlers_info(path) != 0) {
347                 printk(PRELOAD_PREFIX "Cannot set handler path %s\n", path);
348                 ret = -EINVAL;
349                 goto handlers_path_write_out;
350         }
351
352         ret = len;
353
354 handlers_path_write_out:
355         kfree(path);
356
357         return ret;
358 }
359
360 static const struct file_operations handlers_path_file_ops = {
361         .owner = THIS_MODULE,
362         .write = handlers_path_write,
363 };
364
365
366
367
368 unsigned long preload_debugfs_r_debug_offset(void)
369 {
370         return r_debug_offset;
371 }
372
373 int preload_debugfs_init(void)
374 {
375         struct dentry *swap_dentry, *root, *loader, *open_p, *lib_path,
376                   *bin_path, *bin_list, *bin_add, *bin_remove,
377                   *linker_dir, *linker_path, *linker_offset, *handlers_path;
378         int ret;
379
380         ret = -ENODEV;
381         if (!debugfs_initialized())
382                 goto fail;
383
384         ret = -ENOENT;
385         swap_dentry = swap_debugfs_getdir();
386         if (!swap_dentry)
387                 goto fail;
388
389         ret = -ENOMEM;
390         root = debugfs_create_dir(PRELOAD_FOLDER, swap_dentry);
391         if (IS_ERR_OR_NULL(root))
392                 goto fail;
393
394         preload_root = root;
395
396         loader = debugfs_create_dir(PRELOAD_LOADER, root);
397         if (IS_ERR_OR_NULL(root)) {
398                 ret = -ENOMEM;
399                 goto remove;
400         }
401
402         open_p = debugfs_create_ptr(PRELOAD_LOADER_OFFSET, PRELOAD_DEFAULT_PERMS,
403                                     loader, &__loader_info.offset);
404         if (IS_ERR_OR_NULL(open_p)) {
405                 ret = -ENOMEM;
406                 goto remove;
407         }
408
409         lib_path = debugfs_create_file(PRELOAD_LOADER_PATH, PRELOAD_DEFAULT_PERMS,
410                                        loader, NULL, &loader_path_file_ops);
411         if (IS_ERR_OR_NULL(lib_path)) {
412                 ret = -ENOMEM;
413                 goto remove;
414         }
415
416         bin_path = debugfs_create_dir(PRELOAD_BINARIES, root);
417         if (IS_ERR_OR_NULL(bin_path)) {
418                 ret = -ENOMEM;
419                 goto remove;
420         }
421
422         bin_list = debugfs_create_file(PRELOAD_BINARIES_LIST, PRELOAD_DEFAULT_PERMS,
423                                        bin_path, NULL, &bin_list_file_ops);
424         if (IS_ERR_OR_NULL(bin_list)) {
425                 ret = -ENOMEM;
426                 goto remove;
427         }
428
429         bin_add = debugfs_create_file(PRELOAD_BINARIES_ADD, PRELOAD_DEFAULT_PERMS,
430                                        bin_path, NULL, &bin_add_file_ops);
431         if (IS_ERR_OR_NULL(bin_add)) {
432                 ret = -ENOMEM;
433                 goto remove;
434         }
435
436         bin_remove = debugfs_create_file(PRELOAD_BINARIES_REMOVE,
437                                          PRELOAD_DEFAULT_PERMS, bin_path, NULL,
438                                          &bin_remove_file_ops);
439         if (IS_ERR_OR_NULL(bin_remove)) {
440                 ret = -ENOMEM;
441                 goto remove;
442         }
443
444         linker_dir = debugfs_create_dir(PRELOAD_LINKER_DATA, root);
445         if (IS_ERR_OR_NULL(linker_dir)) {
446                 ret = -ENOMEM;
447                 goto remove;
448         }
449
450         linker_path = debugfs_create_file(PRELOAD_LINKER_PATH,
451                                           PRELOAD_DEFAULT_PERMS, linker_dir, NULL,
452                                           &linker_path_file_ops);
453         if (IS_ERR_OR_NULL(linker_path)) {
454                 ret = -ENOMEM;
455                 goto remove;
456         }
457
458         linker_offset = debugfs_create_ptr(PRELOAD_LINKER_R_DEBUG_OFFSET,
459                                            PRELOAD_DEFAULT_PERMS, linker_dir,
460                                            &r_debug_offset);
461         if (IS_ERR_OR_NULL(linker_offset)) {
462                 ret = -ENOMEM;
463                 goto remove;
464         }
465
466         handlers_path = debugfs_create_file(PRELOAD_HANDLERS_PATH,
467                                             PRELOAD_DEFAULT_PERMS, root, NULL,
468                                             &handlers_path_file_ops);
469         if (IS_ERR_OR_NULL(handlers_path)) {
470                 ret = -ENOMEM;
471                 goto remove;
472         }
473
474         return 0;
475
476 remove:
477
478         debugfs_remove_recursive(root);
479
480 fail:
481         printk(PRELOAD_PREFIX "Debugfs initialization failure: %d\n", ret);
482
483         return ret;
484 }
485
486 void preload_debugfs_exit(void)
487 {
488         if (preload_root)
489                 debugfs_remove_recursive(preload_root);
490         preload_root = NULL;
491
492         preload_module_set_not_ready();
493         clean_loader_info();
494 }