2 * Dynamic Binary Instrumentation Module based on KProbes
3 * modules/driver/sspt/sspt_file.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>
25 #include "sspt_file.h"
26 #include "sspt_page.h"
27 #include <linux/slab.h>
28 #include <linux/list.h>
29 #include <linux/hash.h>
30 #include <dbi_kprobes_deps.h>
32 static int calculation_hash_bits(int cnt)
35 for (bits = 1; cnt >>= 1; ++bits);
40 struct sspt_file *sspt_file_create(char *name, struct dentry *dentry, int page_cnt)
42 struct sspt_file *obj = kmalloc(sizeof(*obj), GFP_ATOMIC);
46 INIT_LIST_HEAD(&obj->list);
54 obj->page_probes_hash_bits = calculation_hash_bits(page_cnt);//PAGE_PROBES_HASH_BITS;
55 table_size = (1 << obj->page_probes_hash_bits);
57 obj->page_probes_table = kmalloc(sizeof(*obj->page_probes_table)*table_size, GFP_ATOMIC);
59 for (i = 0; i < table_size; ++i) {
60 INIT_HLIST_HEAD(&obj->page_probes_table[i]);
67 void sspt_file_free(struct sspt_file *file)
69 struct hlist_node *p, *n;
70 struct hlist_head *head;
71 struct sspt_page *page;
72 int i, table_size = (1 << file->page_probes_hash_bits);
74 for (i = 0; i < table_size; ++i) {
75 head = &file->page_probes_table[i];
76 swap_hlist_for_each_entry_safe(page, p, n, head, hlist) {
77 hlist_del(&page->hlist);
82 kfree(file->page_probes_table);
86 static void sspt_add_page(struct sspt_file *file, struct sspt_page *page)
89 hlist_add_head(&page->hlist, &file->page_probes_table[hash_ptr((void *)page->offset,
90 file->page_probes_hash_bits)]);
93 struct sspt_file *sspt_file_copy(const struct sspt_file *file)
95 struct sspt_file *file_out;
98 printk("### WARNING: file_p == NULL\n");
102 file_out = kmalloc(sizeof(*file_out), GFP_ATOMIC);
104 struct sspt_page *page = NULL;
105 struct hlist_node *node = NULL;
106 struct hlist_head *head = NULL;
108 INIT_LIST_HEAD(&file_out->list);
109 file_out->procs = NULL;
110 file_out->dentry = file->dentry;
111 file_out->name = file->name;
112 file_out->loaded = 0;
113 file_out->vm_start = 0;
114 file_out->vm_end = 0;
116 file_out->page_probes_hash_bits = file->page_probes_hash_bits;
117 table_size = (1 << file_out->page_probes_hash_bits);
119 file_out->page_probes_table =
120 kmalloc(sizeof(*file_out->page_probes_table)*table_size, GFP_ATOMIC);
122 for (i = 0; i < table_size; ++i) {
123 INIT_HLIST_HEAD(&file_out->page_probes_table[i]);
127 for (i = 0; i < table_size; ++i) {
128 head = &file->page_probes_table[i];
129 swap_hlist_for_each_entry(page, node, head, hlist) {
130 sspt_add_page(file_out, sspt_page_copy(page));
138 static struct sspt_page *sspt_find_page(struct sspt_file *file, unsigned long offset)
140 struct hlist_node *node;
141 struct hlist_head *head;
142 struct sspt_page *page;
144 head = &file->page_probes_table[hash_ptr((void *)offset, file->page_probes_hash_bits)];
145 swap_hlist_for_each_entry(page, node, head, hlist) {
146 if (page->offset == offset) {
154 static struct sspt_page *sspt_find_page_or_new(struct sspt_file *file, unsigned long offset)
156 struct sspt_page *page = sspt_find_page(file, offset);
159 page = sspt_page_create(offset);
160 sspt_add_page(file, page);
166 struct sspt_page *sspt_find_page_mapped(struct sspt_file *file, unsigned long page)
168 unsigned long offset;
170 if (file->vm_start > page || file->vm_end < page) {
172 printk("ERROR: file_p[vm_start..vm_end] <> page: file_p[vm_start=%lx, vm_end=%lx, path=%s, d_iname=%s] page=%lx\n",
173 file->vm_start, file->vm_end, file->name, file->dentry->d_iname, page);
177 offset = page - file->vm_start;
179 return sspt_find_page(file, offset);
182 void sspt_file_add_ip(struct sspt_file *file, struct ip_data *ip_d)
184 unsigned long offset = ip_d->offset & PAGE_MASK;
185 struct sspt_page *page = sspt_find_page_or_new(file, offset);
188 struct us_ip *ip = create_ip_by_ip_data(ip_d);
190 sspt_add_ip(page, ip);
193 struct sspt_page *sspt_get_page(struct sspt_file *file, unsigned long offset_addr)
195 unsigned long offset = offset_addr & PAGE_MASK;
196 struct sspt_page *page = sspt_find_page_or_new(file, offset);
198 spin_lock(&page->lock);
203 void sspt_put_page(struct sspt_page *page)
205 spin_unlock(&page->lock);