Verify there's no mem map gap for immune region not to break.

This adds code that verifies that there's no memory map gap between
the image space and the main space so that the immune region
functionality won't silently break. For example, if there's a gap and
a large object is allocated in that gap, the large object is
incorrectly part of the immune region and the marking breaks.

Bug: 14059466
Change-Id: Ie6ed82988d74b6d0562ebbbaac96ee43c15b14a6
diff --git a/runtime/mem_map.cc b/runtime/mem_map.cc
index 49e0b54..859269a 100644
--- a/runtime/mem_map.cc
+++ b/runtime/mem_map.cc
@@ -15,6 +15,7 @@
  */
 
 #include "mem_map.h"
+#include "thread-inl.h"
 
 #include <inttypes.h>
 #include <backtrace/BacktraceMap.h>
@@ -51,6 +52,19 @@
   return os;
 }
 
+std::ostream& operator<<(std::ostream& os, const std::multimap<void*, MemMap*>& mem_maps) {
+  os << "MemMap:" << std::endl;
+  for (auto it = mem_maps.begin(); it != mem_maps.end(); ++it) {
+    void* base = it->first;
+    MemMap* map = it->second;
+    CHECK_EQ(base, map->BaseBegin());
+    os << *map << std::endl;
+  }
+  return os;
+}
+
+std::multimap<void*, MemMap*> MemMap::maps_;
+
 #if defined(__LP64__) && !defined(__x86_64__)
 // Handling mem_map in 32b address range for 64b architectures that do not support MAP_32BIT.
 
@@ -351,6 +365,19 @@
   if (result == -1) {
     PLOG(FATAL) << "munmap failed";
   }
+
+  // Remove it from maps_.
+  MutexLock mu(Thread::Current(), *Locks::mem_maps_lock_);
+  bool found = false;
+  for (auto it = maps_.lower_bound(base_begin_), end = maps_.end();
+       it != end && it->first == base_begin_; ++it) {
+    if (it->second == this) {
+      found = true;
+      maps_.erase(it);
+      break;
+    }
+  }
+  CHECK(found) << "MemMap not found";
 }
 
 MemMap::MemMap(const std::string& name, byte* begin, size_t size, void* base_begin,
@@ -365,6 +392,10 @@
     CHECK(begin_ != nullptr);
     CHECK(base_begin_ != nullptr);
     CHECK_NE(base_size_, 0U);
+
+    // Add it to maps_.
+    MutexLock mu(Thread::Current(), *Locks::mem_maps_lock_);
+    maps_.insert(std::pair<void*, MemMap*>(base_begin_, this));
   }
 };
 
@@ -453,10 +484,68 @@
   return false;
 }
 
+bool MemMap::CheckNoGaps(MemMap* begin_map, MemMap* end_map) {
+  MutexLock mu(Thread::Current(), *Locks::mem_maps_lock_);
+  CHECK(begin_map != nullptr);
+  CHECK(end_map != nullptr);
+  CHECK(HasMemMap(begin_map));
+  CHECK(HasMemMap(end_map));
+  CHECK_LE(begin_map->BaseBegin(), end_map->BaseBegin());
+  MemMap* map = begin_map;
+  while (map->BaseBegin() != end_map->BaseBegin()) {
+    MemMap* next_map = GetLargestMemMapAt(map->BaseEnd());
+    if (next_map == nullptr) {
+      // Found a gap.
+      return false;
+    }
+    map = next_map;
+  }
+  return true;
+}
+
+void MemMap::DumpMaps(std::ostream& os) {
+  DumpMaps(os, maps_);
+}
+
+void MemMap::DumpMaps(std::ostream& os, const std::multimap<void*, MemMap*>& mem_maps) {
+  MutexLock mu(Thread::Current(), *Locks::mem_maps_lock_);
+  DumpMapsLocked(os, mem_maps);
+}
+
+void MemMap::DumpMapsLocked(std::ostream& os, const std::multimap<void*, MemMap*>& mem_maps) {
+  os << mem_maps;
+}
+
+bool MemMap::HasMemMap(MemMap* map) {
+  void* base_begin = map->BaseBegin();
+  for (auto it = maps_.lower_bound(base_begin), end = maps_.end();
+       it != end && it->first == base_begin; ++it) {
+    if (it->second == map) {
+      return true;
+    }
+  }
+  return false;
+}
+
+MemMap* MemMap::GetLargestMemMapAt(void* address) {
+  size_t largest_size = 0;
+  MemMap* largest_map = nullptr;
+  for (auto it = maps_.lower_bound(address), end = maps_.end();
+       it != end && it->first == address; ++it) {
+    MemMap* map = it->second;
+    CHECK(map != nullptr);
+    if (largest_size < map->BaseSize()) {
+      largest_size = map->BaseSize();
+      largest_map = map;
+    }
+  }
+  return largest_map;
+}
+
 std::ostream& operator<<(std::ostream& os, const MemMap& mem_map) {
-  os << StringPrintf("[MemMap: %s prot=0x%x %p-%p]",
-                     mem_map.GetName().c_str(), mem_map.GetProtect(),
-                     mem_map.BaseBegin(), mem_map.BaseEnd());
+  os << StringPrintf("[MemMap: %p-%p prot=0x%x %s]",
+                     mem_map.BaseBegin(), mem_map.BaseEnd(), mem_map.GetProtect(),
+                     mem_map.GetName().c_str());
   return os;
 }