Merge patch from JeremyF:

38-hg-lazy-lasttouch

HELGRIND: rather than recording the last access, record the last state
change. This is more interesting and useful, and uses up a lot less
memory when using (now inaccurately named) --show-last-access=all.


git-svn-id: svn://svn.valgrind.org/valgrind/trunk@1309
This commit is contained in:
Julian Seward 2002-11-13 22:37:41 +00:00
parent 84ea07f79d
commit ef4e9cecd5

View File

@ -2393,6 +2393,7 @@ void SK_(pp_SkinError) ( SkinError* err, void (*pp_ExeContext)(void) )
VG_(message)(Vg_UserMsg, "Possible data race %s variable at %p %(y",
err->string, err->addr, err->addr );
pp_ExeContext();
pp_AddrInfo(err->addr, &extra->addrinfo);
switch(extra->prevstate.state) {
case Vge_Virgin:
@ -2428,14 +2429,12 @@ void SK_(pp_SkinError) ( SkinError* err, void (*pp_ExeContext)(void) )
if (*msg)
VG_(message)(Vg_UserMsg, " Previous state: %s", msg);
pp_AddrInfo(err->addr, &extra->addrinfo);
if (clo_execontext == EC_Some && extra->lasttouched.eip != 0) {
Char file[100];
UInt line;
Addr eip = extra->lasttouched.eip;
VG_(message)(Vg_UserMsg, " Word at %p last accessed", err->addr);
VG_(message)(Vg_UserMsg, " Word at %p last changed state", err->addr);
if (VG_(get_filename_linenum)(eip, file, sizeof(file), &line)) {
VG_(message)(Vg_UserMsg, " at %p: %y (%s:%u)",
@ -2447,7 +2446,7 @@ void SK_(pp_SkinError) ( SkinError* err, void (*pp_ExeContext)(void) )
VG_(message)(Vg_UserMsg, " at %p: %y", eip, eip);
}
} else if (clo_execontext == EC_All && extra->lasttouched.ec != NULL) {
VG_(message)(Vg_UserMsg, " Word at %p last accessed", err->addr);
VG_(message)(Vg_UserMsg, " Word at %p last changed state", err->addr);
VG_(pp_ExeContext)(extra->lasttouched.ec);
}
@ -2642,15 +2641,111 @@ void dump_around_a(Addr a)
#define DEBUG_STATE(args...)
#endif
static void eraser_mem_read_word(Addr a, ThreadId tid, ThreadState *tst)
{
shadow_word* sword;
shadow_word prevstate;
ThreadLifeSeg *tls;
const LockSet *ls;
Bool statechange = False;
static const void *const states[4] = {
[Vge_Virgin] &&st_virgin,
[Vge_Excl] &&st_excl,
[Vge_Shar] &&st_shar,
[Vge_SharMod] &&st_sharmod,
};
tls = thread_seg[tid];
sk_assert(tls != NULL && tls->tid == tid);
sword = get_sword_addr(a);
if (sword == SEC_MAP_ACCESS) {
VG_(printf)("read distinguished 2ndary map! 0x%x\n", a);
return;
}
prevstate = *sword;
goto *states[sword->state];
/* This looks like reading of unitialised memory, may be legit. Eg.
* calloc() zeroes its values, so untouched memory may actually be
* initialised. Leave that stuff to Valgrind. */
st_virgin:
if (TID_INDICATING_NONVIRGIN == sword->other) {
DEBUG_STATE("Read VIRGIN --> EXCL: %8x, %u\n", a, tid);
if (DEBUG_VIRGIN_READS)
dump_around_a(a);
} else {
DEBUG_STATE("Read SPECIAL --> EXCL: %8x, %u\n", a, tid);
}
statechange = True;
*sword = SW(Vge_Excl, packTLS(tls)); /* remember exclusive owner */
tls->refcount++;
goto done;
st_excl: {
ThreadLifeSeg *sw_tls = unpackTLS(sword->other);
if (tls == sw_tls) {
DEBUG_STATE("Read EXCL: %8x, %u\n", a, tid);
} else if (unpackTLS(TLSP_INDICATING_ALL) == sw_tls) {
DEBUG_STATE("Read EXCL/ERR: %8x, %u\n", a, tid);
} else if (tlsIsDisjoint(tls, sw_tls)) {
DEBUG_STATE("Read EXCL(%u) --> EXCL: %8x, %u\n", sw_tls->tid, a, tid);
statechange = True;
sword->other = packTLS(tls);
sw_tls->refcount--;
tls->refcount++;
} else {
DEBUG_STATE("Read EXCL(%u) --> SHAR: %8x, %u\n", sw_tls->tid, a, tid);
sw_tls->refcount--;
statechange = True;
*sword = SW(Vge_Shar, packLockSet(thread_locks[tid]));
if (DEBUG_MEM_LOCKSET_CHANGES)
print_LockSet("excl read locks", unpackLockSet(sword->other));
}
goto done;
}
st_shar:
DEBUG_STATE("Read SHAR: %8x, %u\n", a, tid);
sword->other = packLockSet(intersect(unpackLockSet(sword->other),
thread_locks[tid]));
statechange = sword->other != prevstate.other;
goto done;
st_sharmod:
DEBUG_STATE("Read SHAR_MOD: %8x, %u\n", a, tid);
ls = intersect(unpackLockSet(sword->other),
thread_locks[tid]);
sword->other = packLockSet(ls);
statechange = sword->other != prevstate.other;
if (isempty(ls)) {
record_eraser_error(tst, a, False /* !is_write */, prevstate);
}
goto done;
done:
if (clo_execontext != EC_None && statechange) {
EC_EIP eceip;
if (clo_execontext == EC_Some)
eceip.eip = VG_(get_EIP)(tst);
else
eceip.ec = VG_(get_ExeContext)(tst);
setExeContext(a, eceip);
}
}
static void eraser_mem_read(Addr a, UInt size, ThreadState *tst)
{
ThreadId tid;
ThreadLifeSeg *tls;
shadow_word* sword;
Addr end;
shadow_word prevstate;
const LockSet *ls;
end = ROUNDUP(a+size, 4);
a = ROUNDDN(a, 4);
@ -2660,102 +2755,109 @@ static void eraser_mem_read(Addr a, UInt size, ThreadState *tst)
else
tid = VG_(get_tid_from_ThreadState)(tst);
for ( ; a < end; a += 4)
eraser_mem_read_word(a, tid, tst);
}
static void eraser_mem_write_word(Addr a, ThreadId tid, ThreadState *tst)
{
ThreadLifeSeg *tls;
shadow_word* sword;
shadow_word prevstate;
Bool statechange = False;
static const void *const states[4] = {
[Vge_Virgin] &&st_virgin,
[Vge_Excl] &&st_excl,
[Vge_Shar] &&st_shar,
[Vge_SharMod] &&st_sharmod,
};
tls = thread_seg[tid];
sk_assert(tls != NULL && tls->tid == tid);
for ( ; a < end; a += 4) {
static const void *const states[4] = {
[Vge_Virgin] &&st_virgin,
[Vge_Excl] &&st_excl,
[Vge_Shar] &&st_shar,
[Vge_SharMod] &&st_sharmod,
};
sword = get_sword_addr(a);
if (sword == SEC_MAP_ACCESS) {
VG_(printf)("read distinguished 2ndary map! 0x%x\n", a);
return;
}
sword = get_sword_addr(a);
if (sword == SEC_MAP_ACCESS) {
VG_(printf)("read distinguished 2ndary map! 0x%x\n", a);
continue;
}
prevstate = *sword;
prevstate = *sword;
goto *states[sword->state];
goto *states[sword->state];
st_virgin:
if (TID_INDICATING_NONVIRGIN == sword->other)
DEBUG_STATE("Write VIRGIN --> EXCL: %8x, %u\n", a, tid);
else
DEBUG_STATE("Write SPECIAL --> EXCL: %8x, %u\n", a, tid);
statechange = True;
*sword = SW(Vge_Excl, packTLS(tls));/* remember exclusive owner */
tls->refcount++;
goto done;
/* This looks like reading of unitialised memory, may be legit. Eg.
* calloc() zeroes its values, so untouched memory may actually be
* initialised. Leave that stuff to Valgrind. */
st_virgin:
if (TID_INDICATING_NONVIRGIN == sword->other) {
DEBUG_STATE("Read VIRGIN --> EXCL: %8x, %u\n", a, tid);
if (DEBUG_VIRGIN_READS)
dump_around_a(a);
} else {
DEBUG_STATE("Read SPECIAL --> EXCL: %8x, %u\n", a, tid);
}
*sword = SW(Vge_Excl, packTLS(tls)); /* remember exclusive owner */
st_excl: {
ThreadLifeSeg *sw_tls = unpackTLS(sword->other);
if (tls == sw_tls) {
DEBUG_STATE("Write EXCL: %8x, %u\n", a, tid);
goto done;
} else if (unpackTLS(TLSP_INDICATING_ALL) == sw_tls) {
DEBUG_STATE("Write EXCL/ERR: %8x, %u\n", a, tid);
goto done;
} else if (tlsIsDisjoint(tls, sw_tls)) {
DEBUG_STATE("Write EXCL(%u) --> EXCL: %8x, %u\n", sw_tls->tid, a, tid);
sword->other = packTLS(tls);
sw_tls->refcount--;
tls->refcount++;
goto done;
st_excl: {
ThreadLifeSeg *sw_tls = unpackTLS(sword->other);
if (tls == sw_tls) {
DEBUG_STATE("Read EXCL: %8x, %u\n", a, tid);
} else if (unpackTLS(TLSP_INDICATING_ALL) == sw_tls) {
DEBUG_STATE("Read EXCL/ERR: %8x, %u\n", a, tid);
} else if (tlsIsDisjoint(tls, sw_tls)) {
DEBUG_STATE("Read EXCL(%u) --> EXCL: %8x, %u\n", sw_tls->tid, a, tid);
sword->other = packTLS(tls);
sw_tls->refcount--;
tls->refcount++;
} else {
DEBUG_STATE("Read EXCL(%u) --> SHAR: %8x, %u\n", sw_tls->tid, a, tid);
sw_tls->refcount--;
*sword = SW(Vge_Shar, packLockSet(thread_locks[tid]));
if (DEBUG_MEM_LOCKSET_CHANGES)
print_LockSet("excl read locks", unpackLockSet(sword->other));
}
goto done;
} else {
DEBUG_STATE("Write EXCL(%u) --> SHAR_MOD: %8x, %u\n", sw_tls->tid, a, tid);
statechange = True;
sw_tls->refcount--;
*sword = SW(Vge_SharMod, packLockSet(thread_locks[tid]));
if(DEBUG_MEM_LOCKSET_CHANGES)
print_LockSet("excl write locks", unpackLockSet(sword->other));
goto SHARED_MODIFIED;
}
}
st_shar:
DEBUG_STATE("Read SHAR: %8x, %u\n", a, tid);
sword->other = packLockSet(intersect(unpackLockSet(sword->other),
thread_locks[tid]));
goto done;
st_shar:
DEBUG_STATE("Write SHAR --> SHAR_MOD: %8x, %u\n", a, tid);
sword->state = Vge_SharMod;
sword->other = packLockSet(intersect(unpackLockSet(sword->other),
thread_locks[tid]));
statechange = True;
goto SHARED_MODIFIED;
st_sharmod:
DEBUG_STATE("Read SHAR_MOD: %8x, %u\n", a, tid);
ls = intersect(unpackLockSet(sword->other),
thread_locks[tid]);
sword->other = packLockSet(ls);
st_sharmod:
DEBUG_STATE("Write SHAR_MOD: %8x, %u\n", a, tid);
sword->other = packLockSet(intersect(unpackLockSet(sword->other),
thread_locks[tid]));
statechange = sword->other != prevstate.other;
if (isempty(ls)) {
record_eraser_error(tst, a, False /* !is_write */, prevstate);
}
goto done;
SHARED_MODIFIED:
if (isempty(unpackLockSet(sword->other))) {
record_eraser_error(tst, a, True /* is_write */, prevstate);
}
goto done;
done:
if (clo_execontext != EC_None) {
EC_EIP eceip;
done:
if (clo_execontext != EC_None && statechange) {
EC_EIP eceip;
if (clo_execontext == EC_Some)
eceip.eip = VG_(get_EIP)(tst);
else
eceip.ec = VG_(get_ExeContext)(tst);
setExeContext(a, eceip);
}
if (clo_execontext == EC_Some)
eceip.eip = VG_(get_EIP)(tst);
else
eceip.ec = VG_(get_ExeContext)(tst);
setExeContext(a, eceip);
}
}
static void eraser_mem_write(Addr a, UInt size, ThreadState *tst)
{
ThreadId tid;
ThreadLifeSeg *tls;
shadow_word* sword;
Addr end;
shadow_word prevstate;
end = ROUNDUP(a+size, 4);
a = ROUNDDN(a, 4);
@ -2765,89 +2867,8 @@ static void eraser_mem_write(Addr a, UInt size, ThreadState *tst)
else
tid = VG_(get_tid_from_ThreadState)(tst);
tls = thread_seg[tid];
sk_assert(tls != NULL && tls->tid == tid);
for ( ; a < end; a += 4) {
static const void *const states[4] = {
[Vge_Virgin] &&st_virgin,
[Vge_Excl] &&st_excl,
[Vge_Shar] &&st_shar,
[Vge_SharMod] &&st_sharmod,
};
sword = get_sword_addr(a);
if (sword == SEC_MAP_ACCESS) {
VG_(printf)("read distinguished 2ndary map! 0x%x\n", a);
continue;
}
prevstate = *sword;
goto *states[sword->state];
st_virgin:
if (TID_INDICATING_NONVIRGIN == sword->other)
DEBUG_STATE("Write VIRGIN --> EXCL: %8x, %u\n", a, tid);
else
DEBUG_STATE("Write SPECIAL --> EXCL: %8x, %u\n", a, tid);
*sword = SW(Vge_Excl, packTLS(tls));/* remember exclusive owner */
tls->refcount++;
goto done;
st_excl: {
ThreadLifeSeg *sw_tls = unpackTLS(sword->other);
if (tls == sw_tls) {
DEBUG_STATE("Write EXCL: %8x, %u\n", a, tid);
goto done;
} else if (unpackTLS(TLSP_INDICATING_ALL) == sw_tls) {
DEBUG_STATE("Write EXCL/ERR: %8x, %u\n", a, tid);
goto done;
} else if (tlsIsDisjoint(tls, sw_tls)) {
DEBUG_STATE("Write EXCL(%u) --> EXCL: %8x, %u\n", sw_tls->tid, a, tid);
sword->other = packTLS(tls);
sw_tls->refcount--;
tls->refcount++;
goto done;
} else {
DEBUG_STATE("Write EXCL(%u) --> SHAR_MOD: %8x, %u\n", sw_tls->tid, a, tid);
sw_tls->refcount--;
*sword = SW(Vge_SharMod, packLockSet(thread_locks[tid]));
if(DEBUG_MEM_LOCKSET_CHANGES)
print_LockSet("excl write locks", unpackLockSet(sword->other));
goto SHARED_MODIFIED;
}
}
st_shar:
DEBUG_STATE("Write SHAR --> SHAR_MOD: %8x, %u\n", a, tid);
sword->state = Vge_SharMod;
sword->other = packLockSet(intersect(unpackLockSet(sword->other),
thread_locks[tid]));
goto SHARED_MODIFIED;
st_sharmod:
DEBUG_STATE("Write SHAR_MOD: %8x, %u\n", a, tid);
sword->other = packLockSet(intersect(unpackLockSet(sword->other),
thread_locks[tid]));
SHARED_MODIFIED:
if (isempty(unpackLockSet(sword->other))) {
record_eraser_error(tst, a, True /* is_write */, prevstate);
}
goto done;
done:
if (clo_execontext != EC_None) {
EC_EIP eceip;
if (clo_execontext == EC_Some)
eceip.eip = VG_(get_EIP)(tst);
else
eceip.ec = VG_(get_ExeContext)(tst);
setExeContext(a, eceip);
}
}
for ( ; a < end; a += 4)
eraser_mem_write_word(a, tid, tst);
}
#undef DEBUG_STATE