Kernel on-the-go probes feature implemented (#313)
authorNikita Kalyazin <n.kalyazin@samsung.com>
Mon, 23 Apr 2012 06:40:44 +0000 (10:40 +0400)
committerNikita Kalyazin <n.kalyazin@samsung.com>
Mon, 23 Apr 2012 06:41:58 +0000 (10:41 +0400)
Related to 76986670c32162d5d12c741a08bcec4fe935941a (#252).

Interface:
int install_kern_otg_probe(unsigned long addr,
unsigned long pre_handler,
unsigned long jp_handler,
unsigned long rp_handler);

driver/probes_manager.c
driver/probes_manager.h
driver/storage.c
driver/storage.h

index fd7188c..14c3bd9 100644 (file)
@@ -202,6 +202,9 @@ detach_selected_probes (void)
 
        hlist_for_each_entry_rcu (p, node, &kernel_probes, hlist)
                unregister_kernel_probe (p);
+       hlist_for_each_entry_rcu (p, node, &otg_kernel_probes, hlist) {
+               unregister_kernel_probe(p);
+       }
 
        return 0;
 }
@@ -288,6 +291,24 @@ int reset_probes()
                kfree(p);
        }
 
+       hlist_for_each_entry_safe (p, node, tnode, &otg_kernel_probes, hlist) {
+               if (p->addr == pf_addr) {
+                       probes_flags &= ~PROBE_FLAG_PF_INSTLD;
+                       pf_probe = NULL;
+               } else if (p->addr == exit_addr) {
+                       probes_flags &= ~PROBE_FLAG_EXIT_INSTLD;
+                       exit_probe = NULL;
+               } else if (p->addr == fork_addr) {
+                       probes_flags &= ~PROBE_FLAG_FORK_INSTLD;
+                       fork_probe = NULL;
+               } else if (p->addr == exec_addr) {
+                       probes_flags &= ~PROBE_FLAG_EXEC_INSTLD;
+                       exec_probe = NULL;
+               }
+               hlist_del(node);
+               kfree(p);
+       }
+
        return 0;
 }
 
@@ -510,3 +531,67 @@ int is_pf_installed_by_user(void)
        return (probes_flags & PROBE_FLAG_PF_INSTLD) ? 1: 0;
 }
 EXPORT_SYMBOL_GPL(is_pf_installed_by_user);
+
+int install_kern_otg_probe(unsigned long addr,
+                          unsigned long pre_handler,
+                          unsigned long jp_handler,
+                          unsigned long rp_handler)
+{
+       kernel_probe_t *new_probe = NULL;
+       kernel_probe_t *probe;
+       int ret = 0;
+
+       probe = find_probe(addr);
+       if (probe) {
+               /* It is not a problem if we have already registered
+                  this probe before */
+               return 0;
+       }
+
+       new_probe = kmalloc(sizeof (kernel_probe_t), GFP_ATOMIC);
+       if (!new_probe) {
+               EPRINTF("No memory for new probe");
+               return -1;
+       }
+       memset(new_probe, 0, sizeof(kernel_probe_t));
+
+       new_probe->addr = addr;
+       new_probe->jprobe.kp.addr = new_probe->retprobe.kp.addr = (kprobe_opcode_t *)addr;
+       new_probe->jprobe.priv_arg = new_probe->retprobe.priv_arg = new_probe;
+
+       if (pre_handler) {
+               new_probe->jprobe.pre_entry = pre_handler;
+       } else {
+               new_probe->jprobe.pre_entry =
+                       (kprobe_pre_entry_handler_t)
+                       def_jprobe_event_pre_handler;
+       }
+
+       if (jp_handler) {
+               new_probe->jprobe.entry = jp_handler;
+       } else {
+               new_probe->jprobe.entry =
+                       (kprobe_opcode_t *)
+                       def_jprobe_event_handler;
+       }
+
+       if (rp_handler) {
+               new_probe->retprobe.handler = rp_handler;
+       } else {
+               new_probe->retprobe.handler =
+                       (kretprobe_handler_t)
+                       def_retprobe_event_handler;
+       }
+
+       INIT_HLIST_NODE (&new_probe->hlist);
+       hlist_add_head_rcu (&new_probe->hlist, &kernel_probes);
+
+       ret = register_kernel_probe(new_probe);
+       if (ret) {
+               EPRINTF("Cannot set kernel probe at addr %p", addr);
+               return -1;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(install_kern_otg_probe);
index 33de035..91df48b 100644 (file)
@@ -47,6 +47,10 @@ extern int def_retprobe_event_handler (struct kretprobe_instance *probe, struct
 void dbi_install_user_handlers(void);
 void dbi_uninstall_user_handlers(void);
 int is_pf_installed_by_user(void);
+int install_kern_otg_probe(unsigned long addr,
+                          unsigned long pre_handler,
+                          unsigned long jp_handler,
+                          unsigned long rp_handler);
 
 extern unsigned long pf_addr;
 extern unsigned long exit_addr;
index 5764300..38358cf 100644 (file)
@@ -34,6 +34,7 @@ char *deps;
 char *bundle;
 unsigned int inst_pid = 0;
 struct hlist_head kernel_probes;
+struct hlist_head otg_kernel_probes;
 int event_mask = 0L;
 struct cond cond_list;
 int paused = 0; /* a state after a stop condition (events are not collected) */
@@ -1356,7 +1357,8 @@ int storage_init (void)
                return -1;
        }
 
-       INIT_HLIST_HEAD (&kernel_probes);
+       INIT_HLIST_HEAD(&kernel_probes);
+       INIT_HLIST_HEAD(&otg_kernel_probes);
        INIT_LIST_HEAD(&otg_us_proc_info);
 
        return 0;
index 8ae7ecd..49bbfed 100644 (file)
@@ -119,6 +119,9 @@ extern char *p_buffer;
 // list of selected non-predefined kernel probes
 extern struct hlist_head kernel_probes;
 
+/* list of on-the-go installed kernel probes */
+extern struct hlist_head otg_kernel_probes;
+
 extern struct list_head otg_us_proc_info;
 
 // event mask