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 <task_data/task_data.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 inline struct preload_td *get_preload_td(struct task_struct *task)
36 struct preload_td *td = NULL;
39 td = swap_task_data_get(task, &ok);
40 WARN(!ok, "Preload td[%d/%d] seems corrupted", task->tgid, task->pid);
43 td = kzalloc(sizeof(*td), GFP_ATOMIC);
44 WARN(!td, "Failed to allocate preload_td");
47 INIT_LIST_HEAD(&td->slots);
48 /* We use SWAP_TD_FREE flag, i.e. the data will be
49 * kfree'd by task_data module. */
50 swap_task_data_set(task, td, SWAP_TD_FREE);
57 unsigned long get_preload_flags(struct task_struct *task)
59 struct preload_td *td = get_preload_td(task);
67 void set_preload_flags(struct task_struct *task,
70 struct preload_td *td = get_preload_td(task);
73 printk(KERN_ERR "%s: invalid arguments\n", __FUNCTION__);
81 static inline bool __is_addr_found(struct disabled_addr *da,
90 static inline void __remove_from_disable_list(struct disabled_addr *da)
96 static inline void __remove_whole_disable_list(struct thread_slot *slot)
98 struct disabled_addr *da, *n;
100 list_for_each_entry_safe(da, n, &slot->disabled_addrs, list)
101 __remove_from_disable_list(da);
104 static inline void __init_slot(struct thread_slot *slot)
109 INIT_LIST_HEAD(&slot->disabled_addrs);
112 static inline void __reinit_slot(struct thread_slot *slot)
114 __remove_whole_disable_list(slot);
118 static inline void __set_slot(struct thread_slot *slot,
119 struct task_struct *task, unsigned long caller,
120 unsigned char call_type, bool drop)
122 slot->caller = caller;
123 slot->call_type = call_type;
127 static inline int __add_to_disable_list(struct thread_slot *slot,
128 unsigned long disable_addr)
130 struct disabled_addr *da = kmalloc(sizeof(*da), GFP_ATOMIC);
135 INIT_LIST_HEAD(&da->list);
136 da->addr = disable_addr;
137 list_add_tail(&da->list, &slot->disabled_addrs);
142 static inline struct disabled_addr *__find_disabled_addr(struct thread_slot *slot,
145 struct disabled_addr *da;
147 list_for_each_entry(da, &slot->disabled_addrs, list)
148 if (__is_addr_found(da, addr))
154 /* Adds a new slot */
155 static inline struct thread_slot *__grow_slot(void)
157 struct thread_slot *tmp = kmalloc(sizeof(*tmp), GFP_ATOMIC);
162 INIT_LIST_HEAD(&tmp->list);
169 static void __clean_slot(struct thread_slot *slot)
171 list_del(&slot->list);
175 /* There is no list_last_entry in Linux 3.10 */
176 #ifndef list_last_entry
177 #define list_last_entry(ptr, type, member) \
178 list_entry((ptr)->prev, type, member)
179 #endif /* list_last_entry */
181 static inline struct thread_slot *__get_task_slot(struct task_struct *task)
183 struct preload_td *td = get_preload_td(task);
188 return list_empty(&td->slots) ? NULL :
189 list_last_entry(&td->slots, struct thread_slot, list);
195 int preload_threads_set_data(struct task_struct *task, unsigned long caller,
196 unsigned char call_type,
197 unsigned long disable_addr, bool drop)
199 struct preload_td *td = get_preload_td(task);
200 struct thread_slot *slot;
203 slot = __grow_slot();
209 if ((disable_addr != 0) &&
210 (__add_to_disable_list(slot, disable_addr) != 0)) {
211 printk(KERN_ERR PRELOAD_PREFIX "Cannot alloc memory!\n");
216 __set_slot(slot, task, caller, call_type, drop);
217 list_add_tail(&slot->list, &td->slots);
223 int preload_threads_get_caller(struct task_struct *task, unsigned long *caller)
225 struct thread_slot *slot;
228 slot = __get_task_slot(task);
230 *caller = slot->caller;
231 goto get_caller_done;
234 /* If we're here - slot was not found */
241 int preload_threads_get_call_type(struct task_struct *task,
242 unsigned char *call_type)
244 struct thread_slot *slot;
247 slot = __get_task_slot(task);
249 *call_type = slot->call_type;
250 goto get_call_type_done;
253 /* If we're here - slot was not found */
260 int preload_threads_get_drop(struct task_struct *task, bool *drop)
262 struct thread_slot *slot;
265 slot = __get_task_slot(task);
271 /* If we're here - slot was not found */
278 bool preload_threads_check_disabled_probe(struct task_struct *task,
281 struct thread_slot *slot;
284 slot = __get_task_slot(task);
286 ret = __find_disabled_addr(slot, addr) == NULL ? false : true;
291 void preload_threads_enable_probe(struct task_struct *task, unsigned long addr)
293 struct thread_slot *slot;
294 struct disabled_addr *da;
296 slot = __get_task_slot(task);
298 printk(KERN_ERR PRELOAD_PREFIX "Error! Slot not found!\n");
299 goto enable_probe_failed;
302 da = __find_disabled_addr(slot, addr);
304 __remove_from_disable_list(da);
307 return; /* make gcc happy: cannot place label right before '}' */
310 int preload_threads_put_data(struct task_struct *task)
312 struct thread_slot *slot;
315 slot = __get_task_slot(task);
318 __clean_slot(slot); /* remove from list */
326 int preload_threads_init(void)
331 void preload_threads_exit(void)