diff -rNu valgrind/memcheck/docs/mc_main.html valgrind-watchpoints/memcheck/docs/mc_main.html --- valgrind/memcheck/docs/mc_main.html 2004-11-23 12:31:25.000000000 -0800 +++ valgrind-watchpoints/memcheck/docs/mc_main.html 2005-01-19 22:01:43.000000000 -0800 @@ -135,6 +135,32 @@ applied to the post-instrumented intermediate code, aimed at removing redundant value checks.

+

  • --watchpoint=WP,...

    + Set watchpoints. WP is the watchpoint specifier, + and is of the form ADDR, ADDR+LEN + or ADDR-END. +

    + The first form sets a one-byte watchpoint at address + ADDR. The second form sets a watchpoint + starting at address ADDR and ending at address + ADDR+LEN. The third form sets a watchpoint starting at + address ADDR and ending at address END. + Addresses and lengths prefixed by 0x are assumed to + be hexadecimal numbers. All other forms are assumed to be decimal. +

    + All memory operations that occur within the watchpoint address + range are reported by Valgrind, along with a stack backtrace + from the triggering instruction and the watchpoint details. + Operations reported are: +

    +

    @@ -779,9 +805,10 @@

    3.7  Client Requests

    -The following client requests are defined in memcheck.h. They -also work for Addrcheck. See memcheck.h for exact -details of their arguments. +The following client requests are defined in memcheck.h. +With the exception of the watchpoint requests, they also work for +Addrcheck. See memcheck.h for exact details of their +arguments. diff -rNu valgrind/memcheck/mc_main.c valgrind-watchpoints/memcheck/mc_main.c --- valgrind/memcheck/mc_main.c 2005-02-01 15:17:10.000000000 -0800 +++ valgrind-watchpoints/memcheck/mc_main.c 2005-02-01 15:18:25.654592371 -0800 @@ -32,6 +32,7 @@ #include "mc_include.h" #include "memcheck.h" /* for client requests */ +#include "vg_skin.h" /* for ExeContext, malloc */ //#include "vg_profile.c" /* Define to debug the mem audit system. */ @@ -107,7 +108,30 @@ /*------------------------------------------------------------*/ 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 ); + +typedef struct { + WatchpointData *watchpoints; UChar abits[8192]; UChar vbyte[65536]; } @@ -116,6 +140,11 @@ static SecMap* primary_map[ /*65536*/ 262144 ]; static SecMap distinguished_secondary_map; +static UInt current_watchpoint = 0; +static UInt watchpoint_count = 0; +static Watchpoint *watchpoints = NULL; +static Watchpoint *deferred_watchpoints = NULL; + static void init_shadow_memory ( void ) { Int i; @@ -125,6 +154,8 @@ for (i = 0; i < 65536; i++) /* Invalid Value */ distinguished_secondary_map.vbyte[i] = VGM_BYTE_INVALID; + distinguished_secondary_map.watchpoints = NULL; + /* These entries gradually get overwritten as the used address space expands. */ for (i = 0; i < 65536; i++) @@ -396,6 +427,33 @@ set_address_range_perms ( a, len, VGM_BIT_INVALID, VGM_BIT_INVALID ); } +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 ); + } +} + +static __inline__ +void make_stack_noaccess ( Addr a, SizeT len ) +{ + Watchpoint *wp; + DEBUG("mc_make_stack_noaccess(%p, %x)\n", a, len); + if(watchpoint_count && mc_check_watchpoint ( a, len, &wp)) + mc_watchpoint_message ( "out of scope", wp, + VG_(get_ExeContext(VG_(get_VCPU_tid)()))); + mc_make_noaccess ( a, len ); +} + static void mc_make_writable ( Addr a, SizeT len ) { PROF_EVENT(36); @@ -403,6 +461,17 @@ set_address_range_perms ( a, len, VGM_BIT_VALID, VGM_BIT_INVALID ); } +static __inline__ +void make_stack ( Addr a, SizeT len ) +{ + Watchpoint *wp; + DEBUG("mc_make_stack(%p, %x)\n", a, len); + if(watchpoint_count && mc_check_watchpoint ( a, len, &wp)) + mc_watchpoint_message ( "in scope", wp, + VG_(get_ExeContext(VG_(get_VCPU_tid)()))); + mc_make_writable ( a, len ); +} + static void mc_make_readable ( Addr a, SizeT len ) { PROF_EVENT(37); @@ -416,9 +485,13 @@ SecMap* sm; UInt sm_off; UChar mask; + Watchpoint *wp; VGP_PUSHCC(VgpESPAdj); ENSURE_MAPPABLE(a, "make_aligned_word_writable"); + if(watchpoint_count && mc_check_watchpoint ( a, 4, &wp)) + mc_watchpoint_message ( "in scope", wp, + VG_(get_ExeContext(VG_(get_VCPU_tid)()))); sm = primary_map[a >> 16]; sm_off = a & 0xFFFF; ((UInt*)(sm->vbyte))[sm_off >> 2] = VGM_WORD_INVALID; @@ -435,9 +508,13 @@ SecMap* sm; UInt sm_off; UChar mask; + Watchpoint *wp; VGP_PUSHCC(VgpESPAdj); ENSURE_MAPPABLE(a, "make_aligned_word_noaccess"); + if(watchpoint_count && mc_check_watchpoint ( a, 4, &wp)) + mc_watchpoint_message ( "out of scope", wp, + VG_(get_ExeContext(VG_(get_VCPU_tid)()))); sm = primary_map[a >> 16]; sm_off = a & 0xFFFF; ((UInt*)(sm->vbyte))[sm_off >> 2] = VGM_WORD_INVALID; @@ -454,9 +531,13 @@ { SecMap* sm; UInt sm_off; + Watchpoint *wp; VGP_PUSHCC(VgpESPAdj); ENSURE_MAPPABLE(a, "make_aligned_doubleword_writable"); + if(watchpoint_count && mc_check_watchpoint ( a, 8, &wp)) + mc_watchpoint_message ( "in scope", wp, + VG_(get_ExeContext(VG_(get_VCPU_tid)()))); sm = primary_map[a >> 16]; sm_off = a & 0xFFFF; sm->abits[sm_off >> 3] = VGM_BYTE_VALID; @@ -470,9 +551,13 @@ { SecMap* sm; UInt sm_off; + Watchpoint *wp; VGP_PUSHCC(VgpESPAdj); ENSURE_MAPPABLE(a, "make_aligned_doubleword_noaccess"); + if(watchpoint_count && mc_check_watchpoint ( a, 8, &wp)) + mc_watchpoint_message ( "out of scope", wp, + VG_(get_ExeContext(VG_(get_VCPU_tid)()))); sm = primary_map[a >> 16]; sm_off = a & 0xFFFF; sm->abits[sm_off >> 3] = VGM_BYTE_INVALID; @@ -486,10 +571,161 @@ make_aligned_word_noaccess, make_aligned_doubleword_writable, make_aligned_doubleword_noaccess, - mc_make_writable, - mc_make_noaccess + make_stack, + make_stack_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_(get_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 void +mc_deferred_watchpoint ( Addr a, SizeT len ) +{ + Watchpoint *wp = VG_(malloc) (sizeof(Watchpoint)); + wp->a = a; + wp->len = len; + wp->next = NULL; + if (deferred_watchpoints == NULL) { + deferred_watchpoints = wp; + wp->prev = NULL; + } else { + Watchpoint *x = deferred_watchpoints; + while(x->next) x = x->next; + x->next = wp; + wp->prev = x; + } +} + +static void +mc_init_deferred_watchpoints () +{ + Watchpoint *wp = deferred_watchpoints; + while(wp) { + Watchpoint *x = wp; + mc_set_watchpoint ( -1, wp->a, wp->len ); + wp = wp->next; + VG_(free)(x); + } +} + +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; +} + /* Block-copy permissions (needed for implementing realloc()). */ static void mc_copy_address_range_state ( Addr src, Addr dst, SizeT len ) { @@ -584,6 +820,40 @@ return MC_Ok; } +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; +} + /* Check a zero-terminated ascii string. Tricky -- don't want to examine the actual bytes, to find the end, until we're sure it is @@ -625,9 +895,13 @@ { Bool ok; Addr bad_addr; + Watchpoint* wp; VGP_PUSHCC(VgpCheckMem); + if(watchpoint_count && mc_check_watchpoint ( base, size, &wp )) + mc_watchpoint_message ( "write", wp, VG_(get_ExeContext(tid)) ); + /* VG_(message)(Vg_DebugMsg,"check is writable: %x .. %x", base,base+size-1); */ ok = mc_check_writable ( base, size, &bad_addr ); @@ -657,9 +931,13 @@ { Addr bad_addr; MC_ReadResult res; + Watchpoint* wp; VGP_PUSHCC(VgpCheckMem); + if(watchpoint_count && mc_check_watchpoint ( base, size, &wp )) + mc_watchpoint_message ( "read", wp, VG_(get_ExeContext(tid)) ); + /* VG_(message)(Vg_DebugMsg,"check is readable: %x .. %x", base,base+size-1); */ res = mc_check_readable ( base, size, &bad_addr ); @@ -722,6 +1000,13 @@ static void mc_new_mem_heap ( Addr a, SizeT len, Bool is_inited ) { + Watchpoint *wp; + if(watchpoint_count && mc_check_watchpoint(a, len, &wp)) { +/* ThreadId tid = VG_(get_current_or_recent_tid) (); + ThreadState *tst = VG_(get_ThreadState)(tid); */ + mc_watchpoint_message ( "malloc", wp, + VG_(get_ExeContext(VG_(get_VCPU_tid)()))); + } if (is_inited) { mc_make_readable(a, len); } else { @@ -730,6 +1015,19 @@ } static +void mc_die_mem_heap ( Addr a, SizeT len ) +{ + Watchpoint *wp; + if(watchpoint_count && mc_check_watchpoint(a, len, &wp)) { +/* ThreadId tid = VG_(get_current_or_recent_tid) (); + ThreadState *tst = VG_(get_ThreadState)(tid); */ + mc_watchpoint_message ( "free", wp, + VG_(get_ExeContext(VG_(get_VCPU_tid)()))); + } + mc_make_noaccess (a, len); +} + +static void mc_set_perms (Addr a, SizeT len, Bool rr, Bool ww, Bool xx) { DEBUG("mc_set_perms(%p, %llu, rr=%u ww=%u, xx=%u)\n", @@ -808,7 +1106,11 @@ REGPARM(1) UInt MC_(helperc_LOADV4) ( Addr a ) { + Watchpoint* wp; # ifdef VG_DEBUG_MEMORY + if(watchpoint_count && mc_check_watchpoint(a, 4, &wp)) + mc_watchpoint_message ( "read", wp, + VG_(get_ExeContext(VG_(get_VCPU_tid)()))); return mc_rd_V4_SLOWLY(a); # else UInt sec_no = rotateRight16(a) & 0x3FFFF; @@ -818,6 +1120,9 @@ abits >>= (a & 4); abits &= 15; PROF_EVENT(60); + if(watchpoint_count && mc_check_watchpoint(a, 4, &wp)) + mc_watchpoint_message ( "read", wp, + VG_(get_ExeContext(VG_(get_VCPU_tid)()))); if (abits == VGM_NIBBLE_VALID) { /* Handle common case quickly: a is suitably aligned, is mapped, and is addressible. */ @@ -833,7 +1138,11 @@ REGPARM(2) void MC_(helperc_STOREV4) ( Addr a, UInt vbytes ) { + Watchpoint* wp; # ifdef VG_DEBUG_MEMORY + if (watchpoint_count && mc_check_watchpoint(a, 4, &wp)) + mc_watchpoint_message ( "write", wp, + VG_(get_ExeContext(VG_(get_VCPU_tid)()))); mc_wr_V4_SLOWLY(a, vbytes); # else UInt sec_no = rotateRight16(a) & 0x3FFFF; @@ -843,6 +1152,9 @@ abits >>= (a & 4); abits &= 15; PROF_EVENT(61); + if (watchpoint_count && mc_check_watchpoint(a, 4, &wp)) + mc_watchpoint_message ( "write", wp, + VG_(get_ExeContext(VG_(get_VCPU_tid)()))); if (abits == VGM_NIBBLE_VALID) { /* Handle common case quickly: a is suitably aligned, is mapped, and is addressible. */ @@ -858,13 +1170,20 @@ REGPARM(1) UInt MC_(helperc_LOADV2) ( Addr a ) { + Watchpoint* wp; # ifdef VG_DEBUG_MEMORY + if(watchpoint_count && mc_check_watchpoint(a, 4, &wp)) + mc_watchpoint_message ( "read", wp, + VG_(get_ExeContext(VG_(get_VCPU_tid)()))); return mc_rd_V2_SLOWLY(a); # else UInt sec_no = rotateRight16(a) & 0x1FFFF; SecMap* sm = primary_map[sec_no]; UInt a_off = (a & 0xFFFF) >> 3; PROF_EVENT(62); + if(watchpoint_count && mc_check_watchpoint(a, 4, &wp)) + mc_watchpoint_message ( "read", wp, + VG_(get_ExeContext(VG_(get_VCPU_tid)()))); if (sm->abits[a_off] == VGM_BYTE_VALID) { /* Handle common case quickly. */ UInt v_off = a & 0xFFFF; @@ -881,13 +1200,20 @@ REGPARM(2) void MC_(helperc_STOREV2) ( Addr a, UInt vbytes ) { + Watchpoint* wp; # ifdef VG_DEBUG_MEMORY + if (watchpoint_count && mc_check_watchpoint(a, 4, &wp)) + mc_watchpoint_message ( "write", wp, + VG_(get_ExeContext(VG_(get_VCPU_tid)()))); mc_wr_V2_SLOWLY(a, vbytes); # else UInt sec_no = rotateRight16(a) & 0x1FFFF; SecMap* sm = primary_map[sec_no]; UInt a_off = (a & 0xFFFF) >> 3; PROF_EVENT(63); + if (watchpoint_count && mc_check_watchpoint(a, 4, &wp)) + mc_watchpoint_message ( "write", wp, + VG_(get_ExeContext(VG_(get_VCPU_tid)()))); if (sm->abits[a_off] == VGM_BYTE_VALID) { /* Handle common case quickly. */ UInt v_off = a & 0xFFFF; @@ -902,13 +1228,20 @@ REGPARM(1) UInt MC_(helperc_LOADV1) ( Addr a ) { + Watchpoint* wp; # ifdef VG_DEBUG_MEMORY + if(watchpoint_count && mc_check_watchpoint(a, 4, &wp)) + mc_watchpoint_message ( "read", wp, + VG_(get_ExeContext(VG_(get_VCPU_tid)()))); return mc_rd_V1_SLOWLY(a); # else UInt sec_no = shiftRight16(a); SecMap* sm = primary_map[sec_no]; UInt a_off = (a & 0xFFFF) >> 3; PROF_EVENT(64); + if(watchpoint_count && mc_check_watchpoint(a, 4, &wp)) + mc_watchpoint_message ( "read", wp, + VG_(get_ExeContext(VG_(get_VCPU_tid)()))); if (sm->abits[a_off] == VGM_BYTE_VALID) { /* Handle common case quickly. */ UInt v_off = a & 0xFFFF; @@ -925,13 +1258,20 @@ REGPARM(2) void MC_(helperc_STOREV1) ( Addr a, UInt vbytes ) { + Watchpoint* wp; # ifdef VG_DEBUG_MEMORY + if (watchpoint_count && mc_check_watchpoint(a, 4, &wp)) + mc_watchpoint_message ( "write", wp, + VG_(get_ExeContext(VG_(get_VCPU_tid)()))); mc_wr_V1_SLOWLY(a, vbytes); # else UInt sec_no = shiftRight16(a); SecMap* sm = primary_map[sec_no]; UInt a_off = (a & 0xFFFF) >> 3; PROF_EVENT(65); + if (watchpoint_count && mc_check_watchpoint(a, 4, &wp)) + mc_watchpoint_message ( "write", wp, + VG_(get_ExeContext(VG_(get_VCPU_tid)()))); if (sm->abits[a_off] == VGM_BYTE_VALID) { /* Handle common case quickly. */ UInt v_off = a & 0xFFFF; @@ -1586,10 +1926,49 @@ Bool MC_(clo_avoid_strlen_errors) = True; Bool MC_(clo_cleanup) = True; +/* + * Parse a watchpoint specified on the command line. + */ +static void +mc_watchpoint_cmdline (char *str) +{ + char *x; + Addr addr1, addr2; + + if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) { + addr1 = VG_(atoll16)(str + 2); + } else { + addr1 = VG_(atoll)(str); + } + + if ((x = VG_(strchr)(str, '-'))) { + x++; + if (x[0] == '0' && (x[1] == 'x' || x[1] == 'X')) { + addr2 = VG_(atoll16)(x + 2); + } else { + addr2 = VG_(atoll)(x); + } + } else if ((x = VG_(strchr)(str, '+'))) { + x++; + if (x[0] == '0' && (x[1] == 'x' || x[1] == 'X')) { + addr2 = addr1 + VG_(atoll16)(x); + } else { + addr2 = addr1 + VG_(atoll)(x); + } + } else { + addr2 = addr1; + } + + mc_deferred_watchpoint(addr1, addr2 - addr1 + 1); +} + + Bool SK_(process_cmd_line_option)(Char* arg) { VG_BOOL_CLO("--avoid-strlen-errors", MC_(clo_avoid_strlen_errors)) else VG_BOOL_CLO("--cleanup", MC_(clo_cleanup)) + else if (VG_CLO_STREQN(13, arg, "--watchpoint=")) + mc_watchpoint_cmdline(&arg[13]); else return MAC_(process_common_cmd_line_option)(arg); @@ -1601,6 +1980,7 @@ MAC_(print_common_usage)(); VG_(printf)( " --avoid-strlen-errors=no|yes suppress errs from inlined strlen [yes]\n" +" --watchpoint=WATCHPOINT set a watchpoint at WATCHPOINT\n" ); } @@ -1851,6 +2231,14 @@ ( tid, arg[1], arg[2], arg[3], True /* set them */ ); 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; @@ -1892,7 +2280,7 @@ MAC_( new_mem_heap) = & mc_new_mem_heap; MAC_( ban_mem_heap) = & mc_make_noaccess; MAC_(copy_mem_heap) = & mc_copy_address_range_state; - MAC_( die_mem_heap) = & mc_make_noaccess; + MAC_( die_mem_heap) = & mc_die_mem_heap; MAC_(check_noaccess) = & mc_check_noaccess; VG_(init_new_mem_startup) ( & mc_new_mem_startup ); @@ -1950,6 +2338,7 @@ void SK_(post_clo_init) ( void ) { + mc_init_deferred_watchpoints(); } void SK_(fini) ( Int exitcode ) diff -rNu valgrind/memcheck/memcheck.h valgrind-watchpoints/memcheck/memcheck.h --- valgrind/memcheck/memcheck.h 2004-11-23 12:31:25.000000000 -0800 +++ valgrind-watchpoints/memcheck/memcheck.h 2005-01-19 22:01:43.000000000 -0800 @@ -90,6 +90,8 @@ VG_USERREQ__GET_VBITS, VG_USERREQ__SET_VBITS, + VG_USERREQ__SET_WATCHPOINT, + VG_USERREQ__CLEAR_WATCHPOINT, /* This is just for memcheck's internal use - don't use it */ _VG_USERREQ__MEMCHECK_GET_RECORD_OVERLAP = VG_USERREQ_SKIN_BASE('M','C')+256 @@ -215,6 +217,28 @@ } +/* 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; \ + }) + + /* Get in zzvbits the validity data for the zznbytes starting at zzsrc. Return values: 0 if not running on valgrind diff -rNu valgrind/memcheck/tests/Makefile.am valgrind-watchpoints/memcheck/tests/Makefile.am --- valgrind/memcheck/tests/Makefile.am 2005-01-25 11:08:42.000000000 -0800 +++ valgrind-watchpoints/memcheck/tests/Makefile.am 2005-01-25 11:09:34.000000000 -0800 @@ -74,6 +74,9 @@ threadederrno.stderr.exp threadederrno.stdout.exp \ threadederrno.vgtest \ vgtest_ume.stderr.exp vgtest_ume.vgtest \ + wp_cmdline.stderr.exp wp_cmdline.vgtest \ + wp_simple.stderr.exp wp_simple.vgtest \ + wp_stack.stderr.exp wp_stack.vgtest \ writev.stderr.exp writev.stderr.exp2 writev.vgtest \ zeropage.stderr.exp zeropage.stderr.exp2 zeropage.vgtest @@ -95,9 +98,9 @@ trivialleak weirdioctl \ mismatches new_override metadata threadederrno \ vgtest_ume \ + wp_cmdline wp_simple wp_stack \ writev zeropage - AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/include -I$(top_builddir)/include AM_CFLAGS = $(WERROR) -Winline -Wall -Wshadow -g AM_CXXFLAGS = $(AM_CFLAGS) @@ -161,6 +164,9 @@ str_tester_CFLAGS = $(AM_CFLAGS) -Wno-shadow threadederrno_SOURCES = threadederrno.c threadederrno_LDADD = -lpthread +wp_cmdline_SOURCES = wp_cmdline.c +wp_simple_SOURCES = wp_simple.c +wp_stack_SOURCES = wp_stack.c writev_SOURCES = writev.c zeropage_SOURCES = zeropage.c diff -rNu valgrind/memcheck/tests/wp_cmdline.c valgrind-watchpoints/memcheck/tests/wp_cmdline.c --- valgrind/memcheck/tests/wp_cmdline.c 1969-12-31 16:00:00.000000000 -0800 +++ valgrind-watchpoints/memcheck/tests/wp_cmdline.c 2005-01-19 22:01:45.000000000 -0800 @@ -0,0 +1,19 @@ +#include +#include +#include "../memcheck.h" + +static +void segv(int sig) +{ + exit(0); +} + +int +main (int argc, char **argv) +{ + int *x = (int *)0x10000; + + signal(SIGSEGV, segv); + *x = 1; + return 0; +} diff -rNu valgrind/memcheck/tests/wp_cmdline.stderr.exp valgrind-watchpoints/memcheck/tests/wp_cmdline.stderr.exp --- valgrind/memcheck/tests/wp_cmdline.stderr.exp 1969-12-31 16:00:00.000000000 -0800 +++ valgrind-watchpoints/memcheck/tests/wp_cmdline.stderr.exp 2005-01-19 22:01:45.000000000 -0800 @@ -0,0 +1,15 @@ +Set watchpoint 0 at 0x........ - 0x........ + +Watchpoint 0 event: write + at 0x........: main (wp_cmdline.c:17) +This watchpoint has been triggered 1 time +This watchpoint was set on the command line +Invalid write of size 4 + at 0x........: main (wp_cmdline.c:17) + Address 0x........ is not stack'd, malloc'd or (recently) free'd + +ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0) +malloc/free: in use at exit: 0 bytes in 0 blocks. +malloc/free: 0 allocs, 0 frees, 0 bytes allocated. +For a detailed leak analysis, rerun with: --leak-check=yes +For counts of detected errors, rerun with: -v diff -rNu valgrind/memcheck/tests/wp_cmdline.vgtest valgrind-watchpoints/memcheck/tests/wp_cmdline.vgtest --- valgrind/memcheck/tests/wp_cmdline.vgtest 1969-12-31 16:00:00.000000000 -0800 +++ valgrind-watchpoints/memcheck/tests/wp_cmdline.vgtest 2005-01-19 22:01:45.000000000 -0800 @@ -0,0 +1,2 @@ +prog: wp_cmdline +vgopts: --watchpoint=0x10000 diff -rNu valgrind/memcheck/tests/wp_simple.c valgrind-watchpoints/memcheck/tests/wp_simple.c --- valgrind/memcheck/tests/wp_simple.c 1969-12-31 16:00:00.000000000 -0800 +++ valgrind-watchpoints/memcheck/tests/wp_simple.c 2005-01-19 22:01:45.000000000 -0800 @@ -0,0 +1,17 @@ +#include "../memcheck.h" + +int +main (int argc, char **argv) +{ + int a; + int x; + + x = VALGRIND_SET_WATCHPOINT(&a, sizeof(int)); + + a = 1; + + VALGRIND_CLEAR_WATCHPOINT(x); + + a = 0; + return 0; +} diff -rNu valgrind/memcheck/tests/wp_simple.stderr.exp valgrind-watchpoints/memcheck/tests/wp_simple.stderr.exp --- valgrind/memcheck/tests/wp_simple.stderr.exp 1969-12-31 16:00:00.000000000 -0800 +++ valgrind-watchpoints/memcheck/tests/wp_simple.stderr.exp 2005-01-19 22:01:45.000000000 -0800 @@ -0,0 +1,14 @@ + +Set watchpoint 0 at 0x........ - 0x........ +Watchpoint 0 event: write + at 0x........: main (wp_simple.c:11) +This watchpoint has been triggered 1 time +This watchpoint was set at: + at 0x........: main (wp_simple.c:9) +Cleared watchpoint 0 + +ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0) +malloc/free: in use at exit: 0 bytes in 0 blocks. +malloc/free: 0 allocs, 0 frees, 0 bytes allocated. +For a detailed leak analysis, rerun with: --leak-check=yes +For counts of detected errors, rerun with: -v diff -rNu valgrind/memcheck/tests/wp_simple.vgtest valgrind-watchpoints/memcheck/tests/wp_simple.vgtest --- valgrind/memcheck/tests/wp_simple.vgtest 1969-12-31 16:00:00.000000000 -0800 +++ valgrind-watchpoints/memcheck/tests/wp_simple.vgtest 2005-01-19 22:01:45.000000000 -0800 @@ -0,0 +1 @@ +prog: wp_simple diff -rNu valgrind/memcheck/tests/wp_stack.c valgrind-watchpoints/memcheck/tests/wp_stack.c --- valgrind/memcheck/tests/wp_stack.c 1969-12-31 16:00:00.000000000 -0800 +++ valgrind-watchpoints/memcheck/tests/wp_stack.c 2005-01-19 22:01:45.000000000 -0800 @@ -0,0 +1,26 @@ +#include "../memcheck.h" + +int +yo (int *y) +{ + int i = 1; + int x = VALGRIND_SET_WATCHPOINT(&i, sizeof(int)); + + i = 0; + + *y = x; + + return i; +} + + +int +main (int argc, char **argv) +{ + int x; + + yo(&x); + + VALGRIND_CLEAR_WATCHPOINT(x); + return 0; +} diff -rNu valgrind/memcheck/tests/wp_stack.stderr.exp valgrind-watchpoints/memcheck/tests/wp_stack.stderr.exp --- valgrind/memcheck/tests/wp_stack.stderr.exp 1969-12-31 16:00:00.000000000 -0800 +++ valgrind-watchpoints/memcheck/tests/wp_stack.stderr.exp 2005-01-19 22:01:45.000000000 -0800 @@ -0,0 +1,30 @@ + +Set watchpoint 0 at 0x........ - 0x........ +Watchpoint 0 event: write + at 0x........: yo (wp_stack.c:9) + by 0x........: main (wp_stack.c:22) +This watchpoint has been triggered 1 time +This watchpoint was set at: + at 0x........: yo (wp_stack.c:7) + by 0x........: main (wp_stack.c:22) +Watchpoint 0 event: read + at 0x........: yo (wp_stack.c:13) + by 0x........: main (wp_stack.c:22) +This watchpoint has been triggered 2 times +This watchpoint was set at: + at 0x........: yo (wp_stack.c:7) + by 0x........: main (wp_stack.c:22) +Watchpoint 0 event: out of scope + at 0x........: yo (wp_stack.c:14) + by 0x........: main (wp_stack.c:22) +This watchpoint has been triggered 3 times +This watchpoint was set at: + at 0x........: yo (wp_stack.c:7) + by 0x........: main (wp_stack.c:22) +Cleared watchpoint 0 + +ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0) +malloc/free: in use at exit: 0 bytes in 0 blocks. +malloc/free: 0 allocs, 0 frees, 0 bytes allocated. +For a detailed leak analysis, rerun with: --leak-check=yes +For counts of detected errors, rerun with: -v diff -rNu valgrind/memcheck/tests/wp_stack.vgtest valgrind-watchpoints/memcheck/tests/wp_stack.vgtest --- valgrind/memcheck/tests/wp_stack.vgtest 1969-12-31 16:00:00.000000000 -0800 +++ valgrind-watchpoints/memcheck/tests/wp_stack.vgtest 2005-01-19 22:01:45.000000000 -0800 @@ -0,0 +1 @@ +prog: wp_stack