Redesign KProbe module (separating core and arch parts).
[kernel/swap-modules.git] / driver / probes_manager.c
1 ////////////////////////////////////////////////////////////////////////////////////
2 //
3 //      FILE:           probes_manager.c
4 //
5 //      DESCRIPTION:
6 //      This file is C source for SWAP driver.
7 //
8 //      SEE ALSO:       probes_manager.h
9 //      AUTHOR:         L.Komkov, A.Gerenkov
10 //      COMPANY NAME:   Samsung Research Center in Moscow
11 //      DEPT NAME:      Advanced Software Group 
12 //      CREATED:        2008.02.15
13 //      VERSION:        1.0
14 //      REVISION DATE:  2008.12.03
15 //
16 ////////////////////////////////////////////////////////////////////////////////////
17
18 #include <linux/percpu.h>
19 #include "module.h"
20 #include "probes_manager.h"
21
22 #ifdef EC_ARCH_arm
23 /* ARCH == arm */
24 #include "../kprobe/dbi_kprobes.h"
25 #endif /* def EC_ARCH_arm */
26
27 #ifdef EC_ARCH_i386
28 /* ARCH == i386 */
29 //#include <linux/kprobes.h>
30 #include "../kprobe/kprobes.h"
31 #endif /* def EC_ARCH_i386 */
32
33 #ifdef EC_ARCH_mips
34 /* ARCH == mips */
35 #include "../kprobe/kprobes.h"
36 #endif /* def EC_ARCH_mips */
37
38 unsigned long pf_addr;
39 unsigned long exit_addr;
40 kernel_probe_t *pf_probe = NULL;
41 kernel_probe_t *exit_probe = NULL;
42 unsigned int probes_flags = 0;
43
44 int
45 probes_manager_init (void)
46 {
47 #ifdef CONFIG_X86
48         pf_addr = lookup_name("handle_mm_fault");
49 #else
50         pf_addr = lookup_name("do_page_fault");
51 #endif
52         if (pf_addr == 0) {
53                 EPRINTF("Cannot find address for page fault function!");
54                 return -EINVAL;
55         }
56
57         exit_addr = lookup_name("do_exit");
58         if (exit_addr == 0) {
59                 EPRINTF("Cannot find address for do_exit function!");
60                 return -EINVAL;
61         }
62
63         return storage_init ();
64 }
65
66 void
67 probes_manager_down (void)
68 {
69         detach_selected_probes ();
70         storage_down ();
71 }
72
73 static int
74 register_kernel_jprobe (kernel_probe_t * probe)
75 {
76         int result;
77         if (((probe == pf_probe) && (us_proc_probes & US_PROC_PF_INSTLD)) ||
78             ((probe == exit_probe) && (us_proc_probes & US_PROC_EXIT_INSTLD)))
79         {
80                 return 0;       // probe is already registered
81         }
82         result = register_jprobe (&probe->jprobe, 0);
83         if (result)
84         {
85                 EPRINTF ("register_kernel_jprobe(0x%lx) failure %d", probe->addr, result);
86                 return result;
87         }
88         return 0;
89 }
90
91 static int
92 unregister_kernel_jprobe (kernel_probe_t * probe)
93 {
94         if (((probe == pf_probe) && (us_proc_probes & US_PROC_PF_INSTLD)) ||
95             ((probe == exit_probe) && (us_proc_probes & US_PROC_EXIT_INSTLD)))
96         {
97                 return 0;       // probe is necessary for user space instrumentation
98         }
99         unregister_jprobe (&probe->jprobe, 0);
100         return 0;
101 }
102
103 static int
104 register_kernel_retprobe (kernel_probe_t * probe)
105 {
106         int result;
107         if (((probe == pf_probe) && (us_proc_probes & US_PROC_PF_INSTLD)) ||
108             ((probe == exit_probe) && (us_proc_probes & US_PROC_EXIT_INSTLD))/* ||
109             ((probe == fork_probe) && (us_proc_probes & US_PROC_FORK_INSTLD)) || 
110             ((probe == ss_probe) && (us_proc_probes & US_PROC_SS_INSTLD))*/)
111         {
112                 return 0;       // probe is already registered
113         }
114
115         result = register_kretprobe (&probe->retprobe, 0);
116         if (result)
117         {
118                 EPRINTF ("register_kernel_retprobe(0x%lx) failure %d", probe->addr, result);
119                 return result;
120         }
121         return 0;
122 }
123
124 static int
125 unregister_kernel_retprobe (kernel_probe_t * probe)
126 {
127         if (((probe == pf_probe) && (us_proc_probes & US_PROC_PF_INSTLD)) ||
128             ((probe == exit_probe) && (us_proc_probes & US_PROC_EXIT_INSTLD))/* ||
129             ((probe == fork_probe) && (us_proc_probes & US_PROC_FORK_INSTLD)) || 
130             ((probe == ss_probe) && (us_proc_probes & US_PROC_SS_INSTLD))*/)
131         {
132                 return 0;       // probe is necessary for user space instrumentation
133         }
134         unregister_kretprobe (&probe->retprobe, 0);
135         return 0;
136 }
137
138 int
139 register_kernel_probe (kernel_probe_t * probe)
140 {
141         register_kernel_jprobe (probe);
142         register_kernel_retprobe (probe);
143         return 0;
144 }
145
146 int
147 unregister_kernel_probe (kernel_probe_t * probe)
148 {
149         unregister_kernel_jprobe (probe);
150         unregister_kernel_retprobe (probe);
151         return 0;
152 }
153
154 int
155 attach_selected_probes (void)
156 {
157         int result = 0;
158         int partial_result = 0;
159         kernel_probe_t *p;
160         struct hlist_node *node;
161
162         hlist_for_each_entry_rcu (p, node, &kernel_probes, hlist)
163         {
164                 partial_result = register_kernel_probe (p);
165                 if (partial_result)
166                 {
167                         result = partial_result;
168                         detach_selected_probes ();      // return into safe state
169                         break;
170                 }
171         }
172
173         return result;
174 }
175
176 int
177 detach_selected_probes (void)
178 {
179         kernel_probe_t *p;
180         struct hlist_node *node;
181
182         hlist_for_each_entry_rcu (p, node, &kernel_probes, hlist)
183                 unregister_kernel_probe (p);
184
185         return 0;
186 }
187
188 int
189 add_probe (unsigned long addr)
190 {
191         int result = 0;
192         kernel_probe_t **pprobe = NULL;
193
194         DPRINTF("add probe at 0x%0x\n", addr);
195         if (EC_STATE_IDLE != ec_info.ec_state)
196         {
197                 EPRINTF("Probes addition is allowed in IDLE state only.");
198                 return -EINVAL;
199         }
200
201         if (addr == pf_addr) {
202                 probes_flags |= PROBE_FLAG_PF_INSTLD;
203                 if (us_proc_probes & US_PROC_PF_INSTLD)
204                 {
205                         return 0;
206                 }
207                 pprobe = &pf_probe;
208         }
209         else if (addr == exit_addr) {
210                 probes_flags |= PROBE_FLAG_EXIT_INSTLD;
211                 if (us_proc_probes & US_PROC_EXIT_INSTLD)
212                 {
213                         return 0;
214                 }
215                 pprobe = &exit_probe;
216         }
217
218         result = add_probe_to_list (addr, pprobe);
219         if (result) {
220                 if (addr == pf_addr)
221                         probes_flags &= ~PROBE_FLAG_PF_INSTLD;
222                 else if (addr == exit_addr)
223                         probes_flags &= ~PROBE_FLAG_EXIT_INSTLD;
224         }
225         return result;
226 }
227
228 int reset_probes()
229 {
230         struct hlist_node *node, *tnode;
231         kernel_probe_t *p;
232
233         hlist_for_each_entry_safe (p, node, tnode, &kernel_probes, hlist) {
234                 if (p->addr == pf_addr) {
235                         probes_flags &= ~PROBE_FLAG_PF_INSTLD;
236                         pf_probe = NULL;
237                 } else if (p->addr == exit_addr) {
238                         probes_flags &= ~PROBE_FLAG_EXIT_INSTLD;
239                         exit_probe = NULL;
240                 }
241                 hlist_del(node);
242                 kfree(p);
243         }
244
245         return 0;
246 }
247
248 int
249 remove_probe (unsigned long addr)
250 {
251         int result = 0;
252
253         if (EC_STATE_IDLE != ec_info.ec_state)
254         {
255                 EPRINTF("Probes addition is allowed in IDLE state only.");
256                 return -EINVAL;
257         }
258
259         if (addr == pf_addr) {
260                 probes_flags &= ~PROBE_FLAG_PF_INSTLD;
261                 if (us_proc_probes & US_PROC_PF_INSTLD)
262                 {
263                         return 0;
264                 }
265                 pf_probe = NULL;
266         }
267         else if (addr == exit_addr) {
268                 probes_flags &= ~PROBE_FLAG_EXIT_INSTLD;
269                 if (us_proc_probes & US_PROC_EXIT_INSTLD)
270                 {
271                         return 0;
272                 }
273                 exit_probe = NULL;
274         }
275
276         result = remove_probe_from_list (addr);
277
278         return result;
279 }
280
281 DEFINE_PER_CPU (kernel_probe_t *, gpKernProbe) = NULL;
282 EXPORT_PER_CPU_SYMBOL_GPL(gpKernProbe);
283 DEFINE_PER_CPU(struct pt_regs *, gpKernRegs) = NULL;
284 EXPORT_PER_CPU_SYMBOL_GPL(gpKernRegs);
285
286 unsigned long
287 def_jprobe_event_pre_handler (kernel_probe_t * probe, struct pt_regs *regs)
288 {
289         __get_cpu_var (gpKernProbe) = probe;
290         __get_cpu_var (gpKernRegs) = regs;
291
292         return 0;
293 }
294
295 void
296 def_jprobe_event_handler (unsigned long arg1, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5, unsigned long arg6)
297 {
298         //static int nCount;
299         kernel_probe_t *probe = __get_cpu_var(gpKernProbe);
300         int skip = 0;
301
302         if (pf_probe == probe)
303         {
304                 if (!(probes_flags & PROBE_FLAG_PF_INSTLD))
305                         skip = 1;
306         }
307         else if (exit_probe == probe)
308         {
309                 if (us_proc_probes & US_PROC_EXIT_INSTLD)
310                         do_exit_probe_pre_code ();
311                 if (!(probes_flags & PROBE_FLAG_EXIT_INSTLD))
312                         skip = 1;
313         }
314
315         if (!skip)
316                 pack_event_info (KS_PROBE_ID, RECORD_ENTRY, "pxxxxxx", probe->addr, arg1, arg2, arg3, arg4, arg5, arg6);
317         jprobe_return ();
318 }
319
320 int
321 def_retprobe_event_handler (struct kretprobe_instance *pi, struct pt_regs *regs, kernel_probe_t * probe)
322 {
323         int skip = 0;
324
325         if (pf_probe == probe)
326         {
327                 if (us_proc_probes & US_PROC_PF_INSTLD)
328                         do_page_fault_ret_pre_code ();
329                 if (!(probes_flags & PROBE_FLAG_PF_INSTLD))
330                         skip = 1;
331         }
332         else if (exit_probe == probe)
333         {
334                 if (!(probes_flags & PROBE_FLAG_EXIT_INSTLD))
335                         skip = 1;
336         }
337
338         if (!skip)
339                 pack_event_info (KS_PROBE_ID, RECORD_RET, "p", probe->addr);
340         return 0;
341 }
342
343 /* This is a callback that is called by module 'inperfa_handlers'
344  * in order to register user defined handlers */
345 void install_user_handlers(void)
346 {
347         kernel_probe_t *probe;
348         struct hlist_node *node;
349         unsigned long pre_handler_addr, jp_handler_addr, rp_handler_addr;
350
351         /* We must perform this lookup whenever this function is called
352          * because the addresses of find_*_handler functions may differ. */
353         // MCPP inperfa_handlers removed
354         unsigned long (*find_jp_handler)(unsigned long) =
355         // MCPP inperfa_handlers removed
356                 (unsigned long (*)(unsigned long))lookup_name("find_jp_handler");
357         unsigned long (*find_rp_handler)(unsigned long) =
358                         (unsigned long (*)(unsigned long))lookup_name("find_rp_handler");
359         unsigned long (*find_pre_handler)(unsigned long) =
360                         (unsigned long (*)(unsigned long))lookup_name("find_pre_handler");
361         hlist_for_each_entry_rcu (probe, node, &kernel_probes, hlist) {
362                 if(find_pre_handler)
363                 {
364                         pre_handler_addr = find_pre_handler(probe->addr);
365                         if (find_pre_handler != 0) {
366                                 DPRINTF("Added user pre handler for 0x%lx: 0x%lx",
367                                                 probe->addr, find_pre_handler);
368                                 probe->jprobe.pre_entry = (kprobe_pre_entry_handler_t)pre_handler_addr;
369                         }
370                 }
371                 jp_handler_addr = find_jp_handler(probe->addr);
372                 if (jp_handler_addr != 0) {
373                         DPRINTF("Added user jp handler for 0x%lx: 0x%lx",
374                                         probe->addr, jp_handler_addr);
375                         probe->jprobe.entry = (kprobe_opcode_t *)jp_handler_addr;
376                 }
377                 rp_handler_addr = find_rp_handler(probe->addr);
378                 if (rp_handler_addr != 0)
379                         probe->retprobe.handler = (kretprobe_handler_t)rp_handler_addr;
380         }
381 }
382 EXPORT_SYMBOL_GPL(install_user_handlers);
383
384 void uninstall_user_handlers(void)
385 {
386         kernel_probe_t *probe;
387         struct hlist_node *node;
388
389         hlist_for_each_entry_rcu (probe, node, &kernel_probes, hlist) {
390                 DPRINTF("Removed user jp handler for 0x%lx", probe->addr);
391                 probe->jprobe.pre_entry = (kprobe_pre_entry_handler_t)def_jprobe_event_pre_handler;
392                 probe->jprobe.entry = (kprobe_opcode_t *)def_jprobe_event_handler;
393                 probe->retprobe.handler = (kretprobe_handler_t)def_retprobe_event_handler;
394         }
395 }
396 EXPORT_SYMBOL_GPL(uninstall_user_handlers);
397
398 int is_pf_installed_by_user(void)
399 {
400         return (probes_flags & PROBE_FLAG_PF_INSTLD) ? 1: 0;
401 }
402 EXPORT_SYMBOL_GPL(is_pf_installed_by_user);