Revision: 1544 Author: teawater Date: Mon May 6 02:37:26 2013 Log: Let while-stepping auto close irq http://code.google.com/p/kgtp/source/detail?r=1544 Modified: /trunk/gtp.c ======================================= --- /trunk/gtp.c Sat Apr 20 06:58:43 2013 +++ /trunk/gtp.c Mon May 6 02:37:26 2013 @@ -470,6 +470,7 @@ struct gtp_step_s { spinlock_t lock; int step; + int irq_need_open; struct gtp_entry *tpe; }; static DEFINE_PER_CPU(struct gtp_step_s, gtp_step); @@ -488,7 +489,8 @@ static unsigned long gtp_hwb_drx[HWB_NUM]; static unsigned long gtp_hwb_dr7; -#define GTP_HWB_DR7_DEF 0x400UL +#define GTP_HWB_DR7_DEF (0x400UL) +#define GTP_HWB_DR6_MASK (0xe00fUL) /* This part is for all the arch. */ struct gtp_hwb_s { @@ -4825,8 +4827,16 @@ #else regs->eflags &= ~(X86_EFLAGS_TF); #endif + if (__get_cpu_var(gtp_step).irq_need_open) { +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,24)) + regs->flags |= X86_EFLAGS_IF; +#else + regs->eflags |= X86_EFLAGS_IF; +#endif + } __get_cpu_var(gtp_step).step = 0; __get_cpu_var(gtp_step).tpe = NULL; + __get_cpu_var(gtp_step).irq_need_open = 0; } static void @@ -5063,13 +5073,19 @@ if (tpe->step > 1) { /* Let while-stepping begin. *//*XXX if there a another one, maybe we need add end frame to let reader know that this while step stop. */
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,24)) - regs->flags |= X86_EFLAGS_TF; -#else - regs->eflags |= X86_EFLAGS_TF; -#endif __get_cpu_var(gtp_step).step = tpe->step; __get_cpu_var(gtp_step).tpe = tpe; + if (regs->flags & X86_EFLAGS_IF) + __get_cpu_var(gtp_step).irq_need_open = 1; + else + __get_cpu_var(gtp_step).irq_need_open = 0; + #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,24)) + regs->flags |= X86_EFLAGS_TF; + regs->flags &= ~(X86_EFLAGS_IF); + #else + regs->eflags |= X86_EFLAGS_TF; + regs->eflags &= ~(X86_EFLAGS_IF); + #endif } #endif } @@ -5595,6 +5611,31 @@ } #ifdef CONFIG_X86 +static int +gtp_step_check_insn(struct pt_regs *regs) +{ + uint8_t insn; + unsigned long pc = GTP_REGS_PC(regs); + + if (probe_kernel_read(&insn, (void *)pc, 1)) + return -1; + + switch (insn) { + case 0xfb: + /* sti */ + __get_cpu_var(gtp_step).irq_need_open = 1; + GTP_REGS_PC(regs) += 1; + break; + case 0xfa: + /* cli */ + __get_cpu_var(gtp_step).irq_need_open = 0; + GTP_REGS_PC(regs) += 1; + break; + }; + + return 0; +} + static int gtp_notifier_call(struct notifier_block *self, unsigned long cmd, void *ptr) @@ -5623,6 +5664,7 @@ #else dr6 = args->err; #endif + set_debugreg(GTP_HWB_DR7_DEF, 7); /* Handle while-stepping. */ spin_lock(&__get_cpu_var(gtp_step).lock); @@ -5633,9 +5675,13 @@ #else dr6 &= ~(0x4000); #endif - if (!__get_cpu_var(gtp_step).tpe) + if (!__get_cpu_var(gtp_step).tpe || user_mode(args->regs)) gtp_step_stop(args->regs); else { + if (gtp_step_check_insn(args->regs)) + printk(KERN_WARNING "KGTP: check insn in %p got error.", + (void *)GTP_REGS_PC(args->regs)); + preempt_disable(); { struct gtp_trace_s gts; @@ -5649,6 +5695,16 @@ preempt_enable_no_resched(); if (__get_cpu_var(gtp_step).step > 1) { + /* XXX: not sure need set eflags each step. */ +#if 0 + #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,24)) + args->regs->flags |= X86_EFLAGS_TF; + args->regs->flags &= ~(X86_EFLAGS_IF); + #else + args->regs->eflags |= X86_EFLAGS_TF; + args->regs->eflags &= ~(X86_EFLAGS_IF); + #endif +#endif __get_cpu_var(gtp_step).step--; } else { /*XXX: maybe need add a end frame. */ @@ -5663,7 +5719,6 @@ if ((dr6 & 0xf) == 0) goto out; read_lock(>p_hwb_lock); - set_debugreg(GTP_HWB_DR7_DEF, 7); for (i = 0; i < HWB_NUM; i++) { if ((dr6 & (0x1 << i)) == 0) @@ -5718,11 +5773,13 @@ #endif #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)) /* If have some other traps, let other handler handle it. */ - if ((*dr6_p) == 0) + if (((*dr6_p) & GTP_HWB_DR6_MASK) == 0) ret = NOTIFY_STOP; + current->thread.debugreg6 = *dr6_p; #else - if (dr6 == 0) + if ((dr6 & GTP_HWB_DR6_MASK) == 0) ret = NOTIFY_STOP; + current->thread.debugreg6 = dr6; #endif local_irq_restore(flags); @@ -6036,7 +6093,7 @@ #if (LINUX_VERSION_CODE < KERNEL_VERSION(3,0,0)) if (gtp_have_step || gtp_have_watch_tracepoint) #else - if (gtp_have_watch_tracepoint) + if (gtp_have_step) #endif unregister_die_notifier(>p_notifier);