Add handler for printing java stack traces for compiled code SIGSEGV.

Added a new FaultHandler which attempts to print a java stack trace
when a SIGSEGV occurse in generated code. This should help debugging
compiler and GC related heap corruption.

Bug: 13725693
Bug: 12934910

Change-Id: Id54d83ea180c222eb86d449c61926e83f0b026ad
diff --git a/runtime/fault_handler.cc b/runtime/fault_handler.cc
index fcb567e..b8093bc 100644
--- a/runtime/fault_handler.cc
+++ b/runtime/fault_handler.cc
@@ -60,43 +60,50 @@
 }
 
 void FaultManager::HandleFault(int sig, siginfo_t* info, void* context) {
-  bool handled = false;
   LOG(DEBUG) << "Handling fault";
-  if (IsInGeneratedCode(context)) {
+  if (IsInGeneratedCode(context, true)) {
     LOG(DEBUG) << "in generated code, looking for handler";
-    for (auto& handler : handlers_) {
+    for (const auto& handler : generated_code_handlers_) {
       LOG(DEBUG) << "invoking Action on handler " << handler;
-      handled = handler->Action(sig, info, context);
-      if (handled) {
+      if (handler->Action(sig, info, context)) {
         return;
       }
     }
   }
-
-  if (!handled) {
-    LOG(ERROR)<< "Caught unknown SIGSEGV in ART fault handler";
-    oldaction_.sa_sigaction(sig, info, context);
-  }
-}
-
-void FaultManager::AddHandler(FaultHandler* handler) {
-  handlers_.push_back(handler);
-}
-
-void FaultManager::RemoveHandler(FaultHandler* handler) {
-  for (Handlers::iterator i = handlers_.begin(); i != handlers_.end(); ++i) {
-    FaultHandler* h = *i;
-    if (h == handler) {
-      handlers_.erase(i);
+  for (const auto& handler : other_handlers_) {
+    if (handler->Action(sig, info, context)) {
       return;
     }
   }
+  LOG(ERROR)<< "Caught unknown SIGSEGV in ART fault handler";
+  oldaction_.sa_sigaction(sig, info, context);
 }
 
+void FaultManager::AddHandler(FaultHandler* handler, bool generated_code) {
+  if (generated_code) {
+    generated_code_handlers_.push_back(handler);
+  } else {
+    other_handlers_.push_back(handler);
+  }
+}
+
+void FaultManager::RemoveHandler(FaultHandler* handler) {
+  auto it = std::find(generated_code_handlers_.begin(), generated_code_handlers_.end(), handler);
+  if (it != generated_code_handlers_.end()) {
+    generated_code_handlers_.erase(it);
+    return;
+  }
+  auto it2 = std::find(other_handlers_.begin(), other_handlers_.end(), handler);
+  if (it2 != other_handlers_.end()) {
+    other_handlers_.erase(it);
+    return;
+  }
+  LOG(FATAL) << "Attempted to remove non existent handler " << handler;
+}
 
 // This function is called within the signal handler.  It checks that
 // the mutator_lock is held (shared).  No annotalysis is done.
-bool FaultManager::IsInGeneratedCode(void *context) {
+bool FaultManager::IsInGeneratedCode(void* context, bool check_dex_pc) {
   // We can only be running Java code in the current thread if it
   // is in Runnable state.
   LOG(DEBUG) << "Checking for generated code";
@@ -119,27 +126,25 @@
     return false;
   }
 
-  uintptr_t potential_method = 0;
+  mirror::ArtMethod* method_obj = 0;
   uintptr_t return_pc = 0;
+  uintptr_t sp = 0;
 
   // Get the architecture specific method address and return address.  These
-  // are in architecture specific files in arch/<arch>/fault_handler_<arch>.cc
-  GetMethodAndReturnPC(context, /*out*/potential_method, /*out*/return_pc);
+  // are in architecture specific files in arch/<arch>/fault_handler_<arch>.
+  GetMethodAndReturnPCAndSP(context, &method_obj, &return_pc, &sp);
 
   // If we don't have a potential method, we're outta here.
-  LOG(DEBUG) << "potential method: " << potential_method;
-  if (potential_method == 0) {
+  LOG(DEBUG) << "potential method: " << method_obj;
+  if (method_obj == 0 || !IsAligned<kObjectAlignment>(method_obj)) {
     LOG(DEBUG) << "no method";
     return false;
   }
 
   // Verify that the potential method is indeed a method.
   // TODO: check the GC maps to make sure it's an object.
-
-  mirror::Object* method_obj =
-      reinterpret_cast<mirror::Object*>(potential_method);
-
   // Check that the class pointer inside the object is not null and is aligned.
+  // TODO: Method might be not a heap address, and GetClass could fault.
   mirror::Class* cls = method_obj->GetClass<kVerifyNone>();
   if (cls == nullptr) {
     LOG(DEBUG) << "not a class";
@@ -164,41 +169,64 @@
 
   // We can be certain that this is a method now.  Check if we have a GC map
   // at the return PC address.
-  mirror::ArtMethod* method =
-      reinterpret_cast<mirror::ArtMethod*>(potential_method);
   if (true || kIsDebugBuild) {
     LOG(DEBUG) << "looking for dex pc for return pc " << std::hex << return_pc;
-    const void* code = Runtime::Current()->GetInstrumentation()->GetQuickCodeFor(method);
+    const void* code = Runtime::Current()->GetInstrumentation()->GetQuickCodeFor(method_obj);
     uint32_t sought_offset = return_pc - reinterpret_cast<uintptr_t>(code);
     LOG(DEBUG) << "pc offset: " << std::hex << sought_offset;
   }
-  uint32_t dexpc = method->ToDexPc(return_pc, false);
+  uint32_t dexpc = method_obj->ToDexPc(return_pc, false);
   LOG(DEBUG) << "dexpc: " << dexpc;
-  return dexpc != DexFile::kDexNoIndex;
+  return !check_dex_pc || dexpc != DexFile::kDexNoIndex;
+}
+
+FaultHandler::FaultHandler(FaultManager* manager) : manager_(manager) {
 }
 
 //
 // Null pointer fault handler
 //
-
-NullPointerHandler::NullPointerHandler(FaultManager* manager) {
-  manager->AddHandler(this);
+NullPointerHandler::NullPointerHandler(FaultManager* manager) : FaultHandler(manager) {
+  manager_->AddHandler(this, true);
 }
 
 //
 // Suspension fault handler
 //
-
-SuspensionHandler::SuspensionHandler(FaultManager* manager) {
-  manager->AddHandler(this);
+SuspensionHandler::SuspensionHandler(FaultManager* manager) : FaultHandler(manager) {
+  manager_->AddHandler(this, true);
 }
 
 //
 // Stack overflow fault handler
 //
-
-StackOverflowHandler::StackOverflowHandler(FaultManager* manager) {
-  manager->AddHandler(this);
+StackOverflowHandler::StackOverflowHandler(FaultManager* manager) : FaultHandler(manager) {
+  manager_->AddHandler(this, true);
 }
+
+//
+// Stack trace handler, used to help get a stack trace from SIGSEGV inside of compiled code.
+//
+JavaStackTraceHandler::JavaStackTraceHandler(FaultManager* manager) : FaultHandler(manager) {
+  manager_->AddHandler(this, false);
+}
+
+bool JavaStackTraceHandler::Action(int sig, siginfo_t* siginfo, void* context) {
+  // Make sure that we are in the generated code, but we may not have a dex pc.
+  if (manager_->IsInGeneratedCode(context, false)) {
+    LOG(ERROR) << "Dumping java stack trace for crash in generated code";
+    mirror::ArtMethod* method = nullptr;
+    uintptr_t return_pc = 0;
+    uintptr_t sp = 0;
+    manager_->GetMethodAndReturnPCAndSP(context, &method, &return_pc, &sp);
+    Thread* self = Thread::Current();
+    // Inside of generated code, sp[0] is the method, so sp is the frame.
+    mirror::ArtMethod** frame = reinterpret_cast<mirror::ArtMethod**>(sp);
+    self->SetTopOfStack(frame, 0);  // Since we don't necessarily have a dex pc, pass in 0.
+    self->DumpJavaStack(LOG(ERROR));
+  }
+  return false;  // Return false since we want to propagate the fault to the main signal handler.
+}
+
 }   // namespace art