diff options
author | sewardj <sewardj@a5019735-40e9-0310-863c-91ae7b9d1cf9> | 2010-01-03 10:14:03 +0000 |
---|---|---|
committer | sewardj <sewardj@a5019735-40e9-0310-863c-91ae7b9d1cf9> | 2010-01-03 10:14:03 +0000 |
commit | 38a21ac27cec0d1631ad91f8aa3eecd95fa5663b (patch) | |
tree | 8d208fbff708da2e5c25a30cfd6e32506e5fe1cd | |
parent | f5f1e12bd89408917c1ffeb22ec23a1fd11b7a23 (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.c | 91 |
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) |