diff -ru valgrind-3.3.1/memcheck/mc_main.c valgrind-wp-3.3.1/memcheck/mc_main.c --- valgrind-3.3.1/memcheck/mc_main.c 2008-06-01 07:08:48.000000000 +0530 +++ valgrind-wp-3.3.1/memcheck/mc_main.c 2008-08-05 03:58:41.000000000 +0530 @@ -253,7 +253,44 @@ } typedef + struct Watchpoint { + UInt id; + UInt num_times_triggered; + Addr a; + SizeT len; + Addr c; + ExeContext *where_set; + struct Watchpoint *next; + struct Watchpoint *prev; +} +Watchpoint; + +typedef + struct WatchpointData { + Watchpoint *wp; + struct WatchpointData *next; + struct WatchpointData *prev; +} +WatchpointData; + +static Bool mc_check_watchpoint(Addr a, SizeT len, Watchpoint** wp); +static void mc_watchpoint_message ( Char *event, Watchpoint *wp, ExeContext *e ); + +static UInt current_watchpoint = 0; +static UInt watchpoint_count = 0; +static Watchpoint *watchpoints = NULL; + +#define CHECK_MEM_WATCHPOINT(base, size) \ + do {\ + Watchpoint *wp;\ + if(watchpoint_count && mc_check_watchpoint(base, size, &wp)) {\ + mc_watchpoint_message("write", wp, VG_(record_ExeContext)(VG_(get_running_tid)(), 0));\ + }\ + } while(0) + +typedef struct { + WatchpointData *watchpoints; UChar vabits8[SM_CHUNKS]; } SecMap; @@ -1247,6 +1284,8 @@ PROF_EVENT(35, "mc_STOREVn_slow"); + //CHECK_MEM_WATCHPOINT(a, nBits >> 3); + /* ------------ BEGIN semi-fast cases ------------ */ /* These deal quickly-ish with the common auxiliary primary map cases on 64-bit platforms. Are merely a speedup hack; can be @@ -1552,6 +1591,187 @@ } } +/* --- Set watchpoints for arbitrary address ranges -- */ + +static +void mc_watchpoint_message ( Char *event, Watchpoint *wp, ExeContext *e ) +{ + Addr cx = wp->c; + + if(cx && ((unsigned int*)cx)[0] == 0) { + return; + } + + VG_(message)(Vg_UserMsg, "Watchpoint %d event: %s", wp->id, event); + VG_(pp_ExeContext)(e); + VG_(message)(Vg_UserMsg, "This watchpoint has been triggered %d tim%s", + wp->num_times_triggered, + ((wp->num_times_triggered == 1) ? "e" : "es")); + if (wp->where_set == NULL) { + VG_(message)(Vg_UserMsg, "This watchpoint was set on the command line"); + } else { + VG_(message)(Vg_UserMsg, "This watchpoint was set at:"); + VG_(pp_ExeContext)( wp->where_set ); + } +} + +static +UInt mc_set_watchpoint ( ThreadId tid, Addr a, SizeT len, Addr cx ) +{ + Watchpoint* p; + Watchpoint* i; + Addr b, c; + + p = VG_(malloc) (sizeof(Watchpoint)); + p->id = current_watchpoint++; + p->num_times_triggered = 0; + p->a = a; + p->len = len; + p->c = cx; + + if (tid == -1) { + p->where_set = NULL; + } else { + p->where_set = VG_(record_ExeContext(tid, 0)); + } + watchpoint_count++; + + /* + * Add to end of watchpoint list. + */ + + p->next = NULL; + + if(watchpoints == NULL) + { + watchpoints = p; + p->prev = NULL; + } else { + i = watchpoints; + while(i->next) i = i->next; + i->next = p; + p->prev = i; + } + + /* + * Now insert in each secondary map that needs it. + */ + + c = (a + len - 1) >> 16; + for(b = (a >> 16); b <= c; b++) + { + WatchpointData* d = VG_(malloc) (sizeof(WatchpointData)); + + /* ENSURE_MAPPABLE((b << 16), "mc_set_watchpoint"); */ + + d->wp = p; + d->next = primary_map[b]->watchpoints; + d->prev = NULL; + if(d->next) d->next->prev = d; + primary_map[b]->watchpoints = d; + } + + VG_(message)(Vg_UserMsg, "Set watchpoint %d at %p - %p", p->id, a, a + len - 1); + + return p->id; +} + +static +UInt mc_clear_watchpoint ( UInt wpid ) +{ + Watchpoint* p = watchpoints; + Addr b, c; + + DEBUG("mc_clear_watchpoint(%d)\n", wpid); + while (p) + { + if (p->id == wpid) + { + if(p->prev) { + p->prev->next = p->next; + } else { + watchpoints = p->next; + } + if(p->next) { + p->next->prev = p->prev; + } + break; + } + p = p->next; + } + + if (p == NULL) + { + return 1; + } + + c = (p->a + p->len - 1) >> 16; + for(b = (p->a >> 16); b <= c; b++) + { + WatchpointData* d = primary_map[b]->watchpoints; + while(d) + { + if(d->wp == p) + { + if(d->prev) + { + d->prev->next = d->next; + } else { + primary_map[b]->watchpoints = d->next; + } + if(d->next) { + d->next->prev = d->prev; + } + VG_(free)(d); + break; + } + d = d->next; + } + } + + VG_(message)(Vg_UserMsg, "Cleared watchpoint %d", p->id); + VG_(free)(p); + + watchpoint_count--; + + return 0; +} + +static Bool +mc_check_watchpoint ( Addr a, SizeT len, Watchpoint** watchpoint ) +{ + Addr b, c; + + DEBUG("mc_check_watchpoint(%p, %x)\n", a, len); + + c = (a + len) >> 16; + for(b = a >> 16; b <= c; b++) + { + SecMap *m = primary_map[b]; + WatchpointData *d; + d = m->watchpoints; + if(d == NULL) continue; + while(d) + { + Watchpoint *wp = d->wp; + if (((a >= wp->a) && (a < (wp->a + wp->len))) || + (((a + len - 1) >= wp->a) && + ((a + len - 1) < (wp->a + wp->len))) || + ((wp->a >= a) && (wp->a < (a + len))) || + (((wp->a + wp->len - 1) >= a) && + ((wp->a + wp->len - 1) < (a + len)))) { + *watchpoint = wp; + wp->num_times_triggered++; + return True; + } + d = d->next; + } + } + + return False; +} + + /* --- Set permissions for arbitrary address ranges --- */ @@ -2461,6 +2681,8 @@ Addr bad_addr; Bool ok = is_mem_addressable ( base, size, &bad_addr ); + CHECK_MEM_WATCHPOINT(base, size); + if (!ok) { switch (part) { case Vg_CoreSysCall: @@ -3731,10 +3953,12 @@ VG_REGPARM(1) void MC_(helperc_STOREV64be) ( Addr a, ULong vbits64 ) { + CHECK_MEM_WATCHPOINT(a, 8); mc_STOREV64(a, vbits64, True); } VG_REGPARM(1) void MC_(helperc_STOREV64le) ( Addr a, ULong vbits64 ) { + CHECK_MEM_WATCHPOINT(a, 8); mc_STOREV64(a, vbits64, False); } @@ -3869,10 +4093,12 @@ VG_REGPARM(2) void MC_(helperc_STOREV32be) ( Addr a, UWord vbits32 ) { + CHECK_MEM_WATCHPOINT(a, 4); mc_STOREV32(a, vbits32, True); } VG_REGPARM(2) void MC_(helperc_STOREV32le) ( Addr a, UWord vbits32 ) { + CHECK_MEM_WATCHPOINT(a, 4); mc_STOREV32(a, vbits32, False); } @@ -3976,10 +4202,12 @@ VG_REGPARM(2) void MC_(helperc_STOREV16be) ( Addr a, UWord vbits16 ) { + CHECK_MEM_WATCHPOINT(a, 4); mc_STOREV16(a, vbits16, True); } VG_REGPARM(2) void MC_(helperc_STOREV16le) ( Addr a, UWord vbits16 ) { + CHECK_MEM_WATCHPOINT(a, 4); mc_STOREV16(a, vbits16, False); } @@ -4034,6 +4262,8 @@ SecMap* sm; PROF_EVENT(270, "mc_STOREV8"); + + CHECK_MEM_WATCHPOINT(a, 1); #ifndef PERF_FAST_STOREV mc_STOREVn_slow( a, 8, (ULong)vbits8, False/*irrelevant*/ ); @@ -4237,12 +4467,15 @@ /* Build the 3 distinguished secondaries */ sm = &sm_distinguished[SM_DIST_NOACCESS]; for (i = 0; i < SM_CHUNKS; i++) sm->vabits8[i] = VA_BITS8_NOACCESS; + sm->watchpoints = NULL; sm = &sm_distinguished[SM_DIST_UNDEFINED]; for (i = 0; i < SM_CHUNKS; i++) sm->vabits8[i] = VA_BITS8_UNDEFINED; + sm->watchpoints = NULL; sm = &sm_distinguished[SM_DIST_DEFINED]; for (i = 0; i < SM_CHUNKS; i++) sm->vabits8[i] = VA_BITS8_DEFINED; + sm->watchpoints = NULL; /* Set up the primary map. */ /* These entries gradually get overwritten as the used address @@ -4806,6 +5039,22 @@ return True; } + case VG_USERREQ__SET_WATCHPOINT: { /* set a watchpoint */ + Addr a = arg[1]; + SizeT len = arg[2]; + Addr cx = arg[3]; + *ret = mc_set_watchpoint ( tid, a, len, cx ); + return True; + } + + case VG_USERREQ__CLEAR_WATCHPOINT: { /* clear a watchpoint */ + UInt a = arg[1]; + *ret = mc_clear_watchpoint ( a ); + return True; + } + + + default: VG_(message)(Vg_UserMsg, diff -ru valgrind-3.3.1/memcheck/memcheck.h valgrind-wp-3.3.1/memcheck/memcheck.h --- valgrind-3.3.1/memcheck/memcheck.h 2008-06-01 07:08:48.000000000 +0530 +++ valgrind-wp-3.3.1/memcheck/memcheck.h 2008-08-05 03:41:27.000000000 +0530 @@ -93,6 +93,10 @@ VG_USERREQ__MAKE_MEM_DEFINED_IF_ADDRESSABLE, + VG_USERREQ__SET_WATCHPOINT, + VG_USERREQ__CLEAR_WATCHPOINT, + + /* This is just for memcheck's internal use - don't use it */ _VG_USERREQ__MEMCHECK_RECORD_OVERLAP_ERROR = VG_USERREQ_TOOL_BASE('M','C') + 256 @@ -281,5 +285,21 @@ _qzz_res; \ })) +#define VALGRIND_SET_WATCHPOINT(_qzz_addr,_qzz_len, _cx_addr) \ + (__extension__({unsigned int _qzz_res; \ + VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ + VG_USERREQ__SET_WATCHPOINT, \ + _qzz_addr, _qzz_len, _cx_addr, 0, 0); \ + _qzz_res; \ + })) + +#define VALGRIND_CLEAR_WATCHPOINT(_wpid) \ + (__extension__({unsigned int _qzz_res; \ + VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ + VG_USERREQ__CLEAR_WATCHPOINT,\ + (unsigned int)(_wpid), 0, 0, 0, 0); \ + _qzz_res; \ + })) + #endif