Revision: 1548 Author: teawater Date: Mon May 6 19:06:35 2013 Log: Fix build issue with old Linux kernel. Update patches. http://code.google.com/p/kgtp/source/detail?r=1548 Modified: /trunk/gtp.c /trunk/gtp_2.6.20_to_2.6.32.patch /trunk/gtp_2.6.33_to_2.6.38.patch /trunk/gtp_2.6.39.patch /trunk/gtp_3.0_to_3.6.patch /trunk/gtp_3.7_to_upstream.patch /trunk/gtp_older_to_2.6.19.patch ======================================= --- /trunk/gtp.c Mon May 6 07:43:38 2013 +++ /trunk/gtp.c Mon May 6 19:06:35 2013 @@ -5084,7 +5084,11 @@/*XXX if there a another one, maybe we need add end frame to let reader know that this while step stop. */
__get_cpu_var(gtp_step).step = tpe->step; __get_cpu_var(gtp_step).tpe = tpe; + #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,24)) if (regs->flags & X86_EFLAGS_IF) + #else + if (regs->eflags & X86_EFLAGS_IF) + #endif __get_cpu_var(gtp_step).irq_need_open = 1; else __get_cpu_var(gtp_step).irq_need_open = 0; ======================================= --- /trunk/gtp_2.6.20_to_2.6.32.patch Sun Feb 17 20:54:51 2013 +++ /trunk/gtp_2.6.20_to_2.6.32.patch Mon May 6 19:06:35 2013 @@ -3662,7 +3662,7 @@ --- /dev/null +++ b/lib/gtp.c -@@ -0,0 +1,12093 @@ +@@ -0,0 +1,12887 @@ +/* + * Kernel GDB tracepoint module. + * @@ -3680,12 +3680,12 @@ + * along with this program; if not, write to the Free Software+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *-+ * Copyright(C) KGTP team (https://code.google.com/p/kgtp/), 2010, 2011, 2012, 2013
++ * Copyright(C) KGTP team (https://code.google.com/p/kgtp/), 2010-2013 + * + */ + +/* If "* 10" means that this is not a release version. */ -+#define GTP_VERSION (20130218) ++#define GTP_VERSION (20130218 * 10) + +#include <linux/version.h> +#ifndef RHEL_RELEASE_VERSION @@ -3764,6 +3764,9 @@ +#include <linux/slab.h> +#include <linux/ctype.h> +#include <asm/atomic.h> ++#ifdef CONFIG_X86 ++#include <asm/debugreg.h> ++#endif +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)) +#include <linux/kdebug.h> +#else @@ -3874,7 +3877,9 @@ + + sizeof(struct gtp_frame_var)) +#endif +#ifdef GTP_RB -+#define GTP_FRAME_HEAD_SIZE (FID_SIZE + sizeof(u64) + sizeof(ULONGEST))++/* The frame head size: FID_HEAD + count id + frame number + pointer to prev frem */ ++#define GTP_FRAME_HEAD_SIZE (FID_SIZE + sizeof(u64) + sizeof(ULONGEST) + sizeof(void *))
++/* The frame head size: FID_PAGE_BEGIN + count id */ +#define GTP_FRAME_PAGE_BEGIN_SIZE (FID_SIZE + sizeof(u64)) +#endif +#ifdef GTP_FTRACE_RING_BUFFER @@ -3957,7 +3962,7 @@ +/* This gtp entry is registered inside the system. */ +#define GTP_ENTRY_FLAGS_REG 2 +/* See $no_self_trace. */ -+#define GTP_ENTRY_FLAGS_NO_SELF_TRACE 4 ++#define GTP_ENTRY_FLAGS_SELF_TRACE 4 +/* This gtp entry has passcount. */ +#define GTP_ENTRY_FLAGS_HAVE_PASS 8 +/* See $printk_level. */ @@ -4128,14 +4133,32 @@ + +static pid_t gtp_current_pid; + ++#ifdef CONFIG_X86 ++/* Following part is for while-stepping. */ ++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); ++#endif ++ +#ifdef CONFIG_X86 ++static int gtp_have_watch_tracepoint; ++static int gtp_have_step; ++#endif ++ ++#ifdef CONFIG_X86 ++/* Following part is for watch tracepoint. */ +/* This part is X86 special. */ +#define HWB_NUM 4 + +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 { @@ -4213,16 +4236,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; + } +} @@ -4233,11 +4256,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); +} + @@ -4245,11 +4268,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 @@ -4404,7 +4427,7 @@ + GTP_VAR_PRINTK_LEVEL_ID = 11, + GTP_VAR_PRINTK_FORMAT_ID = 12, + GTP_VAR_DUMP_STACK_ID = 13, -+ GTP_VAR_NO_SELF_TRACE_ID = 14, ++ GTP_VAR_SELF_TRACE_ID = 14, + GTP_VAR_CPU_NUMBER_ID = 15, + GTP_VAR_PC_PE_EN_ID = 16, + GTP_VAR_KRET_ID = 17, @@ -4437,8 +4460,11 @@ + GTP_WATCH_VAL_ID = 42, + GTP_WATCH_COUNT_ID = 43, + ++ GTP_STEP_COUNT_ID = 44, ++ GTP_STEP_ID_ID = 45, ++ + GTP_VAR_SPECIAL_MIN = GTP_VAR_VERSION_ID, -+ GTP_VAR_SPECIAL_MAX = GTP_WATCH_COUNT_ID, ++ GTP_VAR_SPECIAL_MAX = GTP_STEP_ID_ID, +}; + +enum pe_tv_id { @@ -5447,6 +5473,44 @@ +}; +#endif + ++#ifdef GTP_RB ++static int ++gtp_step_count_hooks_get_val(struct gtp_trace_s *gts, struct gtp_var *gtv, ++ int64_t *val) ++{ ++ if (gts->step) ++ *val = gts->tpe->step - gts->step + 1; ++ else ++ *val = 0; ++ ++ return 0; ++} ++ ++static struct gtp_var_hooks gtp_step_count_hooks = { ++ .agent_get_val = gtp_step_count_hooks_get_val, ++}; ++ ++static DEFINE_PER_CPU(int64_t, gtp_step_id); ++ ++static int ++gtp_step_id_hooks_get_val(struct gtp_trace_s *gts, struct gtp_var *gtv, ++ int64_t *val) ++{ ++ if (!gts->step) { ++ if (++ __get_cpu_var(gtp_step_id) == 0) ++ __get_cpu_var(gtp_step_id) = 1; ++ } ++ ++ *val = __get_cpu_var(gtp_step_id); ++ ++ return 0; ++} ++ ++static struct gtp_var_hooks gtp_step_id_hooks = { ++ .agent_get_val = gtp_step_id_hooks_get_val, ++}; ++#endif ++ +static int +gtp_var_special_add_all(void) +{ @@ -5539,8 +5603,8 @@ + if (IS_ERR(var)) + return PTR_ERR(var); + -+ var = gtp_var_special_add(GTP_VAR_NO_SELF_TRACE_ID, 0, 0, -+ "no_self_trace", NULL); ++ var = gtp_var_special_add(GTP_VAR_SELF_TRACE_ID, 0, 0, ++ "self_trace", NULL); + if (IS_ERR(var)) + return PTR_ERR(var); + @@ -5666,6 +5730,16 @@ + if (IS_ERR(var)) + return PTR_ERR(var); +#endif ++ var = gtp_var_special_add(GTP_STEP_COUNT_ID, 0, 0, ++ "step_count", >p_step_count_hooks); ++ if (IS_ERR(var)) ++ return PTR_ERR(var); ++#ifdef GTP_RB ++ var = gtp_var_special_add(GTP_STEP_ID_ID, 0, 0, ++ "step_id", >p_step_id_hooks); ++ if (IS_ERR(var)) ++ return PTR_ERR(var); ++#endif + + return 0; +} @@ -7238,6 +7312,11 @@ + } while (0) +#endif + ++static int gtp_collect_var(struct gtp_trace_s *gts, int num); ++#ifdef GTP_RB ++static int gtp_var_array_step_id_id = 0; ++#endif ++ +static int +gtp_action_head(struct gtp_trace_s *gts) +{ @@ -7286,6 +7365,13 @@ + + trace_nump = (ULONGEST *)tmp; + *trace_nump = gts->tpe->num; ++ tmp += sizeof(ULONGEST); ++ ++#ifdef GTP_RB ++ *(void **)tmp = gtp_rb_prev_frame_get(gts->next); ++ gtp_rb_prev_frame_set(gts->next, (void *)(tmp + sizeof(void *) ++ - GTP_FRAME_HEAD_SIZE)); ++#endif + +#ifdef GTP_FTRACE_RING_BUFFER + ring_buffer_unlock_commit(gtp_frame, rbe); @@ -7294,6 +7380,14 @@ + + atomic_inc(>p_frame_create); + ++#ifdef GTP_RB ++ /* Auto collect $step_id. */ ++ if (gts->tpe->step) { ++ if (gtp_collect_var(gts, gtp_var_array_step_id_id)) ++ return -1; ++ } ++#endif ++ + return 0; +} + @@ -7736,6 +7830,8 @@ + + return ret; +} ++ ++/* The number is not the ID of tvar, it is the ID of gtp_var_array. */ + +static int +gtp_collect_var(struct gtp_trace_s *gts, int num) @@ -8391,6 +8487,30 @@ +} +#endif + ++#ifdef CONFIG_X86 ++/* while-stepping stop. */ ++ ++static void ++gtp_step_stop(struct pt_regs *regs) ++{ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,24)) ++ regs->flags &= ~(X86_EFLAGS_TF); ++#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; ++} ++#endif ++ +static void +gtp_handler(struct gtp_trace_s *gts) +{ @@ -8400,6 +8520,10 @@ + printk(GTP_DEBUG_V "gtp_handler: tracepoint %d %p\n", + (int)gts->tpe->num, (void *)(CORE_ADDR)gts->tpe->addr); +#endif ++#ifdef CONFIG_X86 ++ if (gts->step == 0 && __get_cpu_var(gtp_step).step) ++ gtp_step_stop(gts->regs); ++#endif + + gts->read_memory = (void *)probe_kernel_read; + if (gts->tpe->flags & GTP_ENTRY_FLAGS_CURRENT_TASK) { @@ -8416,7 +8540,7 @@ + return; +#endif + -+ if ((gts->tpe->flags & GTP_ENTRY_FLAGS_NO_SELF_TRACE) ++ if ((gts->tpe->flags & GTP_ENTRY_FLAGS_SELF_TRACE) == 0 + && (get_current()->pid == gtp_gtp_pid + || get_current()->pid == gtp_gtpframe_pid)) { + return; @@ -8441,7 +8565,7 @@ + gts->run = NULL; + + /* Pass. */ -+ if (gts->tpe->flags & GTP_ENTRY_FLAGS_HAVE_PASS) { ++ if (gts->step == 0 && gts->tpe->flags & GTP_ENTRY_FLAGS_HAVE_PASS) { + if (atomic_dec_return(>s->tpe->current_pass) < 0) + goto tpe_stop; + } @@ -8601,18 +8725,47 @@ + struct kretprobe *kpret; + struct gtp_kp *gkp; + union gtp_entry_u *u; ++ struct gtp_entry *tpe; + struct gtp_trace_s gts; + -+ memset(>s, 0, sizeof(struct gtp_trace_s)); -+ + kpret = container_of(p, struct kretprobe, kp); + gkp = container_of(kpret, struct gtp_kp, kpret); + u = container_of(gkp, union gtp_entry_u, kp); -+ gts.tpe = container_of(u, struct gtp_entry, u); -+ gts.regs = regs; -+ gts.step = 1; ++ tpe = container_of(u, struct gtp_entry, u); ++ ++ if (tpe->step == 1) { ++ memset(>s, 0, sizeof(struct gtp_trace_s)); ++ ++ gts.tpe = tpe; ++ gts.regs = regs; ++ gts.step = tpe->step; ++ ++ gtp_handler(>s); ++ } + -+ gtp_handler(>s); ++#ifdef CONFIG_X86 ++ 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. */
++ __get_cpu_var(gtp_step).step = tpe->step; ++ __get_cpu_var(gtp_step).tpe = tpe; ++ #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,24)) ++ if (regs->flags & X86_EFLAGS_IF) ++ #else ++ if (regs->eflags & X86_EFLAGS_IF) ++ #endif ++ __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 +} + +static inline void @@ -8893,6 +9046,7 @@ + gtp_list = gtp_list->next; + gtp_action_release(tpe->cond); + gtp_action_release(tpe->action_list); ++ gtp_action_release(tpe->step_action_list); + gtp_src_release(tpe->src); + gtp_src_release(tpe->action_cmd); + gtp_src_release(tpe->printk_str); @@ -9133,6 +9287,238 @@ + + return 0; +} ++ ++#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) ++{ ++ uint32_t opcode; ++ uint8_t opcode8; ++ unsigned long pc = GTP_REGS_PC(regs); ++ ++ /* 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: ++ ++ 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) = pc; ++ break; ++ case 0xfa: ++ /* cli */ ++ __get_cpu_var(gtp_step).irq_need_open = 0; ++ GTP_REGS_PC(regs) = pc; ++ break; ++ case 0x0f07: ++ /* sysret */ ++ return 1; ++ break; ++ }; ++ ++ return 0; ++} ++ ++static int ++gtp_notifier_call(struct notifier_block *self, unsigned long cmd, ++ void *ptr) ++{ ++ int ret = NOTIFY_DONE; ++ unsigned long flags; ++ struct die_args *args; ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,0,0)) ++ int i; ++#endif ++ unsigned long dr6; ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)) ++ unsigned long *dr6_p; ++#endif ++ ++ if (cmd != DIE_DEBUG) ++ return ret; ++ ++ local_irq_save(flags); ++ args = ptr; ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)) ++ /* Get from X86 hw_breakpoint_handler. */ ++ dr6_p = (unsigned long *)ERR_PTR(args->err); ++ dr6 = *dr6_p; ++#else ++ dr6 = args->err; ++#endif ++ gtp_set_debugreg(GTP_HWB_DR7_DEF, 7); ++ ++ /* Handle while-stepping. */ ++ spin_lock(&__get_cpu_var(gtp_step).lock); ++ if ((dr6 & 0x4000) != 0) { ++ /* Clear the bit that handle by KGTP. */ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)) ++ (*dr6_p) &= ~(0x4000); ++#else ++ dr6 &= ~(0x4000); ++#endif ++ if (!__get_cpu_var(gtp_step).tpe || user_mode(args->regs)) ++ gtp_step_stop(args->regs); ++ else { ++ 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)); ++ ++ preempt_disable(); ++ { ++ struct gtp_trace_s gts; ++ ++ memset(>s, 0, sizeof(struct gtp_trace_s)); ++ gts.tpe = __get_cpu_var(gtp_step).tpe; ++ gts.regs = args->regs; ++ gts.step = __get_cpu_var(gtp_step).step; ++ gtp_handler(>s); ++ } ++ preempt_enable_no_resched(); ++ ++ 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)) ++ 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. */ ++ gtp_step_stop(args->regs); ++ } ++ } ++ } ++ spin_unlock(&__get_cpu_var(gtp_step).lock); ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,0,0)) ++ /* Handle watch traceppoint. */ ++ if ((dr6 & 0xf) == 0) ++ goto out; ++ read_lock(>p_hwb_lock); ++ ++ for (i = 0; i < HWB_NUM; i++) { ++ if ((dr6 & (0x1 << i)) == 0) ++ continue; ++ /* Clear the bit that handle by KGTP. */ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)) ++ (*dr6_p) &= ~(0x1 << i); ++#else ++ dr6 &= ~(0x1 << i); ++#endif ++ if (gtp_hwb[i].watch == NULL) ++ continue; ++ /* Check if gtp_hwb is updated in other CPU. */ ++ if (__get_cpu_var(gtp_hwb_sync_count_local) != gtp_hwb_sync_count) { ++ unsigned long addr; ++ ++ gtp_get_debugreg(addr, i); ++ if (addr != gtp_hwb[i].addr) ++ continue; ++ } ++ preempt_disable(); ++ { ++ struct gtp_trace_s gts; ++ ++ memset(>s, 0, sizeof(struct gtp_trace_s)); ++ gts.tpe = gtp_hwb[i].watch; ++ gts.regs = args->regs; ++ gts.hwb = >p_hwb[i]; ++ gtp_handler(>s); ++ } ++ preempt_enable_no_resched(); ++ } ++ ++ /* If the HWB need update in this CPU, just update it. */ ++ if (__get_cpu_var(gtp_hwb_sync_count_local) != gtp_hwb_sync_count) { ++ 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; ++ } ++ ++ gtp_set_debugreg(gtp_hwb_dr7, 7); ++ read_unlock(>p_hwb_lock); ++#endif ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,0,0)) ++out: ++#endif ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33)) ++ 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. */ ++ if (((*dr6_p) & GTP_HWB_DR6_MASK) == 0) ++ ret = NOTIFY_STOP; ++ current->thread.debugreg6 = *dr6_p; ++#else ++ if ((dr6 & GTP_HWB_DR6_MASK) == 0) ++ ret = NOTIFY_STOP; ++ current->thread.debugreg6 = dr6; ++#endif ++ ++ local_irq_restore(flags); ++ return ret; ++} ++ ++static struct notifier_block gtp_notifier = { ++ .notifier_call = gtp_notifier_call, ++ .priority = 0x7ffffffe /* we need to be notified after kprobe. */ ++}; ++#endif + +#ifdef CONFIG_X86 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,0)) @@ -9229,102 +9615,8 @@ + gtp_hw_breakpoint_handler(breakinfo[3].num, regs); +} +#endif -+#else -+static int -+gtp_notifier_call(struct notifier_block *self, unsigned long cmd, -+ void *ptr) -+{ -+ int ret = NOTIFY_DONE; -+ unsigned long flags; -+ struct die_args *args; -+ int i; -+ unsigned long dr6; -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)) -+ unsigned long *dr6_p; +#endif + -+ if (cmd != DIE_DEBUG) -+ return ret; -+ -+ local_irq_save(flags); -+ args = ptr; -+ -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)) -+ /* Get from X86 hw_breakpoint_handler. */ -+ dr6_p = (unsigned long *)ERR_PTR(args->err); -+ dr6 = *dr6_p; -+#else -+ dr6 = args->err; -+#endif -+ 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) -+ continue; -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)) -+ /* Because KGTP handle all the hw-breakpoints. -+ So Just clear it. */ -+ (*dr6_p) &= ~(0x1 << i); -+#endif -+ if (gtp_hwb[i].watch == NULL) -+ continue; -+ /* Check if gtp_hwb is updated in other CPU. */ -+ if (__get_cpu_var(gtp_hwb_sync_count_local) != gtp_hwb_sync_count) { -+ unsigned long addr; -+ -+ gtp_get_debugreg(addr, i); -+ if (addr != gtp_hwb[i].addr) -+ continue; -+ } -+ preempt_disable(); -+ { -+ struct gtp_trace_s gts; -+ -+ memset(>s, 0, sizeof(struct gtp_trace_s)); -+ gts.tpe = gtp_hwb[i].watch; -+ gts.regs = args->regs; -+ gts.hwb = >p_hwb[i]; -+ gtp_handler(>s); -+ } -+ preempt_enable_no_resched(); -+ } -+ -+ /* 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); -+ __get_cpu_var(gtp_hwb_sync_count_local) = gtp_hwb_sync_count; -+ } -+ -+ set_debugreg(gtp_hwb_dr7, 7); -+ read_unlock(>p_hwb_lock); -+ -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)) -+ /* If have some other traps, let other handler handle it. */ -+ if ((dr6 & (~0xf)) == 0) -+ ret = NOTIFY_STOP; -+#else -+ set_debugreg(0UL, 6); -+ ret = NOTIFY_STOP; -+#endif -+ -+out: -+ local_irq_restore(flags); -+ return ret; -+} -+ -+static struct notifier_block gtp_notifier = { -+ .notifier_call = gtp_notifier_call, -+ .priority = 0x7fffffff /* we need to be notified first */ -+}; -+#endif -+ +static unsigned int +gtp_hwb_size_to_arch(int size) +{ @@ -9403,7 +9695,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; @@ -9460,7 +9752,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. */ @@ -9523,54 +9815,74 @@ + tasklet_kill(&tpe->disable_tasklet); + tasklet_kill(&tpe->enable_tasklet); +#endif ++ } ++ ++#ifdef CONFIG_X86 ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,0,0)) ++ if (gtp_have_step || gtp_have_watch_tracepoint) ++#else ++ if (gtp_have_step) ++#endif ++ unregister_die_notifier(>p_notifier); ++ ++ { ++ /* Init data of while-stepping. */ ++ int cpu; ++ for_each_online_cpu(cpu) { ++ struct gtp_step_s *step = &per_cpu(gtp_step, cpu); ++ ++ spin_lock(&step->lock); ++ step->step = 0; ++ step->tpe = NULL; ++ spin_unlock(&step->lock); ++ } + } ++#endif + +#ifdef CONFIG_X86 + /* Stop hwb. */ ++ if (gtp_have_watch_tracepoint) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,0)) -+ { -+ int i; ++ { ++ int i; + -+ /* Register hw breakpoints. */ -+ for (i = 0; i < HWB_NUM; i++) { -+ unregister_wide_hw_breakpoint(breakinfo[i].pev); -+ breakinfo[i].pev = NULL; ++ /* Register hw breakpoints. */ ++ for (i = 0; i < HWB_NUM; i++) { ++ unregister_wide_hw_breakpoint(breakinfo[i].pev); ++ breakinfo[i].pev = NULL; ++ } + } -+ } +#endif + -+ gtp_hwb_stop(NULL); ++ gtp_hwb_stop(NULL); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)) -+ smp_call_function(gtp_hwb_stop, NULL, 1); ++ smp_call_function(gtp_hwb_stop, NULL, 1); +#else -+ smp_call_function(gtp_hwb_stop, NULL, 0, 1); ++ smp_call_function(gtp_hwb_stop, NULL, 0, 1); +#endif + -+ for (tpe = gtp_list; tpe; tpe = tpe->next) { -+ if (tpe->type == gtp_entry_kprobe -+ || (tpe->flags & GTP_ENTRY_FLAGS_REG) == 0 -+ || tpe->disable) -+ continue; ++ for (tpe = gtp_list; tpe; tpe = tpe->next) { ++ if (tpe->type == gtp_entry_kprobe ++ || (tpe->flags & GTP_ENTRY_FLAGS_REG) == 0 ++ || tpe->disable) ++ continue; + -+ if (tpe->type == gtp_entry_watch_static) -+ gtp_unregister_hwb(tpe->addr, 0); ++ if (tpe->type == gtp_entry_watch_static) ++ gtp_unregister_hwb(tpe->addr, 0); + -+ tpe->flags &= ~GTP_ENTRY_FLAGS_REG; ++ tpe->flags &= ~GTP_ENTRY_FLAGS_REG; + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30)) -+ tasklet_kill(&tpe->disable_tasklet); -+ tasklet_kill(&tpe->enable_tasklet); ++ tasklet_kill(&tpe->disable_tasklet); ++ tasklet_kill(&tpe->enable_tasklet); +#endif -+ } ++ } + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)) -+ unregister_kprobe(>p_ipi_kp); ++ unregister_kprobe(>p_ipi_kp); +#endif -+ -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,0,0)) -+ unregister_die_notifier(>p_notifier); ++ } +#endif -+#endif + +#ifdef GTP_PERF_EVENTS + list_for_each(cur, >p_var_list) { @@ -9642,6 +9954,10 @@ + gtp_frame_reset(); + + gtpro_list_clear(); ++#ifdef CONFIG_X86 ++ gtp_have_watch_tracepoint = 0; ++ gtp_have_step = 0; ++#endif + + gtp_var_release(0); + @@ -9756,12 +10072,13 @@ +} + +static int -+gtp_add_backtrace_actions(struct gtp_entry *tpe) ++gtp_add_backtrace_actions(struct gtp_entry *tpe, int step) +{ + struct action *ae, *new_ae; + int got_r = 0, got_m = 0; + -+ for (ae = tpe->action_list; ae; ae = ae->next) { ++ for (ae = step ? tpe->step_action_list : tpe->action_list; ++ ae; ae = ae->next) { + if (ae->type == 'R') + got_r = 1; + else if (ae->type == 'M' && ae->u.m.regnum == GTP_SP_NUM @@ -9769,7 +10086,9 @@ + got_m = 1; + + if (got_r && got_m) -+ break; ++ return 1; ++ ++ /* Let ae point to the last entry of action_list. */ + if (!ae->next) + break; + } @@ -9780,8 +10099,14 @@ + return -ENOMEM; + if (ae) + ae->next = new_ae; -+ else -+ tpe->action_list = ae; ++ else { ++ if (step) ++ tpe->step_action_list = ae; ++ else ++ tpe->action_list = ae; ++ } ++ ++ /* Because new_ae is the new tail. So set it to ae. */ + ae = new_ae; + } + @@ -9793,15 +10118,19 @@ + new_ae->u.m.size = gtp_bt_size; + if (ae) + ae->next = new_ae; -+ else -+ tpe->action_list = ae; ++ else { ++ if (step) ++ tpe->step_action_list = ae; ++ else ++ tpe->action_list = ae; ++ } + } + + return 1; +} + +static int -+gtp_check_getv(struct gtp_entry *tpe, struct action *ae, ++gtp_check_getv(struct gtp_entry *tpe, struct action *ae, int step, + uint8_t *ebuf, unsigned int pc, + struct gtp_x_var **list) +{ @@ -9823,12 +10152,12 @@ + + switch (var->type) { + case gtp_var_special: -+ if (arg == GTP_VAR_NO_SELF_TRACE_ID) { -+ tpe->flags |= GTP_ENTRY_FLAGS_NO_SELF_TRACE; ++ if (arg == GTP_VAR_SELF_TRACE_ID) { ++ tpe->flags |= GTP_ENTRY_FLAGS_SELF_TRACE; + ret = 1; + goto out; + } else if (arg == GTP_VAR_BT_ID) { -+ ret = gtp_add_backtrace_actions (tpe); ++ ret = gtp_add_backtrace_actions (tpe, step); + goto out; + } else if (arg == GTP_VAR_CURRENT_ID) { + tpe->flags |= GTP_ENTRY_FLAGS_CURRENT_TASK; @@ -9897,7 +10226,7 @@ +} + +static int -+gtp_check_setv(struct gtp_entry *tpe, struct action *ae, ++gtp_check_setv(struct gtp_entry *tpe, struct action *ae, int step, + uint8_t *ebuf, unsigned int pc, + struct gtp_x_var **list, int loop, + ULONGEST *stack, ULONGEST top) @@ -9921,8 +10250,8 @@ + switch (var->type) { + case gtp_var_special: + switch (arg) { -+ case GTP_VAR_NO_SELF_TRACE_ID: -+ tpe->flags |= GTP_ENTRY_FLAGS_NO_SELF_TRACE; ++ case GTP_VAR_SELF_TRACE_ID: ++ tpe->flags |= GTP_ENTRY_FLAGS_SELF_TRACE; + ret = 1; + goto out; + break; @@ -9933,7 +10262,7 @@ + goto out; + break; + case GTP_VAR_BT_ID: -+ ret = gtp_add_backtrace_actions (tpe); ++ ret = gtp_add_backtrace_actions (tpe, step); + goto out; + break; + case GTP_VAR_CURRENT_ID: @@ -9942,11 +10271,10 @@ + goto out; + break; + case GTP_VAR_PRINTK_LEVEL_ID: -+ if (loop) { ***The diff for this file has been truncated for email.*** ======================================= --- /trunk/gtp_2.6.33_to_2.6.38.patch Sun Feb 17 20:54:51 2013 +++ /trunk/gtp_2.6.33_to_2.6.38.patch Mon May 6 19:06:35 2013 @@ -3726,7 +3726,7 @@ --- /dev/null +++ b/lib/gtp.c -@@ -0,0 +1,12093 @@ +@@ -0,0 +1,12887 @@ +/* + * Kernel GDB tracepoint module. + * @@ -3744,12 +3744,12 @@ + * along with this program; if not, write to the Free Software+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *-+ * Copyright(C) KGTP team (https://code.google.com/p/kgtp/), 2010, 2011, 2012, 2013
++ * Copyright(C) KGTP team (https://code.google.com/p/kgtp/), 2010-2013 + * + */ + +/* If "* 10" means that this is not a release version. */ -+#define GTP_VERSION (20130218) ++#define GTP_VERSION (20130218 * 10) + +#include <linux/version.h> +#ifndef RHEL_RELEASE_VERSION @@ -3828,6 +3828,9 @@ +#include <linux/slab.h> +#include <linux/ctype.h> +#include <asm/atomic.h> ++#ifdef CONFIG_X86 ++#include <asm/debugreg.h> ++#endif +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)) +#include <linux/kdebug.h> +#else @@ -3938,7 +3941,9 @@ + + sizeof(struct gtp_frame_var)) +#endif +#ifdef GTP_RB -+#define GTP_FRAME_HEAD_SIZE (FID_SIZE + sizeof(u64) + sizeof(ULONGEST))++/* The frame head size: FID_HEAD + count id + frame number + pointer to prev frem */ ++#define GTP_FRAME_HEAD_SIZE (FID_SIZE + sizeof(u64) + sizeof(ULONGEST) + sizeof(void *))
++/* The frame head size: FID_PAGE_BEGIN + count id */ +#define GTP_FRAME_PAGE_BEGIN_SIZE (FID_SIZE + sizeof(u64)) +#endif +#ifdef GTP_FTRACE_RING_BUFFER @@ -4021,7 +4026,7 @@ +/* This gtp entry is registered inside the system. */ +#define GTP_ENTRY_FLAGS_REG 2 +/* See $no_self_trace. */ -+#define GTP_ENTRY_FLAGS_NO_SELF_TRACE 4 ++#define GTP_ENTRY_FLAGS_SELF_TRACE 4 +/* This gtp entry has passcount. */ +#define GTP_ENTRY_FLAGS_HAVE_PASS 8 +/* See $printk_level. */ @@ -4192,14 +4197,32 @@ + +static pid_t gtp_current_pid; + ++#ifdef CONFIG_X86 ++/* Following part is for while-stepping. */ ++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); ++#endif ++ +#ifdef CONFIG_X86 ++static int gtp_have_watch_tracepoint; ++static int gtp_have_step; ++#endif ++ ++#ifdef CONFIG_X86 ++/* Following part is for watch tracepoint. */ +/* This part is X86 special. */ +#define HWB_NUM 4 + +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 { @@ -4277,16 +4300,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; + } +} @@ -4297,11 +4320,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); +} + @@ -4309,11 +4332,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 @@ -4468,7 +4491,7 @@ + GTP_VAR_PRINTK_LEVEL_ID = 11, + GTP_VAR_PRINTK_FORMAT_ID = 12, + GTP_VAR_DUMP_STACK_ID = 13, -+ GTP_VAR_NO_SELF_TRACE_ID = 14, ++ GTP_VAR_SELF_TRACE_ID = 14, + GTP_VAR_CPU_NUMBER_ID = 15, + GTP_VAR_PC_PE_EN_ID = 16, + GTP_VAR_KRET_ID = 17, @@ -4501,8 +4524,11 @@ + GTP_WATCH_VAL_ID = 42, + GTP_WATCH_COUNT_ID = 43, + ++ GTP_STEP_COUNT_ID = 44, ++ GTP_STEP_ID_ID = 45, ++ + GTP_VAR_SPECIAL_MIN = GTP_VAR_VERSION_ID, -+ GTP_VAR_SPECIAL_MAX = GTP_WATCH_COUNT_ID, ++ GTP_VAR_SPECIAL_MAX = GTP_STEP_ID_ID, +}; + +enum pe_tv_id { @@ -5511,6 +5537,44 @@ +}; +#endif + ++#ifdef GTP_RB ++static int ++gtp_step_count_hooks_get_val(struct gtp_trace_s *gts, struct gtp_var *gtv, ++ int64_t *val) ++{ ++ if (gts->step) ++ *val = gts->tpe->step - gts->step + 1; ++ else ++ *val = 0; ++ ++ return 0; ++} ++ ++static struct gtp_var_hooks gtp_step_count_hooks = { ++ .agent_get_val = gtp_step_count_hooks_get_val, ++}; ++ ++static DEFINE_PER_CPU(int64_t, gtp_step_id); ++ ++static int ++gtp_step_id_hooks_get_val(struct gtp_trace_s *gts, struct gtp_var *gtv, ++ int64_t *val) ++{ ++ if (!gts->step) { ++ if (++ __get_cpu_var(gtp_step_id) == 0) ++ __get_cpu_var(gtp_step_id) = 1; ++ } ++ ++ *val = __get_cpu_var(gtp_step_id); ++ ++ return 0; ++} ++ ++static struct gtp_var_hooks gtp_step_id_hooks = { ++ .agent_get_val = gtp_step_id_hooks_get_val, ++}; ++#endif ++ +static int +gtp_var_special_add_all(void) +{ @@ -5603,8 +5667,8 @@ + if (IS_ERR(var)) + return PTR_ERR(var); + -+ var = gtp_var_special_add(GTP_VAR_NO_SELF_TRACE_ID, 0, 0, -+ "no_self_trace", NULL); ++ var = gtp_var_special_add(GTP_VAR_SELF_TRACE_ID, 0, 0, ++ "self_trace", NULL); + if (IS_ERR(var)) + return PTR_ERR(var); + @@ -5730,6 +5794,16 @@ + if (IS_ERR(var)) + return PTR_ERR(var); +#endif ++ var = gtp_var_special_add(GTP_STEP_COUNT_ID, 0, 0, ++ "step_count", >p_step_count_hooks); ++ if (IS_ERR(var)) ++ return PTR_ERR(var); ++#ifdef GTP_RB ++ var = gtp_var_special_add(GTP_STEP_ID_ID, 0, 0, ++ "step_id", >p_step_id_hooks); ++ if (IS_ERR(var)) ++ return PTR_ERR(var); ++#endif + + return 0; +} @@ -7302,6 +7376,11 @@ + } while (0) +#endif + ++static int gtp_collect_var(struct gtp_trace_s *gts, int num); ++#ifdef GTP_RB ++static int gtp_var_array_step_id_id = 0; ++#endif ++ +static int +gtp_action_head(struct gtp_trace_s *gts) +{ @@ -7350,6 +7429,13 @@ + + trace_nump = (ULONGEST *)tmp; + *trace_nump = gts->tpe->num; ++ tmp += sizeof(ULONGEST); ++ ++#ifdef GTP_RB ++ *(void **)tmp = gtp_rb_prev_frame_get(gts->next); ++ gtp_rb_prev_frame_set(gts->next, (void *)(tmp + sizeof(void *) ++ - GTP_FRAME_HEAD_SIZE)); ++#endif + +#ifdef GTP_FTRACE_RING_BUFFER + ring_buffer_unlock_commit(gtp_frame, rbe); @@ -7358,6 +7444,14 @@ + + atomic_inc(>p_frame_create); + ++#ifdef GTP_RB ++ /* Auto collect $step_id. */ ++ if (gts->tpe->step) { ++ if (gtp_collect_var(gts, gtp_var_array_step_id_id)) ++ return -1; ++ } ++#endif ++ + return 0; +} + @@ -7800,6 +7894,8 @@ + + return ret; +} ++ ++/* The number is not the ID of tvar, it is the ID of gtp_var_array. */ + +static int +gtp_collect_var(struct gtp_trace_s *gts, int num) @@ -8455,6 +8551,30 @@ +} +#endif + ++#ifdef CONFIG_X86 ++/* while-stepping stop. */ ++ ++static void ++gtp_step_stop(struct pt_regs *regs) ++{ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,24)) ++ regs->flags &= ~(X86_EFLAGS_TF); ++#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; ++} ++#endif ++ +static void +gtp_handler(struct gtp_trace_s *gts) +{ @@ -8464,6 +8584,10 @@ + printk(GTP_DEBUG_V "gtp_handler: tracepoint %d %p\n", + (int)gts->tpe->num, (void *)(CORE_ADDR)gts->tpe->addr); +#endif ++#ifdef CONFIG_X86 ++ if (gts->step == 0 && __get_cpu_var(gtp_step).step) ++ gtp_step_stop(gts->regs); ++#endif + + gts->read_memory = (void *)probe_kernel_read; + if (gts->tpe->flags & GTP_ENTRY_FLAGS_CURRENT_TASK) { @@ -8480,7 +8604,7 @@ + return; +#endif + -+ if ((gts->tpe->flags & GTP_ENTRY_FLAGS_NO_SELF_TRACE) ++ if ((gts->tpe->flags & GTP_ENTRY_FLAGS_SELF_TRACE) == 0 + && (get_current()->pid == gtp_gtp_pid + || get_current()->pid == gtp_gtpframe_pid)) { + return; @@ -8505,7 +8629,7 @@ + gts->run = NULL; + + /* Pass. */ -+ if (gts->tpe->flags & GTP_ENTRY_FLAGS_HAVE_PASS) { ++ if (gts->step == 0 && gts->tpe->flags & GTP_ENTRY_FLAGS_HAVE_PASS) { + if (atomic_dec_return(>s->tpe->current_pass) < 0) + goto tpe_stop; + } @@ -8665,18 +8789,47 @@ + struct kretprobe *kpret; + struct gtp_kp *gkp; + union gtp_entry_u *u; ++ struct gtp_entry *tpe; + struct gtp_trace_s gts; + -+ memset(>s, 0, sizeof(struct gtp_trace_s)); -+ + kpret = container_of(p, struct kretprobe, kp); + gkp = container_of(kpret, struct gtp_kp, kpret); + u = container_of(gkp, union gtp_entry_u, kp); -+ gts.tpe = container_of(u, struct gtp_entry, u); -+ gts.regs = regs; -+ gts.step = 1; ++ tpe = container_of(u, struct gtp_entry, u); ++ ++ if (tpe->step == 1) { ++ memset(>s, 0, sizeof(struct gtp_trace_s)); ++ ++ gts.tpe = tpe; ++ gts.regs = regs; ++ gts.step = tpe->step; ++ ++ gtp_handler(>s); ++ } + -+ gtp_handler(>s); ++#ifdef CONFIG_X86 ++ 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. */
++ __get_cpu_var(gtp_step).step = tpe->step; ++ __get_cpu_var(gtp_step).tpe = tpe; ++ #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,24)) ++ if (regs->flags & X86_EFLAGS_IF) ++ #else ++ if (regs->eflags & X86_EFLAGS_IF) ++ #endif ++ __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 +} + +static inline void @@ -8957,6 +9110,7 @@ + gtp_list = gtp_list->next; + gtp_action_release(tpe->cond); + gtp_action_release(tpe->action_list); ++ gtp_action_release(tpe->step_action_list); + gtp_src_release(tpe->src); + gtp_src_release(tpe->action_cmd); + gtp_src_release(tpe->printk_str); @@ -9197,6 +9351,238 @@ + + return 0; +} ++ ++#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) ++{ ++ uint32_t opcode; ++ uint8_t opcode8; ++ unsigned long pc = GTP_REGS_PC(regs); ++ ++ /* 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: ++ ++ 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) = pc; ++ break; ++ case 0xfa: ++ /* cli */ ++ __get_cpu_var(gtp_step).irq_need_open = 0; ++ GTP_REGS_PC(regs) = pc; ++ break; ++ case 0x0f07: ++ /* sysret */ ++ return 1; ++ break; ++ }; ++ ++ return 0; ++} ++ ++static int ++gtp_notifier_call(struct notifier_block *self, unsigned long cmd, ++ void *ptr) ++{ ++ int ret = NOTIFY_DONE; ++ unsigned long flags; ++ struct die_args *args; ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,0,0)) ++ int i; ++#endif ++ unsigned long dr6; ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)) ++ unsigned long *dr6_p; ++#endif ++ ++ if (cmd != DIE_DEBUG) ++ return ret; ++ ++ local_irq_save(flags); ++ args = ptr; ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)) ++ /* Get from X86 hw_breakpoint_handler. */ ++ dr6_p = (unsigned long *)ERR_PTR(args->err); ++ dr6 = *dr6_p; ++#else ++ dr6 = args->err; ++#endif ++ gtp_set_debugreg(GTP_HWB_DR7_DEF, 7); ++ ++ /* Handle while-stepping. */ ++ spin_lock(&__get_cpu_var(gtp_step).lock); ++ if ((dr6 & 0x4000) != 0) { ++ /* Clear the bit that handle by KGTP. */ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)) ++ (*dr6_p) &= ~(0x4000); ++#else ++ dr6 &= ~(0x4000); ++#endif ++ if (!__get_cpu_var(gtp_step).tpe || user_mode(args->regs)) ++ gtp_step_stop(args->regs); ++ else { ++ 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)); ++ ++ preempt_disable(); ++ { ++ struct gtp_trace_s gts; ++ ++ memset(>s, 0, sizeof(struct gtp_trace_s)); ++ gts.tpe = __get_cpu_var(gtp_step).tpe; ++ gts.regs = args->regs; ++ gts.step = __get_cpu_var(gtp_step).step; ++ gtp_handler(>s); ++ } ++ preempt_enable_no_resched(); ++ ++ 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)) ++ 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. */ ++ gtp_step_stop(args->regs); ++ } ++ } ++ } ++ spin_unlock(&__get_cpu_var(gtp_step).lock); ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,0,0)) ++ /* Handle watch traceppoint. */ ++ if ((dr6 & 0xf) == 0) ++ goto out; ++ read_lock(>p_hwb_lock); ++ ++ for (i = 0; i < HWB_NUM; i++) { ++ if ((dr6 & (0x1 << i)) == 0) ++ continue; ++ /* Clear the bit that handle by KGTP. */ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)) ++ (*dr6_p) &= ~(0x1 << i); ++#else ++ dr6 &= ~(0x1 << i); ++#endif ++ if (gtp_hwb[i].watch == NULL) ++ continue; ++ /* Check if gtp_hwb is updated in other CPU. */ ++ if (__get_cpu_var(gtp_hwb_sync_count_local) != gtp_hwb_sync_count) { ++ unsigned long addr; ++ ++ gtp_get_debugreg(addr, i); ++ if (addr != gtp_hwb[i].addr) ++ continue; ++ } ++ preempt_disable(); ++ { ++ struct gtp_trace_s gts; ++ ++ memset(>s, 0, sizeof(struct gtp_trace_s)); ++ gts.tpe = gtp_hwb[i].watch; ++ gts.regs = args->regs; ++ gts.hwb = >p_hwb[i]; ++ gtp_handler(>s); ++ } ++ preempt_enable_no_resched(); ++ } ++ ++ /* If the HWB need update in this CPU, just update it. */ ++ if (__get_cpu_var(gtp_hwb_sync_count_local) != gtp_hwb_sync_count) { ++ 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; ++ } ++ ++ gtp_set_debugreg(gtp_hwb_dr7, 7); ++ read_unlock(>p_hwb_lock); ++#endif ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,0,0)) ++out: ++#endif ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33)) ++ 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. */ ++ if (((*dr6_p) & GTP_HWB_DR6_MASK) == 0) ++ ret = NOTIFY_STOP; ++ current->thread.debugreg6 = *dr6_p; ++#else ++ if ((dr6 & GTP_HWB_DR6_MASK) == 0) ++ ret = NOTIFY_STOP; ++ current->thread.debugreg6 = dr6; ++#endif ++ ++ local_irq_restore(flags); ++ return ret; ++} ++ ++static struct notifier_block gtp_notifier = { ++ .notifier_call = gtp_notifier_call, ++ .priority = 0x7ffffffe /* we need to be notified after kprobe. */ ++}; ++#endif + +#ifdef CONFIG_X86 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,0)) @@ -9293,102 +9679,8 @@ + gtp_hw_breakpoint_handler(breakinfo[3].num, regs); +} +#endif -+#else -+static int -+gtp_notifier_call(struct notifier_block *self, unsigned long cmd, -+ void *ptr) -+{ -+ int ret = NOTIFY_DONE; -+ unsigned long flags; -+ struct die_args *args; -+ int i; -+ unsigned long dr6; -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)) -+ unsigned long *dr6_p; +#endif + -+ if (cmd != DIE_DEBUG) -+ return ret; -+ -+ local_irq_save(flags); -+ args = ptr; -+ -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)) -+ /* Get from X86 hw_breakpoint_handler. */ -+ dr6_p = (unsigned long *)ERR_PTR(args->err); -+ dr6 = *dr6_p; -+#else -+ dr6 = args->err; -+#endif -+ 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) -+ continue; -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)) -+ /* Because KGTP handle all the hw-breakpoints. -+ So Just clear it. */ -+ (*dr6_p) &= ~(0x1 << i); -+#endif -+ if (gtp_hwb[i].watch == NULL) -+ continue; -+ /* Check if gtp_hwb is updated in other CPU. */ -+ if (__get_cpu_var(gtp_hwb_sync_count_local) != gtp_hwb_sync_count) { -+ unsigned long addr; -+ -+ gtp_get_debugreg(addr, i); -+ if (addr != gtp_hwb[i].addr) -+ continue; -+ } -+ preempt_disable(); -+ { -+ struct gtp_trace_s gts; -+ -+ memset(>s, 0, sizeof(struct gtp_trace_s)); -+ gts.tpe = gtp_hwb[i].watch; -+ gts.regs = args->regs; -+ gts.hwb = >p_hwb[i]; -+ gtp_handler(>s); -+ } -+ preempt_enable_no_resched(); -+ } -+ -+ /* 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); -+ __get_cpu_var(gtp_hwb_sync_count_local) = gtp_hwb_sync_count; -+ } -+ -+ set_debugreg(gtp_hwb_dr7, 7); -+ read_unlock(>p_hwb_lock); -+ -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)) -+ /* If have some other traps, let other handler handle it. */ -+ if ((dr6 & (~0xf)) == 0) -+ ret = NOTIFY_STOP; -+#else -+ set_debugreg(0UL, 6); -+ ret = NOTIFY_STOP; -+#endif -+ -+out: -+ local_irq_restore(flags); -+ return ret; -+} -+ -+static struct notifier_block gtp_notifier = { -+ .notifier_call = gtp_notifier_call, -+ .priority = 0x7fffffff /* we need to be notified first */ -+}; -+#endif -+ +static unsigned int +gtp_hwb_size_to_arch(int size) +{ @@ -9467,7 +9759,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; @@ -9524,7 +9816,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. */ @@ -9587,54 +9879,74 @@ + tasklet_kill(&tpe->disable_tasklet); + tasklet_kill(&tpe->enable_tasklet); +#endif ++ } ++ ++#ifdef CONFIG_X86 ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,0,0)) ++ if (gtp_have_step || gtp_have_watch_tracepoint) ++#else ++ if (gtp_have_step) ++#endif ++ unregister_die_notifier(>p_notifier); ++ ++ { ++ /* Init data of while-stepping. */ ++ int cpu; ++ for_each_online_cpu(cpu) { ++ struct gtp_step_s *step = &per_cpu(gtp_step, cpu); ++ ++ spin_lock(&step->lock); ++ step->step = 0; ++ step->tpe = NULL; ++ spin_unlock(&step->lock); ++ } + } ++#endif + +#ifdef CONFIG_X86 + /* Stop hwb. */ ++ if (gtp_have_watch_tracepoint) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,0)) -+ { -+ int i; ++ { ++ int i; + -+ /* Register hw breakpoints. */ -+ for (i = 0; i < HWB_NUM; i++) { -+ unregister_wide_hw_breakpoint(breakinfo[i].pev); -+ breakinfo[i].pev = NULL; ++ /* Register hw breakpoints. */ ++ for (i = 0; i < HWB_NUM; i++) { ++ unregister_wide_hw_breakpoint(breakinfo[i].pev); ++ breakinfo[i].pev = NULL; ++ } + } -+ } +#endif + -+ gtp_hwb_stop(NULL); ++ gtp_hwb_stop(NULL); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)) -+ smp_call_function(gtp_hwb_stop, NULL, 1); ++ smp_call_function(gtp_hwb_stop, NULL, 1); +#else -+ smp_call_function(gtp_hwb_stop, NULL, 0, 1); ++ smp_call_function(gtp_hwb_stop, NULL, 0, 1); +#endif + -+ for (tpe = gtp_list; tpe; tpe = tpe->next) { -+ if (tpe->type == gtp_entry_kprobe -+ || (tpe->flags & GTP_ENTRY_FLAGS_REG) == 0 -+ || tpe->disable) -+ continue; ++ for (tpe = gtp_list; tpe; tpe = tpe->next) { ++ if (tpe->type == gtp_entry_kprobe ++ || (tpe->flags & GTP_ENTRY_FLAGS_REG) == 0 ++ || tpe->disable) ++ continue; + -+ if (tpe->type == gtp_entry_watch_static) -+ gtp_unregister_hwb(tpe->addr, 0); ++ if (tpe->type == gtp_entry_watch_static) ++ gtp_unregister_hwb(tpe->addr, 0); + -+ tpe->flags &= ~GTP_ENTRY_FLAGS_REG; ++ tpe->flags &= ~GTP_ENTRY_FLAGS_REG; + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30)) -+ tasklet_kill(&tpe->disable_tasklet); -+ tasklet_kill(&tpe->enable_tasklet); ++ tasklet_kill(&tpe->disable_tasklet); ++ tasklet_kill(&tpe->enable_tasklet); +#endif -+ } ++ } + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)) -+ unregister_kprobe(>p_ipi_kp); ++ unregister_kprobe(>p_ipi_kp); +#endif -+ -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,0,0)) -+ unregister_die_notifier(>p_notifier); ++ } +#endif -+#endif + +#ifdef GTP_PERF_EVENTS + list_for_each(cur, >p_var_list) { @@ -9706,6 +10018,10 @@ + gtp_frame_reset(); + + gtpro_list_clear(); ++#ifdef CONFIG_X86 ++ gtp_have_watch_tracepoint = 0; ++ gtp_have_step = 0; ++#endif + + gtp_var_release(0); + @@ -9820,12 +10136,13 @@ +} + +static int -+gtp_add_backtrace_actions(struct gtp_entry *tpe) ++gtp_add_backtrace_actions(struct gtp_entry *tpe, int step) +{ + struct action *ae, *new_ae; + int got_r = 0, got_m = 0; + -+ for (ae = tpe->action_list; ae; ae = ae->next) { ++ for (ae = step ? tpe->step_action_list : tpe->action_list; ++ ae; ae = ae->next) { + if (ae->type == 'R') + got_r = 1; + else if (ae->type == 'M' && ae->u.m.regnum == GTP_SP_NUM @@ -9833,7 +10150,9 @@ + got_m = 1; + + if (got_r && got_m) -+ break; ++ return 1; ++ ++ /* Let ae point to the last entry of action_list. */ + if (!ae->next) + break; + } @@ -9844,8 +10163,14 @@ + return -ENOMEM; + if (ae) + ae->next = new_ae; -+ else -+ tpe->action_list = ae; ++ else { ++ if (step) ++ tpe->step_action_list = ae; ++ else ++ tpe->action_list = ae; ++ } ++ ++ /* Because new_ae is the new tail. So set it to ae. */ + ae = new_ae; + } + @@ -9857,15 +10182,19 @@ + new_ae->u.m.size = gtp_bt_size; + if (ae) + ae->next = new_ae; -+ else -+ tpe->action_list = ae; ++ else { ++ if (step) ++ tpe->step_action_list = ae; ++ else ++ tpe->action_list = ae; ++ } + } + + return 1; +} + +static int -+gtp_check_getv(struct gtp_entry *tpe, struct action *ae, ++gtp_check_getv(struct gtp_entry *tpe, struct action *ae, int step, + uint8_t *ebuf, unsigned int pc, + struct gtp_x_var **list) +{ @@ -9887,12 +10216,12 @@ + + switch (var->type) { + case gtp_var_special: -+ if (arg == GTP_VAR_NO_SELF_TRACE_ID) { -+ tpe->flags |= GTP_ENTRY_FLAGS_NO_SELF_TRACE; ++ if (arg == GTP_VAR_SELF_TRACE_ID) { ++ tpe->flags |= GTP_ENTRY_FLAGS_SELF_TRACE; + ret = 1; + goto out; + } else if (arg == GTP_VAR_BT_ID) { -+ ret = gtp_add_backtrace_actions (tpe); ++ ret = gtp_add_backtrace_actions (tpe, step); + goto out; + } else if (arg == GTP_VAR_CURRENT_ID) { + tpe->flags |= GTP_ENTRY_FLAGS_CURRENT_TASK; @@ -9961,7 +10290,7 @@ +} + +static int -+gtp_check_setv(struct gtp_entry *tpe, struct action *ae, ++gtp_check_setv(struct gtp_entry *tpe, struct action *ae, int step, + uint8_t *ebuf, unsigned int pc, + struct gtp_x_var **list, int loop, + ULONGEST *stack, ULONGEST top) @@ -9985,8 +10314,8 @@ + switch (var->type) { + case gtp_var_special: + switch (arg) { -+ case GTP_VAR_NO_SELF_TRACE_ID: -+ tpe->flags |= GTP_ENTRY_FLAGS_NO_SELF_TRACE; ++ case GTP_VAR_SELF_TRACE_ID: ++ tpe->flags |= GTP_ENTRY_FLAGS_SELF_TRACE; + ret = 1; + goto out; + break; @@ -9997,7 +10326,7 @@ + goto out; + break; + case GTP_VAR_BT_ID: -+ ret = gtp_add_backtrace_actions (tpe); ++ ret = gtp_add_backtrace_actions (tpe, step); + goto out; + break; + case GTP_VAR_CURRENT_ID: @@ -10006,11 +10335,10 @@ + goto out; + break; + case GTP_VAR_PRINTK_LEVEL_ID: -+ if (loop) { ***The diff for this file has been truncated for email.*** ======================================= --- /trunk/gtp_2.6.39.patch Sun Feb 17 20:54:51 2013 +++ /trunk/gtp_2.6.39.patch Mon May 6 19:06:35 2013 @@ -3716,7 +3716,7 @@ --- /dev/null +++ b/lib/gtp.c -@@ -0,0 +1,12093 @@ +@@ -0,0 +1,12887 @@ +/* + * Kernel GDB tracepoint module. + * @@ -3734,12 +3734,12 @@ + * along with this program; if not, write to the Free Software+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *-+ * Copyright(C) KGTP team (https://code.google.com/p/kgtp/), 2010, 2011, 2012, 2013
++ * Copyright(C) KGTP team (https://code.google.com/p/kgtp/), 2010-2013 + * + */ + +/* If "* 10" means that this is not a release version. */ -+#define GTP_VERSION (20130218) ++#define GTP_VERSION (20130218 * 10) + +#include <linux/version.h> +#ifndef RHEL_RELEASE_VERSION @@ -3818,6 +3818,9 @@ +#include <linux/slab.h> +#include <linux/ctype.h> +#include <asm/atomic.h> ++#ifdef CONFIG_X86 ++#include <asm/debugreg.h> ++#endif +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)) +#include <linux/kdebug.h> +#else @@ -3928,7 +3931,9 @@ + + sizeof(struct gtp_frame_var)) +#endif +#ifdef GTP_RB -+#define GTP_FRAME_HEAD_SIZE (FID_SIZE + sizeof(u64) + sizeof(ULONGEST))++/* The frame head size: FID_HEAD + count id + frame number + pointer to prev frem */ ++#define GTP_FRAME_HEAD_SIZE (FID_SIZE + sizeof(u64) + sizeof(ULONGEST) + sizeof(void *))
++/* The frame head size: FID_PAGE_BEGIN + count id */ +#define GTP_FRAME_PAGE_BEGIN_SIZE (FID_SIZE + sizeof(u64)) +#endif +#ifdef GTP_FTRACE_RING_BUFFER @@ -4011,7 +4016,7 @@ +/* This gtp entry is registered inside the system. */ +#define GTP_ENTRY_FLAGS_REG 2 +/* See $no_self_trace. */ -+#define GTP_ENTRY_FLAGS_NO_SELF_TRACE 4 ++#define GTP_ENTRY_FLAGS_SELF_TRACE 4 +/* This gtp entry has passcount. */ +#define GTP_ENTRY_FLAGS_HAVE_PASS 8 +/* See $printk_level. */ @@ -4182,14 +4187,32 @@ + +static pid_t gtp_current_pid; + ++#ifdef CONFIG_X86 ++/* Following part is for while-stepping. */ ++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); ++#endif ++ +#ifdef CONFIG_X86 ++static int gtp_have_watch_tracepoint; ++static int gtp_have_step; ++#endif ++ ++#ifdef CONFIG_X86 ++/* Following part is for watch tracepoint. */ +/* This part is X86 special. */ +#define HWB_NUM 4 + +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 { @@ -4267,16 +4290,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; + } +} @@ -4287,11 +4310,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); +} + @@ -4299,11 +4322,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 @@ -4458,7 +4481,7 @@ + GTP_VAR_PRINTK_LEVEL_ID = 11, + GTP_VAR_PRINTK_FORMAT_ID = 12, + GTP_VAR_DUMP_STACK_ID = 13, -+ GTP_VAR_NO_SELF_TRACE_ID = 14, ++ GTP_VAR_SELF_TRACE_ID = 14, + GTP_VAR_CPU_NUMBER_ID = 15, + GTP_VAR_PC_PE_EN_ID = 16, + GTP_VAR_KRET_ID = 17, @@ -4491,8 +4514,11 @@ + GTP_WATCH_VAL_ID = 42, + GTP_WATCH_COUNT_ID = 43, + ++ GTP_STEP_COUNT_ID = 44, ++ GTP_STEP_ID_ID = 45, ++ + GTP_VAR_SPECIAL_MIN = GTP_VAR_VERSION_ID, -+ GTP_VAR_SPECIAL_MAX = GTP_WATCH_COUNT_ID, ++ GTP_VAR_SPECIAL_MAX = GTP_STEP_ID_ID, +}; + +enum pe_tv_id { @@ -5501,6 +5527,44 @@ +}; +#endif + ++#ifdef GTP_RB ++static int ++gtp_step_count_hooks_get_val(struct gtp_trace_s *gts, struct gtp_var *gtv, ++ int64_t *val) ++{ ++ if (gts->step) ++ *val = gts->tpe->step - gts->step + 1; ++ else ++ *val = 0; ++ ++ return 0; ++} ++ ++static struct gtp_var_hooks gtp_step_count_hooks = { ++ .agent_get_val = gtp_step_count_hooks_get_val, ++}; ++ ++static DEFINE_PER_CPU(int64_t, gtp_step_id); ++ ++static int ++gtp_step_id_hooks_get_val(struct gtp_trace_s *gts, struct gtp_var *gtv, ++ int64_t *val) ++{ ++ if (!gts->step) { ++ if (++ __get_cpu_var(gtp_step_id) == 0) ++ __get_cpu_var(gtp_step_id) = 1; ++ } ++ ++ *val = __get_cpu_var(gtp_step_id); ++ ++ return 0; ++} ++ ++static struct gtp_var_hooks gtp_step_id_hooks = { ++ .agent_get_val = gtp_step_id_hooks_get_val, ++}; ++#endif ++ +static int +gtp_var_special_add_all(void) +{ @@ -5593,8 +5657,8 @@ + if (IS_ERR(var)) + return PTR_ERR(var); + -+ var = gtp_var_special_add(GTP_VAR_NO_SELF_TRACE_ID, 0, 0, -+ "no_self_trace", NULL); ++ var = gtp_var_special_add(GTP_VAR_SELF_TRACE_ID, 0, 0, ++ "self_trace", NULL); + if (IS_ERR(var)) + return PTR_ERR(var); + @@ -5720,6 +5784,16 @@ + if (IS_ERR(var)) + return PTR_ERR(var); +#endif ++ var = gtp_var_special_add(GTP_STEP_COUNT_ID, 0, 0, ++ "step_count", >p_step_count_hooks); ++ if (IS_ERR(var)) ++ return PTR_ERR(var); ++#ifdef GTP_RB ++ var = gtp_var_special_add(GTP_STEP_ID_ID, 0, 0, ++ "step_id", >p_step_id_hooks); ++ if (IS_ERR(var)) ++ return PTR_ERR(var); ++#endif + + return 0; +} @@ -7292,6 +7366,11 @@ + } while (0) +#endif + ++static int gtp_collect_var(struct gtp_trace_s *gts, int num); ++#ifdef GTP_RB ++static int gtp_var_array_step_id_id = 0; ++#endif ++ +static int +gtp_action_head(struct gtp_trace_s *gts) +{ @@ -7340,6 +7419,13 @@ + + trace_nump = (ULONGEST *)tmp; + *trace_nump = gts->tpe->num; ++ tmp += sizeof(ULONGEST); ++ ++#ifdef GTP_RB ++ *(void **)tmp = gtp_rb_prev_frame_get(gts->next); ++ gtp_rb_prev_frame_set(gts->next, (void *)(tmp + sizeof(void *) ++ - GTP_FRAME_HEAD_SIZE)); ++#endif + +#ifdef GTP_FTRACE_RING_BUFFER + ring_buffer_unlock_commit(gtp_frame, rbe); @@ -7348,6 +7434,14 @@ + + atomic_inc(>p_frame_create); + ++#ifdef GTP_RB ++ /* Auto collect $step_id. */ ++ if (gts->tpe->step) { ++ if (gtp_collect_var(gts, gtp_var_array_step_id_id)) ++ return -1; ++ } ++#endif ++ + return 0; +} + @@ -7790,6 +7884,8 @@ + + return ret; +} ++ ++/* The number is not the ID of tvar, it is the ID of gtp_var_array. */ + +static int +gtp_collect_var(struct gtp_trace_s *gts, int num) @@ -8445,6 +8541,30 @@ +} +#endif + ++#ifdef CONFIG_X86 ++/* while-stepping stop. */ ++ ++static void ++gtp_step_stop(struct pt_regs *regs) ++{ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,24)) ++ regs->flags &= ~(X86_EFLAGS_TF); ++#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; ++} ++#endif ++ +static void +gtp_handler(struct gtp_trace_s *gts) +{ @@ -8454,6 +8574,10 @@ + printk(GTP_DEBUG_V "gtp_handler: tracepoint %d %p\n", + (int)gts->tpe->num, (void *)(CORE_ADDR)gts->tpe->addr); +#endif ++#ifdef CONFIG_X86 ++ if (gts->step == 0 && __get_cpu_var(gtp_step).step) ++ gtp_step_stop(gts->regs); ++#endif + + gts->read_memory = (void *)probe_kernel_read; + if (gts->tpe->flags & GTP_ENTRY_FLAGS_CURRENT_TASK) { @@ -8470,7 +8594,7 @@ + return; +#endif + -+ if ((gts->tpe->flags & GTP_ENTRY_FLAGS_NO_SELF_TRACE) ++ if ((gts->tpe->flags & GTP_ENTRY_FLAGS_SELF_TRACE) == 0 + && (get_current()->pid == gtp_gtp_pid + || get_current()->pid == gtp_gtpframe_pid)) { + return; @@ -8495,7 +8619,7 @@ + gts->run = NULL; + + /* Pass. */ -+ if (gts->tpe->flags & GTP_ENTRY_FLAGS_HAVE_PASS) { ++ if (gts->step == 0 && gts->tpe->flags & GTP_ENTRY_FLAGS_HAVE_PASS) { + if (atomic_dec_return(>s->tpe->current_pass) < 0) + goto tpe_stop; + } @@ -8655,18 +8779,47 @@ + struct kretprobe *kpret; + struct gtp_kp *gkp; + union gtp_entry_u *u; ++ struct gtp_entry *tpe; + struct gtp_trace_s gts; + -+ memset(>s, 0, sizeof(struct gtp_trace_s)); -+ + kpret = container_of(p, struct kretprobe, kp); + gkp = container_of(kpret, struct gtp_kp, kpret); + u = container_of(gkp, union gtp_entry_u, kp); -+ gts.tpe = container_of(u, struct gtp_entry, u); -+ gts.regs = regs; -+ gts.step = 1; ++ tpe = container_of(u, struct gtp_entry, u); ++ ++ if (tpe->step == 1) { ++ memset(>s, 0, sizeof(struct gtp_trace_s)); ++ ++ gts.tpe = tpe; ++ gts.regs = regs; ++ gts.step = tpe->step; ++ ++ gtp_handler(>s); ++ } + -+ gtp_handler(>s); ++#ifdef CONFIG_X86 ++ 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. */
++ __get_cpu_var(gtp_step).step = tpe->step; ++ __get_cpu_var(gtp_step).tpe = tpe; ++ #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,24)) ++ if (regs->flags & X86_EFLAGS_IF) ++ #else ++ if (regs->eflags & X86_EFLAGS_IF) ++ #endif ++ __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 +} + +static inline void @@ -8947,6 +9100,7 @@ + gtp_list = gtp_list->next; + gtp_action_release(tpe->cond); + gtp_action_release(tpe->action_list); ++ gtp_action_release(tpe->step_action_list); + gtp_src_release(tpe->src); + gtp_src_release(tpe->action_cmd); + gtp_src_release(tpe->printk_str); @@ -9187,6 +9341,238 @@ + + return 0; +} ++ ++#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) ++{ ++ uint32_t opcode; ++ uint8_t opcode8; ++ unsigned long pc = GTP_REGS_PC(regs); ++ ++ /* 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: ++ ++ 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) = pc; ++ break; ++ case 0xfa: ++ /* cli */ ++ __get_cpu_var(gtp_step).irq_need_open = 0; ++ GTP_REGS_PC(regs) = pc; ++ break; ++ case 0x0f07: ++ /* sysret */ ++ return 1; ++ break; ++ }; ++ ++ return 0; ++} ++ ++static int ++gtp_notifier_call(struct notifier_block *self, unsigned long cmd, ++ void *ptr) ++{ ++ int ret = NOTIFY_DONE; ++ unsigned long flags; ++ struct die_args *args; ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,0,0)) ++ int i; ++#endif ++ unsigned long dr6; ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)) ++ unsigned long *dr6_p; ++#endif ++ ++ if (cmd != DIE_DEBUG) ++ return ret; ++ ++ local_irq_save(flags); ++ args = ptr; ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)) ++ /* Get from X86 hw_breakpoint_handler. */ ++ dr6_p = (unsigned long *)ERR_PTR(args->err); ++ dr6 = *dr6_p; ++#else ++ dr6 = args->err; ++#endif ++ gtp_set_debugreg(GTP_HWB_DR7_DEF, 7); ++ ++ /* Handle while-stepping. */ ++ spin_lock(&__get_cpu_var(gtp_step).lock); ++ if ((dr6 & 0x4000) != 0) { ++ /* Clear the bit that handle by KGTP. */ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)) ++ (*dr6_p) &= ~(0x4000); ++#else ++ dr6 &= ~(0x4000); ++#endif ++ if (!__get_cpu_var(gtp_step).tpe || user_mode(args->regs)) ++ gtp_step_stop(args->regs); ++ else { ++ 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)); ++ ++ preempt_disable(); ++ { ++ struct gtp_trace_s gts; ++ ++ memset(>s, 0, sizeof(struct gtp_trace_s)); ++ gts.tpe = __get_cpu_var(gtp_step).tpe; ++ gts.regs = args->regs; ++ gts.step = __get_cpu_var(gtp_step).step; ++ gtp_handler(>s); ++ } ++ preempt_enable_no_resched(); ++ ++ 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)) ++ 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. */ ++ gtp_step_stop(args->regs); ++ } ++ } ++ } ++ spin_unlock(&__get_cpu_var(gtp_step).lock); ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,0,0)) ++ /* Handle watch traceppoint. */ ++ if ((dr6 & 0xf) == 0) ++ goto out; ++ read_lock(>p_hwb_lock); ++ ++ for (i = 0; i < HWB_NUM; i++) { ++ if ((dr6 & (0x1 << i)) == 0) ++ continue; ++ /* Clear the bit that handle by KGTP. */ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)) ++ (*dr6_p) &= ~(0x1 << i); ++#else ++ dr6 &= ~(0x1 << i); ++#endif ++ if (gtp_hwb[i].watch == NULL) ++ continue; ++ /* Check if gtp_hwb is updated in other CPU. */ ++ if (__get_cpu_var(gtp_hwb_sync_count_local) != gtp_hwb_sync_count) { ++ unsigned long addr; ++ ++ gtp_get_debugreg(addr, i); ++ if (addr != gtp_hwb[i].addr) ++ continue; ++ } ++ preempt_disable(); ++ { ++ struct gtp_trace_s gts; ++ ++ memset(>s, 0, sizeof(struct gtp_trace_s)); ++ gts.tpe = gtp_hwb[i].watch; ++ gts.regs = args->regs; ++ gts.hwb = >p_hwb[i]; ++ gtp_handler(>s); ++ } ++ preempt_enable_no_resched(); ++ } ++ ++ /* If the HWB need update in this CPU, just update it. */ ++ if (__get_cpu_var(gtp_hwb_sync_count_local) != gtp_hwb_sync_count) { ++ 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; ++ } ++ ++ gtp_set_debugreg(gtp_hwb_dr7, 7); ++ read_unlock(>p_hwb_lock); ++#endif ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,0,0)) ++out: ++#endif ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33)) ++ 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. */ ++ if (((*dr6_p) & GTP_HWB_DR6_MASK) == 0) ++ ret = NOTIFY_STOP; ++ current->thread.debugreg6 = *dr6_p; ++#else ++ if ((dr6 & GTP_HWB_DR6_MASK) == 0) ++ ret = NOTIFY_STOP; ++ current->thread.debugreg6 = dr6; ++#endif ++ ++ local_irq_restore(flags); ++ return ret; ++} ++ ++static struct notifier_block gtp_notifier = { ++ .notifier_call = gtp_notifier_call, ++ .priority = 0x7ffffffe /* we need to be notified after kprobe. */ ++}; ++#endif + +#ifdef CONFIG_X86 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,0)) @@ -9283,102 +9669,8 @@ + gtp_hw_breakpoint_handler(breakinfo[3].num, regs); +} +#endif -+#else -+static int -+gtp_notifier_call(struct notifier_block *self, unsigned long cmd, -+ void *ptr) -+{ -+ int ret = NOTIFY_DONE; -+ unsigned long flags; -+ struct die_args *args; -+ int i; -+ unsigned long dr6; -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)) -+ unsigned long *dr6_p; +#endif + -+ if (cmd != DIE_DEBUG) -+ return ret; -+ -+ local_irq_save(flags); -+ args = ptr; -+ -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)) -+ /* Get from X86 hw_breakpoint_handler. */ -+ dr6_p = (unsigned long *)ERR_PTR(args->err); -+ dr6 = *dr6_p; -+#else -+ dr6 = args->err; -+#endif -+ 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) -+ continue; -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)) -+ /* Because KGTP handle all the hw-breakpoints. -+ So Just clear it. */ -+ (*dr6_p) &= ~(0x1 << i); -+#endif -+ if (gtp_hwb[i].watch == NULL) -+ continue; -+ /* Check if gtp_hwb is updated in other CPU. */ -+ if (__get_cpu_var(gtp_hwb_sync_count_local) != gtp_hwb_sync_count) { -+ unsigned long addr; -+ -+ gtp_get_debugreg(addr, i); -+ if (addr != gtp_hwb[i].addr) -+ continue; -+ } -+ preempt_disable(); -+ { -+ struct gtp_trace_s gts; -+ -+ memset(>s, 0, sizeof(struct gtp_trace_s)); -+ gts.tpe = gtp_hwb[i].watch; -+ gts.regs = args->regs; -+ gts.hwb = >p_hwb[i]; -+ gtp_handler(>s); -+ } -+ preempt_enable_no_resched(); -+ } -+ -+ /* 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); -+ __get_cpu_var(gtp_hwb_sync_count_local) = gtp_hwb_sync_count; -+ } -+ -+ set_debugreg(gtp_hwb_dr7, 7); -+ read_unlock(>p_hwb_lock); -+ -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)) -+ /* If have some other traps, let other handler handle it. */ -+ if ((dr6 & (~0xf)) == 0) -+ ret = NOTIFY_STOP; -+#else -+ set_debugreg(0UL, 6); -+ ret = NOTIFY_STOP; -+#endif -+ -+out: -+ local_irq_restore(flags); -+ return ret; -+} -+ -+static struct notifier_block gtp_notifier = { -+ .notifier_call = gtp_notifier_call, -+ .priority = 0x7fffffff /* we need to be notified first */ -+}; -+#endif -+ +static unsigned int +gtp_hwb_size_to_arch(int size) +{ @@ -9457,7 +9749,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; @@ -9514,7 +9806,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. */ @@ -9577,54 +9869,74 @@ + tasklet_kill(&tpe->disable_tasklet); + tasklet_kill(&tpe->enable_tasklet); +#endif ++ } ++ ++#ifdef CONFIG_X86 ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,0,0)) ++ if (gtp_have_step || gtp_have_watch_tracepoint) ++#else ++ if (gtp_have_step) ++#endif ++ unregister_die_notifier(>p_notifier); ++ ++ { ++ /* Init data of while-stepping. */ ++ int cpu; ++ for_each_online_cpu(cpu) { ++ struct gtp_step_s *step = &per_cpu(gtp_step, cpu); ++ ++ spin_lock(&step->lock); ++ step->step = 0; ++ step->tpe = NULL; ++ spin_unlock(&step->lock); ++ } + } ++#endif + +#ifdef CONFIG_X86 + /* Stop hwb. */ ++ if (gtp_have_watch_tracepoint) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,0)) -+ { -+ int i; ++ { ++ int i; + -+ /* Register hw breakpoints. */ -+ for (i = 0; i < HWB_NUM; i++) { -+ unregister_wide_hw_breakpoint(breakinfo[i].pev); -+ breakinfo[i].pev = NULL; ++ /* Register hw breakpoints. */ ++ for (i = 0; i < HWB_NUM; i++) { ++ unregister_wide_hw_breakpoint(breakinfo[i].pev); ++ breakinfo[i].pev = NULL; ++ } + } -+ } +#endif + -+ gtp_hwb_stop(NULL); ++ gtp_hwb_stop(NULL); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)) -+ smp_call_function(gtp_hwb_stop, NULL, 1); ++ smp_call_function(gtp_hwb_stop, NULL, 1); +#else -+ smp_call_function(gtp_hwb_stop, NULL, 0, 1); ++ smp_call_function(gtp_hwb_stop, NULL, 0, 1); +#endif + -+ for (tpe = gtp_list; tpe; tpe = tpe->next) { -+ if (tpe->type == gtp_entry_kprobe -+ || (tpe->flags & GTP_ENTRY_FLAGS_REG) == 0 -+ || tpe->disable) -+ continue; ++ for (tpe = gtp_list; tpe; tpe = tpe->next) { ++ if (tpe->type == gtp_entry_kprobe ++ || (tpe->flags & GTP_ENTRY_FLAGS_REG) == 0 ++ || tpe->disable) ++ continue; + -+ if (tpe->type == gtp_entry_watch_static) -+ gtp_unregister_hwb(tpe->addr, 0); ++ if (tpe->type == gtp_entry_watch_static) ++ gtp_unregister_hwb(tpe->addr, 0); + -+ tpe->flags &= ~GTP_ENTRY_FLAGS_REG; ++ tpe->flags &= ~GTP_ENTRY_FLAGS_REG; + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30)) -+ tasklet_kill(&tpe->disable_tasklet); -+ tasklet_kill(&tpe->enable_tasklet); ++ tasklet_kill(&tpe->disable_tasklet); ++ tasklet_kill(&tpe->enable_tasklet); +#endif -+ } ++ } + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)) -+ unregister_kprobe(>p_ipi_kp); ++ unregister_kprobe(>p_ipi_kp); +#endif -+ -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,0,0)) -+ unregister_die_notifier(>p_notifier); ++ } +#endif -+#endif + +#ifdef GTP_PERF_EVENTS + list_for_each(cur, >p_var_list) { @@ -9696,6 +10008,10 @@ + gtp_frame_reset(); + + gtpro_list_clear(); ++#ifdef CONFIG_X86 ++ gtp_have_watch_tracepoint = 0; ++ gtp_have_step = 0; ++#endif + + gtp_var_release(0); + @@ -9810,12 +10126,13 @@ +} + +static int -+gtp_add_backtrace_actions(struct gtp_entry *tpe) ++gtp_add_backtrace_actions(struct gtp_entry *tpe, int step) +{ + struct action *ae, *new_ae; + int got_r = 0, got_m = 0; + -+ for (ae = tpe->action_list; ae; ae = ae->next) { ++ for (ae = step ? tpe->step_action_list : tpe->action_list; ++ ae; ae = ae->next) { + if (ae->type == 'R') + got_r = 1; + else if (ae->type == 'M' && ae->u.m.regnum == GTP_SP_NUM @@ -9823,7 +10140,9 @@ + got_m = 1; + + if (got_r && got_m) -+ break; ++ return 1; ++ ++ /* Let ae point to the last entry of action_list. */ + if (!ae->next) + break; + } @@ -9834,8 +10153,14 @@ + return -ENOMEM; + if (ae) + ae->next = new_ae; -+ else -+ tpe->action_list = ae; ++ else { ++ if (step) ++ tpe->step_action_list = ae; ++ else ++ tpe->action_list = ae; ++ } ++ ++ /* Because new_ae is the new tail. So set it to ae. */ + ae = new_ae; + } + @@ -9847,15 +10172,19 @@ + new_ae->u.m.size = gtp_bt_size; + if (ae) + ae->next = new_ae; -+ else -+ tpe->action_list = ae; ++ else { ++ if (step) ++ tpe->step_action_list = ae; ++ else ++ tpe->action_list = ae; ++ } + } + + return 1; +} + +static int -+gtp_check_getv(struct gtp_entry *tpe, struct action *ae, ++gtp_check_getv(struct gtp_entry *tpe, struct action *ae, int step, + uint8_t *ebuf, unsigned int pc, + struct gtp_x_var **list) +{ @@ -9877,12 +10206,12 @@ + + switch (var->type) { + case gtp_var_special: -+ if (arg == GTP_VAR_NO_SELF_TRACE_ID) { -+ tpe->flags |= GTP_ENTRY_FLAGS_NO_SELF_TRACE; ++ if (arg == GTP_VAR_SELF_TRACE_ID) { ++ tpe->flags |= GTP_ENTRY_FLAGS_SELF_TRACE; + ret = 1; + goto out; + } else if (arg == GTP_VAR_BT_ID) { -+ ret = gtp_add_backtrace_actions (tpe); ++ ret = gtp_add_backtrace_actions (tpe, step); + goto out; + } else if (arg == GTP_VAR_CURRENT_ID) { + tpe->flags |= GTP_ENTRY_FLAGS_CURRENT_TASK; @@ -9951,7 +10280,7 @@ +} + +static int -+gtp_check_setv(struct gtp_entry *tpe, struct action *ae, ++gtp_check_setv(struct gtp_entry *tpe, struct action *ae, int step, + uint8_t *ebuf, unsigned int pc, + struct gtp_x_var **list, int loop, + ULONGEST *stack, ULONGEST top) @@ -9975,8 +10304,8 @@ + switch (var->type) { + case gtp_var_special: + switch (arg) { -+ case GTP_VAR_NO_SELF_TRACE_ID: -+ tpe->flags |= GTP_ENTRY_FLAGS_NO_SELF_TRACE; ++ case GTP_VAR_SELF_TRACE_ID: ++ tpe->flags |= GTP_ENTRY_FLAGS_SELF_TRACE; + ret = 1; + goto out; + break; @@ -9987,7 +10316,7 @@ + goto out; + break; + case GTP_VAR_BT_ID: -+ ret = gtp_add_backtrace_actions (tpe); ++ ret = gtp_add_backtrace_actions (tpe, step); + goto out; + break; + case GTP_VAR_CURRENT_ID: @@ -9996,11 +10325,10 @@ + goto out; + break; + case GTP_VAR_PRINTK_LEVEL_ID: -+ if (loop) { ***The diff for this file has been truncated for email.*** ======================================= --- /trunk/gtp_3.0_to_3.6.patch Sun Feb 17 20:54:51 2013 +++ /trunk/gtp_3.0_to_3.6.patch Mon May 6 19:06:35 2013 @@ -3734,7 +3734,7 @@ --- /dev/null +++ b/lib/gtp.c -@@ -0,0 +1,12093 @@ +@@ -0,0 +1,12887 @@ +/* + * Kernel GDB tracepoint module. + * @@ -3752,12 +3752,12 @@ + * along with this program; if not, write to the Free Software+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *-+ * Copyright(C) KGTP team (https://code.google.com/p/kgtp/), 2010, 2011, 2012, 2013
++ * Copyright(C) KGTP team (https://code.google.com/p/kgtp/), 2010-2013 + * + */ + +/* If "* 10" means that this is not a release version. */ -+#define GTP_VERSION (20130218) ++#define GTP_VERSION (20130218 * 10) + +#include <linux/version.h> +#ifndef RHEL_RELEASE_VERSION @@ -3836,6 +3836,9 @@ +#include <linux/slab.h> +#include <linux/ctype.h> +#include <asm/atomic.h> ++#ifdef CONFIG_X86 ++#include <asm/debugreg.h> ++#endif +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)) +#include <linux/kdebug.h> +#else @@ -3946,7 +3949,9 @@ + + sizeof(struct gtp_frame_var)) +#endif +#ifdef GTP_RB -+#define GTP_FRAME_HEAD_SIZE (FID_SIZE + sizeof(u64) + sizeof(ULONGEST))++/* The frame head size: FID_HEAD + count id + frame number + pointer to prev frem */ ++#define GTP_FRAME_HEAD_SIZE (FID_SIZE + sizeof(u64) + sizeof(ULONGEST) + sizeof(void *))
++/* The frame head size: FID_PAGE_BEGIN + count id */ +#define GTP_FRAME_PAGE_BEGIN_SIZE (FID_SIZE + sizeof(u64)) +#endif +#ifdef GTP_FTRACE_RING_BUFFER @@ -4029,7 +4034,7 @@ +/* This gtp entry is registered inside the system. */ +#define GTP_ENTRY_FLAGS_REG 2 +/* See $no_self_trace. */ -+#define GTP_ENTRY_FLAGS_NO_SELF_TRACE 4 ++#define GTP_ENTRY_FLAGS_SELF_TRACE 4 +/* This gtp entry has passcount. */ +#define GTP_ENTRY_FLAGS_HAVE_PASS 8 +/* See $printk_level. */ @@ -4200,14 +4205,32 @@ + +static pid_t gtp_current_pid; + ++#ifdef CONFIG_X86 ++/* Following part is for while-stepping. */ ++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); ++#endif ++ +#ifdef CONFIG_X86 ++static int gtp_have_watch_tracepoint; ++static int gtp_have_step; ++#endif ++ ++#ifdef CONFIG_X86 ++/* Following part is for watch tracepoint. */ +/* This part is X86 special. */ +#define HWB_NUM 4 + +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 { @@ -4285,16 +4308,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; + } +} @@ -4305,11 +4328,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); +} + @@ -4317,11 +4340,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 @@ -4476,7 +4499,7 @@ + GTP_VAR_PRINTK_LEVEL_ID = 11, + GTP_VAR_PRINTK_FORMAT_ID = 12, + GTP_VAR_DUMP_STACK_ID = 13, -+ GTP_VAR_NO_SELF_TRACE_ID = 14, ++ GTP_VAR_SELF_TRACE_ID = 14, + GTP_VAR_CPU_NUMBER_ID = 15, + GTP_VAR_PC_PE_EN_ID = 16, + GTP_VAR_KRET_ID = 17, @@ -4509,8 +4532,11 @@ + GTP_WATCH_VAL_ID = 42, + GTP_WATCH_COUNT_ID = 43, + ++ GTP_STEP_COUNT_ID = 44, ++ GTP_STEP_ID_ID = 45, ++ + GTP_VAR_SPECIAL_MIN = GTP_VAR_VERSION_ID, -+ GTP_VAR_SPECIAL_MAX = GTP_WATCH_COUNT_ID, ++ GTP_VAR_SPECIAL_MAX = GTP_STEP_ID_ID, +}; + +enum pe_tv_id { @@ -5519,6 +5545,44 @@ +}; +#endif + ++#ifdef GTP_RB ++static int ++gtp_step_count_hooks_get_val(struct gtp_trace_s *gts, struct gtp_var *gtv, ++ int64_t *val) ++{ ++ if (gts->step) ++ *val = gts->tpe->step - gts->step + 1; ++ else ++ *val = 0; ++ ++ return 0; ++} ++ ++static struct gtp_var_hooks gtp_step_count_hooks = { ++ .agent_get_val = gtp_step_count_hooks_get_val, ++}; ++ ++static DEFINE_PER_CPU(int64_t, gtp_step_id); ++ ++static int ++gtp_step_id_hooks_get_val(struct gtp_trace_s *gts, struct gtp_var *gtv, ++ int64_t *val) ++{ ++ if (!gts->step) { ++ if (++ __get_cpu_var(gtp_step_id) == 0) ++ __get_cpu_var(gtp_step_id) = 1; ++ } ++ ++ *val = __get_cpu_var(gtp_step_id); ++ ++ return 0; ++} ++ ++static struct gtp_var_hooks gtp_step_id_hooks = { ++ .agent_get_val = gtp_step_id_hooks_get_val, ++}; ++#endif ++ +static int +gtp_var_special_add_all(void) +{ @@ -5611,8 +5675,8 @@ + if (IS_ERR(var)) + return PTR_ERR(var); + -+ var = gtp_var_special_add(GTP_VAR_NO_SELF_TRACE_ID, 0, 0, -+ "no_self_trace", NULL); ++ var = gtp_var_special_add(GTP_VAR_SELF_TRACE_ID, 0, 0, ++ "self_trace", NULL); + if (IS_ERR(var)) + return PTR_ERR(var); + @@ -5738,6 +5802,16 @@ + if (IS_ERR(var)) + return PTR_ERR(var); +#endif ++ var = gtp_var_special_add(GTP_STEP_COUNT_ID, 0, 0, ++ "step_count", >p_step_count_hooks); ++ if (IS_ERR(var)) ++ return PTR_ERR(var); ++#ifdef GTP_RB ++ var = gtp_var_special_add(GTP_STEP_ID_ID, 0, 0, ++ "step_id", >p_step_id_hooks); ++ if (IS_ERR(var)) ++ return PTR_ERR(var); ++#endif + + return 0; +} @@ -7310,6 +7384,11 @@ + } while (0) +#endif + ++static int gtp_collect_var(struct gtp_trace_s *gts, int num); ++#ifdef GTP_RB ++static int gtp_var_array_step_id_id = 0; ++#endif ++ +static int +gtp_action_head(struct gtp_trace_s *gts) +{ @@ -7358,6 +7437,13 @@ + + trace_nump = (ULONGEST *)tmp; + *trace_nump = gts->tpe->num; ++ tmp += sizeof(ULONGEST); ++ ++#ifdef GTP_RB ++ *(void **)tmp = gtp_rb_prev_frame_get(gts->next); ++ gtp_rb_prev_frame_set(gts->next, (void *)(tmp + sizeof(void *) ++ - GTP_FRAME_HEAD_SIZE)); ++#endif + +#ifdef GTP_FTRACE_RING_BUFFER + ring_buffer_unlock_commit(gtp_frame, rbe); @@ -7366,6 +7452,14 @@ + + atomic_inc(>p_frame_create); + ++#ifdef GTP_RB ++ /* Auto collect $step_id. */ ++ if (gts->tpe->step) { ++ if (gtp_collect_var(gts, gtp_var_array_step_id_id)) ++ return -1; ++ } ++#endif ++ + return 0; +} + @@ -7808,6 +7902,8 @@ + + return ret; +} ++ ++/* The number is not the ID of tvar, it is the ID of gtp_var_array. */ + +static int +gtp_collect_var(struct gtp_trace_s *gts, int num) @@ -8463,6 +8559,30 @@ +} +#endif + ++#ifdef CONFIG_X86 ++/* while-stepping stop. */ ++ ++static void ++gtp_step_stop(struct pt_regs *regs) ++{ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,24)) ++ regs->flags &= ~(X86_EFLAGS_TF); ++#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; ++} ++#endif ++ +static void +gtp_handler(struct gtp_trace_s *gts) +{ @@ -8472,6 +8592,10 @@ + printk(GTP_DEBUG_V "gtp_handler: tracepoint %d %p\n", + (int)gts->tpe->num, (void *)(CORE_ADDR)gts->tpe->addr); +#endif ++#ifdef CONFIG_X86 ++ if (gts->step == 0 && __get_cpu_var(gtp_step).step) ++ gtp_step_stop(gts->regs); ++#endif + + gts->read_memory = (void *)probe_kernel_read; + if (gts->tpe->flags & GTP_ENTRY_FLAGS_CURRENT_TASK) { @@ -8488,7 +8612,7 @@ + return; +#endif + -+ if ((gts->tpe->flags & GTP_ENTRY_FLAGS_NO_SELF_TRACE) ++ if ((gts->tpe->flags & GTP_ENTRY_FLAGS_SELF_TRACE) == 0 + && (get_current()->pid == gtp_gtp_pid + || get_current()->pid == gtp_gtpframe_pid)) { + return; @@ -8513,7 +8637,7 @@ + gts->run = NULL; + + /* Pass. */ -+ if (gts->tpe->flags & GTP_ENTRY_FLAGS_HAVE_PASS) { ++ if (gts->step == 0 && gts->tpe->flags & GTP_ENTRY_FLAGS_HAVE_PASS) { + if (atomic_dec_return(>s->tpe->current_pass) < 0) + goto tpe_stop; + } @@ -8673,18 +8797,47 @@ + struct kretprobe *kpret; + struct gtp_kp *gkp; + union gtp_entry_u *u; ++ struct gtp_entry *tpe; + struct gtp_trace_s gts; + -+ memset(>s, 0, sizeof(struct gtp_trace_s)); -+ + kpret = container_of(p, struct kretprobe, kp); + gkp = container_of(kpret, struct gtp_kp, kpret); + u = container_of(gkp, union gtp_entry_u, kp); -+ gts.tpe = container_of(u, struct gtp_entry, u); -+ gts.regs = regs; -+ gts.step = 1; ++ tpe = container_of(u, struct gtp_entry, u); ++ ++ if (tpe->step == 1) { ++ memset(>s, 0, sizeof(struct gtp_trace_s)); ++ ++ gts.tpe = tpe; ++ gts.regs = regs; ++ gts.step = tpe->step; ++ ++ gtp_handler(>s); ++ } + -+ gtp_handler(>s); ++#ifdef CONFIG_X86 ++ 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. */
++ __get_cpu_var(gtp_step).step = tpe->step; ++ __get_cpu_var(gtp_step).tpe = tpe; ++ #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,24)) ++ if (regs->flags & X86_EFLAGS_IF) ++ #else ++ if (regs->eflags & X86_EFLAGS_IF) ++ #endif ++ __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 +} + +static inline void @@ -8965,6 +9118,7 @@ + gtp_list = gtp_list->next; + gtp_action_release(tpe->cond); + gtp_action_release(tpe->action_list); ++ gtp_action_release(tpe->step_action_list); + gtp_src_release(tpe->src); + gtp_src_release(tpe->action_cmd); + gtp_src_release(tpe->printk_str); @@ -9205,6 +9359,238 @@ + + return 0; +} ++ ++#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) ++{ ++ uint32_t opcode; ++ uint8_t opcode8; ++ unsigned long pc = GTP_REGS_PC(regs); ++ ++ /* 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: ++ ++ 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) = pc; ++ break; ++ case 0xfa: ++ /* cli */ ++ __get_cpu_var(gtp_step).irq_need_open = 0; ++ GTP_REGS_PC(regs) = pc; ++ break; ++ case 0x0f07: ++ /* sysret */ ++ return 1; ++ break; ++ }; ++ ++ return 0; ++} ++ ++static int ++gtp_notifier_call(struct notifier_block *self, unsigned long cmd, ++ void *ptr) ++{ ++ int ret = NOTIFY_DONE; ++ unsigned long flags; ++ struct die_args *args; ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,0,0)) ++ int i; ++#endif ++ unsigned long dr6; ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)) ++ unsigned long *dr6_p; ++#endif ++ ++ if (cmd != DIE_DEBUG) ++ return ret; ++ ++ local_irq_save(flags); ++ args = ptr; ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)) ++ /* Get from X86 hw_breakpoint_handler. */ ++ dr6_p = (unsigned long *)ERR_PTR(args->err); ++ dr6 = *dr6_p; ++#else ++ dr6 = args->err; ++#endif ++ gtp_set_debugreg(GTP_HWB_DR7_DEF, 7); ++ ++ /* Handle while-stepping. */ ++ spin_lock(&__get_cpu_var(gtp_step).lock); ++ if ((dr6 & 0x4000) != 0) { ++ /* Clear the bit that handle by KGTP. */ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)) ++ (*dr6_p) &= ~(0x4000); ++#else ++ dr6 &= ~(0x4000); ++#endif ++ if (!__get_cpu_var(gtp_step).tpe || user_mode(args->regs)) ++ gtp_step_stop(args->regs); ++ else { ++ 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)); ++ ++ preempt_disable(); ++ { ++ struct gtp_trace_s gts; ++ ++ memset(>s, 0, sizeof(struct gtp_trace_s)); ++ gts.tpe = __get_cpu_var(gtp_step).tpe; ++ gts.regs = args->regs; ++ gts.step = __get_cpu_var(gtp_step).step; ++ gtp_handler(>s); ++ } ++ preempt_enable_no_resched(); ++ ++ 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)) ++ 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. */ ++ gtp_step_stop(args->regs); ++ } ++ } ++ } ++ spin_unlock(&__get_cpu_var(gtp_step).lock); ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,0,0)) ++ /* Handle watch traceppoint. */ ++ if ((dr6 & 0xf) == 0) ++ goto out; ++ read_lock(>p_hwb_lock); ++ ++ for (i = 0; i < HWB_NUM; i++) { ++ if ((dr6 & (0x1 << i)) == 0) ++ continue; ++ /* Clear the bit that handle by KGTP. */ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)) ++ (*dr6_p) &= ~(0x1 << i); ++#else ++ dr6 &= ~(0x1 << i); ++#endif ++ if (gtp_hwb[i].watch == NULL) ++ continue; ++ /* Check if gtp_hwb is updated in other CPU. */ ++ if (__get_cpu_var(gtp_hwb_sync_count_local) != gtp_hwb_sync_count) { ++ unsigned long addr; ++ ++ gtp_get_debugreg(addr, i); ++ if (addr != gtp_hwb[i].addr) ++ continue; ++ } ++ preempt_disable(); ++ { ++ struct gtp_trace_s gts; ++ ++ memset(>s, 0, sizeof(struct gtp_trace_s)); ++ gts.tpe = gtp_hwb[i].watch; ++ gts.regs = args->regs; ++ gts.hwb = >p_hwb[i]; ++ gtp_handler(>s); ++ } ++ preempt_enable_no_resched(); ++ } ++ ++ /* If the HWB need update in this CPU, just update it. */ ++ if (__get_cpu_var(gtp_hwb_sync_count_local) != gtp_hwb_sync_count) { ++ 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; ++ } ++ ++ gtp_set_debugreg(gtp_hwb_dr7, 7); ++ read_unlock(>p_hwb_lock); ++#endif ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,0,0)) ++out: ++#endif ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33)) ++ 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. */ ++ if (((*dr6_p) & GTP_HWB_DR6_MASK) == 0) ++ ret = NOTIFY_STOP; ++ current->thread.debugreg6 = *dr6_p; ++#else ++ if ((dr6 & GTP_HWB_DR6_MASK) == 0) ++ ret = NOTIFY_STOP; ++ current->thread.debugreg6 = dr6; ++#endif ++ ++ local_irq_restore(flags); ++ return ret; ++} ++ ++static struct notifier_block gtp_notifier = { ++ .notifier_call = gtp_notifier_call, ++ .priority = 0x7ffffffe /* we need to be notified after kprobe. */ ++}; ++#endif + +#ifdef CONFIG_X86 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,0)) @@ -9301,102 +9687,8 @@ + gtp_hw_breakpoint_handler(breakinfo[3].num, regs); +} +#endif -+#else -+static int -+gtp_notifier_call(struct notifier_block *self, unsigned long cmd, -+ void *ptr) -+{ -+ int ret = NOTIFY_DONE; -+ unsigned long flags; -+ struct die_args *args; -+ int i; -+ unsigned long dr6; -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)) -+ unsigned long *dr6_p; +#endif + -+ if (cmd != DIE_DEBUG) -+ return ret; -+ -+ local_irq_save(flags); -+ args = ptr; -+ -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)) -+ /* Get from X86 hw_breakpoint_handler. */ -+ dr6_p = (unsigned long *)ERR_PTR(args->err); -+ dr6 = *dr6_p; -+#else -+ dr6 = args->err; -+#endif -+ 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) -+ continue; -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)) -+ /* Because KGTP handle all the hw-breakpoints. -+ So Just clear it. */ -+ (*dr6_p) &= ~(0x1 << i); -+#endif -+ if (gtp_hwb[i].watch == NULL) -+ continue; -+ /* Check if gtp_hwb is updated in other CPU. */ -+ if (__get_cpu_var(gtp_hwb_sync_count_local) != gtp_hwb_sync_count) { -+ unsigned long addr; -+ -+ gtp_get_debugreg(addr, i); -+ if (addr != gtp_hwb[i].addr) -+ continue; -+ } -+ preempt_disable(); -+ { -+ struct gtp_trace_s gts; -+ -+ memset(>s, 0, sizeof(struct gtp_trace_s)); -+ gts.tpe = gtp_hwb[i].watch; -+ gts.regs = args->regs; -+ gts.hwb = >p_hwb[i]; -+ gtp_handler(>s); -+ } -+ preempt_enable_no_resched(); -+ } -+ -+ /* 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); -+ __get_cpu_var(gtp_hwb_sync_count_local) = gtp_hwb_sync_count; -+ } -+ -+ set_debugreg(gtp_hwb_dr7, 7); -+ read_unlock(>p_hwb_lock); -+ -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)) -+ /* If have some other traps, let other handler handle it. */ -+ if ((dr6 & (~0xf)) == 0) -+ ret = NOTIFY_STOP; -+#else -+ set_debugreg(0UL, 6); -+ ret = NOTIFY_STOP; -+#endif -+ -+out: -+ local_irq_restore(flags); -+ return ret; -+} -+ -+static struct notifier_block gtp_notifier = { -+ .notifier_call = gtp_notifier_call, -+ .priority = 0x7fffffff /* we need to be notified first */ -+}; -+#endif -+ +static unsigned int +gtp_hwb_size_to_arch(int size) +{ @@ -9475,7 +9767,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; @@ -9532,7 +9824,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. */ @@ -9595,54 +9887,74 @@ + tasklet_kill(&tpe->disable_tasklet); + tasklet_kill(&tpe->enable_tasklet); +#endif ++ } ++ ++#ifdef CONFIG_X86 ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,0,0)) ++ if (gtp_have_step || gtp_have_watch_tracepoint) ++#else ++ if (gtp_have_step) ++#endif ++ unregister_die_notifier(>p_notifier); ++ ++ { ++ /* Init data of while-stepping. */ ++ int cpu; ++ for_each_online_cpu(cpu) { ++ struct gtp_step_s *step = &per_cpu(gtp_step, cpu); ++ ++ spin_lock(&step->lock); ++ step->step = 0; ++ step->tpe = NULL; ++ spin_unlock(&step->lock); ++ } + } ++#endif + +#ifdef CONFIG_X86 + /* Stop hwb. */ ++ if (gtp_have_watch_tracepoint) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,0)) -+ { -+ int i; ++ { ++ int i; + -+ /* Register hw breakpoints. */ -+ for (i = 0; i < HWB_NUM; i++) { -+ unregister_wide_hw_breakpoint(breakinfo[i].pev); -+ breakinfo[i].pev = NULL; ++ /* Register hw breakpoints. */ ++ for (i = 0; i < HWB_NUM; i++) { ++ unregister_wide_hw_breakpoint(breakinfo[i].pev); ++ breakinfo[i].pev = NULL; ++ } + } -+ } +#endif + -+ gtp_hwb_stop(NULL); ++ gtp_hwb_stop(NULL); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)) -+ smp_call_function(gtp_hwb_stop, NULL, 1); ++ smp_call_function(gtp_hwb_stop, NULL, 1); +#else -+ smp_call_function(gtp_hwb_stop, NULL, 0, 1); ++ smp_call_function(gtp_hwb_stop, NULL, 0, 1); +#endif + -+ for (tpe = gtp_list; tpe; tpe = tpe->next) { -+ if (tpe->type == gtp_entry_kprobe -+ || (tpe->flags & GTP_ENTRY_FLAGS_REG) == 0 -+ || tpe->disable) -+ continue; ++ for (tpe = gtp_list; tpe; tpe = tpe->next) { ++ if (tpe->type == gtp_entry_kprobe ++ || (tpe->flags & GTP_ENTRY_FLAGS_REG) == 0 ++ || tpe->disable) ++ continue; + -+ if (tpe->type == gtp_entry_watch_static) -+ gtp_unregister_hwb(tpe->addr, 0); ++ if (tpe->type == gtp_entry_watch_static) ++ gtp_unregister_hwb(tpe->addr, 0); + -+ tpe->flags &= ~GTP_ENTRY_FLAGS_REG; ++ tpe->flags &= ~GTP_ENTRY_FLAGS_REG; + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30)) -+ tasklet_kill(&tpe->disable_tasklet); -+ tasklet_kill(&tpe->enable_tasklet); ++ tasklet_kill(&tpe->disable_tasklet); ++ tasklet_kill(&tpe->enable_tasklet); +#endif -+ } ++ } + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)) -+ unregister_kprobe(>p_ipi_kp); ++ unregister_kprobe(>p_ipi_kp); +#endif -+ -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,0,0)) -+ unregister_die_notifier(>p_notifier); ++ } +#endif -+#endif + +#ifdef GTP_PERF_EVENTS + list_for_each(cur, >p_var_list) { @@ -9714,6 +10026,10 @@ + gtp_frame_reset(); + + gtpro_list_clear(); ++#ifdef CONFIG_X86 ++ gtp_have_watch_tracepoint = 0; ++ gtp_have_step = 0; ++#endif + + gtp_var_release(0); + @@ -9828,12 +10144,13 @@ +} + +static int -+gtp_add_backtrace_actions(struct gtp_entry *tpe) ++gtp_add_backtrace_actions(struct gtp_entry *tpe, int step) +{ + struct action *ae, *new_ae; + int got_r = 0, got_m = 0; + -+ for (ae = tpe->action_list; ae; ae = ae->next) { ++ for (ae = step ? tpe->step_action_list : tpe->action_list; ++ ae; ae = ae->next) { + if (ae->type == 'R') + got_r = 1; + else if (ae->type == 'M' && ae->u.m.regnum == GTP_SP_NUM @@ -9841,7 +10158,9 @@ + got_m = 1; + + if (got_r && got_m) -+ break; ++ return 1; ++ ++ /* Let ae point to the last entry of action_list. */ + if (!ae->next) + break; + } @@ -9852,8 +10171,14 @@ + return -ENOMEM; + if (ae) + ae->next = new_ae; -+ else -+ tpe->action_list = ae; ++ else { ++ if (step) ++ tpe->step_action_list = ae; ++ else ++ tpe->action_list = ae; ++ } ++ ++ /* Because new_ae is the new tail. So set it to ae. */ + ae = new_ae; + } + @@ -9865,15 +10190,19 @@ + new_ae->u.m.size = gtp_bt_size; + if (ae) + ae->next = new_ae; -+ else -+ tpe->action_list = ae; ++ else { ++ if (step) ++ tpe->step_action_list = ae; ++ else ++ tpe->action_list = ae; ++ } + } + + return 1; +} + +static int -+gtp_check_getv(struct gtp_entry *tpe, struct action *ae, ++gtp_check_getv(struct gtp_entry *tpe, struct action *ae, int step, + uint8_t *ebuf, unsigned int pc, + struct gtp_x_var **list) +{ @@ -9895,12 +10224,12 @@ + + switch (var->type) { + case gtp_var_special: -+ if (arg == GTP_VAR_NO_SELF_TRACE_ID) { -+ tpe->flags |= GTP_ENTRY_FLAGS_NO_SELF_TRACE; ++ if (arg == GTP_VAR_SELF_TRACE_ID) { ++ tpe->flags |= GTP_ENTRY_FLAGS_SELF_TRACE; + ret = 1; + goto out; + } else if (arg == GTP_VAR_BT_ID) { -+ ret = gtp_add_backtrace_actions (tpe); ++ ret = gtp_add_backtrace_actions (tpe, step); + goto out; + } else if (arg == GTP_VAR_CURRENT_ID) { + tpe->flags |= GTP_ENTRY_FLAGS_CURRENT_TASK; @@ -9969,7 +10298,7 @@ +} + +static int -+gtp_check_setv(struct gtp_entry *tpe, struct action *ae, ++gtp_check_setv(struct gtp_entry *tpe, struct action *ae, int step, + uint8_t *ebuf, unsigned int pc, + struct gtp_x_var **list, int loop, + ULONGEST *stack, ULONGEST top) @@ -9993,8 +10322,8 @@ + switch (var->type) { + case gtp_var_special: + switch (arg) { -+ case GTP_VAR_NO_SELF_TRACE_ID: -+ tpe->flags |= GTP_ENTRY_FLAGS_NO_SELF_TRACE; ++ case GTP_VAR_SELF_TRACE_ID: ++ tpe->flags |= GTP_ENTRY_FLAGS_SELF_TRACE; + ret = 1; + goto out; + break; @@ -10005,7 +10334,7 @@ + goto out; + break; + case GTP_VAR_BT_ID: -+ ret = gtp_add_backtrace_actions (tpe); ++ ret = gtp_add_backtrace_actions (tpe, step); + goto out; + break; + case GTP_VAR_CURRENT_ID: @@ -10014,11 +10343,10 @@ + goto out; + break; + case GTP_VAR_PRINTK_LEVEL_ID: -+ if (loop) { ***The diff for this file has been truncated for email.*** ======================================= --- /trunk/gtp_3.7_to_upstream.patch Sun Feb 17 20:54:51 2013 +++ /trunk/gtp_3.7_to_upstream.patch Mon May 6 19:06:35 2013 @@ -3614,7 +3614,7 @@ +Please go to HOWTO to get more message about howto use KGTP. --- a/arch/arm/mm/flush.c +++ b/arch/arm/mm/flush.c -@@ -336,3 +336,5 @@ void __flush_anon_page(struct vm_area_st +@@ -339,3 +339,5 @@ void __flush_anon_page(struct vm_area_st */ __cpuc_flush_dcache_area(page_address(page), PAGE_SIZE); } @@ -3622,7 +3622,7 @@ + --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h -@@ -829,4 +829,12 @@ _name##_show(struct device *dev, \ +@@ -847,4 +847,12 @@ _name##_show(struct device *dev, \ \ static struct device_attribute format_attr_##_name = __ATTR_RO(_name) @@ -3637,7 +3637,7 @@ #endif /* _LINUX_PERF_EVENT_H */ --- a/kernel/events/core.c +++ b/kernel/events/core.c -@@ -42,6 +42,12 @@ +@@ -44,6 +44,12 @@ #include <asm/irq_regs.h> @@ -3650,7 +3650,7 @@ struct remote_function_call { struct task_struct *p; int (*func)(void *info); -@@ -1393,6 +1399,9 @@ static void perf_set_shadow_time(struct +@@ -1434,6 +1440,9 @@ static void perf_set_shadow_time(struct else event->shadow_ctx_time = tstamp - ctx->timestamp; } @@ -3660,7 +3660,7 @@ #define MAX_INTERRUPTS (~0ULL) -@@ -1890,6 +1899,9 @@ static void ctx_sched_out(struct perf_ev +@@ -1931,6 +1940,9 @@ static void ctx_sched_out(struct perf_ev } perf_pmu_enable(ctx->pmu); } @@ -3670,7 +3670,7 @@ /* * Test whether two contexts are equivalent, i.e. whether they -@@ -3175,6 +3187,14 @@ static void perf_event_reset(struct perf +@@ -3226,6 +3238,14 @@ static void perf_event_reset(struct perf perf_event_update_userpage(event); } @@ -3685,8 +3685,8 @@ /* * Holding the top-level event's child_mutex means that any * descendant process that has inherited this event will block -@@ -7521,3 +7541,15 @@ struct cgroup_subsys perf_subsys = { - .broken_hierarchy = true, +@@ -7579,3 +7599,15 @@ struct cgroup_subsys perf_subsys = { + .attach = perf_cgroup_attach, }; #endif /* CONFIG_CGROUP_PERF */ + @@ -3703,7 +3703,7 @@ +EXPORT_SYMBOL_GPL(local_perf_event_disable); --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug -@@ -1453,6 +1453,16 @@ config ASYNC_RAID6_TEST +@@ -1475,6 +1475,16 @@ config ASYNC_RAID6_TEST If unsure, say N. @@ -3722,7 +3722,7 @@ source "lib/Kconfig.kgdb" --- a/lib/Makefile +++ b/lib/Makefile -@@ -148,6 +148,8 @@ interval_tree_test-objs := interval_tree +@@ -151,6 +151,8 @@ interval_tree_test-objs := interval_tree obj-$(CONFIG_ASN1) += asn1_decoder.o @@ -3733,7 +3733,7 @@ --- /dev/null +++ b/lib/gtp.c -@@ -0,0 +1,12093 @@ +@@ -0,0 +1,12887 @@ +/* + * Kernel GDB tracepoint module. + * @@ -3751,12 +3751,12 @@ + * along with this program; if not, write to the Free Software+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *-+ * Copyright(C) KGTP team (https://code.google.com/p/kgtp/), 2010, 2011, 2012, 2013
++ * Copyright(C) KGTP team (https://code.google.com/p/kgtp/), 2010-2013 + * + */ + +/* If "* 10" means that this is not a release version. */ -+#define GTP_VERSION (20130218) ++#define GTP_VERSION (20130218 * 10) + +#include <linux/version.h> +#ifndef RHEL_RELEASE_VERSION @@ -3835,6 +3835,9 @@ +#include <linux/slab.h> +#include <linux/ctype.h> +#include <asm/atomic.h> ++#ifdef CONFIG_X86 ++#include <asm/debugreg.h> ++#endif +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)) +#include <linux/kdebug.h> +#else @@ -3945,7 +3948,9 @@ + + sizeof(struct gtp_frame_var)) +#endif +#ifdef GTP_RB -+#define GTP_FRAME_HEAD_SIZE (FID_SIZE + sizeof(u64) + sizeof(ULONGEST))++/* The frame head size: FID_HEAD + count id + frame number + pointer to prev frem */ ++#define GTP_FRAME_HEAD_SIZE (FID_SIZE + sizeof(u64) + sizeof(ULONGEST) + sizeof(void *))
++/* The frame head size: FID_PAGE_BEGIN + count id */ +#define GTP_FRAME_PAGE_BEGIN_SIZE (FID_SIZE + sizeof(u64)) +#endif +#ifdef GTP_FTRACE_RING_BUFFER @@ -4028,7 +4033,7 @@ +/* This gtp entry is registered inside the system. */ +#define GTP_ENTRY_FLAGS_REG 2 +/* See $no_self_trace. */ -+#define GTP_ENTRY_FLAGS_NO_SELF_TRACE 4 ++#define GTP_ENTRY_FLAGS_SELF_TRACE 4 +/* This gtp entry has passcount. */ +#define GTP_ENTRY_FLAGS_HAVE_PASS 8 +/* See $printk_level. */ @@ -4200,13 +4205,31 @@ +static pid_t gtp_current_pid; + +#ifdef CONFIG_X86 ++/* Following part is for while-stepping. */ ++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); ++#endif ++ ++#ifdef CONFIG_X86 ++static int gtp_have_watch_tracepoint; ++static int gtp_have_step; ++#endif ++ ++#ifdef CONFIG_X86 ++/* Following part is for watch tracepoint. */ +/* This part is X86 special. */ +#define HWB_NUM 4 + +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 { @@ -4284,16 +4307,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; + } +} @@ -4304,11 +4327,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); +} + @@ -4316,11 +4339,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 @@ -4475,7 +4498,7 @@ + GTP_VAR_PRINTK_LEVEL_ID = 11, + GTP_VAR_PRINTK_FORMAT_ID = 12, + GTP_VAR_DUMP_STACK_ID = 13, -+ GTP_VAR_NO_SELF_TRACE_ID = 14, ++ GTP_VAR_SELF_TRACE_ID = 14, + GTP_VAR_CPU_NUMBER_ID = 15, + GTP_VAR_PC_PE_EN_ID = 16, + GTP_VAR_KRET_ID = 17, @@ -4508,8 +4531,11 @@ + GTP_WATCH_VAL_ID = 42, + GTP_WATCH_COUNT_ID = 43, + ++ GTP_STEP_COUNT_ID = 44, ++ GTP_STEP_ID_ID = 45, ++ + GTP_VAR_SPECIAL_MIN = GTP_VAR_VERSION_ID, -+ GTP_VAR_SPECIAL_MAX = GTP_WATCH_COUNT_ID, ++ GTP_VAR_SPECIAL_MAX = GTP_STEP_ID_ID, +}; + +enum pe_tv_id { @@ -5518,6 +5544,44 @@ +}; +#endif + ++#ifdef GTP_RB ++static int ++gtp_step_count_hooks_get_val(struct gtp_trace_s *gts, struct gtp_var *gtv, ++ int64_t *val) ++{ ++ if (gts->step) ++ *val = gts->tpe->step - gts->step + 1; ++ else ++ *val = 0; ++ ++ return 0; ++} ++ ++static struct gtp_var_hooks gtp_step_count_hooks = { ++ .agent_get_val = gtp_step_count_hooks_get_val, ++}; ++ ++static DEFINE_PER_CPU(int64_t, gtp_step_id); ++ ++static int ++gtp_step_id_hooks_get_val(struct gtp_trace_s *gts, struct gtp_var *gtv, ++ int64_t *val) ++{ ++ if (!gts->step) { ++ if (++ __get_cpu_var(gtp_step_id) == 0) ++ __get_cpu_var(gtp_step_id) = 1; ++ } ++ ++ *val = __get_cpu_var(gtp_step_id); ++ ++ return 0; ++} ++ ++static struct gtp_var_hooks gtp_step_id_hooks = { ++ .agent_get_val = gtp_step_id_hooks_get_val, ++}; ++#endif ++ +static int +gtp_var_special_add_all(void) +{ @@ -5610,8 +5674,8 @@ + if (IS_ERR(var)) + return PTR_ERR(var); + -+ var = gtp_var_special_add(GTP_VAR_NO_SELF_TRACE_ID, 0, 0, -+ "no_self_trace", NULL); ++ var = gtp_var_special_add(GTP_VAR_SELF_TRACE_ID, 0, 0, ++ "self_trace", NULL); + if (IS_ERR(var)) + return PTR_ERR(var); + @@ -5737,6 +5801,16 @@ + if (IS_ERR(var)) + return PTR_ERR(var); +#endif ++ var = gtp_var_special_add(GTP_STEP_COUNT_ID, 0, 0, ++ "step_count", >p_step_count_hooks); ++ if (IS_ERR(var)) ++ return PTR_ERR(var); ++#ifdef GTP_RB ++ var = gtp_var_special_add(GTP_STEP_ID_ID, 0, 0, ++ "step_id", >p_step_id_hooks); ++ if (IS_ERR(var)) ++ return PTR_ERR(var); ++#endif + + return 0; +} @@ -7309,6 +7383,11 @@ + } while (0) +#endif + ++static int gtp_collect_var(struct gtp_trace_s *gts, int num); ++#ifdef GTP_RB ++static int gtp_var_array_step_id_id = 0; ++#endif ++ +static int +gtp_action_head(struct gtp_trace_s *gts) +{ @@ -7357,6 +7436,13 @@ + + trace_nump = (ULONGEST *)tmp; + *trace_nump = gts->tpe->num; ++ tmp += sizeof(ULONGEST); ++ ++#ifdef GTP_RB ++ *(void **)tmp = gtp_rb_prev_frame_get(gts->next); ++ gtp_rb_prev_frame_set(gts->next, (void *)(tmp + sizeof(void *) ++ - GTP_FRAME_HEAD_SIZE)); ++#endif + +#ifdef GTP_FTRACE_RING_BUFFER + ring_buffer_unlock_commit(gtp_frame, rbe); @@ -7365,6 +7451,14 @@ + + atomic_inc(>p_frame_create); + ++#ifdef GTP_RB ++ /* Auto collect $step_id. */ ++ if (gts->tpe->step) { ++ if (gtp_collect_var(gts, gtp_var_array_step_id_id)) ++ return -1; ++ } ++#endif ++ + return 0; +} + @@ -7807,6 +7901,8 @@ + + return ret; +} ++ ++/* The number is not the ID of tvar, it is the ID of gtp_var_array. */ + +static int +gtp_collect_var(struct gtp_trace_s *gts, int num) @@ -8462,6 +8558,30 @@ +} +#endif + ++#ifdef CONFIG_X86 ++/* while-stepping stop. */ ++ ++static void ++gtp_step_stop(struct pt_regs *regs) ++{ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,24)) ++ regs->flags &= ~(X86_EFLAGS_TF); ++#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; ++} ++#endif ++ +static void +gtp_handler(struct gtp_trace_s *gts) +{ @@ -8471,6 +8591,10 @@ + printk(GTP_DEBUG_V "gtp_handler: tracepoint %d %p\n", + (int)gts->tpe->num, (void *)(CORE_ADDR)gts->tpe->addr); +#endif ++#ifdef CONFIG_X86 ++ if (gts->step == 0 && __get_cpu_var(gtp_step).step) ++ gtp_step_stop(gts->regs); ++#endif + + gts->read_memory = (void *)probe_kernel_read; + if (gts->tpe->flags & GTP_ENTRY_FLAGS_CURRENT_TASK) { @@ -8487,7 +8611,7 @@ + return; +#endif + -+ if ((gts->tpe->flags & GTP_ENTRY_FLAGS_NO_SELF_TRACE) ++ if ((gts->tpe->flags & GTP_ENTRY_FLAGS_SELF_TRACE) == 0 + && (get_current()->pid == gtp_gtp_pid + || get_current()->pid == gtp_gtpframe_pid)) { + return; @@ -8512,7 +8636,7 @@ + gts->run = NULL; + + /* Pass. */ -+ if (gts->tpe->flags & GTP_ENTRY_FLAGS_HAVE_PASS) { ++ if (gts->step == 0 && gts->tpe->flags & GTP_ENTRY_FLAGS_HAVE_PASS) { + if (atomic_dec_return(>s->tpe->current_pass) < 0) + goto tpe_stop; + } @@ -8672,18 +8796,47 @@ + struct kretprobe *kpret; + struct gtp_kp *gkp; + union gtp_entry_u *u; ++ struct gtp_entry *tpe; + struct gtp_trace_s gts; + -+ memset(>s, 0, sizeof(struct gtp_trace_s)); -+ + kpret = container_of(p, struct kretprobe, kp); + gkp = container_of(kpret, struct gtp_kp, kpret); + u = container_of(gkp, union gtp_entry_u, kp); -+ gts.tpe = container_of(u, struct gtp_entry, u); -+ gts.regs = regs; -+ gts.step = 1; ++ tpe = container_of(u, struct gtp_entry, u); ++ ++ if (tpe->step == 1) { ++ memset(>s, 0, sizeof(struct gtp_trace_s)); ++ ++ gts.tpe = tpe; ++ gts.regs = regs; ++ gts.step = tpe->step; + -+ gtp_handler(>s); ++ gtp_handler(>s); ++ } ++ ++#ifdef CONFIG_X86 ++ 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. */
++ __get_cpu_var(gtp_step).step = tpe->step; ++ __get_cpu_var(gtp_step).tpe = tpe; ++ #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,24)) ++ if (regs->flags & X86_EFLAGS_IF) ++ #else ++ if (regs->eflags & X86_EFLAGS_IF) ++ #endif ++ __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 +} + +static inline void @@ -8964,6 +9117,7 @@ + gtp_list = gtp_list->next; + gtp_action_release(tpe->cond); + gtp_action_release(tpe->action_list); ++ gtp_action_release(tpe->step_action_list); + gtp_src_release(tpe->src); + gtp_src_release(tpe->action_cmd); + gtp_src_release(tpe->printk_str); @@ -9204,6 +9358,238 @@ + + return 0; +} ++ ++#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) ++{ ++ uint32_t opcode; ++ uint8_t opcode8; ++ unsigned long pc = GTP_REGS_PC(regs); ++ ++ /* 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: ++ ++ 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) = pc; ++ break; ++ case 0xfa: ++ /* cli */ ++ __get_cpu_var(gtp_step).irq_need_open = 0; ++ GTP_REGS_PC(regs) = pc; ++ break; ++ case 0x0f07: ++ /* sysret */ ++ return 1; ++ break; ++ }; ++ ++ return 0; ++} ++ ++static int ++gtp_notifier_call(struct notifier_block *self, unsigned long cmd, ++ void *ptr) ++{ ++ int ret = NOTIFY_DONE; ++ unsigned long flags; ++ struct die_args *args; ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,0,0)) ++ int i; ++#endif ++ unsigned long dr6; ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)) ++ unsigned long *dr6_p; ++#endif ++ ++ if (cmd != DIE_DEBUG) ++ return ret; ++ ++ local_irq_save(flags); ++ args = ptr; ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)) ++ /* Get from X86 hw_breakpoint_handler. */ ++ dr6_p = (unsigned long *)ERR_PTR(args->err); ++ dr6 = *dr6_p; ++#else ++ dr6 = args->err; ++#endif ++ gtp_set_debugreg(GTP_HWB_DR7_DEF, 7); ++ ++ /* Handle while-stepping. */ ++ spin_lock(&__get_cpu_var(gtp_step).lock); ++ if ((dr6 & 0x4000) != 0) { ++ /* Clear the bit that handle by KGTP. */ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)) ++ (*dr6_p) &= ~(0x4000); ++#else ++ dr6 &= ~(0x4000); ++#endif ++ if (!__get_cpu_var(gtp_step).tpe || user_mode(args->regs)) ++ gtp_step_stop(args->regs); ++ else { ++ 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)); ++ ++ preempt_disable(); ++ { ++ struct gtp_trace_s gts; ++ ++ memset(>s, 0, sizeof(struct gtp_trace_s)); ++ gts.tpe = __get_cpu_var(gtp_step).tpe; ++ gts.regs = args->regs; ++ gts.step = __get_cpu_var(gtp_step).step; ++ gtp_handler(>s); ++ } ++ preempt_enable_no_resched(); ++ ++ 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)) ++ 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. */ ++ gtp_step_stop(args->regs); ++ } ++ } ++ } ++ spin_unlock(&__get_cpu_var(gtp_step).lock); ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,0,0)) ++ /* Handle watch traceppoint. */ ++ if ((dr6 & 0xf) == 0) ++ goto out; ++ read_lock(>p_hwb_lock); ++ ++ for (i = 0; i < HWB_NUM; i++) { ++ if ((dr6 & (0x1 << i)) == 0) ++ continue; ++ /* Clear the bit that handle by KGTP. */ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)) ++ (*dr6_p) &= ~(0x1 << i); ++#else ++ dr6 &= ~(0x1 << i); ++#endif ++ if (gtp_hwb[i].watch == NULL) ++ continue; ++ /* Check if gtp_hwb is updated in other CPU. */ ++ if (__get_cpu_var(gtp_hwb_sync_count_local) != gtp_hwb_sync_count) { ++ unsigned long addr; ++ ++ gtp_get_debugreg(addr, i); ++ if (addr != gtp_hwb[i].addr) ++ continue; ++ } ++ preempt_disable(); ++ { ++ struct gtp_trace_s gts; ++ ++ memset(>s, 0, sizeof(struct gtp_trace_s)); ++ gts.tpe = gtp_hwb[i].watch; ++ gts.regs = args->regs; ++ gts.hwb = >p_hwb[i]; ++ gtp_handler(>s); ++ } ++ preempt_enable_no_resched(); ++ } ++ ++ /* If the HWB need update in this CPU, just update it. */ ++ if (__get_cpu_var(gtp_hwb_sync_count_local) != gtp_hwb_sync_count) { ++ 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; ++ } ++ ++ gtp_set_debugreg(gtp_hwb_dr7, 7); ++ read_unlock(>p_hwb_lock); ++#endif ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,0,0)) ++out: ++#endif ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33)) ++ 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. */ ++ if (((*dr6_p) & GTP_HWB_DR6_MASK) == 0) ++ ret = NOTIFY_STOP; ++ current->thread.debugreg6 = *dr6_p; ++#else ++ if ((dr6 & GTP_HWB_DR6_MASK) == 0) ++ ret = NOTIFY_STOP; ++ current->thread.debugreg6 = dr6; ++#endif ++ ++ local_irq_restore(flags); ++ return ret; ++} ++ ++static struct notifier_block gtp_notifier = { ++ .notifier_call = gtp_notifier_call, ++ .priority = 0x7ffffffe /* we need to be notified after kprobe. */ ++}; ++#endif + +#ifdef CONFIG_X86 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,0)) @@ -9300,102 +9686,8 @@ + gtp_hw_breakpoint_handler(breakinfo[3].num, regs); +} +#endif -+#else -+static int -+gtp_notifier_call(struct notifier_block *self, unsigned long cmd, -+ void *ptr) -+{ -+ int ret = NOTIFY_DONE; -+ unsigned long flags; -+ struct die_args *args; -+ int i; -+ unsigned long dr6; -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)) -+ unsigned long *dr6_p; +#endif + -+ if (cmd != DIE_DEBUG) -+ return ret; -+ -+ local_irq_save(flags); -+ args = ptr; -+ -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)) -+ /* Get from X86 hw_breakpoint_handler. */ -+ dr6_p = (unsigned long *)ERR_PTR(args->err); -+ dr6 = *dr6_p; -+#else -+ dr6 = args->err; -+#endif -+ 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) -+ continue; -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)) -+ /* Because KGTP handle all the hw-breakpoints. -+ So Just clear it. */ -+ (*dr6_p) &= ~(0x1 << i); -+#endif -+ if (gtp_hwb[i].watch == NULL) -+ continue; -+ /* Check if gtp_hwb is updated in other CPU. */ -+ if (__get_cpu_var(gtp_hwb_sync_count_local) != gtp_hwb_sync_count) { -+ unsigned long addr; -+ -+ gtp_get_debugreg(addr, i); -+ if (addr != gtp_hwb[i].addr) -+ continue; -+ } -+ preempt_disable(); -+ { -+ struct gtp_trace_s gts; -+ -+ memset(>s, 0, sizeof(struct gtp_trace_s)); -+ gts.tpe = gtp_hwb[i].watch; -+ gts.regs = args->regs; -+ gts.hwb = >p_hwb[i]; -+ gtp_handler(>s); -+ } -+ preempt_enable_no_resched(); -+ } -+ -+ /* 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); -+ __get_cpu_var(gtp_hwb_sync_count_local) = gtp_hwb_sync_count; -+ } -+ -+ set_debugreg(gtp_hwb_dr7, 7); -+ read_unlock(>p_hwb_lock); -+ -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)) -+ /* If have some other traps, let other handler handle it. */ -+ if ((dr6 & (~0xf)) == 0) -+ ret = NOTIFY_STOP; -+#else -+ set_debugreg(0UL, 6); -+ ret = NOTIFY_STOP; -+#endif -+ -+out: -+ local_irq_restore(flags); -+ return ret; -+} -+ -+static struct notifier_block gtp_notifier = { -+ .notifier_call = gtp_notifier_call, -+ .priority = 0x7fffffff /* we need to be notified first */ -+}; -+#endif -+ +static unsigned int +gtp_hwb_size_to_arch(int size) +{ @@ -9474,7 +9766,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; @@ -9531,7 +9823,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. */ @@ -9594,54 +9886,74 @@ + tasklet_kill(&tpe->disable_tasklet); + tasklet_kill(&tpe->enable_tasklet); +#endif ++ } ++ ++#ifdef CONFIG_X86 ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,0,0)) ++ if (gtp_have_step || gtp_have_watch_tracepoint) ++#else ++ if (gtp_have_step) ++#endif ++ unregister_die_notifier(>p_notifier); ++ ++ { ++ /* Init data of while-stepping. */ ++ int cpu; ++ for_each_online_cpu(cpu) { ++ struct gtp_step_s *step = &per_cpu(gtp_step, cpu); ++ ++ spin_lock(&step->lock); ++ step->step = 0; ++ step->tpe = NULL; ++ spin_unlock(&step->lock); ++ } + } ++#endif + +#ifdef CONFIG_X86 + /* Stop hwb. */ ++ if (gtp_have_watch_tracepoint) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,0)) -+ { -+ int i; ++ { ++ int i; + -+ /* Register hw breakpoints. */ -+ for (i = 0; i < HWB_NUM; i++) { -+ unregister_wide_hw_breakpoint(breakinfo[i].pev); -+ breakinfo[i].pev = NULL; ++ /* Register hw breakpoints. */ ++ for (i = 0; i < HWB_NUM; i++) { ++ unregister_wide_hw_breakpoint(breakinfo[i].pev); ++ breakinfo[i].pev = NULL; ++ } + } -+ } +#endif + -+ gtp_hwb_stop(NULL); ++ gtp_hwb_stop(NULL); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)) -+ smp_call_function(gtp_hwb_stop, NULL, 1); ++ smp_call_function(gtp_hwb_stop, NULL, 1); +#else -+ smp_call_function(gtp_hwb_stop, NULL, 0, 1); ++ smp_call_function(gtp_hwb_stop, NULL, 0, 1); +#endif + -+ for (tpe = gtp_list; tpe; tpe = tpe->next) { -+ if (tpe->type == gtp_entry_kprobe -+ || (tpe->flags & GTP_ENTRY_FLAGS_REG) == 0 -+ || tpe->disable) -+ continue; ++ for (tpe = gtp_list; tpe; tpe = tpe->next) { ++ if (tpe->type == gtp_entry_kprobe ++ || (tpe->flags & GTP_ENTRY_FLAGS_REG) == 0 ++ || tpe->disable) ++ continue; + -+ if (tpe->type == gtp_entry_watch_static) -+ gtp_unregister_hwb(tpe->addr, 0); ++ if (tpe->type == gtp_entry_watch_static) ++ gtp_unregister_hwb(tpe->addr, 0); + -+ tpe->flags &= ~GTP_ENTRY_FLAGS_REG; ++ tpe->flags &= ~GTP_ENTRY_FLAGS_REG; + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30)) -+ tasklet_kill(&tpe->disable_tasklet); -+ tasklet_kill(&tpe->enable_tasklet); ++ tasklet_kill(&tpe->disable_tasklet); ++ tasklet_kill(&tpe->enable_tasklet); +#endif -+ } ++ } + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)) -+ unregister_kprobe(>p_ipi_kp); ++ unregister_kprobe(>p_ipi_kp); +#endif -+ -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,0,0)) -+ unregister_die_notifier(>p_notifier); ++ } +#endif -+#endif + +#ifdef GTP_PERF_EVENTS + list_for_each(cur, >p_var_list) { @@ -9713,6 +10025,10 @@ + gtp_frame_reset(); + + gtpro_list_clear(); ++#ifdef CONFIG_X86 ++ gtp_have_watch_tracepoint = 0; ++ gtp_have_step = 0; ++#endif + + gtp_var_release(0); + @@ -9827,12 +10143,13 @@ +} + +static int -+gtp_add_backtrace_actions(struct gtp_entry *tpe) ++gtp_add_backtrace_actions(struct gtp_entry *tpe, int step) +{ + struct action *ae, *new_ae; + int got_r = 0, got_m = 0; + -+ for (ae = tpe->action_list; ae; ae = ae->next) { ++ for (ae = step ? tpe->step_action_list : tpe->action_list; ++ ae; ae = ae->next) { + if (ae->type == 'R') + got_r = 1; + else if (ae->type == 'M' && ae->u.m.regnum == GTP_SP_NUM @@ -9840,7 +10157,9 @@ + got_m = 1; + + if (got_r && got_m) -+ break; ++ return 1; ++ ++ /* Let ae point to the last entry of action_list. */ + if (!ae->next) + break; + } @@ -9851,8 +10170,14 @@ + return -ENOMEM; + if (ae) + ae->next = new_ae; -+ else -+ tpe->action_list = ae; ++ else { ++ if (step) ***The diff for this file has been truncated for email.*** ======================================= --- /trunk/gtp_older_to_2.6.19.patch Sun Feb 17 20:54:51 2013 +++ /trunk/gtp_older_to_2.6.19.patch Mon May 6 19:06:35 2013 @@ -3655,7 +3655,7 @@ --- /dev/null +++ b/lib/gtp.c -@@ -0,0 +1,12093 @@ +@@ -0,0 +1,12887 @@ +/* + * Kernel GDB tracepoint module. + * @@ -3673,12 +3673,12 @@ + * along with this program; if not, write to the Free Software+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *-+ * Copyright(C) KGTP team (https://code.google.com/p/kgtp/), 2010, 2011, 2012, 2013
++ * Copyright(C) KGTP team (https://code.google.com/p/kgtp/), 2010-2013 + * + */ + +/* If "* 10" means that this is not a release version. */ -+#define GTP_VERSION (20130218) ++#define GTP_VERSION (20130218 * 10) + +#include <linux/version.h> +#ifndef RHEL_RELEASE_VERSION @@ -3757,6 +3757,9 @@ +#include <linux/slab.h> +#include <linux/ctype.h> +#include <asm/atomic.h> ++#ifdef CONFIG_X86 ++#include <asm/debugreg.h> ++#endif +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)) +#include <linux/kdebug.h> +#else @@ -3867,7 +3870,9 @@ + + sizeof(struct gtp_frame_var)) +#endif +#ifdef GTP_RB -+#define GTP_FRAME_HEAD_SIZE (FID_SIZE + sizeof(u64) + sizeof(ULONGEST))++/* The frame head size: FID_HEAD + count id + frame number + pointer to prev frem */ ++#define GTP_FRAME_HEAD_SIZE (FID_SIZE + sizeof(u64) + sizeof(ULONGEST) + sizeof(void *))
++/* The frame head size: FID_PAGE_BEGIN + count id */ +#define GTP_FRAME_PAGE_BEGIN_SIZE (FID_SIZE + sizeof(u64)) +#endif +#ifdef GTP_FTRACE_RING_BUFFER @@ -3950,7 +3955,7 @@ +/* This gtp entry is registered inside the system. */ +#define GTP_ENTRY_FLAGS_REG 2 +/* See $no_self_trace. */ -+#define GTP_ENTRY_FLAGS_NO_SELF_TRACE 4 ++#define GTP_ENTRY_FLAGS_SELF_TRACE 4 +/* This gtp entry has passcount. */ +#define GTP_ENTRY_FLAGS_HAVE_PASS 8 +/* See $printk_level. */ @@ -4121,14 +4126,32 @@ + +static pid_t gtp_current_pid; + ++#ifdef CONFIG_X86 ++/* Following part is for while-stepping. */ ++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); ++#endif ++ +#ifdef CONFIG_X86 ++static int gtp_have_watch_tracepoint; ++static int gtp_have_step; ++#endif ++ ++#ifdef CONFIG_X86 ++/* Following part is for watch tracepoint. */ +/* This part is X86 special. */ +#define HWB_NUM 4 + +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 { @@ -4206,16 +4229,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; + } +} @@ -4226,11 +4249,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); +} + @@ -4238,11 +4261,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 @@ -4397,7 +4420,7 @@ + GTP_VAR_PRINTK_LEVEL_ID = 11, + GTP_VAR_PRINTK_FORMAT_ID = 12, + GTP_VAR_DUMP_STACK_ID = 13, -+ GTP_VAR_NO_SELF_TRACE_ID = 14, ++ GTP_VAR_SELF_TRACE_ID = 14, + GTP_VAR_CPU_NUMBER_ID = 15, + GTP_VAR_PC_PE_EN_ID = 16, + GTP_VAR_KRET_ID = 17, @@ -4430,8 +4453,11 @@ + GTP_WATCH_VAL_ID = 42, + GTP_WATCH_COUNT_ID = 43, + ++ GTP_STEP_COUNT_ID = 44, ++ GTP_STEP_ID_ID = 45, ++ + GTP_VAR_SPECIAL_MIN = GTP_VAR_VERSION_ID, -+ GTP_VAR_SPECIAL_MAX = GTP_WATCH_COUNT_ID, ++ GTP_VAR_SPECIAL_MAX = GTP_STEP_ID_ID, +}; + +enum pe_tv_id { @@ -5440,6 +5466,44 @@ +}; +#endif + ++#ifdef GTP_RB ++static int ++gtp_step_count_hooks_get_val(struct gtp_trace_s *gts, struct gtp_var *gtv, ++ int64_t *val) ++{ ++ if (gts->step) ++ *val = gts->tpe->step - gts->step + 1; ++ else ++ *val = 0; ++ ++ return 0; ++} ++ ++static struct gtp_var_hooks gtp_step_count_hooks = { ++ .agent_get_val = gtp_step_count_hooks_get_val, ++}; ++ ++static DEFINE_PER_CPU(int64_t, gtp_step_id); ++ ++static int ++gtp_step_id_hooks_get_val(struct gtp_trace_s *gts, struct gtp_var *gtv, ++ int64_t *val) ++{ ++ if (!gts->step) { ++ if (++ __get_cpu_var(gtp_step_id) == 0) ++ __get_cpu_var(gtp_step_id) = 1; ++ } ++ ++ *val = __get_cpu_var(gtp_step_id); ++ ++ return 0; ++} ++ ++static struct gtp_var_hooks gtp_step_id_hooks = { ++ .agent_get_val = gtp_step_id_hooks_get_val, ++}; ++#endif ++ +static int +gtp_var_special_add_all(void) +{ @@ -5532,8 +5596,8 @@ + if (IS_ERR(var)) + return PTR_ERR(var); + -+ var = gtp_var_special_add(GTP_VAR_NO_SELF_TRACE_ID, 0, 0, -+ "no_self_trace", NULL); ++ var = gtp_var_special_add(GTP_VAR_SELF_TRACE_ID, 0, 0, ++ "self_trace", NULL); + if (IS_ERR(var)) + return PTR_ERR(var); + @@ -5659,6 +5723,16 @@ + if (IS_ERR(var)) + return PTR_ERR(var); +#endif ++ var = gtp_var_special_add(GTP_STEP_COUNT_ID, 0, 0, ++ "step_count", >p_step_count_hooks); ++ if (IS_ERR(var)) ++ return PTR_ERR(var); ++#ifdef GTP_RB ++ var = gtp_var_special_add(GTP_STEP_ID_ID, 0, 0, ++ "step_id", >p_step_id_hooks); ++ if (IS_ERR(var)) ++ return PTR_ERR(var); ++#endif + + return 0; +} @@ -7231,6 +7305,11 @@ + } while (0) +#endif + ++static int gtp_collect_var(struct gtp_trace_s *gts, int num); ++#ifdef GTP_RB ++static int gtp_var_array_step_id_id = 0; ++#endif ++ +static int +gtp_action_head(struct gtp_trace_s *gts) +{ @@ -7279,6 +7358,13 @@ + + trace_nump = (ULONGEST *)tmp; + *trace_nump = gts->tpe->num; ++ tmp += sizeof(ULONGEST); ++ ++#ifdef GTP_RB ++ *(void **)tmp = gtp_rb_prev_frame_get(gts->next); ++ gtp_rb_prev_frame_set(gts->next, (void *)(tmp + sizeof(void *) ++ - GTP_FRAME_HEAD_SIZE)); ++#endif + +#ifdef GTP_FTRACE_RING_BUFFER + ring_buffer_unlock_commit(gtp_frame, rbe); @@ -7287,6 +7373,14 @@ + + atomic_inc(>p_frame_create); + ++#ifdef GTP_RB ++ /* Auto collect $step_id. */ ++ if (gts->tpe->step) { ++ if (gtp_collect_var(gts, gtp_var_array_step_id_id)) ++ return -1; ++ } ++#endif ++ + return 0; +} + @@ -7729,6 +7823,8 @@ + + return ret; +} ++ ++/* The number is not the ID of tvar, it is the ID of gtp_var_array. */ + +static int +gtp_collect_var(struct gtp_trace_s *gts, int num) @@ -8384,6 +8480,30 @@ +} +#endif + ++#ifdef CONFIG_X86 ++/* while-stepping stop. */ ++ ++static void ++gtp_step_stop(struct pt_regs *regs) ++{ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,24)) ++ regs->flags &= ~(X86_EFLAGS_TF); ++#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; ++} ++#endif ++ +static void +gtp_handler(struct gtp_trace_s *gts) +{ @@ -8393,6 +8513,10 @@ + printk(GTP_DEBUG_V "gtp_handler: tracepoint %d %p\n", + (int)gts->tpe->num, (void *)(CORE_ADDR)gts->tpe->addr); +#endif ++#ifdef CONFIG_X86 ++ if (gts->step == 0 && __get_cpu_var(gtp_step).step) ++ gtp_step_stop(gts->regs); ++#endif + + gts->read_memory = (void *)probe_kernel_read; + if (gts->tpe->flags & GTP_ENTRY_FLAGS_CURRENT_TASK) { @@ -8409,7 +8533,7 @@ + return; +#endif + -+ if ((gts->tpe->flags & GTP_ENTRY_FLAGS_NO_SELF_TRACE) ++ if ((gts->tpe->flags & GTP_ENTRY_FLAGS_SELF_TRACE) == 0 + && (get_current()->pid == gtp_gtp_pid + || get_current()->pid == gtp_gtpframe_pid)) { + return; @@ -8434,7 +8558,7 @@ + gts->run = NULL; + + /* Pass. */ -+ if (gts->tpe->flags & GTP_ENTRY_FLAGS_HAVE_PASS) { ++ if (gts->step == 0 && gts->tpe->flags & GTP_ENTRY_FLAGS_HAVE_PASS) { + if (atomic_dec_return(>s->tpe->current_pass) < 0) + goto tpe_stop; + } @@ -8594,18 +8718,47 @@ + struct kretprobe *kpret; + struct gtp_kp *gkp; + union gtp_entry_u *u; ++ struct gtp_entry *tpe; + struct gtp_trace_s gts; + -+ memset(>s, 0, sizeof(struct gtp_trace_s)); -+ + kpret = container_of(p, struct kretprobe, kp); + gkp = container_of(kpret, struct gtp_kp, kpret); + u = container_of(gkp, union gtp_entry_u, kp); -+ gts.tpe = container_of(u, struct gtp_entry, u); -+ gts.regs = regs; -+ gts.step = 1; ++ tpe = container_of(u, struct gtp_entry, u); ++ ++ if (tpe->step == 1) { ++ memset(>s, 0, sizeof(struct gtp_trace_s)); ++ ++ gts.tpe = tpe; ++ gts.regs = regs; ++ gts.step = tpe->step; ++ ++ gtp_handler(>s); ++ } + -+ gtp_handler(>s); ++#ifdef CONFIG_X86 ++ 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. */
++ __get_cpu_var(gtp_step).step = tpe->step; ++ __get_cpu_var(gtp_step).tpe = tpe; ++ #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,24)) ++ if (regs->flags & X86_EFLAGS_IF) ++ #else ++ if (regs->eflags & X86_EFLAGS_IF) ++ #endif ++ __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 +} + +static inline void @@ -8886,6 +9039,7 @@ + gtp_list = gtp_list->next; + gtp_action_release(tpe->cond); + gtp_action_release(tpe->action_list); ++ gtp_action_release(tpe->step_action_list); + gtp_src_release(tpe->src); + gtp_src_release(tpe->action_cmd); + gtp_src_release(tpe->printk_str); @@ -9126,6 +9280,238 @@ + + return 0; +} ++ ++#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) ++{ ++ uint32_t opcode; ++ uint8_t opcode8; ++ unsigned long pc = GTP_REGS_PC(regs); ++ ++ /* 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: ++ ++ 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) = pc; ++ break; ++ case 0xfa: ++ /* cli */ ++ __get_cpu_var(gtp_step).irq_need_open = 0; ++ GTP_REGS_PC(regs) = pc; ++ break; ++ case 0x0f07: ++ /* sysret */ ++ return 1; ++ break; ++ }; ++ ++ return 0; ++} ++ ++static int ++gtp_notifier_call(struct notifier_block *self, unsigned long cmd, ++ void *ptr) ++{ ++ int ret = NOTIFY_DONE; ++ unsigned long flags; ++ struct die_args *args; ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,0,0)) ++ int i; ++#endif ++ unsigned long dr6; ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)) ++ unsigned long *dr6_p; ++#endif ++ ++ if (cmd != DIE_DEBUG) ++ return ret; ++ ++ local_irq_save(flags); ++ args = ptr; ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)) ++ /* Get from X86 hw_breakpoint_handler. */ ++ dr6_p = (unsigned long *)ERR_PTR(args->err); ++ dr6 = *dr6_p; ++#else ++ dr6 = args->err; ++#endif ++ gtp_set_debugreg(GTP_HWB_DR7_DEF, 7); ++ ++ /* Handle while-stepping. */ ++ spin_lock(&__get_cpu_var(gtp_step).lock); ++ if ((dr6 & 0x4000) != 0) { ++ /* Clear the bit that handle by KGTP. */ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)) ++ (*dr6_p) &= ~(0x4000); ++#else ++ dr6 &= ~(0x4000); ++#endif ++ if (!__get_cpu_var(gtp_step).tpe || user_mode(args->regs)) ++ gtp_step_stop(args->regs); ++ else { ++ 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)); ++ ++ preempt_disable(); ++ { ++ struct gtp_trace_s gts; ++ ++ memset(>s, 0, sizeof(struct gtp_trace_s)); ++ gts.tpe = __get_cpu_var(gtp_step).tpe; ++ gts.regs = args->regs; ++ gts.step = __get_cpu_var(gtp_step).step; ++ gtp_handler(>s); ++ } ++ preempt_enable_no_resched(); ++ ++ 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)) ++ 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. */ ++ gtp_step_stop(args->regs); ++ } ++ } ++ } ++ spin_unlock(&__get_cpu_var(gtp_step).lock); ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,0,0)) ++ /* Handle watch traceppoint. */ ++ if ((dr6 & 0xf) == 0) ++ goto out; ++ read_lock(>p_hwb_lock); ++ ++ for (i = 0; i < HWB_NUM; i++) { ++ if ((dr6 & (0x1 << i)) == 0) ++ continue; ++ /* Clear the bit that handle by KGTP. */ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)) ++ (*dr6_p) &= ~(0x1 << i); ++#else ++ dr6 &= ~(0x1 << i); ++#endif ++ if (gtp_hwb[i].watch == NULL) ++ continue; ++ /* Check if gtp_hwb is updated in other CPU. */ ++ if (__get_cpu_var(gtp_hwb_sync_count_local) != gtp_hwb_sync_count) { ++ unsigned long addr; ++ ++ gtp_get_debugreg(addr, i); ++ if (addr != gtp_hwb[i].addr) ++ continue; ++ } ++ preempt_disable(); ++ { ++ struct gtp_trace_s gts; ++ ++ memset(>s, 0, sizeof(struct gtp_trace_s)); ++ gts.tpe = gtp_hwb[i].watch; ++ gts.regs = args->regs; ++ gts.hwb = >p_hwb[i]; ++ gtp_handler(>s); ++ } ++ preempt_enable_no_resched(); ++ } ++ ++ /* If the HWB need update in this CPU, just update it. */ ++ if (__get_cpu_var(gtp_hwb_sync_count_local) != gtp_hwb_sync_count) { ++ 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; ++ } ++ ++ gtp_set_debugreg(gtp_hwb_dr7, 7); ++ read_unlock(>p_hwb_lock); ++#endif ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,0,0)) ++out: ++#endif ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33)) ++ 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. */ ++ if (((*dr6_p) & GTP_HWB_DR6_MASK) == 0) ++ ret = NOTIFY_STOP; ++ current->thread.debugreg6 = *dr6_p; ++#else ++ if ((dr6 & GTP_HWB_DR6_MASK) == 0) ++ ret = NOTIFY_STOP; ++ current->thread.debugreg6 = dr6; ++#endif ++ ++ local_irq_restore(flags); ++ return ret; ++} ++ ++static struct notifier_block gtp_notifier = { ++ .notifier_call = gtp_notifier_call, ++ .priority = 0x7ffffffe /* we need to be notified after kprobe. */ ++}; ++#endif + +#ifdef CONFIG_X86 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,0)) @@ -9222,102 +9608,8 @@ + gtp_hw_breakpoint_handler(breakinfo[3].num, regs); +} +#endif -+#else -+static int -+gtp_notifier_call(struct notifier_block *self, unsigned long cmd, -+ void *ptr) -+{ -+ int ret = NOTIFY_DONE; -+ unsigned long flags; -+ struct die_args *args; -+ int i; -+ unsigned long dr6; -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)) -+ unsigned long *dr6_p; +#endif + -+ if (cmd != DIE_DEBUG) -+ return ret; -+ -+ local_irq_save(flags); -+ args = ptr; -+ -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)) -+ /* Get from X86 hw_breakpoint_handler. */ -+ dr6_p = (unsigned long *)ERR_PTR(args->err); -+ dr6 = *dr6_p; -+#else -+ dr6 = args->err; -+#endif -+ 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) -+ continue; -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)) -+ /* Because KGTP handle all the hw-breakpoints. -+ So Just clear it. */ -+ (*dr6_p) &= ~(0x1 << i); -+#endif -+ if (gtp_hwb[i].watch == NULL) -+ continue; -+ /* Check if gtp_hwb is updated in other CPU. */ -+ if (__get_cpu_var(gtp_hwb_sync_count_local) != gtp_hwb_sync_count) { -+ unsigned long addr; -+ -+ gtp_get_debugreg(addr, i); -+ if (addr != gtp_hwb[i].addr) -+ continue; -+ } -+ preempt_disable(); -+ { -+ struct gtp_trace_s gts; -+ -+ memset(>s, 0, sizeof(struct gtp_trace_s)); -+ gts.tpe = gtp_hwb[i].watch; -+ gts.regs = args->regs; -+ gts.hwb = >p_hwb[i]; -+ gtp_handler(>s); -+ } -+ preempt_enable_no_resched(); -+ } -+ -+ /* 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); -+ __get_cpu_var(gtp_hwb_sync_count_local) = gtp_hwb_sync_count; -+ } -+ -+ set_debugreg(gtp_hwb_dr7, 7); -+ read_unlock(>p_hwb_lock); -+ -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)) -+ /* If have some other traps, let other handler handle it. */ -+ if ((dr6 & (~0xf)) == 0) -+ ret = NOTIFY_STOP; -+#else -+ set_debugreg(0UL, 6); -+ ret = NOTIFY_STOP; -+#endif -+ -+out: -+ local_irq_restore(flags); -+ return ret; -+} -+ -+static struct notifier_block gtp_notifier = { -+ .notifier_call = gtp_notifier_call, -+ .priority = 0x7fffffff /* we need to be notified first */ -+}; -+#endif -+ +static unsigned int +gtp_hwb_size_to_arch(int size) +{ @@ -9396,7 +9688,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; @@ -9453,7 +9745,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. */ @@ -9516,54 +9808,74 @@ + tasklet_kill(&tpe->disable_tasklet); + tasklet_kill(&tpe->enable_tasklet); +#endif ++ } ++ ++#ifdef CONFIG_X86 ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,0,0)) ++ if (gtp_have_step || gtp_have_watch_tracepoint) ++#else ++ if (gtp_have_step) ++#endif ++ unregister_die_notifier(>p_notifier); ++ ++ { ++ /* Init data of while-stepping. */ ++ int cpu; ++ for_each_online_cpu(cpu) { ++ struct gtp_step_s *step = &per_cpu(gtp_step, cpu); ++ ++ spin_lock(&step->lock); ++ step->step = 0; ++ step->tpe = NULL; ++ spin_unlock(&step->lock); ++ } + } ++#endif + +#ifdef CONFIG_X86 + /* Stop hwb. */ ++ if (gtp_have_watch_tracepoint) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,0)) -+ { -+ int i; ++ { ++ int i; + -+ /* Register hw breakpoints. */ -+ for (i = 0; i < HWB_NUM; i++) { -+ unregister_wide_hw_breakpoint(breakinfo[i].pev); -+ breakinfo[i].pev = NULL; ++ /* Register hw breakpoints. */ ++ for (i = 0; i < HWB_NUM; i++) { ++ unregister_wide_hw_breakpoint(breakinfo[i].pev); ++ breakinfo[i].pev = NULL; ++ } + } -+ } +#endif + -+ gtp_hwb_stop(NULL); ++ gtp_hwb_stop(NULL); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)) -+ smp_call_function(gtp_hwb_stop, NULL, 1); ++ smp_call_function(gtp_hwb_stop, NULL, 1); +#else -+ smp_call_function(gtp_hwb_stop, NULL, 0, 1); ++ smp_call_function(gtp_hwb_stop, NULL, 0, 1); +#endif + -+ for (tpe = gtp_list; tpe; tpe = tpe->next) { -+ if (tpe->type == gtp_entry_kprobe -+ || (tpe->flags & GTP_ENTRY_FLAGS_REG) == 0 -+ || tpe->disable) -+ continue; ++ for (tpe = gtp_list; tpe; tpe = tpe->next) { ++ if (tpe->type == gtp_entry_kprobe ++ || (tpe->flags & GTP_ENTRY_FLAGS_REG) == 0 ++ || tpe->disable) ++ continue; + -+ if (tpe->type == gtp_entry_watch_static) -+ gtp_unregister_hwb(tpe->addr, 0); ++ if (tpe->type == gtp_entry_watch_static) ++ gtp_unregister_hwb(tpe->addr, 0); + -+ tpe->flags &= ~GTP_ENTRY_FLAGS_REG; ++ tpe->flags &= ~GTP_ENTRY_FLAGS_REG; + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30)) -+ tasklet_kill(&tpe->disable_tasklet); -+ tasklet_kill(&tpe->enable_tasklet); ++ tasklet_kill(&tpe->disable_tasklet); ++ tasklet_kill(&tpe->enable_tasklet); +#endif -+ } ++ } + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)) -+ unregister_kprobe(>p_ipi_kp); ++ unregister_kprobe(>p_ipi_kp); +#endif -+ -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,0,0)) -+ unregister_die_notifier(>p_notifier); ++ } +#endif -+#endif + +#ifdef GTP_PERF_EVENTS + list_for_each(cur, >p_var_list) { @@ -9635,6 +9947,10 @@ + gtp_frame_reset(); + + gtpro_list_clear(); ++#ifdef CONFIG_X86 ++ gtp_have_watch_tracepoint = 0; ++ gtp_have_step = 0; ++#endif + + gtp_var_release(0); + @@ -9749,12 +10065,13 @@ +} + +static int -+gtp_add_backtrace_actions(struct gtp_entry *tpe) ++gtp_add_backtrace_actions(struct gtp_entry *tpe, int step) +{ + struct action *ae, *new_ae; + int got_r = 0, got_m = 0; + -+ for (ae = tpe->action_list; ae; ae = ae->next) { ++ for (ae = step ? tpe->step_action_list : tpe->action_list; ++ ae; ae = ae->next) { + if (ae->type == 'R') + got_r = 1; + else if (ae->type == 'M' && ae->u.m.regnum == GTP_SP_NUM @@ -9762,7 +10079,9 @@ + got_m = 1; + + if (got_r && got_m) -+ break; ++ return 1; ++ ++ /* Let ae point to the last entry of action_list. */ + if (!ae->next) + break; + } @@ -9773,8 +10092,14 @@ + return -ENOMEM; + if (ae) + ae->next = new_ae; -+ else -+ tpe->action_list = ae; ++ else { ++ if (step) ++ tpe->step_action_list = ae; ++ else ++ tpe->action_list = ae; ++ } ++ ++ /* Because new_ae is the new tail. So set it to ae. */ + ae = new_ae; + } + @@ -9786,15 +10111,19 @@ + new_ae->u.m.size = gtp_bt_size; + if (ae) + ae->next = new_ae; -+ else -+ tpe->action_list = ae; ++ else { ++ if (step) ++ tpe->step_action_list = ae; ++ else ++ tpe->action_list = ae; ++ } + } + + return 1; +} + +static int -+gtp_check_getv(struct gtp_entry *tpe, struct action *ae, ++gtp_check_getv(struct gtp_entry *tpe, struct action *ae, int step, + uint8_t *ebuf, unsigned int pc, + struct gtp_x_var **list) +{ @@ -9816,12 +10145,12 @@ + + switch (var->type) { + case gtp_var_special: -+ if (arg == GTP_VAR_NO_SELF_TRACE_ID) { -+ tpe->flags |= GTP_ENTRY_FLAGS_NO_SELF_TRACE; ++ if (arg == GTP_VAR_SELF_TRACE_ID) { ++ tpe->flags |= GTP_ENTRY_FLAGS_SELF_TRACE; + ret = 1; + goto out; + } else if (arg == GTP_VAR_BT_ID) { -+ ret = gtp_add_backtrace_actions (tpe); ++ ret = gtp_add_backtrace_actions (tpe, step); + goto out; + } else if (arg == GTP_VAR_CURRENT_ID) { + tpe->flags |= GTP_ENTRY_FLAGS_CURRENT_TASK; @@ -9890,7 +10219,7 @@ +} + +static int -+gtp_check_setv(struct gtp_entry *tpe, struct action *ae, ++gtp_check_setv(struct gtp_entry *tpe, struct action *ae, int step, + uint8_t *ebuf, unsigned int pc, + struct gtp_x_var **list, int loop, + ULONGEST *stack, ULONGEST top) @@ -9914,8 +10243,8 @@ + switch (var->type) { + case gtp_var_special: + switch (arg) { -+ case GTP_VAR_NO_SELF_TRACE_ID: -+ tpe->flags |= GTP_ENTRY_FLAGS_NO_SELF_TRACE; ++ case GTP_VAR_SELF_TRACE_ID: ++ tpe->flags |= GTP_ENTRY_FLAGS_SELF_TRACE; + ret = 1; + goto out; + break; @@ -9926,7 +10255,7 @@ + goto out; + break; + case GTP_VAR_BT_ID: -+ ret = gtp_add_backtrace_actions (tpe); ++ ret = gtp_add_backtrace_actions (tpe, step); + goto out; + break; + case GTP_VAR_CURRENT_ID: @@ -9935,11 +10264,10 @@ + goto out; + break; + case GTP_VAR_PRINTK_LEVEL_ID: -+ if (loop) { ***The diff for this file has been truncated for email.***