Fix and extend debugging output for bug 74410240.

Test: Manually break in the resolution trampoline and
      force printing the message.
Bug: 74410240

(cherry picked from commit 606adb3a515b31e6d4b02becb36f732918fe7713)

Change-Id: I9bd79f80012b99838c0765e9934f69b4763d70a5
Merged-In: I5f3fea53a7ec2170b644fb13bca84bae099243c8
diff --git a/runtime/Android.bp b/runtime/Android.bp
index c0f1c36..0802582 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -46,6 +46,7 @@
         "class_table.cc",
         "common_throws.cc",
         "compiler_filter.cc",
+        "debug_print.cc",
         "debugger.cc",
         "dex/art_dex_file_loader.cc",
         "dex/dex_file_annotations.cc",
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 69b17c1..9b80e7a 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -53,6 +53,7 @@
 #include "class_loader_utils.h"
 #include "class_table-inl.h"
 #include "compiler_callbacks.h"
+#include "debug_print.h"
 #include "debugger.h"
 #include "dex/descriptors_names.h"
 #include "dex/dex_file-inl.h"
@@ -7833,83 +7834,6 @@
   return resolved;
 }
 
-std::string DescribeSpace(ObjPtr<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_) {
-  std::ostringstream oss;
-  gc::Heap* heap = Runtime::Current()->GetHeap();
-  gc::space::ContinuousSpace* cs = heap->FindContinuousSpaceFromAddress(klass.Ptr());
-  if (cs != nullptr) {
-    if (cs->IsImageSpace()) {
-      oss << "image;" << cs->GetName() << ";" << cs->AsImageSpace()->GetImageFilename();
-    } else {
-      oss << "continuous;" << cs->GetName();
-    }
-  } else {
-    gc::space::DiscontinuousSpace* ds =
-        heap->FindDiscontinuousSpaceFromObject(klass, /* fail_ok */ true);
-    if (ds != nullptr) {
-      oss << "discontinuous;" << ds->GetName();
-    } else {
-      oss << "invalid";
-    }
-  }
-  return oss.str();
-}
-
-std::string DescribeLoaders(ObjPtr<mirror::ClassLoader> loader, const char* class_descriptor)
-    REQUIRES_SHARED(Locks::mutator_lock_) {
-  std::ostringstream oss;
-  uint32_t hash = ComputeModifiedUtf8Hash(class_descriptor);
-  ObjPtr<mirror::Class> path_class_loader =
-      WellKnownClasses::ToClass(WellKnownClasses::dalvik_system_PathClassLoader);
-  ObjPtr<mirror::Class> dex_class_loader =
-      WellKnownClasses::ToClass(WellKnownClasses::dalvik_system_DexClassLoader);
-  ObjPtr<mirror::Class> delegate_last_class_loader =
-      WellKnownClasses::ToClass(WellKnownClasses::dalvik_system_DelegateLastClassLoader);
-
-  // Print the class loader chain.
-  bool found_class = false;
-  const char* loader_separator = "";
-  if (loader == nullptr) {
-    oss << "BootClassLoader";  // This would be unexpected.
-  }
-  for (; loader != nullptr; loader = loader->GetParent()) {
-    oss << loader_separator << loader->GetClass()->PrettyDescriptor();
-    loader_separator = ";";
-    // If we didn't find the interface yet, try to find it in the current class loader.
-    if (!found_class) {
-      ClassTable* table = Runtime::Current()->GetClassLinker()->ClassTableForClassLoader(loader);
-      ObjPtr<mirror::Class> klass =
-          (table != nullptr) ? table->Lookup(class_descriptor, hash) : nullptr;
-      if (klass != nullptr) {
-        found_class = true;
-        oss << "[hit:" << DescribeSpace(klass) << "]";
-      }
-    }
-
-    // For PathClassLoader, DexClassLoader or DelegateLastClassLoader
-    // also dump the dex file locations.
-    if (loader->GetClass() == path_class_loader ||
-        loader->GetClass() == dex_class_loader ||
-        loader->GetClass() == delegate_last_class_loader) {
-      oss << "(";
-      ScopedObjectAccessUnchecked soa(Thread::Current());
-      StackHandleScope<1> hs(soa.Self());
-      Handle<mirror::ClassLoader> handle(hs.NewHandle(loader));
-      const char* path_separator = "";
-      VisitClassLoaderDexFiles(soa,
-                               handle,
-                               [&](const DexFile* dex_file) {
-                                 oss << path_separator << dex_file->GetLocation();
-                                 path_separator = ":";
-                                 return true;  // Continue with the next DexFile.
-                               });
-      oss << ")";
-    }
-  }
-
-  return oss.str();
-}
-
 ArtMethod* ClassLinker::FindResolvedMethod(ObjPtr<mirror::Class> klass,
                                            ObjPtr<mirror::DexCache> dex_cache,
                                            ObjPtr<mirror::ClassLoader> class_loader,
diff --git a/runtime/debug_print.cc b/runtime/debug_print.cc
new file mode 100644
index 0000000..44a1836
--- /dev/null
+++ b/runtime/debug_print.cc
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <sstream>
+
+#include "debug_print.h"
+
+#include "class_linker.h"
+#include "class_table.h"
+#include "class_loader_utils.h"
+#include "dex/utf.h"
+#include "gc/heap.h"
+#include "gc/space/space-inl.h"
+#include "mirror/class.h"
+#include "mirror/class_loader.h"
+#include "runtime.h"
+#include "scoped_thread_state_change-inl.h"
+#include "thread-current-inl.h"
+#include "well_known_classes.h"
+
+namespace art {
+
+std::string DescribeSpace(ObjPtr<mirror::Class> klass) {
+  std::ostringstream oss;
+  gc::Heap* heap = Runtime::Current()->GetHeap();
+  gc::space::ContinuousSpace* cs =
+      heap->FindContinuousSpaceFromObject(klass.Ptr(), /* fail_ok */ true);
+  if (cs != nullptr) {
+    if (cs->IsImageSpace()) {
+      oss << "image;" << cs->GetName() << ";" << cs->AsImageSpace()->GetImageFilename();
+    } else {
+      oss << "continuous;" << cs->GetName();
+    }
+  } else {
+    gc::space::DiscontinuousSpace* ds =
+        heap->FindDiscontinuousSpaceFromObject(klass, /* fail_ok */ true);
+    if (ds != nullptr) {
+      oss << "discontinuous;" << ds->GetName();
+    } else {
+      oss << "invalid";
+    }
+  }
+  return oss.str();
+}
+
+std::string DescribeLoaders(ObjPtr<mirror::ClassLoader> loader, const char* class_descriptor) {
+  std::ostringstream oss;
+  uint32_t hash = ComputeModifiedUtf8Hash(class_descriptor);
+  ObjPtr<mirror::Class> path_class_loader =
+      WellKnownClasses::ToClass(WellKnownClasses::dalvik_system_PathClassLoader);
+  ObjPtr<mirror::Class> dex_class_loader =
+      WellKnownClasses::ToClass(WellKnownClasses::dalvik_system_DexClassLoader);
+  ObjPtr<mirror::Class> delegate_last_class_loader =
+      WellKnownClasses::ToClass(WellKnownClasses::dalvik_system_DelegateLastClassLoader);
+
+  // Print the class loader chain.
+  bool found_class = false;
+  const char* loader_separator = "";
+  if (loader == nullptr) {
+    oss << "BootClassLoader";  // This would be unexpected.
+  }
+  for (; loader != nullptr; loader = loader->GetParent()) {
+    oss << loader_separator << loader->GetClass()->PrettyDescriptor();
+    loader_separator = ";";
+    // If we didn't find the class yet, try to find it in the current class loader.
+    if (!found_class) {
+      ClassTable* table = Runtime::Current()->GetClassLinker()->ClassTableForClassLoader(loader);
+      ObjPtr<mirror::Class> klass =
+          (table != nullptr) ? table->Lookup(class_descriptor, hash) : nullptr;
+      if (klass != nullptr) {
+        found_class = true;
+        oss << "[hit:" << DescribeSpace(klass) << "]";
+      }
+    }
+
+    // For PathClassLoader, DexClassLoader or DelegateLastClassLoader
+    // also dump the dex file locations.
+    if (loader->GetClass() == path_class_loader ||
+        loader->GetClass() == dex_class_loader ||
+        loader->GetClass() == delegate_last_class_loader) {
+      oss << "(";
+      ScopedObjectAccessUnchecked soa(Thread::Current());
+      StackHandleScope<1> hs(soa.Self());
+      Handle<mirror::ClassLoader> handle(hs.NewHandle(loader));
+      const char* path_separator = "";
+      VisitClassLoaderDexFiles(soa,
+                               handle,
+                               [&](const DexFile* dex_file) {
+                                 oss << path_separator << dex_file->GetLocation();
+                                 path_separator = ":";
+                                 return true;  // Continue with the next DexFile.
+                               });
+      oss << ")";
+    }
+  }
+
+  return oss.str();
+}
+
+}  // namespace art
diff --git a/runtime/debug_print.h b/runtime/debug_print.h
new file mode 100644
index 0000000..479c36a
--- /dev/null
+++ b/runtime/debug_print.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_RUNTIME_DEBUG_PRINT_H_
+#define ART_RUNTIME_DEBUG_PRINT_H_
+
+#include "base/mutex.h"
+#include "mirror/object.h"
+
+// Helper functions for printing extra information for certain hard to diagnose bugs.
+
+namespace art {
+
+std::string DescribeSpace(ObjPtr<mirror::Class> klass)
+    REQUIRES_SHARED(Locks::mutator_lock_) COLD_ATTR;
+std::string DescribeLoaders(ObjPtr<mirror::ClassLoader> loader, const char* class_descriptor)
+    REQUIRES_SHARED(Locks::mutator_lock_) COLD_ATTR;
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_DEBUG_PRINT_H_
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index 2eb3ab9..66cec71 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -19,6 +19,7 @@
 #include "base/enums.h"
 #include "callee_save_frame.h"
 #include "common_throws.h"
+#include "debug_print.h"
 #include "debugger.h"
 #include "dex/dex_file-inl.h"
 #include "dex/dex_file_types.h"
@@ -1187,9 +1188,24 @@
   }
 }
 
