Initial version for x86 tizen emulator
authorVasiliy Ulyanov <v.ulyanov@samsung.com>
Thu, 28 Jun 2012 10:29:24 +0000 (14:29 +0400)
committerVasiliy Ulyanov <v.ulyanov@samsung.com>
Thu, 28 Jun 2012 10:29:24 +0000 (14:29 +0400)
driver/probes_manager.c
driver/us_proc_inst.c
kprobe/arch/asm-x86/dbi_kprobes.c
kprobe/dbi_kprobes_deps.c

index 14c3bd9..498f4bf 100644 (file)
@@ -53,7 +53,8 @@ probes_manager_init (void)
        spin_lock_init(&ec_probe_spinlock);
 #endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38) */
 #ifdef CONFIG_X86
-       pf_addr = lookup_name("handle_mm_fault");
+       //pf_addr = lookup_name("handle_mm_fault");
+       pf_addr = lookup_name("do_page_fault");
 #else
        pf_addr = lookup_name("do_page_fault");
 #endif
index ac3e210..016e126 100644 (file)
@@ -33,6 +33,14 @@ DEFINE_PER_CPU (struct pt_regs *, gpCurVtpRegs) = NULL;
 #      warning ARCH_REG_VAL is not implemented for this architecture. FBI will work improperly or even crash!!!
 #endif // ARCH
 
+#if defined(CONFIG_ARM)
+#define SP(regs) (regs)->ARM_sp
+#elif defined(CONFIG_X86)
+#define SP(regs) (regs)->EREG(sp)
+#else
+#error SP(regs) is not implemented
+#endif /* CONFIG_* */
+
 unsigned long (*dbi_ujprobe_event_pre_handler_custom_p)
 (us_proc_ip_t *, struct pt_regs *) = NULL;
 EXPORT_SYMBOL(dbi_ujprobe_event_pre_handler_custom_p);
