|
From: <sv...@va...> - 2005-09-17 01:50:20
|
Author: sewardj
Date: 2005-09-17 02:50:15 +0100 (Sat, 17 Sep 2005)
New Revision: 4671
Log:
Reimplement wrapper for sys_mremap and attach to new aspacem.
Modified:
branches/ASPACEM/coregrind/m_aspacemgr/aspacemgr.c
branches/ASPACEM/coregrind/m_signals.c
branches/ASPACEM/coregrind/m_syswrap/syswrap-generic.c
branches/ASPACEM/coregrind/pub_core_aspacemgr.h
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:48:1=
8 UTC (rev 4670)
+++ branches/ASPACEM/coregrind/m_aspacemgr/aspacemgr.c 2005-09-17 01:50:1=
5 UTC (rev 4671)
@@ -1471,7 +1471,8 @@
=20
//--------------------------------------------------------------
// Direct access to a handful of syscalls. This avoids dependence on
-// m_libc*.
+// m_libc*. THESE DO NOT UPDATE THE SEGMENT LIST. DO NOT USE THEM
+// UNLESS YOU KNOW WHAT YOU ARE DOING.
=20
SysRes VG_(am_do_mmap_NO_NOTIFY)( Addr start, SizeT length, UInt prot,=20
UInt flags, UInt fd, OffT offset)
@@ -1510,6 +1511,37 @@
return VG_(do_syscall2)(__NR_munmap, (UWord)start, length );
}
=20
+static SysRes do_extend_mapping_NO_NOTIFY( Addr old_addr, SizeT old_len=
,
+ SizeT new_len )
+{
+ /* Extend the mapping old_addr .. old_addr+old_len-1 to have length
+ new_len, WITHOUT moving it. If it can't be extended in place,
+ fail. */
+ return VG_(do_syscall5)(
+ __NR_mremap,=20
+ old_addr, old_len, new_len,=20
+ 0/*flags, meaning: must be at old_addr, else FAIL */,
+ 0/*new_addr, is ignored*/
+ );
+}
+
+static SysRes do_relocate_nooverlap_mapping_NO_NOTIFY(=20
+ Addr old_addr, Addr old_len,=20
+ Addr new_addr, Addr new_len=20
+ )
+{
+ /* Move the mapping old_addr .. old_addr+old_len-1 to the new
+ location and with the new length. Only needs to handle the case
+ where the two areas do not overlap, neither length is zero, and
+ all args are page aligned. */
+ return VG_(do_syscall5)(
+ __NR_mremap,=20
+ old_addr, old_len, new_len,=20
+ VKI_MREMAP_MAYMOVE|VKI_MREMAP_FIXED/*move-or-fail*/,
+ 0/*new_addr*/
+ );
+}
+
static Int aspacem_readlink(HChar* path, HChar* buf, UInt bufsiz)
{
SysRes res;
@@ -2007,8 +2039,8 @@
be consider part of the client's addressable space. It also
considers reservations to be allowable, since from the client's
point of view they don't exist. */
-Bool VG_(am_is_free_or_valid_for_client)( Addr start, SizeT len,=20
- UInt prot )
+Bool VG_(am_is_valid_for_client_or_free_or_resvn)
+ ( Addr start, SizeT len, UInt prot )
{
return is_valid_for_client( start, len, prot, True/*free is OK*/ );
}
@@ -2102,6 +2134,7 @@
aspacem_assert(sStart <=3D sEnd);
aspacem_assert(VG_IS_PAGE_ALIGNED(sStart));
aspacem_assert(VG_IS_PAGE_ALIGNED(sEnd+1));
+ /* if (!sane_NSegment(seg)) show_nsegment_full(0,seg); */
aspacem_assert(sane_NSegment(seg));
=20
split_nsegments_lo_and_hi( sStart, sEnd, &iLo, &iHi );
@@ -2528,14 +2561,15 @@
seg.hasR =3D toBool(prot & VKI_PROT_READ);
seg.hasW =3D toBool(prot & VKI_PROT_WRITE);
seg.hasX =3D toBool(prot & VKI_PROT_EXEC);
- /* TODO: what about seg.hasT ? */
- if (get_inode_for_fd(fd, &dev, &ino)) {
- seg.dev =3D dev;
- seg.ino =3D ino;
+ if (!(flags & VKI_MAP_ANONYMOUS)) {
+ if (get_inode_for_fd(fd, &dev, &ino)) {
+ seg.dev =3D dev;
+ seg.ino =3D ino;
+ }
+ if (get_name_for_fd(fd, buf, VKI_PATH_MAX)) {
+ seg.fnIdx =3D allocate_segname( buf );
+ }
}
- if (get_name_for_fd(fd, buf, VKI_PATH_MAX)) {
- seg.fnIdx =3D allocate_segname( buf );
- }
add_segment( &seg );
}
=20
@@ -2620,6 +2654,8 @@
/*--- ---*/
/*-----------------------------------------------------------------*/
=20
+/* --- --- --- map, unmap, protect --- --- --- */
+
/* Map a file at a fixed address for the client, and update the
segment array accordingly. */
=20
@@ -2857,9 +2893,54 @@
}
=20
=20
-/* See comment on prototype in pub_core_aspacemgr.h for a description
- of this. */
+/* Unmap the given address range an update the segment array
+ accordingly. This fails if the range isn't valid for the
+ client. */
=20
+SysRes VG_(am_munmap_client)( Addr start, SizeT len )
+{
+ SysRes sres;
+
+ if (!VG_IS_PAGE_ALIGNED(start))
+ goto eINVAL;
+
+ if (len =3D=3D 0)
+ return VG_(mk_SysRes_Success)( 0 );
+
+ if (start + len < len)
+ goto eINVAL;
+
+ len =3D VG_PGROUNDUP(len);
+ aspacem_assert(VG_IS_PAGE_ALIGNED(start));
+ aspacem_assert(VG_IS_PAGE_ALIGNED(len));
+
+ if (!VG_(am_is_valid_for_client_or_free_or_resvn)
+ ( start, len, VKI_PROT_NONE ))
+ goto eINVAL;
+
+ sres =3D do_munmap_NO_NOTIFY( start, len );
+ if (sres.isError)
+ return sres;
+
+ VG_(am_notify_munmap)( start, len );
+ return sres;
+
+ eINVAL:
+ return VG_(mk_SysRes_Error)( VKI_EINVAL );
+}
+
+
+/* --- --- --- reservations --- --- --- */
+
+/* Create a reservation from START .. START+LENGTH-1, with the given
+ ShrinkMode. When checking whether the reservation can be created,
+ also ensure that at least abs(EXTRA) extra free bytes will remain
+ above (> 0) or below (< 0) the reservation.
+
+ The reservation will only be created if it, plus the extra-zone,
+ falls entirely within a single free segment. The returned Bool
+ indicates whether the creation succeeded. */
+
Bool VG_(am_create_reservation) ( Addr start, SizeT length,=20
ShrinkMode smode, SSizeT extra )
{
@@ -2910,10 +2991,17 @@
}
=20
=20
-/* See comment on prototype in pub_core_aspacemgr.h for a description
- of this. */
+/* Let SEG be an anonymous client mapping. This fn extends the
+ mapping by DELTA bytes, taking the space from a reservation section
+ which must be adjacent. If DELTA is positive, the segment is
+ extended forwards in the address space, and the reservation must be
+ the next one along. If DELTA is negative, the segment is extended
+ backwards in the address space and the reservation must be the
+ previous one. DELTA must be page aligned and must not exceed the
+ size of the reservation segment. */
=20
-Bool VG_(am_extend_into_adjacent_reservation)( NSegment* seg, SSizeT del=
ta )
+Bool VG_(am_extend_into_adjacent_reservation_client) ( NSegment* seg,=20
+ SSizeT delta )
{
Int segA, segR;
UInt prot;
@@ -2924,7 +3012,7 @@
segA =3D segAddr_to_index( seg );
aspacem_assert(segA >=3D 0 && segA < nsegments_used);
=20
- if (nsegments[segA].kind !=3D SkAnonC && nsegments[segA].kind !=3D Sk=
AnonV)
+ if (nsegments[segA].kind !=3D SkAnonC)
return False;
=20
if (delta =3D=3D 0)
@@ -2958,7 +3046,7 @@
return False; /* kernel bug if this happens? */
if (sres.val !=3D nsegments[segR].start) {
/* kernel bug if this happens? */
- do_munmap_NO_NOTIFY( sres.val, delta );
+ (void)do_munmap_NO_NOTIFY( sres.val, delta );
return False;
}
=20
@@ -2992,7 +3080,7 @@
return False; /* kernel bug if this happens? */
if (sres.val !=3D nsegments[segA].start-delta) {
/* kernel bug if this happens? */
- do_munmap_NO_NOTIFY( sres.val, delta );
+ (void)do_munmap_NO_NOTIFY( sres.val, delta );
return False;
}
=20
@@ -3007,6 +3095,109 @@
}
=20
=20
+/* --- --- --- resizing/move a mapping --- --- --- */
+
+/* Let SEG be a client mapping (anonymous or file). This fn extends
+ the mapping forwards only by DELTA bytes, and trashes whatever was
+ in the new area. Fails if SEG is not a single client mapping or if
+ the new area is not accessible to the client. Fails if DELTA is
+ not page aligned. *seg is invalid after a successful return. */
+
+Bool VG_(am_extend_map_client)( NSegment* seg, SizeT delta )
+{
+ Addr xStart;
+ SysRes sres;
+ NSegment seg_copy;
+
+ if (seg->kind !=3D SkFileC && seg->kind !=3D SkAnonC)
+ return False;
+
+ if (delta =3D=3D 0 || !VG_IS_PAGE_ALIGNED(delta))=20
+ return False;
+
+ xStart =3D seg->end+1;
+ if (xStart + delta < delta)
+ return False;
+
+ if (!VG_(am_is_valid_for_client_or_free_or_resvn)( xStart, delta,=20
+ VKI_PROT_NONE ))
+ return False;
+
+ sres =3D do_extend_mapping_NO_NOTIFY( seg->start, seg->end+1-seg->sta=
rt,
+ delta );
+ if (sres.isError)
+ return False;
+
+ seg_copy =3D *seg;
+ seg_copy.end +=3D delta;
+ add_segment( &seg_copy );
+ return True;
+}
+
+
+/* Remap the old address range to the new address range. Fails if any
+ parameter is not page aligned, if the either size is zero, if any
+ wraparound is implied, if the old address range does not fall
+ entirely within a single segment, if the new address range overlaps
+ with the old one, or if the old address range is not a valid client
+ mapping. */
+
+Bool VG_(am_relocate_nooverlap_client)( Addr old_addr, SizeT old_len,
+ Addr new_addr, SizeT new_len )
+{
+ Int iLo, iHi;
+ SysRes sres;
+ NSegment seg, oldseg;
+
+ if (old_len =3D=3D 0 || new_len =3D=3D 0)
+ return False;
+
+ if (!VG_IS_PAGE_ALIGNED(old_addr) || !VG_IS_PAGE_ALIGNED(old_len)
+ || !VG_IS_PAGE_ALIGNED(new_addr) || !VG_IS_PAGE_ALIGNED(new_len))
+ return False;
+
+ if (old_addr + old_len < old_addr
+ || new_addr + new_len < new_addr)
+ return False;
+
+ if (old_addr + old_len - 1 < new_addr
+ || new_addr + new_len - 1 < old_addr) {
+ /* no overlap */
+ } else
+ return False;
+
+ iLo =3D find_nsegment_idx( old_addr );
+ iHi =3D find_nsegment_idx( old_addr + old_len - 1 );
+ if (iLo !=3D iHi)
+ return False;
+
+ if (nsegments[iLo].kind !=3D SkFileC && nsegments[iLo].kind !=3D SkAn=
onC)
+ return False;
+
+ sres =3D do_relocate_nooverlap_mapping_NO_NOTIFY( old_addr, old_len,=20
+ new_addr, new_len );
+ if (sres.isError)
+ return False;
+
+ oldseg =3D nsegments[iLo];
+
+ /* Create a free hole in the old location. */
+ init_nsegment( &seg );
+ seg.kind =3D SkFree;
+ seg.start =3D old_addr;
+ seg.end =3D old_addr + old_len - 1;
+ add_segment( &seg );
+
+ /* Mark the new area based on the old seg. */
+ oldseg.offset +=3D ((ULong)old_addr) - ((ULong)oldseg.start);
+ oldseg.start =3D new_addr;
+ oldseg.end =3D new_addr + new_len - 1;
+ add_segment( &seg );
+
+ return True;
+}
+
+
/*-----------------------------------------------------------------*/
/*--- ---*/
/*--- Manage stacks for Valgrind itself. ---*/
Modified: branches/ASPACEM/coregrind/m_signals.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_signals.c 2005-09-17 01:48:18 UTC (rev 4=
670)
+++ branches/ASPACEM/coregrind/m_signals.c 2005-09-17 01:50:15 UTC (rev 4=
671)
@@ -1339,6 +1339,11 @@
haveaddr =3D False;
break;
}
+ VG_(am_show_nsegments)(0,"post segfault");
+ {HChar buf[110];
+ VG_(sprintf)(buf, "/bin/cat /proc/%d/maps", VG_(getpid)());
+ VG_(system)(buf);
+ }
break;
=20
case VKI_SIGILL:
@@ -1726,15 +1731,14 @@
=20
udelta =3D VG_PGROUNDUP(seg_next->start - addr);
VG_(debugLog)(1, "signals",=20
- "extending a stack base 0x%llx down by %lld ..\n",
+ "extending a stack base 0x%llx down by %lld\n",
(ULong)seg_next->start, (ULong)udelta);
- if (! VG_(am_extend_into_adjacent_reservation)( seg_next, -(SSizeT)ud=
elta )) {
- VG_(debugLog)(1, "signals", " .. failure\n");
+ if (! VG_(am_extend_into_adjacent_reservation_client)
+ ( seg_next, -(SSizeT)udelta )) {
+ VG_(debugLog)(1, "signals", "extending a stack base: FAILED\n");
return False;
}
=20
- VG_(debugLog)(1, "signals", " .. success\n");
-
/* When we change the main stack, we have to let the stack handling
code know about it. */
/// FIXME VG_(change_stack)(VG_(clstk_id), base, VG_(clstk_end));
Modified: branches/ASPACEM/coregrind/m_syswrap/syswrap-generic.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_syswrap/syswrap-generic.c 2005-09-17 01:=
48:18 UTC (rev 4670)
+++ branches/ASPACEM/coregrind/m_syswrap/syswrap-generic.c 2005-09-17 01:=
50:15 UTC (rev 4671)
@@ -59,7 +59,7 @@
=20
/* Returns True iff address range is something the client can
plausibly mess with: all of it is either already belongs to the
- client or is free. */
+ client or is free or a reservation. */
=20
Bool ML_(valid_client_addr)(Addr start, SizeT size, ThreadId tid,
const Char *syscallname)
@@ -69,7 +69,8 @@
if (size =3D=3D 0)
return True;
=20
- ret =3D VG_(am_is_free_or_valid_for_client)(start,size,VKI_PROT_NONE)=
;
+ ret =3D VG_(am_is_valid_for_client_or_free_or_resvn)
+ (start,size,VKI_PROT_NONE);
=20
if (0)
VG_(printf)("%s: test=3D%p-%p ret=3D%d\n",
@@ -149,140 +150,211 @@
VG_TRACK( new_mem_mmap, a, len, rr, ww, xx );
}
=20
-static=20
-SysRes mremap_segment ( Addr old_addr, SizeT old_size,
- Addr new_addr, SizeT new_size,
- UInt flags, ThreadId tid)
+/* Expand (or shrink) an existing mapping, potentially moving it at
+ the same time (controlled by the MREMAP_MAYMOVE flag). Nightmare.
+*/
+static
+SysRes do_mremap( Addr old_addr, SizeT old_len,=20
+ Addr new_addr, SizeT new_len,
+ UWord flags, ThreadId tid )
{
- SysRes ret;
- Segment *seg, *next;
+ Bool ok;
+ NSegment* old_seg;
+ Addr advised;
+ Bool f_fixed =3D toBool(flags & VKI_MREMAP_FIXED);
+ Bool f_maymove =3D toBool(flags & VKI_MREMAP_MAYMOVE);
=20
- old_size =3D VG_PGROUNDUP(old_size);
- new_size =3D VG_PGROUNDUP(new_size);
+ if (0)
+ VG_(printf)("do_remap (old %p %d) (new %p %d) %s %s\n",
+ old_addr,old_len,new_addr,new_len,=20
+ flags & VKI_MREMAP_MAYMOVE ? "MAYMOVE" : "",
+ flags & VKI_MREMAP_FIXED ? "FIXED" : "");
=20
- if (VG_PGROUNDDN(old_addr) !=3D old_addr)
- return VG_(mk_SysRes_Error)( VKI_EINVAL );
+ if (flags & ~(VKI_MREMAP_FIXED | VKI_MREMAP_MAYMOVE))
+ goto eINVAL;
=20
- if (!ML_(valid_client_addr)(old_addr, old_size, tid, "mremap(old_addr=
)"))
- return VG_(mk_SysRes_Error)( VKI_EFAULT );
+ if (!VG_IS_PAGE_ALIGNED(old_addr))
+ goto eINVAL;
=20
- /* fixed at the current address means we don't move it */
- if ((flags & VKI_MREMAP_FIXED) && (old_addr =3D=3D new_addr))
- flags &=3D ~(VKI_MREMAP_FIXED|VKI_MREMAP_MAYMOVE);
+ old_len =3D VG_PGROUNDUP(old_len);
+ new_len =3D VG_PGROUNDUP(new_len);
=20
- if (flags & VKI_MREMAP_FIXED) {
- if (VG_PGROUNDDN(new_addr) !=3D new_addr)
- return VG_(mk_SysRes_Error)( VKI_EINVAL );
+ if (new_len =3D=3D 0)
+ goto eINVAL;
=20
- if (!ML_(valid_client_addr)(new_addr, new_size, tid, "mremap(new_a=
ddr)"))
- return VG_(mk_SysRes_Error)( VKI_ENOMEM );
+ /* kernel doesn't reject this, but we do. */
+ if (old_len =3D=3D 0)
+ goto eINVAL;
=20
- /* check for overlaps */
- if ((old_addr < (new_addr+new_size) &&
- (old_addr+old_size) > new_addr) ||
- (new_addr < (old_addr+new_size) &&
- (new_addr+new_size) > old_addr))
- return VG_(mk_SysRes_Error)( VKI_EINVAL );
- }
+ /* reject wraparounds */
+ if (old_addr + old_len < old_addr
+ || new_addr + new_len < new_len)
+ goto eINVAL;
=20
- /* Do nothing */
- if (!(flags & VKI_MREMAP_FIXED) && new_size =3D=3D old_size)
- return VG_(mk_SysRes_Success)( old_addr );
+ /* kernel rejects all fixed, no-move requests (which are
+ meaningless). */
+ if (f_fixed =3D=3D True && f_maymove =3D=3D False)
+ goto eINVAL;
=20
- seg =3D VG_(find_segment)(old_addr);
+ /* Stay away from non-client areas. */
+ if (!ML_(valid_client_addr)(old_addr, old_len, tid, "mremap(old_addr)=
"))
+ goto eINVAL;
=20
- /* range must be contained within segment */
- if (seg =3D=3D NULL || !VG_(seg_contains)(seg, old_addr, old_size))
- return VG_(mk_SysRes_Error)( VKI_EINVAL );
+ /* In all remaining cases, if the old range does not fall within a
+ single segment, fail. */
+ old_seg =3D VG_(am_find_nsegment)( old_addr );
+ if (old_addr < old_seg->start || old_addr+old_len-1 > old_seg->end)
+ goto eINVAL;
+ if (old_seg->kind !=3D SkAnonC && old_seg->kind !=3D SkAnonV)
+ goto eINVAL;
=20
- next =3D VG_(find_segment_above_mapped)(old_addr);
+ vg_assert(old_len > 0);
+ vg_assert(new_len > 0);
+ vg_assert(VG_IS_PAGE_ALIGNED(old_len));
+ vg_assert(VG_IS_PAGE_ALIGNED(new_len));
+ vg_assert(VG_IS_PAGE_ALIGNED(old_addr));
=20
- if (0)
- VG_(printf)("mremap: old_addr+new_size=3D%p next->addr=3D%p flags=3D=
%d\n",
- old_addr+new_size, next->addr, flags);
- =20
- if ((flags & VKI_MREMAP_FIXED) ||
- (next !=3D NULL && (old_addr+new_size) > next->addr)) {
- /* we're moving the block */
- Addr a;
- =20
- if ((flags & (VKI_MREMAP_FIXED|VKI_MREMAP_MAYMOVE)) =3D=3D 0)
- /* not allowed to move */
- return VG_(mk_SysRes_Error)( VKI_ENOMEM );=20
+ /* There are 3 remaining cases:
=20
- if ((flags & VKI_MREMAP_FIXED) =3D=3D 0)
- new_addr =3D 0;
+ * maymove =3D=3D False
=20
- a =3D VG_(find_map_space)(new_addr, new_size, True);
+ new space has to be at old address, so:
+ - shrink -> unmap end
+ - same size -> do nothing
+ - grow -> if can grow in-place, do so, else fail
=20
- if ((flags & VKI_MREMAP_FIXED) && a !=3D new_addr)
- /* didn't find the place we wanted */
- return VG_(mk_SysRes_Error)( VKI_ENOMEM );
+ * maymove =3D=3D True, fixed =3D=3D False
=20
- new_addr =3D a;
+ new space can be anywhere, so:
+ - shrink -> unmap end
+ - same size -> do nothing
+ - grow -> if can grow in-place, do so, else=20
+ move to anywhere large enough, else fail
=20
- /* we've nailed down the location */
- flags |=3D VKI_MREMAP_FIXED|VKI_MREMAP_MAYMOVE;
+ * maymove =3D=3D True, fixed =3D=3D True
=20
- ret =3D VG_(do_syscall5)(__NR_mremap, old_addr, old_size, new_size=
,=20
- flags, new_addr);
+ new space must be at new address, so:
=20
- if (ret.isError) {
- return ret;
- }
+ - if new address is not page aligned, fail
+ - if new address range overlaps old one, fail
+ - if new address range cannot be allocated, fail
+ - else move to new address range with new size
+ - else fail
+ */
=20
- VG_TRACK(copy_mem_remap, old_addr, new_addr,=20
- (old_size < new_size) ? old_size : new_size);
+ if (f_maymove =3D=3D False) {
+ /* new space has to be at old address */
+ if (new_len < old_len)
+ goto shrink_in_place;
+ if (new_len > old_len)
+ goto grow_in_place_or_fail;
+ goto same_in_place;
+ }
=20
- if (new_size > old_size)
- VG_TRACK(new_mem_mmap, new_addr+old_size, new_size-old_size,
- seg->prot & VKI_PROT_READ,=20
- seg->prot & VKI_PROT_WRITE,=20
- seg->prot & VKI_PROT_EXEC);
- VG_TRACK(die_mem_munmap, old_addr, old_size);
+ if (f_maymove =3D=3D True && f_fixed =3D=3D False) {
+ /* new space can be anywhere */
+ if (new_len < old_len)
+ goto shrink_in_place;
+ if (new_len > old_len)
+ goto grow_in_place_or_move_anywhere_or_fail;
+ goto same_in_place;
+ }
=20
- VG_(map_file_segment)(new_addr, new_size,
- seg->prot,=20
- seg->flags,
- seg->dev, seg->ino,
- seg->offset, seg->filename);
-
- VG_(munmap)((void *)old_addr, old_size);
- } else {
- /* staying in place */
- ret =3D VG_(mk_SysRes_Success)( old_addr );
-
- if (new_size < old_size) {
- VG_TRACK(die_mem_munmap, old_addr+new_size, old_size-new_size);
- VG_(munmap)((void *)(old_addr+new_size), old_size-new_size);
+ if (f_maymove =3D=3D True && f_fixed =3D=3D True) {
+ /* new space can only be at the new address */
+ if (!VG_IS_PAGE_ALIGNED(new_addr))=20
+ goto eINVAL;
+ if (new_addr+new_len-1 < old_addr || new_addr > old_addr+old_len-1=
) {
+ /* no overlap */
} else {
- /* we've nailed down the location */
- flags &=3D ~VKI_MREMAP_MAYMOVE;
+ goto eINVAL;
+ }
+ if (new_addr =3D=3D 0)=20
+ goto eINVAL;=20
+ /* VG_(am_get_advisory_client_simple) interprets zero to mean
+ non-fixed, which is not what we want */
+ advised =3D VG_(am_get_advisory_client_simple)(new_addr, new_len, =
&ok);
+ if (!ok || advised !=3D new_addr)
+ goto eNOMEM;
+ ok =3D VG_(am_relocate_nooverlap_client)
+ ( old_addr, old_len, new_addr, new_len );
+ if (ok)=20
+ return VG_(mk_SysRes_Success)( new_addr );
+ goto eNOMEM;
+ }
=20
- if (0)
- VG_(printf)("mremap: old_addr=3D%p old_size=3D%d new_size=3D%d flag=
s=3D%d\n",
- old_addr, old_size, new_size, flags);
+ /* end of the 3 cases */
+ /*NOTREACHED*/ vg_assert(0);
=20
- ret =3D VG_(do_syscall5)(__NR_mremap, old_addr, old_size, new_size,=20
- flags, 0);
+ grow_in_place_or_move_anywhere_or_fail:=20
+ {=20
+ /* try growing it in-place */
+ Addr needA =3D old_addr + old_len;
+ SSizeT needL =3D new_len - old_len;
=20
- if (ret.isError || (!ret.isError && ret.val !=3D old_addr))
- return ret;
+ vg_assert(needL > 0);
+ if (needA =3D=3D 0)
+ goto eINVAL;=20
+ /* VG_(am_get_advisory_client_simple) interprets zero to mean
+ non-fixed, which is not what we want */
+ advised =3D VG_(am_get_advisory_client_simple)( needA, needL, &ok );
+ if (ok && advised =3D=3D needA) {
+ ok =3D VG_(am_extend_map_client)( old_seg, needL );
+ old_seg =3D NULL;
+ if (ok)
+ return VG_(mk_SysRes_Success)( old_addr );
+ }
=20
- VG_TRACK(new_mem_mmap, old_addr+old_size, new_size-old_size,
- seg->prot & VKI_PROT_READ,=20
- seg->prot & VKI_PROT_WRITE,=20
- seg->prot & VKI_PROT_EXEC);
+ /* that failed. Look elsewhere. */
+ advised =3D VG_(am_get_advisory_client_simple)( 0, new_len, &ok );
+ if (ok) {
+ /* assert new area does not overlap old */
+ vg_assert(advised+new_len-1 < old_addr=20
+ || advised > old_addr+old_len-1);
+ ok =3D VG_(am_relocate_nooverlap_client)
+ ( old_addr, old_len, advised, new_len );
+ if (ok) return VG_(mk_SysRes_Success)( advised );
+ }
+ goto eNOMEM;
+ }
+ /*NOTREACHED*/ vg_assert(0);
=20
- VG_(map_file_segment)(old_addr+old_size, new_size-old_size,
- seg->prot,=20
- seg->flags,
- seg->dev, seg->ino,
- seg->offset, seg->filename); =20
- }
+ grow_in_place_or_fail:
+ {
+ Addr needA =3D old_addr + old_len;
+ SizeT needL =3D new_len - old_len;
+ if (needA =3D=3D 0)=20
+ goto eINVAL;
+ /* VG_(am_get_advisory_client_simple) interprets zero to mean
+ non-fixed, which is not what we want */
+ advised =3D VG_(am_get_advisory_client_simple)( needA, needL, &ok );
+ if (!ok || advised !=3D needA)
+ goto eNOMEM;
+ ok =3D VG_(am_extend_map_client)( old_seg, needL );
+ old_seg =3D NULL;
+ if (!ok)
+ goto eNOMEM;
+ return VG_(mk_SysRes_Success)( old_addr );
}
+ /*NOTREACHED*/ vg_assert(0);
=20
- return ret;
+ shrink_in_place:
+ {
+ SysRes sres =3D VG_(am_munmap_client)( old_addr+new_len, old_len-new_=
len);
+ if (sres.isError)
+ return sres;
+ return VG_(mk_SysRes_Success)( old_addr );
+ }
+ /*NOTREACHED*/ vg_assert(0);
+
+ same_in_place:
+ return VG_(mk_SysRes_Success)( old_addr );
+ /*NOTREACHED*/ vg_assert(0);
+
+ eINVAL:
+ return VG_(mk_SysRes_Error)( VKI_EINVAL );
+ eNOMEM:
+ return VG_(mk_SysRes_Error)( VKI_ENOMEM );
}
=20
=20
@@ -851,7 +923,7 @@
vg_assert(delta > 0);
vg_assert(VG_IS_PAGE_ALIGNED(delta));
=20
- ok =3D VG_(am_extend_into_adjacent_reservation)( aseg, delta );
+ ok =3D VG_(am_extend_into_adjacent_reservation_client)( aseg, delta )=
;
if (!ok) goto bad;
=20
VG_(brk_limit) =3D newbrk;
@@ -2033,7 +2105,7 @@
unsigned long, new_size, unsigned long, flags,
unsigned long, new_addr);
SET_STATUS_from_SysRes(=20
- mremap_segment((Addr)ARG1, ARG2, (Addr)ARG5, ARG3, ARG4, tid)=20
+ do_mremap((Addr)ARG1, ARG2, (Addr)ARG5, ARG3, ARG4, tid)=20
);
}
=20
Modified: branches/ASPACEM/coregrind/pub_core_aspacemgr.h
=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/pub_core_aspacemgr.h 2005-09-17 01:48:18 U=
TC (rev 4670)
+++ branches/ASPACEM/coregrind/pub_core_aspacemgr.h 2005-09-17 01:50:15 U=
TC (rev 4671)
@@ -263,15 +263,15 @@
VKI_PROT_NONE as 'prot'. Will return False if any part of the
area does not belong to the client or does not have at least
the stated permissions. */
-extern Bool VG_(am_is_valid_for_client)( Addr start, SizeT len,=20
- UInt prot );
+extern Bool VG_(am_is_valid_for_client)
+ ( Addr start, SizeT len, UInt prot );
=20
/* Variant of VG_(am_is_valid_for_client) which allows free areas to
be consider part of the client's addressable space. It also
considers reservations to be allowable, since from the client's
point of view they don't exist. */
-extern Bool VG_(am_is_free_or_valid_for_client)( Addr start, SizeT len,=20
- UInt prot );
+extern Bool VG_(am_is_valid_for_client_or_free_or_resvn)
+ ( Addr start, SizeT len, UInt prot );
=20
/* Trivial fn: return the total amount of space in anonymous mappings,
both for V and the client. Is used for printing stats in
@@ -349,6 +349,8 @@
// loading the client and building its stack/data segment, before
// execution begins. Also for V's own administrative use.
=20
+/* --- --- --- map, unmap, protect --- --- --- */
+
/* Map a file at a fixed address for the client, and update the
segment array accordingly. */
extern SysRes VG_(am_mmap_file_fixed_client)
@@ -368,6 +370,13 @@
itself more address space when needed. */
extern SysRes VG_(am_mmap_anon_float_valgrind)( SizeT cszB );
=20
+/* Unmap the given address range an update the segment array
+ accordingly. This fails if the range isn't valid for the
+ client. */
+extern SysRes VG_(am_munmap_client)( Addr start, SizeT length );
+
+/* --- --- --- reservations --- --- --- */
+
/* Create a reservation from START .. START+LENGTH-1, with the given
ShrinkMode. When checking whether the reservation can be created,
also ensure that at least abs(EXTRA) extra free bytes will remain
@@ -387,10 +396,27 @@
backwards in the address space and the reservation must be the
previous one. DELTA must be page aligned and must not exceed the
size of the reservation segment. */
-extern Bool VG_(am_extend_into_adjacent_reservation)=20
+extern Bool VG_(am_extend_into_adjacent_reservation_client)=20
( NSegment* seg, SSizeT delta );
=20
+/* --- --- --- resizing/move a mapping --- --- --- */
=20
+/* Let SEG be a client mapping (anonymous or file). This fn extends
+ the mapping forwards only by DELTA bytes, and trashes whatever was
+ in the new area. Fails if SEG is not a single client mapping or if
+ the new area is not accessible to the client. Fails if DELTA is
+ not page aligned. *seg is invalid after a successful return. */
+extern Bool VG_(am_extend_map_client)( NSegment* seg, SizeT delta );
+
+/* Remap the old address range to the new address range. Fails if any
+ parameter is not page aligned, if the either size is zero, if any
+ wraparound is implied, if the old address range does not fall
+ entirely within a single segment, if the new address range overlaps
+ with the old one, or if the old address range is not a valid client
+ mapping. */
+extern Bool VG_(am_relocate_nooverlap_client)( Addr old_addr, SizeT old_=
len,
+ Addr new_addr, SizeT new_=
len );
+
//--------------------------------------------------------------
// Valgrind (non-client) thread stacks. V itself runs on such
// stacks. The address space manager provides and suitably
|