1 #include <linux/kernel.h>
2 #include <linux/sched.h>
3 #include <linux/slab.h>
4 #include <linux/spinlock.h>
6 #include <linux/mman.h>
7 #include <linux/list.h>
8 #include <kprobe/swap_ktd.h>
10 #include "preload_threads.h"
11 #include "preload_debugfs.h"
12 #include "preload_pd.h"
15 struct list_head slots;
20 struct list_head list;
21 struct list_head disabled_addrs;
24 unsigned char call_type;
25 bool drop; /* TODO Workaround, remove when will be possible to install
26 * several us probes at the same addr. */
29 struct disabled_addr {
30 struct list_head list;
34 static void preload_ktd_init(struct task_struct *task, void *data)
36 struct preload_td *td = (struct preload_td *)data;
38 INIT_LIST_HEAD(&td->slots);
42 static void preload_ktd_exit(struct task_struct *task, void *data)
44 /* TODO: to be implement */
47 static struct ktask_data preload_ktd = {
48 .init = preload_ktd_init,
49 .exit = preload_ktd_exit,
50 .size = sizeof(struct preload_td),
54 static inline struct preload_td *get_preload_td(struct task_struct *task)
56 return (struct preload_td *)swap_ktd(&preload_ktd, task);
59 unsigned long get_preload_flags(struct task_struct *task)
61 return get_preload_td(task)->flags;
64 void set_preload_flags(struct task_struct *task,
67 get_preload_td(task)->flags = flags;
71 static inline bool __is_addr_found(struct disabled_addr *da,
80 static inline void __remove_from_disable_list(struct disabled_addr *da)
86 static inline void __remove_whole_disable_list(struct thread_slot *slot)
88 struct disabled_addr *da, *n;
90 list_for_each_entry_safe(da, n, &slot->disabled_addrs, list)
91 __remove_from_disable_list(da);
94 static inline void __init_slot(struct thread_slot *slot)
99 INIT_LIST_HEAD(&slot->disabled_addrs);
102 static inline void __reinit_slot(struct thread_slot *slot)
104 __remove_whole_disable_list(slot);
108 static inline void __set_slot(struct thread_slot *slot,
109 struct task_struct *task, unsigned long caller,
110 unsigned char call_type, bool drop)
112 slot->caller = caller;
113 slot->call_type = call_type;
117 static inline int __add_to_disable_list(struct thread_slot *slot,
118 unsigned long disable_addr)
120 struct disabled_addr *da = kmalloc(sizeof(*da), GFP_ATOMIC);
125 INIT_LIST_HEAD(&da->list);
126 da->addr = disable_addr;
127 list_add_tail(&da->list, &slot->disabled_addrs);
132 static inline struct disabled_addr *__find_disabled_addr(struct thread_slot *slot,
135 struct disabled_addr *da;
137 list_for_each_entry(da, &slot->disabled_addrs, list)
138 if (__is_addr_found(da, addr))
144 /* Adds a new slot */
145 static inline struct thread_slot *__grow_slot(void)
147 struct thread_slot *tmp = kmalloc(sizeof(*tmp), GFP_ATOMIC);
152 INIT_LIST_HEAD(&tmp->list);
159 static void __clean_slot(struct thread_slot *slot)
161 list_del(&slot->list);
165 /* There is no list_last_entry in Linux 3.10 */
166 #ifndef list_last_entry
167 #define list_last_entry(ptr, type, member) \
168 list_entry((ptr)->prev, type, member)
169 #endif /* list_last_entry */
171 static inline struct thread_slot *__get_task_slot(struct task_struct *task)
173 struct preload_td *td = get_preload_td(task);
175 return list_empty(&td->slots) ? NULL :
176 list_last_entry(&td->slots, struct thread_slot, list);
182 int preload_threads_set_data(struct task_struct *task, unsigned long caller,
183 unsigned char call_type,
184 unsigned long disable_addr, bool drop)
186 struct preload_td *td = get_preload_td(task);
187 struct thread_slot *slot;
190 slot = __grow_slot();
196 if ((disable_addr != 0) &&
197 (__add_to_disable_list(slot, disable_addr) != 0)) {
198 printk(KERN_ERR PRELOAD_PREFIX "Cannot alloc memory!\n");
203 __set_slot(slot, task, caller, call_type, drop);
204 list_add_tail(&slot->list, &td->slots);
210 int preload_threads_get_caller(struct task_struct *task, unsigned long *caller)
212 struct thread_slot *slot;
215 slot = __get_task_slot(task);
217 *caller = slot->caller;
218 goto get_caller_done;
221 /* If we're here - slot was not found */
228 int preload_threads_get_call_type(struct task_struct *task,
229 unsigned char *call_type)
231 struct thread_slot *slot;
234 slot = __get_task_slot(task);
236 *call_type = slot->call_type;
237 goto get_call_type_done;
240 /* If we're here - slot was not found */
247 int preload_threads_get_drop(struct task_struct *task)
249 struct thread_slot *slot;
252 slot = __get_task_slot(task);
254 ret = (int) slot->drop;
258 /* If we're here - slot was not found */
265 bool preload_threads_check_disabled_probe(struct task_struct *task,
268 struct thread_slot *slot;
271 slot = __get_task_slot(task);
273 ret = __find_disabled_addr(slot, addr) == NULL ? false : true;
278 void preload_threads_enable_probe(struct task_struct *task, unsigned long addr)
280 struct thread_slot *slot;
281 struct disabled_addr *da;
283 slot = __get_task_slot(task);
285 printk(KERN_ERR PRELOAD_PREFIX "Error! Slot not found!\n");
286 goto enable_probe_failed;
289 da = __find_disabled_addr(slot, addr);
291 __remove_from_disable_list(da);
294 return; /* make gcc happy: cannot place label right before '}' */
297 int preload_threads_put_data(struct task_struct *task)
299 struct thread_slot *slot;
302 slot = __get_task_slot(task);
305 __clean_slot(slot); /* remove from list */
313 int preload_threads_init(void)
315 return swap_ktd_reg(&preload_ktd);
318 void preload_threads_exit(void)
320 swap_ktd_unreg(&preload_ktd);