|
From: <sv...@va...> - 2010-01-03 10:14:11
|
Author: sewardj
Date: 2010-01-03 10:14:03 +0000 (Sun, 03 Jan 2010)
New Revision: 10993
Log:
arm-linux: fake up the commpage entry at a lower level (in
parse_procselfmaps) so that the sync checker still works.
Modified:
trunk/coregrind/m_aspacemgr/aspacemgr-linux.c
Modified: trunk/coregrind/m_aspacemgr/aspacemgr-linux.c
===================================================================
--- trunk/coregrind/m_aspacemgr/aspacemgr-linux.c 2010-01-02 13:24:58 UTC (rev 10992)
+++ trunk/coregrind/m_aspacemgr/aspacemgr-linux.c 2010-01-03 10:14:03 UTC (rev 10993)
@@ -338,7 +338,16 @@
void (*record_gap)( Addr addr, SizeT len )
);
+/* ----- Hacks to do with the "commpage" on arm-linux ----- */
+/* Not that I have anything against the commpage per se. It's just
+ that it's not listed in /proc/self/maps, which is a royal PITA --
+ we have to fake it up, in parse_procselfmaps. */
+#if defined(VGP_arm_linux)
+# define ARM_LINUX_FAKE_COMMPAGE_START 0xFFFF0000
+# define ARM_LINUX_FAKE_COMMPAGE_END1 0xFFFFF000
+#endif
+
/*-----------------------------------------------------------------*/
/*--- ---*/
/*--- SegName array management. ---*/
@@ -1540,11 +1549,27 @@
seg.kind = SkAnonV;
if (dev != 0 && ino != 0)
seg.kind = SkFileV;
-#if defined(VGO_darwin)
+
+# if defined(VGO_darwin)
// GrP fixme no dev/ino on darwin
if (offset != 0)
- seg.kind = SkFileV;
-#endif
+ seg.kind = SkFileV;
+# endif // defined(VGO_darwin)
+
+# if defined(VGP_arm_linux)
+ /* The standard handling of entries read from /proc/self/maps will
+ cause the faked up commpage segment to have type SkAnonV, which
+ is a problem because it contains code we want the client to
+ execute, and so later m_translate will segfault the client when
+ it tries to go in there. Hence change the ownership of it here
+ to the client (SkAnonC). The least-worst kludge I could think
+ of. */
+ if (addr == ARM_LINUX_FAKE_COMMPAGE_START
+ && addr + len == ARM_LINUX_FAKE_COMMPAGE_END1
+ && seg.kind == SkAnonV)
+ seg.kind = SkAnonC;
+# endif // defined(VGP_arm_linux)
+
if (filename)
seg.fnIdx = allocate_segname( filename );
@@ -1682,26 +1707,16 @@
VG_(debugLog)(2, "aspacem", "Reading /proc/self/maps\n");
parse_procselfmaps( read_maps_callback, NULL );
+ /* NB: on arm-linux, parse_procselfmaps automagically kludges up
+ (iow, hands to its callbacks) a description of the ARM Commpage,
+ since that's not listed in /proc/self/maps (kernel bug IMO). We
+ have to fake up its existence in parse_procselfmaps and not
+ merely add it here as an extra segment, because doing the latter
+ causes sync checking to fail: we see we have an extra segment in
+ the segments array, which isn't listed in /proc/self/maps.
+ Hence we must make it appear that /proc/self/maps contained this
+ segment all along. Sigh. */
-#if defined(VGP_arm_linux)
- /* ARM puts code at the end of memory that contains processor
- specific stuff (cmpxchg, getting the thread local storage, etc.)
- This isn't specified in /proc/self/maps, so do it here
-
- EAZG: Is this the proper place for this? Seems like this is one
- of the few contexts when we can punch holes in the map
- */
- init_nsegment( &seg );
- seg.kind = SkFileC;
- seg.start = 0xFFFF0000;
- seg.end = 0xFFFFEFFF;
- seg.hasR = toBool(1);
- seg.hasW = toBool(0);
- seg.hasX = toBool(1);
- seg.fnIdx = allocate_segname( "arm_commpage" );
- add_segment( &seg );
-#endif
-
VG_(am_show_nsegments)(2, "With contents of /proc/self/maps");
AM_SANITY_CHECK;
@@ -3017,6 +3032,8 @@
/*--- ---*/
/*-----------------------------------------------------------------*/
+/*------BEGIN-procmaps-parser-for-Linux--------------------------*/
+
/* Size of a smallish table used to read /proc/self/map entries. */
#define M_PROCMAP_BUF 100000
@@ -3301,10 +3318,37 @@
gapStart = endPlusOne;
}
+# if defined(VGP_arm_linux)
+ /* ARM puts code at the end of memory that contains processor
+ specific stuff (cmpxchg, getting the thread local storage, etc.)
+ This isn't specified in /proc/self/maps, so do it here. This
+ kludgery causes the view of memory, as presented to
+ record_gap/record_mapping, to actually reflect reality. IMO
+ (JRS, 2010-Jan-03) the fact that /proc/.../maps does not list
+ the commpage should be regarded as a bug in the kernel. */
+ { const Addr commpage_start = ARM_LINUX_FAKE_COMMPAGE_START;
+ const Addr commpage_end1 = ARM_LINUX_FAKE_COMMPAGE_END1;
+ if (gapStart < commpage_start) {
+ if (record_gap)
+ (*record_gap)( gapStart, commpage_start - gapStart );
+ if (record_mapping)
+ (*record_mapping)( commpage_start, commpage_end1 - commpage_start,
+ VKI_PROT_READ|VKI_PROT_EXEC,
+ 0/*dev*/, 0/*ino*/, 0/*foffset*/,
+ NULL);
+ gapStart = commpage_end1;
+ }
+ }
+# endif
+
if (record_gap && gapStart < Addr_MAX)
(*record_gap) ( gapStart, Addr_MAX - gapStart + 1 );
}
+/*------END-procmaps-parser-for-Linux----------------------------*/
+
+/*------BEGIN-procmaps-parser-for-Darwin-------------------------*/
+
#elif defined(VGO_darwin)
#include <mach/mach.h>
#include <mach/mach_vm.h>
@@ -3513,8 +3557,9 @@
return !css_overflowed;
}
-#endif // defined(VGO_linux)
+#endif // defined(VGO_darwin)
+/*------END-procmaps-parser-for-Darwin---------------------------*/
#endif // defined(VGO_linux) || defined(VGO_darwin)
|