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 |