Revision: 1545 Author: teawater Date: Mon May 6 06:34:14 2013 Log: Fix some bug of step http://code.google.com/p/kgtp/source/detail?r=1545 Modified: /trunk/gtp.c ======================================= --- /trunk/gtp.c Mon May 6 02:37:26 2013 +++ /trunk/gtp.c Mon May 6 06:34:14 2013 @@ -99,6 +99,7 @@ #include <linux/slab.h> #include <linux/ctype.h> #include <asm/atomic.h> +#include <asm/debugreg.h> #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)) #include <linux/kdebug.h> #else @@ -568,16 +569,16 @@ { switch(reg) { case 0: - set_debugreg(val, 0); + gtp_set_debugreg(val, 0); break; case 1: - set_debugreg(val, 1); + gtp_set_debugreg(val, 1); break; case 2: - set_debugreg(val, 2); + gtp_set_debugreg(val, 2); break; case 3: - set_debugreg(val, 3); + gtp_set_debugreg(val, 3); break; } } @@ -588,11 +589,11 @@ { read_lock(>p_hwb_lock); __get_cpu_var(gtp_hwb_sync_count_local) = gtp_hwb_sync_count; - set_debugreg(0UL, 0); - set_debugreg(0UL, 1); - set_debugreg(0UL, 2); - set_debugreg(0UL, 3); - set_debugreg(GTP_HWB_DR7_DEF, 7); + gtp_set_debugreg(0UL, 0); + gtp_set_debugreg(0UL, 1); + gtp_set_debugreg(0UL, 2); + gtp_set_debugreg(0UL, 3); + gtp_set_debugreg(GTP_HWB_DR7_DEF, 7); read_unlock(>p_hwb_lock); } @@ -600,11 +601,11 @@ gtp_hwb_sync_local(void) { __get_cpu_var(gtp_hwb_sync_count_local) = gtp_hwb_sync_count; - set_debugreg(gtp_hwb_drx[0], 0); - set_debugreg(gtp_hwb_drx[1], 1); - set_debugreg(gtp_hwb_drx[2], 2); - set_debugreg(gtp_hwb_drx[3], 3); - set_debugreg(gtp_hwb_dr7, 7); + gtp_set_debugreg(gtp_hwb_drx[0], 0); + gtp_set_debugreg(gtp_hwb_drx[1], 1); + gtp_set_debugreg(gtp_hwb_drx[2], 2); + gtp_set_debugreg(gtp_hwb_drx[3], 3); + gtp_set_debugreg(gtp_hwb_dr7, 7); } static void @@ -5611,25 +5612,74 @@ } #ifdef CONFIG_X86 +#define ADDR_PREFIX_OPCODE 0x67 +#define DATA_PREFIX_OPCODE 0x66 +#define LOCK_PREFIX_OPCODE 0xf0 +#define CS_PREFIX_OPCODE 0x2e +#define DS_PREFIX_OPCODE 0x3e +#define ES_PREFIX_OPCODE 0x26 +#define FS_PREFIX_OPCODE 0x64 +#define GS_PREFIX_OPCODE 0x65 +#define SS_PREFIX_OPCODE 0x36 +#define REPNE_PREFIX_OPCODE 0xf2 +#define REPE_PREFIX_OPCODE 0xf3 + static int gtp_step_check_insn(struct pt_regs *regs) { - uint8_t insn; + uint32_t opcode; + uint8_t opcode8; unsigned long pc = GTP_REGS_PC(regs); - if (probe_kernel_read(&insn, (void *)pc, 1)) - return -1; + /* prefixes */ + while (1) { + if (probe_kernel_read(&opcode8, (void *)pc, 1)) + return -1; + pc++; + switch (opcode8) { + case REPE_PREFIX_OPCODE: + case REPNE_PREFIX_OPCODE: + case LOCK_PREFIX_OPCODE: + case CS_PREFIX_OPCODE: + case SS_PREFIX_OPCODE: + case DS_PREFIX_OPCODE: + case ES_PREFIX_OPCODE: + case FS_PREFIX_OPCODE: + case GS_PREFIX_OPCODE: + case DATA_PREFIX_OPCODE: + case ADDR_PREFIX_OPCODE: +#ifndef CONFIG_X86_32 + case 0x40 ... 0x4f: +#endif + break; + default: + goto out_prefixes; + } + } +out_prefixes: - switch (insn) { + opcode = (uint32_t)opcode8; +reswitch: + switch (opcode) { + case 0x0f: + if (probe_kernel_read(&opcode8, (void *)pc, 1)) + return -1; + opcode = (uint32_t) opcode8 | 0x0f00; + goto reswitch; + break; case 0xfb: /* sti */ __get_cpu_var(gtp_step).irq_need_open = 1; - GTP_REGS_PC(regs) += 1; + GTP_REGS_PC(regs) = pc; break; case 0xfa: /* cli */ __get_cpu_var(gtp_step).irq_need_open = 0; - GTP_REGS_PC(regs) += 1; + GTP_REGS_PC(regs) = pc; + break; + case 0x0f07: + /* sysret */ + return 1; break; }; @@ -5664,7 +5714,7 @@ #else dr6 = args->err; #endif - set_debugreg(GTP_HWB_DR7_DEF, 7); + gtp_set_debugreg(GTP_HWB_DR7_DEF, 7); /* Handle while-stepping. */ spin_lock(&__get_cpu_var(gtp_step).lock); @@ -5678,7 +5728,8 @@ if (!__get_cpu_var(gtp_step).tpe || user_mode(args->regs)) gtp_step_stop(args->regs); else { - if (gtp_step_check_insn(args->regs)) + int need_stop = gtp_step_check_insn(args->regs); + if (need_stop < 0) printk(KERN_WARNING "KGTP: check insn in %p got error.", (void *)GTP_REGS_PC(args->regs)); @@ -5694,7 +5745,7 @@ } preempt_enable_no_resched(); - if (__get_cpu_var(gtp_step).step > 1) { + if (__get_cpu_var(gtp_step).step > 1 && !need_stop) { /* XXX: not sure need set eflags each step. */ #if 0 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,24)) @@ -5754,14 +5805,14 @@ /* If the HWB need update in this CPU, just update it. */ if (__get_cpu_var(gtp_hwb_sync_count_local) != gtp_hwb_sync_count) { - set_debugreg(gtp_hwb_drx[0], 0); - set_debugreg(gtp_hwb_drx[1], 1); - set_debugreg(gtp_hwb_drx[2], 2); - set_debugreg(gtp_hwb_drx[3], 3); + gtp_set_debugreg(gtp_hwb_drx[0], 0); + gtp_set_debugreg(gtp_hwb_drx[1], 1); + gtp_set_debugreg(gtp_hwb_drx[2], 2); + gtp_set_debugreg(gtp_hwb_drx[3], 3); __get_cpu_var(gtp_hwb_sync_count_local) = gtp_hwb_sync_count; } - set_debugreg(gtp_hwb_dr7, 7); + gtp_set_debugreg(gtp_hwb_dr7, 7); read_unlock(>p_hwb_lock); #endif @@ -5769,7 +5820,7 @@ out: #endif #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33)) - set_debugreg(dr6, 6); + gtp_set_debugreg(dr6, 6); #endif #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)) /* If have some other traps, let other handler handle it. */ @@ -5967,7 +6018,7 @@ /* Set gtp_hwb_dr7 and gtp_hwb_drx[num] to hwb. */ gtp_set_debugreg(gtp_hwb_drx[num], num); - set_debugreg(gtp_hwb_dr7, 7); + gtp_set_debugreg(gtp_hwb_dr7, 7); gtp_hwb_sync_count++; hwb->count = gtp_hwb_sync_count; @@ -6024,7 +6075,7 @@ gtp_hwb_sync_count++; /* Sync gtp_hwb_dr7 update to hwb. */ - set_debugreg(gtp_hwb_dr7, 7); + gtp_set_debugreg(gtp_hwb_dr7, 7); #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)) /* Send ipi to let other cpu update. */