@@ -1667,7 +1675,7 @@ static unsigned long get_stack_size(struct task_struct *task,
                struct pt_regs *regs)
 {
 #ifdef CONFIG_ADD_THREAD_STACK_INFO
-       return (task->stack_start - regs->ARM_sp);
+       return (task->stack_start - SP(regs));
 #else
        struct vm_area_struct *vma = NULL;
        struct mm_struct *mm = NULL;
@@ -1680,10 +1688,10 @@ static unsigned long get_stack_size(struct task_struct *task,
                if (!atomic)
                        down_read(&mm->mmap_sem);
 
-               vma = find_vma(mm, regs->ARM_sp);
+               vma = find_vma(mm, SP(regs));
 
                if (vma)
-                       result = vma->vm_end - regs->ARM_sp;
+                       result = vma->vm_end - SP(regs);
                else
                        result = 0;
 
@@ -1703,7 +1711,7 @@ static unsigned long get_stack(struct task_struct *task, struct pt_regs *regs,
 {
        unsigned long stack_sz = get_stack_size(task, regs);
        unsigned long real_sz = (stack_sz > sz ? sz: stack_sz);
-       int res = read_proc_vm_atomic(task, regs->ARM_sp, buf, real_sz);
+       int res = read_proc_vm_atomic(task, SP(regs), buf, real_sz);
        return res;
 }
 EXPORT_SYMBOL_GPL(get_stack);
index 48ae675..0c51e68 100644 (file)
 
 #define SUPRESS_BUG_MESSAGES
 
+extern unsigned int *sched_addr;
+extern unsigned int *fork_addr;
+
+extern struct kprobe * per_cpu__current_kprobe;
+
 extern struct kprobe * per_cpu__current_kprobe;
+extern spinlock_t kretprobe_lock;
+extern struct kretprobe *sched_rp;
 
 extern struct hlist_head kprobe_insn_pages;
 extern struct hlist_head uprobe_insn_pages;
@@ -125,6 +132,9 @@ DECLARE_MOD_FUNC_DEP(module_alloc, void *, unsigned long size);
 DECLARE_MOD_FUNC_DEP(module_free, void, struct module *mod, void *module_region);
 DECLARE_MOD_FUNC_DEP(fixup_exception, int, struct pt_regs * regs);
 
+DECLARE_MOD_FUNC_DEP(freeze_processes, int, void);
+DECLARE_MOD_FUNC_DEP(thaw_processes, void, void);
+
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26))
 DECLARE_MOD_FUNC_DEP(text_poke, void, void *addr, unsigned char *opcode, int len);
 #else
@@ -353,7 +363,7 @@ int arch_prepare_kprobe (struct kprobe *p)
        if ((unsigned long) p->addr & 0x01)
        {
                DBPRINTF ("Attempt to register kprobe at an unaligned address\n");
-               ret = -EINVAL;
+               //ret = -EINVAL;
        }
 
 
@@ -435,7 +445,6 @@ int arch_prepare_uretprobe (struct kretprobe *p, struct task_struct *task)
 
 void prepare_singlestep (struct kprobe *p, struct pt_regs *regs)
 {
-
        if(p->ss_addr)
        {
                regs->EREG (ip) = (unsigned long)p->ss_addr;
@@ -739,8 +748,133 @@ no_kprobe:
        return ret;
 }
 
+void patch_suspended_task_ret_addr(struct task_struct *p, struct kretprobe *rp)
+{
+       struct kretprobe_instance *ri = NULL;
+       struct hlist_node *node, *tmp;
+       struct hlist_head *head;
+       unsigned long flags;
+       int found = 0;
+
+       /* DO NOT patch exiting tasks */
+       /*if ((p->state & TASK_DEAD) || (p->exit_state != 0) || (p->flags & PF_EXITING) || (p->flags & PF_EXITPIDONE))
+               return;*/
+       /*spin_lock_irq(&p->pi_lock);
+       if (unlikely((p->flags & PF_EXITING) || (p->flags & PF_EXITPIDONE))) {
+               spin_unlock_irq(&p->pi_lock);
+               return;
+       }
+       spin_unlock_irq(&p->pi_lock);*/
+
+       spin_lock_irqsave(&kretprobe_lock, flags);
+       head = kretprobe_inst_table_head(p);
+       hlist_for_each_entry_safe(ri, node, tmp, head, hlist) {
+               if (ri->rp == rp && p == ri->task) {
+                       found = 1;
+                       break;
+               }
+       }
+       spin_unlock_irqrestore(&kretprobe_lock, flags);
+
+       if (found) {
+               /* update PC */
+               if (p->thread.EREG(ip) != &kretprobe_trampoline) {
+                       ri->ret_addr = (kprobe_opcode_t *)p->thread.EREG(ip);
+                       p->thread.EREG(ip) = &kretprobe_trampoline;
+               }
+               return;
+       }
+
+       spin_lock_irqsave(&kretprobe_lock, flags);
+       if ((ri = get_free_rp_inst(rp)) != NULL) {
+               ri->rp = rp;
+               ri->rp2 = NULL;
+               ri->task = p;
+               ri->ret_addr = (kprobe_opcode_t *)p->thread.EREG(ip);
+               p->thread.EREG(ip) = &kretprobe_trampoline;
+               add_rp_inst(ri);
+       } else {
+               printk("no ri for %d\n", p->pid);
+               BUG();
+       }
+       spin_unlock_irqrestore(&kretprobe_lock, flags);
+}
+
 int setjmp_pre_handler (struct kprobe *p, struct pt_regs *regs) 
 {
+//#if 0
+       struct jprobe *jp = container_of (p, struct jprobe, kp);
+       kprobe_pre_entry_handler_t pre_entry;
+       entry_point_t entry;
+
+       unsigned long addr, args[6];
+       struct kprobe_ctlblk *kcb = get_kprobe_ctlblk ();
+
+       DBPRINTF ("setjmp_pre_handler %p:%d", p->addr, p->tgid);
+       pre_entry = (kprobe_pre_entry_handler_t) jp->pre_entry;
+       entry = (entry_point_t) jp->entry;
+
+       if (!p->tgid || (p->tgid == current->tgid)) {
+               /* handle __switch_to probe */
+               if(!p->tgid && (p->addr == sched_addr) && sched_rp) {
+                       struct task_struct *p, *g;
+                       rcu_read_lock();
+                       //swapper task
+                       if(current != &init_task)
+                               patch_suspended_task_ret_addr(&init_task, sched_rp);
+                       // other tasks
+                       do_each_thread(g, p){
+                               if(current != p)
+                                       patch_suspended_task_ret_addr(p, sched_rp);
+                       } while_each_thread(g, p);
+                       rcu_read_unlock();
+               }
+
+               /* TODO handle do_exit probe */
+       }
+
+       if (p->tgid) {
+               regs->EREG(flags) &= ~IF_MASK;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18)
+               trace_hardirqs_off ();
+#endif
+               if (p->tgid == current->tgid) {
+                       // read first 6 args from stack
+                       if (!read_proc_vm_atomic (current, regs->EREG(sp) + 4, args, sizeof(args)))
+                               panic ("failed to read user space func arguments %lx!\n", regs->EREG(sp)+4);
+                       if (pre_entry)
+                               p->ss_addr = pre_entry (jp->priv_arg, regs);
+                       if (entry)
+                               entry (args[0], args[1], args[2], args[3], args[4], args[5]);
+               } else {
+                       dbi_arch_uprobe_return();
+               }
+
+               return 2;
+       } else {
+               kcb->jprobe_saved_regs = *regs;
+               kcb->jprobe_saved_esp = &regs->EREG(sp);
+               addr = (unsigned long) (kcb->jprobe_saved_esp);
+
+               /* TBD: As Linus pointed out, gcc assumes that the callee
+                * owns the argument space and could overwrite it, e.g.
+                * tailcall optimization. So, to be absolutely safe
+                * we also save and restore enough stack bytes to cover
+                * the argument area. */
+               memcpy (kcb->jprobes_stack, (kprobe_opcode_t *)addr, MIN_STACK_SIZE (addr));
+               regs->EREG (flags) &= ~IF_MASK;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18)
+               trace_hardirqs_off ();
+#endif
+               if (pre_entry)
+                       p->ss_addr = pre_entry(jp->priv_arg, regs);
+               regs->EREG(ip) = (unsigned long) (jp->entry);
+       }
+
+       return 1;
+//#endif /* 0 */
+
+#if 0 /* initial version */
        struct jprobe *jp = container_of (p, struct jprobe, kp);
        kprobe_pre_entry_handler_t pre_entry;
        entry_point_t entry;
@@ -794,6 +928,7 @@ int setjmp_pre_handler (struct kprobe *p, struct pt_regs *regs)
        }
 
        return 1;
