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>
20 #include "probes_manager.h"
24 #include "../kprobe/dbi_kprobes.h"
25 #endif /* def EC_ARCH_arm */
29 //#include <linux/kprobes.h>
30 #include "../kprobe/dbi_kprobes.h"
31 #endif /* def EC_ARCH_x86 */
35 #include "../kprobe/dbi_kprobes.h"
36 #endif /* def EC_ARCH_mips */
38 unsigned long pf_addr;
39 unsigned long cp_addr;
40 unsigned long mr_addr;
41 unsigned long exit_addr;
42 unsigned long unmap_addr;
43 kernel_probe_t *pf_probe = NULL;
44 kernel_probe_t *cp_probe = NULL;
45 kernel_probe_t *mr_probe = NULL;
46 kernel_probe_t *exit_probe = NULL;
47 kernel_probe_t *unmap_probe = NULL;
48 unsigned int probes_flags = 0;
51 probes_manager_init (void)
53 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38)
54 spin_lock_init(&ec_spinlock);
55 spin_lock_init(&ec_probe_spinlock);
56 #endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38) */
58 //pf_addr = lookup_name("handle_mm_fault");
59 pf_addr = lookup_name("do_page_fault");
61 pf_addr = lookup_name("do_page_fault");
64 EPRINTF("Cannot find address for page fault function!");
68 cp_addr = lookup_name("copy_process");
70 EPRINTF("Cannot find address for copy_process function!");
74 mr_addr = lookup_name("mm_release");
76 EPRINTF("Cannot find address for mm_release function!");
80 exit_addr = lookup_name("do_exit");
82 EPRINTF("Cannot find address for do_exit function!");
86 unmap_addr = lookup_name("do_munmap");
87 if (unmap_addr == 0) {
88 EPRINTF("Cannot find address for do_munmap function!");
92 return storage_init ();
96 probes_manager_down (void)
98 detach_selected_probes ();
103 register_kernel_jprobe (kernel_probe_t * probe)
106 if( ((probe == pf_probe) && (us_proc_probes & US_PROC_PF_INSTLD)) ||
107 ((probe == cp_probe) && (us_proc_probes & US_PROC_CP_INSTLD)) ||
108 ((probe == mr_probe) && (us_proc_probes & US_PROC_MR_INSTLD)) ||
109 ((probe == unmap_probe) && (us_proc_probes & US_PROC_UNMAP_INSTLD)) ||
110 ((probe == exit_probe) && (us_proc_probes & US_PROC_EXIT_INSTLD)))
112 return 0; // probe is already registered
114 result = dbi_register_jprobe (&probe->jprobe);
117 EPRINTF ("register_kernel_jprobe(0x%lx) failure %d", probe->addr, result);
124 unregister_kernel_jprobe (kernel_probe_t * probe)
126 if( ((probe == pf_probe) && (us_proc_probes & US_PROC_PF_INSTLD)) ||
127 ((probe == cp_probe) && (us_proc_probes & US_PROC_CP_INSTLD)) ||
128 ((probe == mr_probe) && (us_proc_probes & US_PROC_MR_INSTLD)) ||
129 ((probe == unmap_probe) && (us_proc_probes & US_PROC_UNMAP_INSTLD)) ||
130 ((probe == exit_probe) && (us_proc_probes & US_PROC_EXIT_INSTLD)) ) {
131 return 0; // probe is necessary for user space instrumentation
133 dbi_unregister_jprobe (&probe->jprobe);
138 register_kernel_retprobe (kernel_probe_t * probe)
141 if( ((probe == pf_probe) && (us_proc_probes & US_PROC_PF_INSTLD)) ||
142 ((probe == cp_probe) && (us_proc_probes & US_PROC_CP_INSTLD)) ||
143 ((probe == mr_probe) && (us_proc_probes & US_PROC_MR_INSTLD)) ||
144 ((probe == unmap_probe) && (us_proc_probes & US_PROC_UNMAP_INSTLD)) ||
145 ((probe == exit_probe) && (us_proc_probes & US_PROC_EXIT_INSTLD)) ) {
147 return 0; // probe is already registered
150 result = dbi_register_kretprobe (&probe->retprobe);
153 EPRINTF ("register_kernel_retprobe(0x%lx) failure %d", probe->addr, result);
160 unregister_kernel_retprobe (kernel_probe_t * probe)
162 if( ((probe == pf_probe) && (us_proc_probes & US_PROC_PF_INSTLD)) ||
163 ((probe == cp_probe) && (us_proc_probes & US_PROC_CP_INSTLD)) ||
164 ((probe == mr_probe) && (us_proc_probes & US_PROC_MR_INSTLD)) ||
165 ((probe == unmap_probe) && (us_proc_probes & US_PROC_UNMAP_INSTLD)) ||
166 ((probe == exit_probe) && (us_proc_probes & US_PROC_EXIT_INSTLD)) ) {
167 return 0; // probe is necessary for user space instrumentation
169 dbi_unregister_kretprobe (&probe->retprobe);
174 register_kernel_probe (kernel_probe_t * probe)
176 register_kernel_jprobe (probe);
177 register_kernel_retprobe (probe);
182 unregister_kernel_probe (kernel_probe_t * probe)
184 unregister_kernel_jprobe (probe);
185 unregister_kernel_retprobe (probe);
190 attach_selected_probes (void)
193 int partial_result = 0;
195 struct hlist_node *node;
197 hlist_for_each_entry_rcu (p, node, &kernel_probes, hlist)
199 partial_result = register_kernel_probe (p);
202 result = partial_result;
203 detach_selected_probes (); // return into safe state
212 detach_selected_probes (void)
215 struct hlist_node *node;
217 hlist_for_each_entry_rcu (p, node, &kernel_probes, hlist)
218 unregister_kernel_probe (p);
219 hlist_for_each_entry_rcu (p, node, &otg_kernel_probes, hlist) {
220 unregister_kernel_probe(p);
227 add_probe (unsigned long addr)
230 kernel_probe_t **pprobe = NULL;
232 DPRINTF("add probe at 0x%0x\n", addr);
233 if (EC_STATE_IDLE != ec_info.ec_state)
235 EPRINTF("Probes addition is allowed in IDLE state only.");
239 if (addr == pf_addr) {
240 probes_flags |= PROBE_FLAG_PF_INSTLD;
241 if (us_proc_probes & US_PROC_PF_INSTLD)
247 else if (addr == cp_addr) {
248 probes_flags |= PROBE_FLAG_CP_INSTLD;
249 if (us_proc_probes & US_PROC_CP_INSTLD)
255 else if (addr == exit_addr) {
256 probes_flags |= PROBE_FLAG_EXIT_INSTLD;
257 if (us_proc_probes & US_PROC_EXIT_INSTLD)
261 pprobe = &exit_probe;
263 else if (addr == mr_addr) {
264 probes_flags |= PROBE_FLAG_MR_INSTLD;
265 if (us_proc_probes & US_PROC_MR_INSTLD) {
270 else if (addr == unmap_addr) {
271 probes_flags |= PROBE_FLAG_UNMAP_INSTLD;
272 if (us_proc_probes & US_PROC_UNMAP_INSTLD)
276 pprobe = &unmap_probe;
279 result = add_probe_to_list (addr, pprobe);
282 probes_flags &= ~PROBE_FLAG_PF_INSTLD;
283 else if (addr == cp_addr)
284 probes_flags &= ~PROBE_FLAG_CP_INSTLD;
285 else if (addr == exit_addr)
286 probes_flags &= ~PROBE_FLAG_EXIT_INSTLD;
287 else if (addr == mr_addr)
288 probes_flags &= ~PROBE_FLAG_MR_INSTLD;
289 else if (addr == unmap_addr)
290 probes_flags &= ~PROBE_FLAG_UNMAP_INSTLD;
297 struct hlist_node *node, *tnode;
300 hlist_for_each_entry_safe (p, node, tnode, &kernel_probes, hlist) {
301 if (p->addr == pf_addr) {
302 probes_flags &= ~PROBE_FLAG_PF_INSTLD;
304 } else if (p->addr == cp_addr) {
305 probes_flags &= ~PROBE_FLAG_CP_INSTLD;
307 } else if (p->addr == exit_addr) {
308 probes_flags &= ~PROBE_FLAG_EXIT_INSTLD;
310 } else if (p->addr == mr_addr) {
311 probes_flags &= ~PROBE_FLAG_MR_INSTLD;
313 } else if (p->addr == unmap_addr) {
314 probes_flags &= ~PROBE_FLAG_UNMAP_INSTLD;
321 hlist_for_each_entry_safe (p, node, tnode, &otg_kernel_probes, hlist) {
322 if (p->addr == pf_addr) {
323 probes_flags &= ~PROBE_FLAG_PF_INSTLD;
325 } else if (p->addr == cp_addr) {
326 probes_flags &= ~PROBE_FLAG_CP_INSTLD;
328 } else if (p->addr == exit_addr) {
329 probes_flags &= ~PROBE_FLAG_EXIT_INSTLD;
331 } else if (p->addr == mr_addr) {
332 probes_flags &= ~PROBE_FLAG_MR_INSTLD;
334 } else if (p->addr == unmap_addr) {
335 probes_flags &= ~PROBE_FLAG_UNMAP_INSTLD;
346 remove_probe (unsigned long addr)
350 if (EC_STATE_IDLE != ec_info.ec_state)
352 EPRINTF("Probes addition is allowed in IDLE state only.");
356 if (addr == pf_addr) {
357 probes_flags &= ~PROBE_FLAG_PF_INSTLD;
358 if (us_proc_probes & US_PROC_PF_INSTLD)
364 else if (addr == cp_addr) {
365 probes_flags &= ~PROBE_FLAG_CP_INSTLD;
366 if (us_proc_probes & US_PROC_CP_INSTLD)
372 else if (addr == mr_addr) {
373 probes_flags &= ~PROBE_FLAG_MR_INSTLD;
374 if (us_proc_probes & US_PROC_MR_INSTLD) {
379 else if (addr == exit_addr) {
380 probes_flags &= ~PROBE_FLAG_EXIT_INSTLD;
381 if (us_proc_probes & US_PROC_EXIT_INSTLD)
387 else if (addr == unmap_addr) {
388 probes_flags &= ~PROBE_FLAG_UNMAP_INSTLD;
389 if (us_proc_probes & US_PROC_UNMAP_INSTLD)
396 result = remove_probe_from_list (addr);
401 DEFINE_PER_CPU (kernel_probe_t *, gpKernProbe) = NULL;
402 EXPORT_PER_CPU_SYMBOL_GPL(gpKernProbe);
405 def_jprobe_event_pre_handler (kernel_probe_t * probe, struct pt_regs *regs)
407 __get_cpu_var (gpKernProbe) = probe;
413 def_jprobe_event_handler (unsigned long arg1, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5, unsigned long arg6)
416 kernel_probe_t *probe = __get_cpu_var(gpKernProbe);
419 if (pf_probe == probe)
422 /* FIXME on x86 targets do_page_fault instrumentation may lead to
423 * abnormal termination of some applications (in most cases GUI apps).
424 * It looks like when do_page_fault probe is hit and the
425 * def_jprobe_event_handler is executed it tries to write event info
426 * into the SWAP buffer which seems not to be mapped into the
427 * process memory yet. Such behaviour causes segmentation faults.
428 * For now as a workaround we just avoid to write the ENTRY event into
429 * the buffer in all cases. */
431 #else /* CONFIG_X86 */
432 if (!(probes_flags & PROBE_FLAG_PF_INSTLD))
434 #endif /* CONFIG_X86 */
436 else if (cp_probe == probe)
438 if (!(probes_flags & PROBE_FLAG_CP_INSTLD))
441 else if (mr_probe == probe)
443 if (us_proc_probes & US_PROC_MR_INSTLD)
444 mm_release_probe_pre_code();
445 if (!(probes_flags & PROBE_FLAG_MR_INSTLD))
448 else if (exit_probe == probe)
450 if (us_proc_probes & US_PROC_EXIT_INSTLD)
451 do_exit_probe_pre_code();
452 if (!(probes_flags & PROBE_FLAG_EXIT_INSTLD))
455 else if (unmap_probe == probe)
457 if (us_proc_probes & US_PROC_UNMAP_INSTLD)
458 do_munmap_probe_pre_code((struct mm_struct *)arg1, arg2, (size_t)arg3);
459 if (!(probes_flags & PROBE_FLAG_UNMAP_INSTLD))
464 pack_event_info (KS_PROBE_ID, RECORD_ENTRY, "pxxxxxx", probe->addr, arg1, arg2, arg3, arg4, arg5, arg6);
465 dbi_jprobe_return ();
469 def_retprobe_event_handler (struct kretprobe_instance *pi, struct pt_regs *regs, kernel_probe_t * probe)
474 if (pf_probe == probe)
476 if (us_proc_probes & US_PROC_PF_INSTLD)
477 do_page_fault_ret_pre_code ();
478 if (!(probes_flags & PROBE_FLAG_PF_INSTLD))
481 if (cp_probe == probe)
483 if (us_proc_probes & US_PROC_CP_INSTLD)
484 copy_process_ret_pre_code((struct task_struct*)(regs_return_value(regs)));
486 if (!(probes_flags & PROBE_FLAG_CP_INSTLD))
489 else if (mr_probe == probe)
491 if (!(probes_flags & PROBE_FLAG_MR_INSTLD))
494 else if (exit_probe == probe)
496 if (!(probes_flags & PROBE_FLAG_EXIT_INSTLD))
499 else if (unmap_probe == probe)
501 if (!(probes_flags & PROBE_FLAG_UNMAP_INSTLD))
506 ret_val = regs_return_value(regs);
507 pack_event_info (KS_PROBE_ID, RECORD_RET, "pd",
508 probe->addr, ret_val);
513 /* This is a callback that is called by module 'swap_handlers'
514 * in order to register user defined handlers */
515 void dbi_install_user_handlers(void)
517 kernel_probe_t *probe;
518 struct hlist_node *node;
519 unsigned long pre_handler_addr, jp_handler_addr, rp_handler_addr;
521 /* We must perform this lookup whenever this function is called
522 * because the addresses of find_*_handler functions may differ. */
523 // swap_handlers removed
524 unsigned long (*find_jp_handler)(unsigned long) =
525 // swap_handlers removed
526 (unsigned long (*)(unsigned long))lookup_name("find_jp_handler");
527 unsigned long (*find_rp_handler)(unsigned long) =
528 (unsigned long (*)(unsigned long))lookup_name("find_rp_handler");
529 unsigned long (*find_pre_handler)(unsigned long) =
530 (unsigned long (*)(unsigned long))lookup_name("find_pre_handler");
531 hlist_for_each_entry_rcu (probe, node, &kernel_probes, hlist) {
534 pre_handler_addr = find_pre_handler(probe->addr);
535 if (find_pre_handler != 0) {
536 DPRINTF("Added user pre handler for 0x%lx: 0x%lx",
537 probe->addr, find_pre_handler);
538 probe->jprobe.pre_entry = (kprobe_pre_entry_handler_t)pre_handler_addr;
541 jp_handler_addr = find_jp_handler(probe->addr);
542 if (jp_handler_addr != 0) {
543 DPRINTF("Added user jp handler for 0x%lx: 0x%lx",
544 probe->addr, jp_handler_addr);
545 probe->jprobe.entry = (kprobe_opcode_t *)jp_handler_addr;
547 rp_handler_addr = find_rp_handler(probe->addr);
548 if (rp_handler_addr != 0)
549 probe->retprobe.handler = (kretprobe_handler_t)rp_handler_addr;
552 EXPORT_SYMBOL_GPL(dbi_install_user_handlers);
554 void dbi_uninstall_user_handlers(void)
556 kernel_probe_t *probe;
557 struct hlist_node *node;
559 hlist_for_each_entry_rcu (probe, node, &kernel_probes, hlist) {
560 DPRINTF("Removed user jp handler for 0x%lx", probe->addr);
561 probe->jprobe.pre_entry = (kprobe_pre_entry_handler_t)def_jprobe_event_pre_handler;
562 probe->jprobe.entry = (kprobe_opcode_t *)def_jprobe_event_handler;
563 probe->retprobe.handler = (kretprobe_handler_t)def_retprobe_event_handler;
566 EXPORT_SYMBOL_GPL(dbi_uninstall_user_handlers);
568 int is_pf_installed_by_user(void)
570 return (probes_flags & PROBE_FLAG_PF_INSTLD) ? 1: 0;
572 EXPORT_SYMBOL_GPL(is_pf_installed_by_user);
574 int install_kern_otg_probe(unsigned long addr,
575 unsigned long pre_handler,
576 unsigned long jp_handler,
577 unsigned long rp_handler)
579 kernel_probe_t *new_probe = NULL;
580 kernel_probe_t *probe;
583 probe = find_probe(addr);
585 /* It is not a problem if we have already registered
590 new_probe = kmalloc(sizeof (kernel_probe_t), GFP_ATOMIC);
592 EPRINTF("No memory for new probe");
595 memset(new_probe, 0, sizeof(kernel_probe_t));
597 new_probe->addr = addr;
598 new_probe->jprobe.kp.addr = new_probe->retprobe.kp.addr = (kprobe_opcode_t *)addr;
599 new_probe->jprobe.priv_arg = new_probe->retprobe.priv_arg = new_probe;
602 new_probe->jprobe.pre_entry =
603 (kprobe_pre_entry_handler_t)
606 new_probe->jprobe.pre_entry =
607 (kprobe_pre_entry_handler_t)
608 def_jprobe_event_pre_handler;
612 new_probe->jprobe.entry = (kprobe_opcode_t *)jp_handler;
614 new_probe->jprobe.entry =
616 def_jprobe_event_handler;
620 new_probe->retprobe.handler = (kretprobe_handler_t)rp_handler;
622 new_probe->retprobe.handler =
623 (kretprobe_handler_t)
624 def_retprobe_event_handler;
627 INIT_HLIST_NODE (&new_probe->hlist);
628 hlist_add_head_rcu (&new_probe->hlist, &kernel_probes);
630 ret = register_kernel_probe(new_probe);
632 EPRINTF("Cannot set kernel probe at addr %lx", addr);
638 EXPORT_SYMBOL_GPL(install_kern_otg_probe);