[IMPROVE] create slot_manager
[kernel/swap-modules.git] / driver / us_proc_inst.c
index 6b84363..b14eb70 100644 (file)
@@ -24,6 +24,8 @@
 #include "sspt/sspt.h"
 #include "java_inst.h"
 
+#include <dbi_insn_slots.h>
+
 #define mm_read_lock(task, mm, atomic, lock)                   \
        mm = atomic ? task->active_mm : get_task_mm(task);      \
        if (mm == NULL) {                                       \
@@ -95,6 +97,87 @@ static inline int is_us_instrumentation(void)
        return !!us_proc_info.path;
 }
 
+static unsigned long alloc_user_pages(struct task_struct *task, unsigned long len, unsigned long prot, unsigned long flags)
+{
+       unsigned long ret = 0;
+       struct task_struct *otask = current;
+       struct mm_struct *mm;
+       int atomic = in_atomic();
+
+       mm = atomic ? task->active_mm : get_task_mm (task);
+       if (mm) {
+               if (!atomic) {
+                       if (!down_write_trylock(&mm->mmap_sem)) {
+                               rcu_read_lock();
+
+                               up_read(&mm->mmap_sem);
+                               down_write(&mm->mmap_sem);
+
+                               rcu_read_unlock();
+                       }
+               }
+               // FIXME: its seems to be bad decision to replace 'current' pointer temporarily
+               current_thread_info()->task = task;
+               ret = do_mmap_pgoff(NULL, 0, len, prot, flags, 0);
+               current_thread_info()->task = otask;
+               if (!atomic) {
+                       downgrade_write (&mm->mmap_sem);
+                       mmput(mm);
+               }
+       } else {
+               printk("proc %d has no mm", task->tgid);
+       }
+
+       return ret;
+}
+
+static void *sm_alloc_us(struct slot_manager *sm)
+{
+       struct task_struct *task = sm->data;
+
+       return (void *)alloc_user_pages(task, PAGE_SIZE,
+                                       PROT_EXEC|PROT_READ|PROT_WRITE,
+                                       MAP_ANONYMOUS|MAP_PRIVATE);
+}
+
+static void sm_free_us(struct slot_manager *sm, void *ptr)
+{
+       struct task_struct *task = sm->data;
+
+       /*
+        * E. G.: This code provides kernel dump because of rescheduling while atomic.
+        * As workaround, this code was commented. In this case we will have memory leaks
+        * for instrumented process, but instrumentation process should functionate correctly.
+        * Planned that good solution for this problem will be done during redesigning KProbe
+        * for improving supportability and performance.
+        */
+#if 0
+       mm = get_task_mm(task);
+       if (mm) {
+               down_write(&mm->mmap_sem);
+               do_munmap(mm, (unsigned long)(ptr), PAGE_SIZE);
+               up_write(&mm->mmap_sem);
+               mmput(mm);
+       }
+#endif
+       /* FIXME: implement the removal of memory for task */
+}
+
+struct slot_manager *create_sm_us(struct task_struct *task)
+{
+       struct slot_manager *sm = kmalloc(sizeof(*sm), GFP_ATOMIC);
+       sm->slot_size = UPROBES_TRAMP_LEN;
+       sm->alloc = sm_alloc_us;
+       sm->free = sm_free_us;
+       INIT_HLIST_NODE(&sm->page_list);
+       sm->data = task;
+}
+
+void free_sm_us(struct slot_manager *sm)
+{
+       /* FIXME: free */
+}
+
 static struct sspt_procs *get_proc_probes_by_task(struct task_struct *task)
 {
        struct sspt_procs *procs, *tmp;
@@ -127,6 +210,7 @@ static struct sspt_procs *get_proc_probes_by_task_or_new(struct task_struct *tas
        struct sspt_procs *procs = get_proc_probes_by_task(task);
        if (procs == NULL) {
                procs = sspt_procs_copy(us_proc_info.pp, task);
+               procs->sm = create_sm_us(task);
                add_proc_probes(task, procs);
        }
 
@@ -577,6 +661,7 @@ int inst_usr_space_proc (void)
                {
                        DPRINTF("task found. installing probes");
                        us_proc_info.tgid = task->pid;
+                       us_proc_info.pp->sm = create_sm_us(task);
                        install_proc_probes(task, us_proc_info.pp, 0);
                        put_task_struct (task);
                }
@@ -762,9 +847,7 @@ static void install_file_probes(struct task_struct *task, struct mm_struct *mm,
        for (i = 0; i < table_size; ++i) {
                head = &file->page_probes_table[i];
                hlist_for_each_entry_rcu(page, node, head, hlist) {
-                       if (page_present(mm, page->offset)) {
-                               register_us_page_probe(page, file, task);
-                       }
+                       register_us_page_probe(page, file, task);
                }
        }
 }
@@ -936,6 +1019,7 @@ void do_page_fault_ret_pre_code (void)
                        if (tgid) {
                                us_proc_info.tgid = gl_nNotifyTgid = tgid;
 
+                               us_proc_info.pp->sm = create_sm_us(task);
                                /* install probes in already mapped memory */
                                install_proc_probes(task, us_proc_info.pp, 1);
                        }
@@ -1008,7 +1092,7 @@ static int remove_unmap_probes(struct task_struct *task, struct sspt_procs *proc
                file = sspt_procs_find_file(procs, dentry);
                if (file) {
                        if (vma->vm_start == start || vma->vm_end == end) {
-                               unregister_us_file_probes(task, file, US_NOT_RP2);
+                               unregister_us_file_probes(task, file, US_UNREGS_PROBE);
                                file->loaded = 0;
                        } else {
                                unsigned long page_addr;
@@ -1017,7 +1101,7 @@ static int remove_unmap_probes(struct task_struct *task, struct sspt_procs *proc
                                for (page_addr = vma->vm_start; page_addr < vma->vm_end; page_addr += PAGE_SIZE) {
                                        page = sspt_find_page_mapped(file, page_addr);
                                        if (page) {
-                                               unregister_us_page_probe(task, page, US_NOT_RP2);
+                                               unregister_us_page_probe(task, page, US_UNREGS_PROBE);
                                        }
                                }
 
@@ -1076,7 +1160,7 @@ void mm_release_probe_pre_code(void)
        }
 
        if (procs) {
-               int ret = uninstall_us_proc_probes(task, procs, US_NOT_RP2);
+               int ret = uninstall_us_proc_probes(task, procs, US_UNREGS_PROBE);
                if (ret != 0) {
                        EPRINTF ("failed to uninstall IPs (%d)!", ret);
                }
@@ -1131,7 +1215,7 @@ unsigned long ujprobe_event_pre_handler(struct us_ip *ip, struct pt_regs *regs)
 void ujprobe_event_handler (unsigned long arg1, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5, unsigned long arg6)
 {
        struct us_ip *ip = __get_cpu_var(gpCurIp);
-       unsigned long addr = (unsigned long)ip->jprobe.kp.addr;
+       unsigned long addr = (unsigned long)ip->jprobe.up.kp.addr;
 
 #ifdef __ANDROID
        struct pt_regs *regs = __get_cpu_var(gpUserRegs);
@@ -1158,13 +1242,13 @@ void ujprobe_event_handler (unsigned long arg1, unsigned long arg2, unsigned lon
 
 static void send_plt(struct us_ip *ip)
 {
-       unsigned long addr = (unsigned long)ip->jprobe.kp.addr;
+       unsigned long addr = (unsigned long)ip->jprobe.up.kp.addr;
        struct vm_area_struct *vma = find_vma(current->mm, addr);
 
        if (vma && check_vma(vma)) {
                char *name = NULL;
                unsigned long real_addr;
-               unsigned long real_got = vma->vm_flags & VM_EXECUTABLE ?
+               unsigned long real_got = current->mm->exe_file == vma->vm_file ?
                                ip->got_addr :
                                ip->got_addr + vma->vm_start;
 
@@ -1192,7 +1276,7 @@ static void send_plt(struct us_ip *ip)
 int uretprobe_event_handler(struct uretprobe_instance *probe, struct pt_regs *regs, struct us_ip *ip)
 {
        int retval = regs_return_value(regs);
-       unsigned long addr = (unsigned long)ip->jprobe.kp.addr;
+       unsigned long addr = (unsigned long)ip->jprobe.up.kp.addr;
 
        if (ip->got_addr && ip->flag_got == 0) {
                send_plt(ip);
@@ -1217,35 +1301,42 @@ int uretprobe_event_handler(struct uretprobe_instance *probe, struct pt_regs *re
 int register_usprobe(struct task_struct *task, struct us_ip *ip, int atomic)
 {
        int ret = 0;
-       ip->jprobe.kp.tgid = task->tgid;
 
        if (ip->jprobe.entry == NULL) {
-               ip->jprobe.entry = (kprobe_opcode_t *)ujprobe_event_handler;
+               ip->jprobe.entry = (void *)ujprobe_event_handler;
                DPRINTF("Set default event handler for %x\n", ip->offset);
        }
 
        if (ip->jprobe.pre_entry == NULL) {
-               ip->jprobe.pre_entry = (kprobe_pre_entry_handler_t)ujprobe_event_pre_handler;
+               ip->jprobe.pre_entry = (uprobe_pre_entry_handler_t)ujprobe_event_pre_handler;
                DPRINTF("Set default pre handler for %x\n", ip->offset);
        }
 
        ip->jprobe.priv_arg = ip;
-       ret = dbi_register_ujprobe(task, &ip->jprobe, atomic);
+       ip->jprobe.up.task = task;
+       ip->jprobe.up.sm = ip->page->file->procs->sm;
+       ret = dbi_register_ujprobe(&ip->jprobe, atomic);
        if (ret) {
+               if (ret == -ENOEXEC) {
+                       pack_event_info(ERR_MSG_ID, RECORD_ENTRY, "dp",
+                                       0x1,
+                                       ip->jprobe.up.kp.addr);
+               }
                DPRINTF ("dbi_register_ujprobe() failure %d", ret);
                return ret;
        }
 
        if (ip->flag_retprobe) {
                // Mr_Nobody: comment for valencia
-               ip->retprobe.kp.tgid = task->tgid;
                if (ip->retprobe.handler == NULL) {
                        ip->retprobe.handler = (uretprobe_handler_t)uretprobe_event_handler;
                        DPRINTF("Set default ret event handler for %x\n", ip->offset);
                }
 
                ip->retprobe.priv_arg = ip;
-               ret = dbi_register_uretprobe(task, &ip->retprobe, atomic);
+               ip->retprobe.up.task = task;
+               ip->retprobe.up.sm = ip->page->file->procs->sm;
+               ret = dbi_register_uretprobe(&ip->retprobe, atomic);
                if (ret) {
                        EPRINTF ("dbi_register_uretprobe() failure %d", ret);
                        return ret;
@@ -1255,12 +1346,12 @@ int register_usprobe(struct task_struct *task, struct us_ip *ip, int atomic)
        return 0;
 }
 
-int unregister_usprobe(struct task_struct *task, struct us_ip *ip, int atomic, int not_rp2)
+int unregister_usprobe(struct task_struct *task, struct us_ip *ip, int atomic)
 {
-       dbi_unregister_ujprobe(task, &ip->jprobe, atomic);
+       dbi_unregister_ujprobe(&ip->jprobe, atomic);
 
        if (ip->flag_retprobe) {
-               dbi_unregister_uretprobe(task, &ip->retprobe, atomic, not_rp2);
+               dbi_unregister_uretprobe(&ip->retprobe, atomic);
        }
 
        return 0;