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>
26 #include "sspt_file.h"
27 #include "sspt_page.h"
28 #include "sspt_proc.h"
29 #include <linux/slab.h>
30 #include <linux/list.h>
31 #include <linux/hash.h>
32 #include <linux/sched.h>
33 #include <kprobe/swap_kprobes_deps.h>
34 #include <us_manager/probes/probes.h>
35 #include <us_manager/img/img_ip.h>
37 static int calculation_hash_bits(int cnt)
40 for (bits = 1; cnt >>= 1; ++bits)
47 * @brief Create sspt_file struct
49 * @param dentry Dentry of file
50 * @param page_cnt Size of hash-table
51 * @return Pointer to the created sspt_file struct
53 struct sspt_file *sspt_file_create(struct dentry *dentry, int page_cnt)
56 struct sspt_file *obj = kmalloc(sizeof(*obj), GFP_ATOMIC);
61 INIT_LIST_HEAD(&obj->list);
68 obj->page_probes_hash_bits = calculation_hash_bits(page_cnt);
69 table_size = (1 << obj->page_probes_hash_bits);
71 obj->page_probes_table =
72 kmalloc(sizeof(*obj->page_probes_table)*table_size,
75 if (obj->page_probes_table == NULL)
78 for (i = 0; i < table_size; ++i)
79 INIT_HLIST_HEAD(&obj->page_probes_table[i]);
89 * @brief Remove sspt_file struct
91 * @param file remove object
94 void sspt_file_free(struct sspt_file *file)
96 struct hlist_head *head;
97 struct sspt_page *page;
98 int i, table_size = (1 << file->page_probes_hash_bits);
100 DECLARE_NODE_PTR_FOR_HLIST(p);
102 for (i = 0; i < table_size; ++i) {
103 head = &file->page_probes_table[i];
104 swap_hlist_for_each_entry_safe(page, p, n, head, hlist) {
105 hlist_del(&page->hlist);
106 sspt_page_free(page);
110 kfree(file->page_probes_table);
114 static void sspt_add_page(struct sspt_file *file, struct sspt_page *page)
117 hlist_add_head(&page->hlist,
118 &file->page_probes_table[hash_ptr(
119 (void *)page->offset,
120 file->page_probes_hash_bits)]);
123 static struct sspt_page *sspt_find_page(struct sspt_file *file,
124 unsigned long offset)
126 struct hlist_head *head;
127 struct sspt_page *page;
128 DECLARE_NODE_PTR_FOR_HLIST(node);
130 head = &file->page_probes_table[hash_ptr((void *)offset,
131 file->page_probes_hash_bits)];
132 swap_hlist_for_each_entry(page, node, head, hlist) {
133 if (page->offset == offset)
140 static struct sspt_page *sspt_find_page_or_new(struct sspt_file *file,
141 unsigned long offset)
143 struct sspt_page *page = sspt_find_page(file, offset);
146 page = sspt_page_create(offset);
148 sspt_add_page(file, page);
155 * @brief Get sspt_page from sspt_file
157 * @param file Pointer to the sspt_file struct
158 * @param page Page address
159 * @return Pointer to the sspt_page struct
161 struct sspt_page *sspt_find_page_mapped(struct sspt_file *file,
164 unsigned long offset;
166 if (file->vm_start > page || file->vm_end < page) {
167 /* TODO: or panic?! */
168 printk(KERN_INFO "ERROR: file_p[vm_start..vm_end] <> page: "
169 "file_p[vm_start=%lx, vm_end=%lx, "
170 "d_iname=%s] page=%lx\n",
171 file->vm_start, file->vm_end,
172 file->dentry->d_iname, page);
176 offset = page - file->vm_start;
178 return sspt_find_page(file, offset);
182 * @brief Add instruction pointer to sspt_file
184 * @param file Pointer to the sspt_file struct
185 * @param offset File offset
186 * @param args Function arguments
187 * @param ret_type Return type
190 void sspt_file_add_ip(struct sspt_file *file, struct img_ip *img_ip)
192 unsigned long offset = 0;
193 struct sspt_page *page = NULL;
194 struct us_ip *ip = NULL;
196 offset = img_ip->addr & PAGE_MASK;
197 page = sspt_find_page_or_new(file, offset);
199 /* FIXME: delete ip */
200 ip = create_ip(img_ip);
204 sspt_add_ip(page, ip);
205 probe_info_init(ip->desc->type, ip);
208 void sspt_file_on_each_ip(struct sspt_file *file,
209 void (*func)(struct us_ip *, void *), void *data)
212 const int table_size = (1 << file->page_probes_hash_bits);
213 struct sspt_page *page;
214 struct hlist_head *head;
215 DECLARE_NODE_PTR_FOR_HLIST(node);
217 for (i = 0; i < table_size; ++i) {
218 head = &file->page_probes_table[i];
219 swap_hlist_for_each_entry(page, node, head, hlist)
220 sspt_page_on_each_ip(page, func, data);
225 * @brief Get sspt_page from sspt_file (look)
227 * @param file Pointer to the sspt_file struct
228 * @param offset_addr File offset
229 * @return Pointer to the sspt_page struct
231 struct sspt_page *sspt_get_page(struct sspt_file *file,
232 unsigned long offset_addr)
234 unsigned long offset = offset_addr & PAGE_MASK;
235 struct sspt_page *page = sspt_find_page_or_new(file, offset);
237 spin_lock(&page->lock);
243 * @brief Put sspt_page (unlook)
245 * @param file Pointer to the sspt_page struct
248 void sspt_put_page(struct sspt_page *page)
250 spin_unlock(&page->lock);
254 * @brief Check install sspt_file (legacy code, it is need remove)
256 * @param file Pointer to the sspt_file struct
261 int sspt_file_check_install_pages(struct sspt_file *file)
264 struct sspt_page *page;
265 struct hlist_head *head;
266 struct hlist_node *tmp;
267 DECLARE_NODE_PTR_FOR_HLIST(node);
269 table_size = (1 << file->page_probes_hash_bits);
270 for (i = 0; i < table_size; ++i) {
271 head = &file->page_probes_table[i];
272 swap_hlist_for_each_entry_safe(page, node, tmp, head, hlist) {
273 if (sspt_page_is_installed(page))
282 * @brief Install sspt_file
284 * @param file Pointer to the sspt_file struct
287 void sspt_file_install(struct sspt_file *file)
289 struct sspt_page *page = NULL;
290 struct hlist_head *head = NULL;
291 int i, table_size = (1 << file->page_probes_hash_bits);
292 unsigned long page_addr;
293 struct mm_struct *mm;
294 DECLARE_NODE_PTR_FOR_HLIST(node);
296 for (i = 0; i < table_size; ++i) {
297 head = &file->page_probes_table[i];
298 swap_hlist_for_each_entry_rcu(page, node, head, hlist) {
299 page_addr = file->vm_start + page->offset;
300 if (page_addr < file->vm_start ||
301 page_addr >= file->vm_end)
304 mm = page->file->proc->task->mm;
305 if (page_present(mm, page_addr))
306 sspt_register_page(page, file);
312 * @brief Uninstall sspt_file
314 * @param file Pointer to the sspt_file struct
315 * @param task Pointer to the task_stract struct
316 * @param flag Action for probes
319 int sspt_file_uninstall(struct sspt_file *file,
320 struct task_struct *task,
324 int table_size = (1 << file->page_probes_hash_bits);
325 struct sspt_page *page;
326 struct hlist_head *head;
327 struct hlist_node *tmp;
328 DECLARE_NODE_PTR_FOR_HLIST(node);
330 for (i = 0; i < table_size; ++i) {
331 head = &file->page_probes_table[i];
332 swap_hlist_for_each_entry_safe(page, node, tmp, head, hlist) {
333 err = sspt_unregister_page(page, flag, task);
335 printk(KERN_INFO "ERROR sspt_file_uninstall: "
342 if (flag != US_DISARM) {
352 * @brief Set mapping for sspt_file
354 * @param file Pointer to the sspt_file struct
355 * @param vma Pointer to the vm_area_struct struct
358 void sspt_file_set_mapping(struct sspt_file *file, struct vm_area_struct *vma)
360 if (file->loaded == 0) {
362 file->vm_start = vma->vm_start;
363 file->vm_end = vma->vm_end;