]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
arm-linux: fake up the commpage entry at a lower level (in
authorJulian Seward <jseward@acm.org>
Sun, 3 Jan 2010 10:14:03 +0000 (10:14 +0000)
committerJulian Seward <jseward@acm.org>
Sun, 3 Jan 2010 10:14:03 +0000 (10:14 +0000)
parse_procselfmaps) so that the sync checker still works.

git-svn-id: svn://svn.valgrind.org/valgrind/trunk@10993

coregrind/m_aspacemgr/aspacemgr-linux.c

index 15faf860a4590c67bcbf751bd3b9cd424f6e5afc..e2e50e3d41e9b4117a194e0e057d7f155546fc7d 100644 (file)
@@ -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)