Add custom SIGSEGV handler to help find heap corruption.

The new signal handler prints heap diagnostics when you get a SIGSEGV.
Added a fault message member in runtime which is modifiable by
Runtime::SetFaultMessage. When you get a SIGSEGV it will print out
whatever is stored in this string as well as the normal information.
This is useful for debugging heap corruption since it lets you see
which threads were in which methods when the last GC occured.

Added some smarter object dumping logic when the faulting address is
in the heap.

Bug: 12934910

Change-Id: Ia72be2c39f70ad711cbd746d66fad2b617d5d29f
diff --git a/runtime/gc/collector/semi_space.cc b/runtime/gc/collector/semi_space.cc
index a4c9dea..4668a19 100644
--- a/runtime/gc/collector/semi_space.cc
+++ b/runtime/gc/collector/semi_space.cc
@@ -61,7 +61,8 @@
 namespace collector {
 
 static constexpr bool kProtectFromSpace = true;
-static constexpr bool kResetFromSpace = true;
+static constexpr bool kClearFromSpace = true;
+static constexpr bool kStoreStackTraces = false;
 
 // TODO: Unduplicate logic.
 void SemiSpace::ImmuneSpace(space::ContinuousSpace* space) {
@@ -169,6 +170,19 @@
 }
 
 void SemiSpace::MarkingPhase() {
+  if (kStoreStackTraces) {
+    Locks::mutator_lock_->AssertExclusiveHeld(self_);
+    // Store the stack traces into the runtime fault string in case we get a heap corruption
+    // related crash later.
+    ThreadState old_state = self_->SetStateUnsafe(kRunnable);
+    std::ostringstream oss;
+    Runtime* runtime = Runtime::Current();
+    runtime->GetThreadList()->DumpForSigQuit(oss);
+    runtime->GetThreadList()->DumpNativeStacks(oss);
+    runtime->SetFaultMessage(oss.str());
+    CHECK_EQ(self_->SetStateUnsafe(old_state), kRunnable);
+  }
+
   if (generational_) {
     if (gc_cause_ == kGcCauseExplicit || gc_cause_ == kGcCauseForNativeAlloc ||
         clear_soft_references_) {
@@ -353,19 +367,17 @@
     TimingLogger::ScopedSplit split("UnBindBitmaps", &timings_);
     GetHeap()->UnBindBitmaps();
   }
-  // Release the memory used by the from space.
-  if (kResetFromSpace) {
-    // Clearing from space.
+  if (kClearFromSpace) {
+    // Release the memory used by the from space.
     from_space_->Clear();
   }
+  from_space_->Reset();
   // Protect the from space.
-  VLOG(heap)
-      << "mprotect region " << reinterpret_cast<void*>(from_space_->Begin()) << " - "
-      << reinterpret_cast<void*>(from_space_->Limit());
+  VLOG(heap) << "Protecting space " << *from_space_;
   if (kProtectFromSpace) {
-    mprotect(from_space_->Begin(), from_space_->Capacity(), PROT_NONE);
+    from_space_->GetMemMap()->Protect(PROT_NONE);
   } else {
-    mprotect(from_space_->Begin(), from_space_->Capacity(), PROT_READ);
+    from_space_->GetMemMap()->Protect(PROT_READ);
   }
   if (saved_bytes_ > 0) {
     VLOG(heap) << "Avoided dirtying " << PrettySize(saved_bytes_);