+#endif /* 0 */
 }
 
 void dbi_jprobe_return (void)
@@ -1057,11 +1192,11 @@ int kprobe_exceptions_notify (struct notifier_block *self, unsigned long val, vo
        DBPRINTF ("switch (val) %lu %d %d", val, DIE_INT3, DIE_TRAP);
        switch (val)
        {
-               //#ifdef CONFIG_KPROBES
-               //      case DIE_INT3:
-               //#else
+#ifdef CONFIG_KPROBES
+               case DIE_INT3:
+#else
                case DIE_TRAP:
-                       //#endif
+#endif
                        DBPRINTF ("before kprobe_handler ret=%d %p", ret, args->regs);
                        if (kprobe_handler (args->regs))
                                ret = NOTIFY_STOP;
index ad454ec..be76025 100644 (file)
@@ -129,7 +129,7 @@ IMP_MOD_DEP_WRAPPER (get_gate_vma, tsk)
 #endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38) */
 
 #ifdef CONFIG_HUGETLB_PAGE
-       DECLARE_MOD_DEP_WRAPPER (follow_hugetlb_page, int, struct mm_struct *mm, struct vm_area_struct *vma, struct page **pages, struct vm_area_struct **vmas, unsigned long *position, int *length, int i, int write)
+       DECLARE_MOD_DEP_WRAPPER (follow_hugetlb_page, int, struct mm_struct *mm, struct vm_area_struct *vma, struct page **pages, struct vm_area_struct **vmas, unsigned long *position, int *length, int i, unsigned int write)
        IMP_MOD_DEP_WRAPPER (follow_hugetlb_page, mm, vma, pages, vmas, position, length, i, write)
 #endif