Re-add proper support for mremap().  Also, fix a bug in munmap().


git-svn-id: svn://svn.valgrind.org/valgrind/trunk@2142 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/coregrind/vg_memory.c b/coregrind/vg_memory.c
index ff6a040..3a50975 100644
--- a/coregrind/vg_memory.c
+++ b/coregrind/vg_memory.c
@@ -114,8 +114,8 @@
    VG_(SkipNode_Free)(&sk_segments, s);
 }
 
-/* Split a segment at address a */
-static Segment *split_segment(Addr a)
+/* Split a segment at address a, returning the new segment */
+Segment *VG_(split_segment)(Addr a)
 {
    Segment *s = VG_(SkipList_Find)(&sk_segments, &a);
    Segment *ns;
@@ -157,6 +157,7 @@
    Segment *s;
    Segment *next;
    static const Bool debug = False || mem_debug;
+   Addr end = addr+len;
 
    if (len == 0)
       return;
@@ -174,19 +175,25 @@
    for(s = VG_(SkipList_Find)(&sk_segments, &addr); 
        s != NULL && s->addr < (addr+len); 
        s = next) {
+      Addr seg_end = s->addr + s->len;
 
       /* fetch next now in case we end up deleting this segment */
       next = VG_(SkipNode_Next)(&sk_segments, s);
 
       if (debug)
-	 VG_(printf)("unmap: addr=%p s=%p ->addr=%p len=%d end=%p\n",
-		     addr, s, s->addr, s->len, s->addr+s->len);
+	 VG_(printf)("unmap: addr=%p-%p s=%p ->addr=%p-%p len=%d\n",
+		     addr, addr+len, s, s->addr, s->addr+s->len, s->len);
 
-      if (!VG_(seg_overlaps)(s, addr, len))
+      if (!VG_(seg_overlaps)(s, addr, len)) {
+	 if (debug)
+	    VG_(printf)("   (no overlap)\n");
 	 continue;
+      }
 
       /* 4 cases: */
-      if (addr > s->addr && addr < (s->addr + s->len)) {
+      if (addr > s->addr &&
+	  addr < seg_end &&
+	  end >= seg_end) {
 	 /* this segment's tail is truncated by [addr, addr+len)
 	    -> truncate tail
 	 */
@@ -194,7 +201,7 @@
 
 	 if (debug)
 	    VG_(printf)("  case 1: s->len=%d\n", s->len);
-      } else if (addr <= s->addr && (addr+len) >= (s->addr + s->len)) {
+      } else if (addr <= s->addr && end >= seg_end) {
 	 /* this segment is completely contained within [addr, addr+len)
 	    -> delete segment
 	 */
@@ -204,7 +211,7 @@
 
 	 if (debug)
 	    VG_(printf)("  case 2: s==%p deleted\n", s);
-      } else if ((addr+len) > s->addr && (addr+len) < (s->addr+s->len)) {
+      } else if (addr <= s->addr && end > s->addr && end < seg_end) {
 	 /* this segment's head is truncated by [addr, addr+len)
 	    -> truncate head
 	 */
@@ -216,14 +223,14 @@
 
 	 if (debug)
 	    VG_(printf)("  case 3: s->addr=%p s->len=%d delta=%d\n", s->addr, s->len, delta);
-      } else if (addr > s->addr && (addr+len) < (s->addr + s->len)) {
+      } else if (addr > s->addr && end < seg_end) {
 	 /* [addr, addr+len) is contained within a single segment
 	    -> split segment into 3, delete middle portion
 	  */
 	 Segment *middle, *rs;
 
-	 middle = split_segment(addr);
-	 split_segment(addr+len);
+	 middle = VG_(split_segment)(addr);
+	 VG_(split_segment)(addr+len);
 
 	 vg_assert(middle->addr == addr);
 	 rs = VG_(SkipList_Remove)(&sk_segments, &addr);
@@ -455,8 +462,8 @@
    vg_assert((a & (VKI_BYTES_PER_PAGE-1)) == 0);
    vg_assert((len & (VKI_BYTES_PER_PAGE-1)) == 0);
 
-   split_segment(a);
-   split_segment(a+len);
+   VG_(split_segment)(a);
+   VG_(split_segment)(a+len);
 
    for(s = VG_(SkipList_Find)(&sk_segments, &a);
        s != NULL && s->addr < a+len;