+static void DumpB74410240ClassData(ObjPtr<mirror::Class> klass)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  std::string storage;
+  const char* descriptor = klass->GetDescriptor(&storage);
+  LOG(FATAL_WITHOUT_ABORT) << "  " << DescribeLoaders(klass->GetClassLoader(), descriptor);
+  const OatDexFile* oat_dex_file = klass->GetDexFile().GetOatDexFile();
+  if (oat_dex_file != nullptr) {
+    const OatFile* oat_file = oat_dex_file->GetOatFile();
+    const char* dex2oat_cmdline =
+        oat_file->GetOatHeader().GetStoreValueByKey(OatHeader::kDex2OatCmdLineKey);
+    LOG(FATAL_WITHOUT_ABORT) << "    OatFile: " << oat_file->GetLocation()
+        << "; " << (dex2oat_cmdline != nullptr ? dex2oat_cmdline : "<not recorded>");
+  }
+}
+
 static void DumpB74410240DebugData(ArtMethod** sp) REQUIRES_SHARED(Locks::mutator_lock_) {
   // Mimick the search for the caller and dump some data while doing so.
-  LOG(FATAL_WITHOUT_ABORT) << "Dumping debugging data for b/74410240.";
+  LOG(FATAL_WITHOUT_ABORT) << "Dumping debugging data, please attach a bugreport to b/74410240.";
 
   constexpr CalleeSaveType type = CalleeSaveType::kSaveRefsAndArgs;
   CHECK_EQ(*sp, Runtime::Current()->GetCalleeSaveMethod(type));
@@ -1227,6 +1243,7 @@
       << " dex pc: " << dex_pc
       << " dex file: " << outer_method->GetDexFile()->GetLocation()
       << " class table: " << class_linker->ClassTableForClassLoader(outer_method->GetClassLoader());
+  DumpB74410240ClassData(outer_method->GetDeclaringClass());
   LOG(FATAL_WITHOUT_ABORT) << "  instruction: " << DumpInstruction(outer_method, dex_pc);
 
   ArtMethod* caller = outer_method;
@@ -1260,7 +1277,8 @@
           << " dex pc: " << dex_pc
           << " dex file: " << caller->GetDexFile()->GetLocation()
           << " class table: "
-          << class_linker->ClassTableForClassLoader(outer_method->GetClassLoader());
+          << class_linker->ClassTableForClassLoader(caller->GetClassLoader());
+      DumpB74410240ClassData(caller->GetDeclaringClass());
       LOG(FATAL_WITHOUT_ABORT) << "  instruction: " << DumpInstruction(caller, dex_pc);
     }
   }