Redesign KProbe module (separating core and arch parts).
[kernel/swap-modules.git] / kprobe / dbi_uprobes.c
1 /*
2  *  Dynamic Binary Instrumentation Module based on KProbes
3  *  modules/kprobe/dbi_uprobes.h
4  *
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.
9  *
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.
14  *
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.
18  *
19  * Copyright (C) Samsung Electronics, 2006-2010
20  *
21  * 2008-2009    Alexey Gerenkov <a.gerenkov@samsung.com> User-Space
22  *              Probes initial implementation; Support x86/ARM/MIPS for both user and kernel spaces.
23  * 2010         Ekaterina Gorelkina <e.gorelkina@samsung.com>: redesign module for separating core and arch parts 
24  *
25
26  */
27
28 #include <linux/hash.h>
29 #include <linux/mempolicy.h>
30 #include <linux/module.h>
31
32 #include "dbi_uprobes.h"
33 #include "dbi_insn_slots.h"
34 #include "dbi_kdebug.h"
35
36 extern atomic_t kprobe_count;
37 extern struct hlist_head kprobe_table[KPROBE_TABLE_SIZE];
38 extern struct hlist_head kretprobe_inst_table[KPROBE_TABLE_SIZE];
39 extern spinlock_t kretprobe_lock;
40
41 extern struct kretprobe *sched_rp;
42
43 struct hlist_head uprobe_insn_slot_table[KPROBE_TABLE_SIZE];
44
45 static 
46 int __register_uprobe (struct kprobe *p, struct task_struct *task, int atomic, unsigned long called_from)
47 {
48         int ret = 0;
49         struct kprobe *old_p;
50
51         if (!p->addr)
52                 return -EINVAL;
53
54         DBPRINTF ("p->addr = 0x%p p = 0x%p\n", p->addr, p);
55
56         p->mod_refcounted = 0;
57         p->nmissed = 0;
58 #ifdef KPROBES_PROFILE
59         p->start_tm.tv_sec = p->start_tm.tv_usec = 0;
60         p->hnd_tm_sum.tv_sec = p->hnd_tm_sum.tv_usec = 0;
61         p->count = 0;
62 #endif
63
64         // get the first item
65         old_p = get_kprobe (p->addr, p->tgid, NULL);
66         if (old_p)
67         {
68                 ret = register_aggr_kprobe (old_p, p);
69                 if (!ret)
70                         atomic_inc (&kprobe_count);
71                 goto out;
72         }
73         if ((ret = arch_prepare_uprobe (p, task, atomic)) != 0)
74         {
75                 goto out;
76         }
77
78         DBPRINTF ("before out ret = 0x%x\n", ret);
79
80         INIT_HLIST_NODE (&p->hlist);
81         hlist_add_head_rcu (&p->hlist, &kprobe_table[hash_ptr (p->addr, KPROBE_HASH_BITS)]);
82
83         INIT_HLIST_NODE (&p->is_hlist);
84         hlist_add_head_rcu (&p->is_hlist, &uprobe_insn_slot_table[hash_ptr (p->ainsn.insn, KPROBE_HASH_BITS)]);
85
86         arch_arm_uprobe (p, task);
87 out:
88         DBPRINTF ("out ret = 0x%x\n", ret);
89
90         return ret;
91 }
92
93 void unregister_uprobe (struct kprobe *p, struct task_struct *task, int atomic)
94 {
95         unregister_kprobe (p, task, atomic);
96 }
97
98
99 int register_ujprobe (struct task_struct *task, struct mm_struct *mm, struct jprobe *jp, int atomic)
100 {
101         int ret = 0;
102
103         /* Todo: Verify probepoint is a function entry point */
104         jp->kp.pre_handler = setjmp_pre_handler;
105         jp->kp.break_handler = longjmp_break_handler;
106
107         ret = __register_uprobe (&jp->kp, task, atomic,
108                         (unsigned long) __builtin_return_address (0));
109
110         return ret;
111 }
112
113 void unregister_ujprobe (struct task_struct *task, struct jprobe *jp, int atomic)
114 {
115         unregister_uprobe (&jp->kp, task, atomic);
116 }
117
118 int register_uretprobe (struct task_struct *task, struct mm_struct *mm, struct kretprobe *rp, int atomic)
119 {
120         int ret = 0;
121         struct kretprobe_instance *inst;
122         int i;
123
124         DBPRINTF ("START\n");
125
126         rp->kp.pre_handler = pre_handler_kretprobe;
127         rp->kp.post_handler = NULL;
128         rp->kp.fault_handler = NULL;
129         rp->kp.break_handler = NULL;
130
131         rp->disarm = 0;
132
133         /* Pre-allocate memory for max kretprobe instances */
134         if (rp->maxactive <= 0)
135         {
136 #if 1//def CONFIG_PREEMPT
137                 rp->maxactive = max (10, 2 * NR_CPUS);
138 #else
139                 rp->maxactive = NR_CPUS;
140 #endif
141         }
142         INIT_HLIST_HEAD (&rp->used_instances);
143         INIT_HLIST_HEAD (&rp->free_instances);
144         for (i = 0; i < rp->maxactive; i++)
145         {
146                 inst = kmalloc (sizeof (struct kretprobe_instance), GFP_KERNEL);
147                 if (inst == NULL)
148                 {
149                         free_rp_inst (rp);
150                         ret = -ENOMEM;
151                         goto out;
152                 }
153                 INIT_HLIST_NODE (&inst->uflist);
154                 hlist_add_head (&inst->uflist, &rp->free_instances);
155         }
156
157         rp->nmissed = 0;
158
159         /* Establish function exit probe point */
160         if ((ret = arch_prepare_uretprobe (rp, task)) != 0)
161                 goto out;
162         /* Establish function entry probe point */
163         if ((ret = __register_uprobe (&rp->kp, task, atomic,
164                                         (unsigned long) __builtin_return_address (0))) != 0)
165         {
166                 free_rp_inst (rp);
167                 goto out;
168         }
169
170         arch_arm_uretprobe (rp, task);//vmas[1], pages[1], kaddrs[1]);
171 out:
172         return ret;
173 }
174
175
176 void unregister_uretprobe (struct task_struct *task, struct kretprobe *rp, int atomic)
177 {
178         unsigned long flags;
179         struct kretprobe_instance *ri;
180         struct kretprobe *rp2 = NULL;
181
182         spin_lock_irqsave (&kretprobe_lock, flags);
183         if (hlist_empty (&rp->used_instances))
184         {
185                 // if there are no used retprobe instances (i.e. function is not entered) - disarm retprobe
186                 arch_disarm_uretprobe (rp, task);//vmas[1], pages[1], kaddrs[1]);
187         }
188         else
189         {
190                 rp2 = clone_kretprobe (rp);
191                 if (!rp2)
192                         DBPRINTF ("unregister_uretprobe addr %p: failed to clone retprobe!", rp->kp.addr);
193                 else
194                 {
195                         DBPRINTF ("initiating deferred retprobe deletion addr %p", rp->kp.addr);
196                         printk ("initiating deferred retprobe deletion addr %p\n", rp->kp.addr);
197                         rp2->disarm = 1;
198                 }
199         }
200
201         while ((ri = get_used_rp_inst (rp)) != NULL)
202         {
203                 ri->rp = NULL;
204                 ri->rp2 = rp2;
205                 hlist_del (&ri->uflist);
206         }
207         spin_unlock_irqrestore (&kretprobe_lock, flags);
208         free_rp_inst (rp);
209
210         unregister_uprobe (&rp->kp, task, atomic);
211 }
212
213 void unregister_all_uprobes (struct task_struct *task, int atomic)
214 {
215         struct hlist_head *head;
216         struct hlist_node *node, *tnode;
217         struct kprobe *p;
218         int i;
219
220         for(i = 0; i < KPROBE_TABLE_SIZE; i++){
221                 head = &kprobe_table[i];
222                 hlist_for_each_entry_safe (p, node, tnode, head, hlist){                        
223                         if(p->tgid == task->tgid){
224                                 printk("unregister_all_uprobes: delete uprobe at %pf for %s/%d\n", p->addr, task->comm, task->pid);
225                                 unregister_uprobe (p, task, atomic);
226                         }
227                 }
228         }
229         purge_garbage_uslots(task, atomic);
230 }
231
232 void init_uprobes_insn_slots(int i) 
233 {
234         INIT_HLIST_HEAD (&uprobe_insn_slot_table[i]);
235 }
236
237 void uprobe_return (void)
238 {
239         arch_uprobe_return();
240 }
241
242
243 EXPORT_SYMBOL_GPL (uprobe_return);
244 EXPORT_SYMBOL_GPL (register_ujprobe);
245 EXPORT_SYMBOL_GPL (unregister_ujprobe);
246 EXPORT_SYMBOL_GPL (register_uretprobe);
247 EXPORT_SYMBOL_GPL (unregister_uretprobe);
248 EXPORT_SYMBOL_GPL (unregister_all_uprobes);
249