summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsewardj <sewardj@a5019735-40e9-0310-863c-91ae7b9d1cf9>2010-01-03 10:14:03 +0000
committersewardj <sewardj@a5019735-40e9-0310-863c-91ae7b9d1cf9>2010-01-03 10:14:03 +0000
commit38a21ac27cec0d1631ad91f8aa3eecd95fa5663b (patch)
tree8d208fbff708da2e5c25a30cfd6e32506e5fe1cd
parentf5f1e12bd89408917c1ffeb22ec23a1fd11b7a23 (diff)
arm-linux: fake up the commpage entry at a lower level (in
parse_procselfmaps) so that the sync checker still works. git-svn-id: svn://svn.valgrind.org/valgrind/trunk@10993 a5019735-40e9-0310-863c-91ae7b9d1cf9
-rw-r--r--coregrind/m_aspacemgr/aspacemgr-linux.c91
1 files changed, 68 insertions, 23 deletions
diff --git a/coregrind/m_aspacemgr/aspacemgr-linux.c b/coregrind/m_aspacemgr/aspacemgr-linux.c
index 15faf860..e2e50e3d 100644
--- a/coregrind/m_aspacemgr/aspacemgr-linux.c
+++ b/coregrind/m_aspacemgr/aspacemgr-linux.c
@@ -338,6 +338,15 @@ static void parse_procselfmaps (
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
+
/*-----------------------------------------------------------------*/
/*--- ---*/
@@ -1540,11 +1549,27 @@ static void read_maps_callback ( Addr addr, SizeT len, UInt prot,
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 @@ Addr VG_(am_startup) ( Addr sp_at_startup )
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 @@ Bool VG_(am_relocate_nooverlap_client)( /*OUT*/Bool* need_discard,
/*--- ---*/
/*-----------------------------------------------------------------*/
+/*------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 @@ static void parse_procselfmaps (
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 @@ Bool VG_(get_changed_segments)(
return !css_overflowed;
}
-#endif // defined(VGO_linux)
+#endif // defined(VGO_darwin)
+/*------END-procmaps-parser-for-Darwin---------------------------*/
#endif // defined(VGO_linux) || defined(VGO_darwin)