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:
+
+ - Memory reads.
+
- Memory writes.
+
- Memory allocated on top of a watchpoint.
+
- Memory freed from on top of a watchpoint.
+
- Watchpoint goes in to scope on stack.
+
- Watchpoint goes out of scope on stack.
+
+
@@ -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.
VALGRIND_MAKE_NOACCESS
,
@@ -837,5 +864,14 @@
have got with VALGRIND_GET_VBITS
. Only for those who really
know what they are doing.
+
VALGRIND_SET_WATCHPOINT(addr, len)
: set a watchpoint
+ from address addr
to address addr+len
.
+ Returns an int
, which is the watchpoint identifier.
+ See the documentation for the --watchpoint
switch for
+ more details.
+
+
VALGRIND_CLEAR_WATCHPOINT(watchpoint_id)
: clear the
+ watchpoint identified by watchpoint_id
.
+
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