Revision: 1574 Author: teawater Date: Tue May 28 22:14:05 2013 Log: Add $watch_prev_val http://code.google.com/p/kgtp/source/detail?r=1574 Modified: /trunk/gtp.c /trunk/gtp.h ======================================= --- /trunk/gtp.c Thu May 9 05:33:59 2013 +++ /trunk/gtp.c Tue May 28 22:14:05 2013 @@ -508,6 +508,10 @@ int size; int type; + /* The previous of the address that this watch tracepoint + watch on. */ + int64_t prev_val; + /* This is the num and address that setup this hardware breakpoints. For the static watch, this is the num and address of this @@ -793,13 +797,14 @@ GTP_WATCH_TRACE_ADDR_ID = 40, GTP_WATCH_ADDR_ID = 41, GTP_WATCH_VAL_ID = 42, + GTP_WATCH_PREV_VAL_ID = 46, 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_STEP_ID_ID, + GTP_VAR_SPECIAL_MAX = GTP_WATCH_PREV_VAL_ID, }; enum pe_tv_id { @@ -1751,10 +1756,56 @@ .agent_get_val = gtp_watch_get_val, }; +static int gtp_get_addr_val(CORE_ADDR addr, int size, int64_t *val); + static int gtp_watch_val_get_val(struct gtp_trace_s *gts, struct gtp_var *gtv, int64_t *val) { + int ret; + + if (gts->tpe->type == gtp_entry_kprobe) + return -EINVAL; + + if (gts->hwb_current_val_gotten) { + *val = gts->hwb_current_val; + return 0; + } + + ret = gtp_get_addr_val(gts->hwb->addr, gts->hwb->size, val); + if (ret == 0) { + gts->hwb_current_val = *val; + gts->hwb_current_val_gotten = 1; + } + + return ret; +} + +static struct gtp_var_hooks gtp_watch_val_hooks = { + .agent_get_val = gtp_watch_val_get_val, +}; + +static int +gtp_watch_prev_val_get_val(struct gtp_trace_s *gts, struct gtp_var *gtv, + int64_t *val) +{ + if (gts->tpe->type == gtp_entry_kprobe) + return -EINVAL; + + *val = gts->hwb->prev_val; + return 0; +} + +static struct gtp_var_hooks gtp_watch_prev_val_hooks = { + .agent_get_val = gtp_watch_prev_val_get_val, +}; +#endif + +static int +gtp_get_addr_val(CORE_ADDR addr, int size, int64_t *val) +{ + int ret = -EINVAL; + union { union { uint8_t bytes[1]; @@ -1774,40 +1825,44 @@ } u64; } cnv; - if (gts->tpe->type == gtp_entry_kprobe) - return -1; - - switch (gts->hwb->size) { + switch (size) { case 1: - if (probe_kernel_read(cnv.u8.bytes, (void *)gts->hwb->addr, 1)) - return -1; + ret = probe_kernel_read(cnv.u8.bytes, (void *)addr, 1); + if (ret) + goto error; *val = (int64_t) cnv.u8.val; break; case 2: - if (probe_kernel_read(cnv.u16.bytes, (void *)gts->hwb->addr, 2)) - return -1; + ret = probe_kernel_read(cnv.u16.bytes, (void *)addr, 2); + if (ret) + goto error; *val = (int64_t) cnv.u16.val; break; case 4: - if (probe_kernel_read(cnv.u32.bytes, (void *)gts->hwb->addr, 4)) - return -1; + ret = probe_kernel_read(cnv.u32.bytes, (void *)addr, 4); + if (ret) + goto error; *val = (int64_t) cnv.u32.val; break; case 8: - if (probe_kernel_read(cnv.u64.bytes, (void *)gts->hwb->addr, 8)) - return -1; + ret = probe_kernel_read(cnv.u64.bytes, (void *)addr, 8); + if (ret) + goto error; *val = (int64_t) cnv.u64.val; break; + default: + goto error; + break; } return 0; + +error: + printk(KERN_WARNING "KGTP: fail get value from address %p size %d.\n", + (void *)addr, size); + return ret; } -static struct gtp_var_hooks gtp_watch_val_hooks = { - .agent_get_val = gtp_watch_val_get_val, -}; -#endif - #ifdef GTP_RB static int gtp_step_count_hooks_get_val(struct gtp_trace_s *gts, struct gtp_var *gtv, @@ -2059,6 +2114,10 @@ var = gtp_var_special_add(GTP_WATCH_VAL_ID, 0, 0, "watch_val", >p_watch_val_hooks); if (IS_ERR(var)) + return PTR_ERR(var); + var = gtp_var_special_add(GTP_WATCH_PREV_VAL_ID, 0, 0, + "watch_prev_val", >p_watch_prev_val_hooks); + if (IS_ERR(var)) return PTR_ERR(var); var = gtp_var_special_add(GTP_WATCH_COUNT_ID, 0, 0, "watch_count", >p_watch_get_hooks); @@ -5622,6 +5681,28 @@ return 0; } + +static void +gtp_hw_breakpoint_handler_1 (struct gtp_hwb_s *hwb, struct pt_regs *regs) +{ + struct gtp_trace_s gts; + + preempt_disable(); + + memset(>s, 0, sizeof(struct gtp_trace_s)); + gts.tpe = hwb->watch; + gts.regs = regs; + gts.hwb = hwb; + gtp_handler(>s); + + preempt_enable_no_resched(); + + /* Update hwb->prev_val. */ + if (gts.hwb_current_val_gotten) + hwb->prev_val = gts.hwb_current_val; + else + gtp_get_addr_val(hwb->addr, hwb->size, &(hwb->prev_val)); +} #ifdef CONFIG_X86 #define ADDR_PREFIX_OPCODE 0x67 @@ -5802,17 +5883,7 @@ 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(); + gtp_hw_breakpoint_handler_1(>p_hwb[i], args->regs); } /* If the HWB need update in this CPU, just update it. */ @@ -5874,17 +5945,7 @@ } } - preempt_disable(); - { - struct gtp_trace_s gts; - - memset(>s, 0, sizeof(struct gtp_trace_s)); - gts.tpe = gtp_hwb[num].watch; - gts.regs = regs; - gts.hwb = >p_hwb[num]; - gtp_handler(>s); - } - preempt_enable_no_resched(); + gtp_hw_breakpoint_handler_1(>p_hwb[num], regs); read_unlock(>p_hwb_lock); } @@ -6007,6 +6068,12 @@ write_lock_irqsave(>p_hwb_lock, flags); if (!list_empty(>p_hwb_unused_list)) { int num; + int64_t prev_val; + + /* Get the value from address that will watch as prev value. */ + ret = gtp_get_addr_val(arg->addr, arg->size, &prev_val); + if (ret) + goto out; hwb = list_first_entry(>p_hwb_unused_list, struct gtp_hwb_s, node); list_del_init(&hwb->node); @@ -6015,6 +6082,7 @@ memcpy((void *)&arg->node, (void *)&hwb->node, sizeof (hwb->node)); memcpy(hwb, arg, sizeof(struct gtp_hwb_s)); hwb->num = num; + hwb->prev_val = prev_val; /* Update gtp_hwb_dr7 and gtp_hwb_drx[num]. */ /* Set Gx. */ @@ -6048,6 +6116,7 @@ ret = 0; } +out: write_unlock_irqrestore(>p_hwb_lock, flags); if (ret == 0 && !nowait) ======================================= --- /trunk/gtp.h Fri Apr 12 00:19:48 2013 +++ /trunk/gtp.h Tue May 28 22:14:05 2013 @@ -114,6 +114,10 @@ HWB point to the struct. If not, it will set to NULL. */ struct gtp_hwb_s *hwb; + /* hwb_current_val have the value of hwb address watch + when hwb_current_val_gotten is true. */ + int64_t hwb_current_val; + int hwb_current_val_gotten; int64_t printk_tmp; unsigned int printk_level;