diff -u -r valgrind-3.1.1/memcheck/mc_main.c valgrind-watchpoint/memcheck/mc_main.c --- valgrind-3.1.1/memcheck/mc_main.c 2006-02-22 19:17:04.000000000 +0530 +++ valgrind-watchpoint/memcheck/mc_main.c 2006-05-24 20:40:50.000000000 +0530 @@ -53,6 +53,7 @@ #include "pub_tool_threadstate.h" #include "mc_include.h" +#include "mac_shared.h" /* for ExeContext, malloc */ #include "memcheck.h" /* for client requests */ @@ -136,8 +137,35 @@ /* --------------- Secondary maps --------------- */ +typedef + struct Watchpoint { + UInt id; /* Watchpoint ID (unique) */ + UInt num_times_triggered; /* Count of times this watchpoint hit */ + Addr a; /* Watchpoint address */ + SizeT len; /* Length of watchpoint */ + ExeContext *where_set; /* Where this watchpoint was set */ + struct Watchpoint *next; /* List of watchpoints */ + struct Watchpoint *prev; /* List of watchpoints */ + } + Watchpoint; + +typedef + struct WatchpointData { + Watchpoint *wp; + struct WatchpointData *next; /* Local list of watchpoints */ + struct WatchpointData *prev; /* Local list of watchpoints */ + } + WatchpointData; + +static Bool mc_check_watchpoint ( Addr a, SizeT len, Watchpoint** watchpoint ); + +static UInt current_watchpoint = 0; +static UInt watchpoint_count = 0; +static Watchpoint *watchpoints = NULL; + typedef struct { + WatchpointData *watchpoints; UChar abits[8192]; UChar vbyte[65536]; } @@ -713,6 +741,22 @@ # endif } +static +void mc_watchpoint_message ( Char *event, Watchpoint *wp, ExeContext *e ) +{ + 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 ); + } +} + /* --- Set permissions for arbitrary address ranges --- */ @@ -949,6 +993,163 @@ mc_make_writable, mc_make_noaccess ); + + +static +UInt mc_set_watchpoint ( ThreadId tid, Addr a, SizeT len ) +{ + 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; + if (tid == -1) { + p->where_set = NULL; + } else { + p->where_set = VG_(record_ExeContext(tid)); + } + 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_(free)(p); + + VG_(message)(Vg_UserMsg, "Cleared watchpoint %d", p->id); + + 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; +} + void MC_(helperc_MAKE_STACK_UNINIT) ( Addr base, UWord len ) @@ -1180,6 +1381,14 @@ Addr bad_addr; VGP_PUSHCC(VgpCheckMem); + + + if(1) + { + Watchpoint * wp; + if(watchpoint_count && mc_check_watchpoint ( base, size, &wp )) + mc_watchpoint_message ( "write", wp, VG_(record_ExeContext(tid)) ); + } /* VG_(message)(Vg_DebugMsg,"check is writable: %x .. %x", base,base+size-1); */ @@ -1510,6 +1719,15 @@ SecMap* sm; \ \ PROF_EVENT(200, #nAME); \ + \ + if(1) {\ + Watchpoint* wp;\ + if (watchpoint_count && mc_check_watchpoint(aA, 8, &wp)) {\ + mc_watchpoint_message ( "read", wp,\ + VG_(record_ExeContext(VG_(get_running_tid)())));\ +\ + }\ + }\ \ if (VG_DEBUG_MEMORY >= 2) \ return mc_LOADVn_slow( aA, 8, iS_BIGENDIAN ); \ @@ -1560,6 +1778,15 @@ SecMap* sm; \ \ PROF_EVENT(210, #nAME); \ + \ + if(1) {\ + Watchpoint* wp;\ + if (watchpoint_count && mc_check_watchpoint(aA, 8, &wp)) {\ + mc_watchpoint_message ( "write", wp,\ + VG_(record_ExeContext(VG_(get_running_tid)())));\ +\ + }\ + }\ \ if (VG_DEBUG_MEMORY >= 2) \ mc_STOREVn_slow( aA, 8, vbytes, iS_BIGENDIAN ); \ @@ -1614,6 +1841,15 @@ SecMap* sm; \ \ PROF_EVENT(220, #nAME); \ + \ + if(1) {\ + Watchpoint* wp;\ + if (watchpoint_count && mc_check_watchpoint(aA, 4, &wp)) {\ + mc_watchpoint_message ( "read", wp,\ + VG_(record_ExeContext(VG_(get_running_tid)())));\ +\ + }\ + }\ \ if (VG_DEBUG_MEMORY >= 2) \ return (UWord)mc_LOADVn_slow( aA, 4, iS_BIGENDIAN ); \ @@ -1672,6 +1908,15 @@ SecMap* sm; \ \ PROF_EVENT(230, #nAME); \ + \ + if(1) {\ + Watchpoint* wp;\ + if (watchpoint_count && mc_check_watchpoint(aA, 4, &wp)) {\ + mc_watchpoint_message ( "write", wp,\ + VG_(record_ExeContext(VG_(get_running_tid)())));\ +\ + }\ + }\ \ if (VG_DEBUG_MEMORY >= 2) \ mc_STOREVn_slow( aA, 4, (ULong)vbytes, iS_BIGENDIAN ); \ @@ -1727,6 +1972,15 @@ SecMap* sm; \ \ PROF_EVENT(240, #nAME); \ + \ + if(1) {\ + Watchpoint* wp;\ + if (watchpoint_count && mc_check_watchpoint(aA, 2, &wp)) {\ + mc_watchpoint_message ( "read", wp,\ + VG_(record_ExeContext(VG_(get_running_tid)())));\ +\ + }\ + }\ \ if (VG_DEBUG_MEMORY >= 2) \ return (UWord)mc_LOADVn_slow( aA, 2, iS_BIGENDIAN ); \ @@ -1781,6 +2035,15 @@ SecMap* sm; \ \ PROF_EVENT(250, #nAME); \ + \ + if(1) {\ + Watchpoint* wp;\ + if (watchpoint_count && mc_check_watchpoint(aA, 2, &wp)) {\ + mc_watchpoint_message ( "write", wp,\ + VG_(record_ExeContext(VG_(get_running_tid)())));\ +\ + }\ + }\ \ if (VG_DEBUG_MEMORY >= 2) \ mc_STOREVn_slow( aA, 2, (ULong)vbytes, iS_BIGENDIAN ); \ @@ -1833,6 +2096,15 @@ SecMap* sm; PROF_EVENT(260, "helperc_LOADV1"); + + if(1) { + Watchpoint* wp; + if (watchpoint_count && mc_check_watchpoint(aA, 1, &wp)) { + mc_watchpoint_message ( "read", wp, + VG_(record_ExeContext(VG_(get_running_tid)()))); + + } + } # if VG_DEBUG_MEMORY >= 2 return (UWord)mc_LOADVn_slow( aA, 1, False/*irrelevant*/ ); @@ -1884,6 +2156,15 @@ SecMap* sm; PROF_EVENT(270, "helperc_STOREV1"); + + if(1) { + Watchpoint* wp; + if (watchpoint_count && mc_check_watchpoint(aA, 1, &wp)) { + mc_watchpoint_message ( "write", wp, + VG_(record_ExeContext(VG_(get_running_tid)()))); + + } + } # if VG_DEBUG_MEMORY >= 2 mc_STOREVn_slow( aA, 1, (ULong)vbyte, False/*irrelevant*/ ); @@ -2103,6 +2384,7 @@ sm->vbyte[i] = VGM_BYTE_INVALID; for (i = 0; i < 8192; i++) sm->abits[i] = VGM_BYTE_INVALID; + sm->watchpoints = NULL; /* Set A valid, V invalid. */ sm = &sm_distinguished[SM_DIST_ACCESS_UNDEFINED]; @@ -2110,6 +2392,7 @@ sm->vbyte[i] = VGM_BYTE_INVALID; for (i = 0; i < 8192; i++) sm->abits[i] = VGM_BYTE_VALID; + sm->watchpoints = NULL; /* Set A valid, V valid. */ sm = &sm_distinguished[SM_DIST_ACCESS_DEFINED]; @@ -2117,6 +2400,7 @@ sm->vbyte[i] = VGM_BYTE_VALID; for (i = 0; i < 8192; i++) sm->abits[i] = VGM_BYTE_VALID; + sm->watchpoints = NULL; /* Set up the primary map. */ /* These entries gradually get overwritten as the used address @@ -2497,6 +2781,14 @@ //zz ( tid, arg[1], arg[2], arg[3], True /* set them */ ); //zz break; + case VG_USERREQ__SET_WATCHPOINT: /* set a watchpoint */ + *ret = mc_set_watchpoint ( tid, arg[1], arg[2] ); + break; + + case VG_USERREQ__CLEAR_WATCHPOINT: /* clear a watchpoint */ + *ret = mc_clear_watchpoint ( arg[1] ); + break; + default: if (MAC_(handle_common_client_requests)(tid, arg, ret )) { return True; diff -u -r valgrind-3.1.1/memcheck/memcheck.h valgrind-watchpoint/memcheck/memcheck.h --- valgrind-3.1.1/memcheck/memcheck.h 2006-02-20 20:46:23.000000000 +0530 +++ valgrind-watchpoint/memcheck/memcheck.h 2006-05-24 19:45:26.000000000 +0530 @@ -86,6 +86,9 @@ VG_USERREQ__CREATE_BLOCK, + 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 @@ -251,5 +254,27 @@ _qzz_res; \ })) +/* Set a watchpoint on a piece of memory. +*/ +#define VALGRIND_SET_WATCHPOINT(_qzz_addr,_qzz_len) \ + ({unsigned int _qzz_res; \ + VALGRIND_MAGIC_SEQUENCE(_qzz_res, 0, \ + VG_USERREQ__SET_WATCHPOINT, \ + (unsigned int)(_qzz_addr), \ + (unsigned int)(_qzz_len), 0, 0); \ + _qzz_res; \ + }) + +/* Clear a watchpoint on a piece of memory. +*/ +#define VALGRIND_CLEAR_WATCHPOINT(_wpid) \ + ({unsigned int _qzz_res; \ + VALGRIND_MAGIC_SEQUENCE(_qzz_res, 0, \ + VG_USERREQ__CLEAR_WATCHPOINT, \ + (unsigned int)(_wpid), 0, 0, 0); \ + _qzz_res; \ + }) + + #endif