|
From: <sv...@va...> - 2005-09-18 00:25:37
|
Author: sewardj
Date: 2005-09-18 01:25:33 +0100 (Sun, 18 Sep 2005)
New Revision: 4672
Log:
Add a sanity checker which can check Valgrind's segment array against
what the kernel believes is going on, by rereading /proc/self/maps at
any time.
Use this to find and fix a bug in VG_(am_extend_map_client).
Modified:
branches/ASPACEM/coregrind/m_aspacemgr/aspacemgr.c
Modified: branches/ASPACEM/coregrind/m_aspacemgr/aspacemgr.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- branches/ASPACEM/coregrind/m_aspacemgr/aspacemgr.c 2005-09-17 01:50:1=
5 UTC (rev 4671)
+++ branches/ASPACEM/coregrind/m_aspacemgr/aspacemgr.c 2005-09-18 00:25:3=
3 UTC (rev 4672)
@@ -41,6 +41,9 @@
#include "pub_core_syscall.h"
#include "pub_core_tooliface.h"
#include "pub_core_transtab.h" // For VG_(discard_translations)
+
+#include "pub_core_options.h" // VG_(clo_sanity_level)
+
#include "vki_unistd.h"
=20
static void aspacem_barf ( HChar* what );
@@ -1386,6 +1389,14 @@
static Addr aspacem_vStart =3D 0;
=20
=20
+#define AM_SANITY_CHECK \
+ do { \
+ if (VG_(clo_sanity_level > 1)) \
+ aspacem_assert(do_sync_check(__PRETTY_FUNCTION__, \
+ __FILE__,__LINE__)); \
+ } while (0)=20
+
+
/*-----------------------------------------------------------------*/
/*--- ---*/
/*--- Stuff to make aspacem almost completely independent of ---*/
@@ -1424,11 +1435,11 @@
VG_(exit)(1);
}
=20
-#define aspacem_assert(expr) \
- ((void) ((expr) ? 0 : \
- (aspacem_assert_fail(#expr, \
- __FILE__, __LINE__, \
- __PRETTY_FUNCTION__))))
+#define aspacem_assert(expr) \
+ ((void) ((expr) ? 0 : \
+ (aspacem_assert_fail(#expr, \
+ __FILE__, __LINE__, \
+ __PRETTY_FUNCTION__))))
=20
=20
//--------------------------------------------------------------
@@ -1881,6 +1892,90 @@
}
=20
=20
+/* Check the segment array corresponds with the kernel's view of
+ memory layout. sync_check_ok returns True if no anomalies were
+ found, else False. In the latter case the mismatching segments are
+ displayed. */
+
+static Int sync_check_i =3D 0;
+static Bool sync_check_ok =3D False;
+
+static void sync_check_callback ( Addr addr, SizeT len, UInt prot,
+ UInt dev, UInt ino, ULong offset,=20
+ const UChar* filename )
+{
+ Bool same;
+
+ /* If a problem has already been detected, don't continue comparing
+ segments, so as to avoid flooding the output with error
+ messages. */
+ if (!sync_check_ok)
+ return;
+
+ /* Advance sync_check_i to the first possible nsegment entry which
+ could map the kernel's offering. It will have been left at the
+ previous match. We are prepared to skip any sequence of free
+ and reservation segments, but everything else must match the
+ kernel's segments. */
+ sync_check_i++;
+
+ while (sync_check_i < nsegments_used
+ && (nsegments[sync_check_i].kind =3D=3D SkFree
+ || nsegments[sync_check_i].kind =3D=3D SkResvn))
+ sync_check_i++;
+
+ aspacem_assert(sync_check_i >=3D 0 && sync_check_i <=3D nsegments_use=
d);
+
+ if (sync_check_i =3D=3D nsegments_used) {
+ sync_check_ok =3D False;
+ VG_(debugLog)(0,"aspacem","sync_check_callback: out of segments\n"=
);
+ goto show_kern_seg;
+ }
+
+ /* compare the kernel's offering against ours. */
+ same =3D nsegments[sync_check_i].start =3D=3D addr
+ && nsegments[sync_check_i].end =3D=3D addr+len-1
+ && nsegments[sync_check_i].dev =3D=3D dev
+ && nsegments[sync_check_i].ino =3D=3D ino
+ && nsegments[sync_check_i].offset =3D=3D offset;
+ if (!same) {
+ sync_check_ok =3D False;
+ VG_(debugLog)(0,"aspacem",
+ "sync_check_callback: segment mismatch: V's seg:\n=
");
+ show_nsegment_full( 0, &nsegments[sync_check_i] );
+ goto show_kern_seg;
+ }
+
+ /* Looks harmless. Keep going. */
+ return;
+
+ show_kern_seg:
+ VG_(debugLog)(0,"aspacem",
+ "sync_check_callback: segment mismatch: kernel's seg:=
\n");
+ VG_(debugLog)(0,"aspacem",=20
+ "start=3D0x%llx end=3D0x%llx dev=3D%u ino=3D%u offset=
=3D%lld\n",
+ (ULong)addr, ((ULong)addr) + ((ULong)len) - 1,
+ dev, ino, offset );
+ return;
+}
+
+static Bool do_sync_check ( HChar* fn, HChar* file, Int line )
+{
+ sync_check_i =3D -1;
+ sync_check_ok =3D True;
+ if (0)
+ VG_(debugLog)(0,"aspacem", "do_sync_check %s:%d\n", file,line);
+ VG_(parse_procselfmaps)( sync_check_callback );
+ if (!sync_check_ok) {
+ VG_(debugLog)(0,"aspacem",=20
+ "sync check at %s:%d (%s): FAILED\n",
+ file, line, fn);
+ VG_(debugLog)(0,"aspacem", "\n");
+ }
+ return sync_check_ok;
+}
+
+
/*-----------------------------------------------------------------*/
/*--- ---*/
/*--- Low level access / modification of the segment array. ---*/
@@ -2321,6 +2416,7 @@
=20
VG_(am_show_nsegments)(2, "With contents of /proc/self/maps");
=20
+ AM_SANITY_CHECK;
return suggested_clstack_top;
}
=20
@@ -2484,6 +2580,8 @@
if (floatIdx >=3D 0)=20
aspacem_assert(nsegments[floatIdx].kind =3D=3D SkFree);
=20
+ AM_SANITY_CHECK;
+
/* Now see if we found anything which can satisfy the request. */
switch (req->rkind) {
case MFixed:
@@ -2571,6 +2669,7 @@
}
}
add_segment( &seg );
+ AM_SANITY_CHECK;
}
=20
/* Notifies aspacem that an mprotect was completed successfully. The
@@ -2618,6 +2717,7 @@
/* Changing permissions could have made previously un-mergable
segments mergeable. Therefore have to re-preen them. */
(void)preen_nsegments();
+ AM_SANITY_CHECK;
}
=20
=20
@@ -2644,6 +2744,7 @@
=20
/* Unmapping could create two adjacent free segments, so a preen is
needed. add_segment() will do that, so no need to here. */
+ AM_SANITY_CHECK;
}
=20
=20
@@ -2719,6 +2820,7 @@
}
add_segment( &seg );
=20
+ AM_SANITY_CHECK;
return sres;
}
=20
@@ -2775,6 +2877,7 @@
seg.hasX =3D toBool(prot & VKI_PROT_EXEC);
add_segment( &seg );
=20
+ AM_SANITY_CHECK;
return sres;
}
=20
@@ -2831,6 +2934,7 @@
seg.hasX =3D toBool(prot & VKI_PROT_EXEC);
add_segment( &seg );
=20
+ AM_SANITY_CHECK;
return sres;
}
=20
@@ -2889,6 +2993,7 @@
seg.hasX =3D True;
add_segment( &seg );
=20
+ AM_SANITY_CHECK;
return sres;
}
=20
@@ -2923,6 +3028,7 @@
return sres;
=20
VG_(am_notify_munmap)( start, len );
+ AM_SANITY_CHECK;
return sres;
=20
eINVAL:
@@ -2987,6 +3093,8 @@
seg.end =3D end1;
seg.smode =3D smode;
add_segment( &seg );
+
+ AM_SANITY_CHECK;
return True;
}
=20
@@ -3091,6 +3199,7 @@
=20
}
=20
+ AM_SANITY_CHECK;
return True;
}
=20
@@ -3107,7 +3216,8 @@
{
Addr xStart;
SysRes sres;
- NSegment seg_copy;
+ NSegment seg_copy =3D *seg;
+ SizeT seg_old_len =3D seg->end + 1 - seg->start;
=20
if (seg->kind !=3D SkFileC && seg->kind !=3D SkAnonC)
return False;
@@ -3123,14 +3233,19 @@
VKI_PROT_NONE ))
return False;
=20
- sres =3D do_extend_mapping_NO_NOTIFY( seg->start, seg->end+1-seg->sta=
rt,
- delta );
- if (sres.isError)
+ AM_SANITY_CHECK;
+ sres =3D do_extend_mapping_NO_NOTIFY( seg->start,=20
+ seg_old_len,
+ seg_old_len + delta );
+ if (sres.isError) {
+ AM_SANITY_CHECK;
return False;
+ }
=20
- seg_copy =3D *seg;
seg_copy.end +=3D delta;
add_segment( &seg_copy );
+
+ AM_SANITY_CHECK;
return True;
}
=20
@@ -3176,8 +3291,10 @@
=20
sres =3D do_relocate_nooverlap_mapping_NO_NOTIFY( old_addr, old_len,=20
new_addr, new_len );
- if (sres.isError)
+ if (sres.isError) {
return False;
+ AM_SANITY_CHECK;
+ }
=20
oldseg =3D nsegments[iLo];
=20
@@ -3194,6 +3311,7 @@
oldseg.end =3D new_addr + new_len - 1;
add_segment( &seg );
=20
+ AM_SANITY_CHECK;
return True;
}
=20
@@ -3265,12 +3383,14 @@
=20
VG_(debugLog)( 1,"aspacem","allocated thread stack at 0x%llx size %d\=
n",
(ULong)(Addr)stack, szB);
+ AM_SANITY_CHECK;
return stack;
=20
protect_failed:
/* The stack was allocated, but we can't protect it. Unmap it and
return NULL (failure). */
(void)do_munmap_NO_NOTIFY( (Addr)stack, szB );
+ AM_SANITY_CHECK;
return NULL;
}
=20
|