1 ////////////////////////////////////////////////////////////////////////////////////
3 // FILE: probes_manager.c
6 // This file is C source for SWAP driver.
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
14 // REVISION DATE: 2008.12.03
16 ////////////////////////////////////////////////////////////////////////////////////
18 #include <linux/percpu.h>
21 #include "probes_manager.h"
25 #include "../kprobe/dbi_kprobes.h"
26 #endif /* def EC_ARCH_arm */
30 //#include <linux/kprobes.h>
31 #include "../kprobe/dbi_kprobes.h"
32 #endif /* def EC_ARCH_x86 */
36 #include "../kprobe/dbi_kprobes.h"
37 #endif /* def EC_ARCH_mips */
39 unsigned long pf_addr;
40 unsigned long cp_addr;
41 unsigned long mr_addr;
42 unsigned long exit_addr;
43 unsigned long unmap_addr;
44 kernel_probe_t *pf_probe = NULL;
45 kernel_probe_t *cp_probe = NULL;
46 kernel_probe_t *mr_probe = NULL;
47 kernel_probe_t *exit_probe = NULL;
48 kernel_probe_t *unmap_probe = NULL;
49 unsigned int probes_flags = 0;
52 probes_manager_init (void)
54 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38)
55 spin_lock_init(&ec_spinlock);
56 spin_lock_init(&ec_probe_spinlock);
57 #endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38) */
58 pf_addr = swap_ksyms("do_page_fault");
60 EPRINTF("Cannot find address for page fault function!");
64 cp_addr = swap_ksyms("copy_process");
66 EPRINTF("Cannot find address for copy_process function!");
70 mr_addr = swap_ksyms("mm_release");
72 EPRINTF("Cannot find address for mm_release function!");
76 exit_addr = swap_ksyms("do_exit");
78 EPRINTF("Cannot find address for do_exit function!");
82 unmap_addr = swap_ksyms("do_munmap");
83 if (unmap_addr == 0) {
84 EPRINTF("Cannot find address for do_munmap function!");
88 return storage_init ();
92 probes_manager_down (void)
94 detach_selected_probes ();
99 register_kernel_jprobe (kernel_probe_t * probe)
102 if( ((probe == pf_probe) && (us_proc_probes & US_PROC_PF_INSTLD)) ||
103 ((probe == cp_probe) && (us_proc_probes & US_PROC_CP_INSTLD)) ||
104 ((probe == mr_probe) && (us_proc_probes & US_PROC_MR_INSTLD)) ||
105 ((probe == unmap_probe) && (us_proc_probes & US_PROC_UNMAP_INSTLD)) ||
106 ((probe == exit_probe) && (us_proc_probes & US_PROC_EXIT_INSTLD)))
108 return 0; // probe is already registered
110 result = dbi_register_jprobe (&probe->jprobe);
113 EPRINTF ("register_kernel_jprobe(0x%lx) failure %d", probe->addr, result);
120 unregister_kernel_jprobe (kernel_probe_t * probe)
122 if( ((probe == pf_probe) && (us_proc_probes & US_PROC_PF_INSTLD)) ||
123 ((probe == cp_probe) && (us_proc_probes & US_PROC_CP_INSTLD)) ||
124 ((probe == mr_probe) && (us_proc_probes & US_PROC_MR_INSTLD)) ||
125 ((probe == unmap_probe) && (us_proc_probes & US_PROC_UNMAP_INSTLD)) ||
126 ((probe == exit_probe) && (us_proc_probes & US_PROC_EXIT_INSTLD)) ) {
127 return 0; // probe is necessary for user space instrumentation
129 dbi_unregister_jprobe (&probe->jprobe);
134 register_kernel_retprobe (kernel_probe_t * probe)
137 if( ((probe == pf_probe) && (us_proc_probes & US_PROC_PF_INSTLD)) ||
138 ((probe == cp_probe) && (us_proc_probes & US_PROC_CP_INSTLD)) ||
139 ((probe == mr_probe) && (us_proc_probes & US_PROC_MR_INSTLD)) ||
140 ((probe == unmap_probe) && (us_proc_probes & US_PROC_UNMAP_INSTLD)) ||
141 ((probe == exit_probe) && (us_proc_probes & US_PROC_EXIT_INSTLD)) ) {
143 return 0; // probe is already registered
146 result = dbi_register_kretprobe (&probe->retprobe);
149 EPRINTF ("register_kernel_retprobe(0x%lx) failure %d", probe->addr, result);
156 unregister_kernel_retprobe (kernel_probe_t * probe)
158 if( ((probe == pf_probe) && (us_proc_probes & US_PROC_PF_INSTLD)) ||
159 ((probe == cp_probe) && (us_proc_probes & US_PROC_CP_INSTLD)) ||
160 ((probe == mr_probe) && (us_proc_probes & US_PROC_MR_INSTLD)) ||
161 ((probe == unmap_probe) && (us_proc_probes & US_PROC_UNMAP_INSTLD)) ||
162 ((probe == exit_probe) && (us_proc_probes & US_PROC_EXIT_INSTLD)) ) {
163 return 0; // probe is necessary for user space instrumentation
165 dbi_unregister_kretprobe (&probe->retprobe);
170 register_kernel_probe (kernel_probe_t * probe)
172 register_kernel_jprobe (probe);
173 register_kernel_retprobe (probe);
178 unregister_kernel_probe (kernel_probe_t * probe)
180 unregister_kernel_jprobe (probe);
181 unregister_kernel_retprobe (probe);
186 attach_selected_probes (void)
189 int partial_result = 0;
191 struct hlist_node *node;
193 hlist_for_each_entry_rcu (p, node, &kernel_probes, hlist)
195 partial_result = register_kernel_probe (p);
198 result = partial_result;
199 detach_selected_probes (); // return into safe state
208 detach_selected_probes (void)
211 struct hlist_node *node;
213 hlist_for_each_entry_rcu (p, node, &kernel_probes, hlist)
214 unregister_kernel_probe (p);
215 hlist_for_each_entry_rcu (p, node, &otg_kernel_probes, hlist) {
216 unregister_kernel_probe(p);
223 add_probe (unsigned long addr)
226 kernel_probe_t **pprobe = NULL;
228 DPRINTF("add probe at 0x%0x\n", addr);
229 if (EC_STATE_IDLE != ec_info.ec_state)
231 EPRINTF("Probes addition is allowed in IDLE state only.");
235 if (addr == pf_addr) {
236 probes_flags |= PROBE_FLAG_PF_INSTLD;
237 if (us_proc_probes & US_PROC_PF_INSTLD)
243 else if (addr == cp_addr) {
244 probes_flags |= PROBE_FLAG_CP_INSTLD;
245 if (us_proc_probes & US_PROC_CP_INSTLD)
251 else if (addr == exit_addr) {
252 probes_flags |= PROBE_FLAG_EXIT_INSTLD;
253 if (us_proc_probes & US_PROC_EXIT_INSTLD)
257 pprobe = &exit_probe;
259 else if (addr == mr_addr) {
260 probes_flags |= PROBE_FLAG_MR_INSTLD;
261 if (us_proc_probes & US_PROC_MR_INSTLD) {
266 else if (addr == unmap_addr) {
267 probes_flags |= PROBE_FLAG_UNMAP_INSTLD;
268 if (us_proc_probes & US_PROC_UNMAP_INSTLD)
272 pprobe = &unmap_probe;
275 result = add_probe_to_list (addr, pprobe);
278 probes_flags &= ~PROBE_FLAG_PF_INSTLD;
279 else if (addr == cp_addr)
280 probes_flags &= ~PROBE_FLAG_CP_INSTLD;
281 else if (addr == exit_addr)
282 probes_flags &= ~PROBE_FLAG_EXIT_INSTLD;
283 else if (addr == mr_addr)
284 probes_flags &= ~PROBE_FLAG_MR_INSTLD;
285 else if (addr == unmap_addr)
286 probes_flags &= ~PROBE_FLAG_UNMAP_INSTLD;
293 struct hlist_node *node, *tnode;
296 hlist_for_each_entry_safe (p, node, tnode, &kernel_probes, hlist) {
297 if (p->addr == pf_addr) {
298 probes_flags &= ~PROBE_FLAG_PF_INSTLD;
300 } else if (p->addr == cp_addr) {
301 probes_flags &= ~PROBE_FLAG_CP_INSTLD;
303 } else if (p->addr == exit_addr) {
304 probes_flags &= ~PROBE_FLAG_EXIT_INSTLD;
306 } else if (p->addr == mr_addr) {
307 probes_flags &= ~PROBE_FLAG_MR_INSTLD;
309 } else if (p->addr == unmap_addr) {
310 probes_flags &= ~PROBE_FLAG_UNMAP_INSTLD;
317 hlist_for_each_entry_safe (p, node, tnode, &otg_kernel_probes, hlist) {
318 if (p->addr == pf_addr) {
319 probes_flags &= ~PROBE_FLAG_PF_INSTLD;
321 } else if (p->addr == cp_addr) {
322 probes_flags &= ~PROBE_FLAG_CP_INSTLD;
324 } else if (p->addr == exit_addr) {
325 probes_flags &= ~PROBE_FLAG_EXIT_INSTLD;
327 } else if (p->addr == mr_addr) {
328 probes_flags &= ~PROBE_FLAG_MR_INSTLD;
330 } else if (p->addr == unmap_addr) {
331 probes_flags &= ~PROBE_FLAG_UNMAP_INSTLD;
342 remove_probe (unsigned long addr)
346 if (EC_STATE_IDLE != ec_info.ec_state)
348 EPRINTF("Probes addition is allowed in IDLE state only.");
352 if (addr == pf_addr) {
353 probes_flags &= ~PROBE_FLAG_PF_INSTLD;
354 if (us_proc_probes & US_PROC_PF_INSTLD)
360 else if (addr == cp_addr) {
361 probes_flags &= ~PROBE_FLAG_CP_INSTLD;
362 if (us_proc_probes & US_PROC_CP_INSTLD)
368 else if (addr == mr_addr) {
369 probes_flags &= ~PROBE_FLAG_MR_INSTLD;
370 if (us_proc_probes & US_PROC_MR_INSTLD) {
375 else if (addr == exit_addr) {
376 probes_flags &= ~PROBE_FLAG_EXIT_INSTLD;
377 if (us_proc_probes & US_PROC_EXIT_INSTLD)
383 else if (addr == unmap_addr) {
384 probes_flags &= ~PROBE_FLAG_UNMAP_INSTLD;
385 if (us_proc_probes & US_PROC_UNMAP_INSTLD)
392 result = remove_probe_from_list (addr);
397 DEFINE_PER_CPU (kernel_probe_t *, gpKernProbe) = NULL;
398 EXPORT_PER_CPU_SYMBOL_GPL(gpKernProbe);
401 def_jprobe_event_pre_handler (kernel_probe_t * probe, struct pt_regs *regs)
403 __get_cpu_var (gpKernProbe) = probe;
409 def_jprobe_event_handler (unsigned long arg1, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5, unsigned long arg6)
412 kernel_probe_t *probe = __get_cpu_var(gpKernProbe);
415 if (pf_probe == probe)
418 /* FIXME on x86 targets do_page_fault instrumentation may lead to
419 * abnormal termination of some applications (in most cases GUI apps).
420 * It looks like when do_page_fault probe is hit and the
421 * def_jprobe_event_handler is executed it tries to write event info
422 * into the SWAP buffer which seems not to be mapped into the
423 * process memory yet. Such behaviour causes segmentation faults.
424 * For now as a workaround we just avoid to write the ENTRY event into
425 * the buffer in all cases. */
427 #else /* CONFIG_X86 */
428 if (!(probes_flags & PROBE_FLAG_PF_INSTLD))
430 #endif /* CONFIG_X86 */
432 else if (cp_probe == probe)
434 if (!(probes_flags & PROBE_FLAG_CP_INSTLD))
437 else if (mr_probe == probe)
439 if (us_proc_probes & US_PROC_MR_INSTLD)
440 mm_release_probe_pre_code();
441 if (!(probes_flags & PROBE_FLAG_MR_INSTLD))
444 else if (exit_probe == probe)
446 if (us_proc_probes & US_PROC_EXIT_INSTLD)
447 do_exit_probe_pre_code();
448 if (!(probes_flags & PROBE_FLAG_EXIT_INSTLD))
451 else if (unmap_probe == probe)
453 if (us_proc_probes & US_PROC_UNMAP_INSTLD)
454 do_munmap_probe_pre_code((struct mm_struct *)arg1, arg2, (size_t)arg3);
455 if (!(probes_flags & PROBE_FLAG_UNMAP_INSTLD))
460 pack_event_info (KS_PROBE_ID, RECORD_ENTRY, "pxxxxxx", probe->addr, arg1, arg2, arg3, arg4, arg5, arg6);
461 dbi_jprobe_return ();
465 def_retprobe_event_handler (struct kretprobe_instance *pi, struct pt_regs *regs, kernel_probe_t * probe)
470 if (pf_probe == probe)
472 if (us_proc_probes & US_PROC_PF_INSTLD)
473 do_page_fault_ret_pre_code ();
474 if (!(probes_flags & PROBE_FLAG_PF_INSTLD))
477 if (cp_probe == probe)
479 if (us_proc_probes & US_PROC_CP_INSTLD)
480 copy_process_ret_pre_code((struct task_struct*)(regs_return_value(regs)));
482 if (!(probes_flags & PROBE_FLAG_CP_INSTLD))
485 else if (mr_probe == probe)
487 if (!(probes_flags & PROBE_FLAG_MR_INSTLD))
490 else if (exit_probe == probe)
492 if (!(probes_flags & PROBE_FLAG_EXIT_INSTLD))
495 else if (unmap_probe == probe)
497 if (!(probes_flags & PROBE_FLAG_UNMAP_INSTLD))
502 ret_val = regs_return_value(regs);
503 pack_event_info (KS_PROBE_ID, RECORD_RET, "pd",
504 probe->addr, ret_val);
509 /* This is a callback that is called by module 'swap_handlers'
510 * in order to register user defined handlers */
511 void dbi_install_user_handlers(void)
513 kernel_probe_t *probe;
514 struct hlist_node *node;
515 unsigned long pre_handler_addr, jp_handler_addr, rp_handler_addr;
517 // FIXME: functions 'find_jp_handler', 'find_rp_handler', 'find_pre_handler' - not found
518 /* We must perform this lookup whenever this function is called
519 * because the addresses of find_*_handler functions may differ. */
520 // swap_handlers removed
521 unsigned long (*find_jp_handler)(unsigned long) =
522 // swap_handlers removed
523 (unsigned long (*)(unsigned long))swap_ksyms("find_jp_handler");
524 unsigned long (*find_rp_handler)(unsigned long) =
525 (unsigned long (*)(unsigned long))swap_ksyms("find_rp_handler");
526 unsigned long (*find_pre_handler)(unsigned long) =
527 (unsigned long (*)(unsigned long))swap_ksyms("find_pre_handler");
528 hlist_for_each_entry_rcu (probe, node, &kernel_probes, hlist) {
531 pre_handler_addr = find_pre_handler(probe->addr);
532 if (find_pre_handler != 0) {
533 DPRINTF("Added user pre handler for 0x%lx: 0x%lx",
534 probe->addr, find_pre_handler);
535 probe->jprobe.pre_entry = (kprobe_pre_entry_handler_t)pre_handler_addr;
538 jp_handler_addr = find_jp_handler(probe->addr);
539 if (jp_handler_addr != 0) {
540 DPRINTF("Added user jp handler for 0x%lx: 0x%lx",
541 probe->addr, jp_handler_addr);
542 probe->jprobe.entry = (kprobe_opcode_t *)jp_handler_addr;
544 rp_handler_addr = find_rp_handler(probe->addr);
545 if (rp_handler_addr != 0)
546 probe->retprobe.handler = (kretprobe_handler_t)rp_handler_addr;
549 EXPORT_SYMBOL_GPL(dbi_install_user_handlers);
551 void dbi_uninstall_user_handlers(void)
553 kernel_probe_t *probe;
554 struct hlist_node *node;
556 hlist_for_each_entry_rcu (probe, node, &kernel_probes, hlist) {
557 DPRINTF("Removed user jp handler for 0x%lx", probe->addr);
558 probe->jprobe.pre_entry = (kprobe_pre_entry_handler_t)def_jprobe_event_pre_handler;
559 probe->jprobe.entry = (kprobe_opcode_t *)def_jprobe_event_handler;
560 probe->retprobe.handler = (kretprobe_handler_t)def_retprobe_event_handler;
563 EXPORT_SYMBOL_GPL(dbi_uninstall_user_handlers);
565 int is_pf_installed_by_user(void)
567 return (probes_flags & PROBE_FLAG_PF_INSTLD) ? 1: 0;
569 EXPORT_SYMBOL_GPL(is_pf_installed_by_user);
571 int install_kern_otg_probe(unsigned long addr,
572 unsigned long pre_handler,
573 unsigned long jp_handler,
574 unsigned long rp_handler)
576 kernel_probe_t *new_probe = NULL;
577 kernel_probe_t *probe;
580 probe = find_probe(addr);
582 /* It is not a problem if we have already registered
587 new_probe = kmalloc(sizeof (kernel_probe_t), GFP_ATOMIC);
589 EPRINTF("No memory for new probe");
592 memset(new_probe, 0, sizeof(kernel_probe_t));
594 new_probe->addr = addr;
595 new_probe->jprobe.kp.addr = new_probe->retprobe.kp.addr = (kprobe_opcode_t *)addr;
596 new_probe->jprobe.priv_arg = new_probe->retprobe.priv_arg = new_probe;
599 new_probe->jprobe.pre_entry =
600 (kprobe_pre_entry_handler_t)
603 new_probe->jprobe.pre_entry =
604 (kprobe_pre_entry_handler_t)
605 def_jprobe_event_pre_handler;
609 new_probe->jprobe.entry = (kprobe_opcode_t *)jp_handler;
611 new_probe->jprobe.entry =
613 def_jprobe_event_handler;
617 new_probe->retprobe.handler = (kretprobe_handler_t)rp_handler;
619 new_probe->retprobe.handler =
620 (kretprobe_handler_t)
621 def_retprobe_event_handler;
624 INIT_HLIST_NODE (&new_probe->hlist);
625 hlist_add_head_rcu (&new_probe->hlist, &kernel_probes);
627 ret = register_kernel_probe(new_probe);
629 EPRINTF("Cannot set kernel probe at addr %lx", addr);
635 EXPORT_SYMBOL_GPL(install_kern_otg_probe);