2 * Dynamic Binary Instrumentation Module based on KProbes
3 * modules/ksyms/ksyms.c
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.
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.
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.
19 * Copyright (C) Samsung Electronics, 2013
21 * 2013 Vyacheslav Cherkashin <v.cherkashin@samsung.com>
26 #include <linux/module.h>
27 #include <linux/types.h>
28 #include <linux/vmalloc.h>
29 #include <linux/semaphore.h>
31 #include <linux/slab.h>
32 #include <asm/fcntl.h>
35 #ifndef CONFIG_KALLSYMS
37 #define KSYMS_ERR(format, args...) \
40 char *n = strrchr(f, '/'); \
41 printk("%s:%u \'%s\' ERROR: " format "\n" , (n) ? n+1 : f, __LINE__, __FUNCTION__, ##args); \
46 struct list_head list;
52 static char* sm_path = NULL;
53 module_param(sm_path, charp, 0);
56 static struct file *file = NULL;
58 static int cnt_init_sm = 0;
59 DEFINE_SEMAPHORE(cnt_init_sm_lock);
61 static int file_open(void)
63 struct file *f = filp_open(sm_path, O_RDONLY, 0);
66 KSYMS_ERR("cannot open file \'%s\'", sm_path);
75 static void file_close(void)
78 int ret = filp_close(file, NULL);
82 KSYMS_ERR("while closing file \'%s\' err=%d", sm_path, ret);
87 static int file_check(void)
89 int ret = file_open();
97 static long file_size(struct file *file)
100 if (vfs_getattr(file->f_path.mnt, file->f_path.dentry, &st)) {
104 if (!S_ISREG(st.mode)) {
108 if (st.size != (long)st.size) {
115 static struct sys_map_item *create_smi(unsigned long addr, const char *name)
117 struct sys_map_item *smi = kmalloc(sizeof(*smi), GFP_KERNEL);
120 KSYMS_ERR("not enough memory");
124 smi->name = kmalloc(strlen(name) + 1, GFP_KERNEL);
125 if (smi->name == NULL) {
127 KSYMS_ERR("not enough memory");
131 INIT_LIST_HEAD(&smi->list);
133 strcpy(smi->name, name);
138 static void free_smi(struct sys_map_item *smi)
144 static void add_smi(const struct sys_map_item *smi)
146 list_add_tail(&smi->list, &smi_list);
149 static int is_endline(char c)
151 return c == '\n' || c == '\r' || c == '\0';
154 static int is_symbol_attr(char c)
156 return c == 't' || c == 'T';
159 static struct sys_map_item *get_sys_map_item(char *begin, char *end)
161 struct sys_map_item *smi = NULL;
162 int n, len = end - begin;
164 char attr, name[128], *line;
166 line = kmalloc(len + 1, GFP_KERNEL);
167 memcpy(line, begin, len);
170 n = sscanf(line, "%x %c %127s", &addr, &attr, &name);
174 KSYMS_ERR("parsing line: \"%s\"", line);
180 if (is_symbol_attr(attr)) {
181 smi = create_smi(addr, name);
188 static void parsing(char *buf, int size)
190 struct sys_map_item *smi;
191 char *start, *end, *c;
196 for (c = start; c < end; ++c) {
197 if (is_endline(*c)) {
198 smi = get_sys_map_item(start, c);
203 for (start = c; c < end; ++c) {
204 if (!is_endline(*c)) {
213 static int create_sys_map(void)
217 int ret = file_open();
223 size = file_size(file);
225 KSYMS_ERR("cannot get file size");
230 data = vmalloc(size);
232 KSYMS_ERR("not enough memory");
237 if (kernel_read(file, 0, data, size) != size) {
238 KSYMS_ERR("reading file %s", sm_path);
254 static void free_sys_map(void)
256 struct sys_map_item *smi, *n;
257 list_for_each_entry_safe(smi, n, &smi_list, list) {
258 list_del(&smi->list);
263 int swap_get_ksyms(void)
267 down(&cnt_init_sm_lock);
268 if (cnt_init_sm == 0) {
269 ret = create_sys_map();
273 up(&cnt_init_sm_lock);
277 EXPORT_SYMBOL_GPL(swap_get_ksyms);
279 void swap_put_ksyms(void)
281 down(&cnt_init_sm_lock);
283 if (cnt_init_sm == 0) {
287 if (cnt_init_sm < 0) {
288 KSYMS_ERR("cnt_init_sm=%d", cnt_init_sm);
292 up(&cnt_init_sm_lock);
294 EXPORT_SYMBOL_GPL(swap_put_ksyms);
296 unsigned long swap_ksyms(const char *name)
298 struct sys_map_item *smi;
300 list_for_each_entry(smi, &smi_list, list) {
301 if (strcmp(name, smi->name) == 0) {
308 EXPORT_SYMBOL_GPL(swap_ksyms);
310 int __init swap_ksyms_init(void)
314 if (sm_path == NULL) {
315 KSYMS_ERR("sm_path=NULL");
324 // TODO: calling func 'swap_get_ksyms' in module used func 'swap_ksyms'
330 void __exit swap_ksyms_exit(void)
332 down(&cnt_init_sm_lock);
334 if (cnt_init_sm > 0) {
338 up(&cnt_init_sm_lock);
341 module_init(swap_ksyms_init);
342 module_exit(swap_ksyms_exit);
344 MODULE_LICENSE("GPL");
345 MODULE_DESCRIPTION("SWAP ksyms module");
346 MODULE_AUTHOR("Vyacheslav Cherkashin <v.cherkashin@samaung.com>");
348 #endif /*CONFIG_KALLSYMS*/