Add extra logging for bug 74410240.

Test: Manually break in the resolution trampoline and
      force printing the message.
Bug: 74410240
Change-Id: Id3480399fae30840d73ef105707fe1977f0f2a19
diff --git a/runtime/entrypoints/entrypoint_utils-inl.h b/runtime/entrypoints/entrypoint_utils-inl.h
index 404c535..270bce2 100644
--- a/runtime/entrypoints/entrypoint_utils-inl.h
+++ b/runtime/entrypoints/entrypoint_utils-inl.h
@@ -81,13 +81,14 @@
 
   // Lookup the declaring class of the inlined method.
   ObjPtr<mirror::DexCache> dex_cache = caller->GetDexCache();
-  const DexFile* dex_file = dex_cache->GetDexFile();
-  const DexFile::MethodId& method_id = dex_file->GetMethodId(method_index);
   ArtMethod* inlined_method = dex_cache->GetResolvedMethod(method_index, kRuntimePointerSize);
   if (inlined_method != nullptr) {
     DCHECK(!inlined_method->IsRuntimeMethod());
     return inlined_method;
   }
+  // TODO: Use ClassLoader::LookupResolvedMethod() instead.
+  const DexFile* dex_file = dex_cache->GetDexFile();
+  const DexFile::MethodId& method_id = dex_file->GetMethodId(method_index);
   const char* descriptor = dex_file->StringByTypeIdx(method_id.class_idx_);
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
   Thread* self = Thread::Current();
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index e9a0808..b335872 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -1175,6 +1175,97 @@
   return return_or_deoptimize_pc;
 }
 
+static std::string DumpInstruction(ArtMethod* method, uint32_t dex_pc)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  if (dex_pc == static_cast<uint32_t>(-1)) {
+    CHECK(method == jni::DecodeArtMethod(WellKnownClasses::java_lang_String_charAt));
+    return "<native>";
+  } else {
+    CodeItemInstructionAccessor accessor = method->DexInstructions();
+    CHECK_LT(dex_pc, accessor.InsnsSizeInCodeUnits());
+    return accessor.InstructionAt(dex_pc).DumpString(method->GetDexFile());
+  }
+}
+
+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.";
+
+  constexpr CalleeSaveType type = CalleeSaveType::kSaveRefsAndArgs;
+  CHECK_EQ(*sp, Runtime::Current()->GetCalleeSaveMethod(type));
+
+  const size_t callee_frame_size = GetCalleeSaveFrameSize(kRuntimeISA, type);
+  auto** caller_sp = reinterpret_cast<ArtMethod**>(
+      reinterpret_cast<uintptr_t>(sp) + callee_frame_size);
+  const size_t callee_return_pc_offset = GetCalleeSaveReturnPcOffset(kRuntimeISA, type);
+  uintptr_t caller_pc = *reinterpret_cast<uintptr_t*>(
+      (reinterpret_cast<uint8_t*>(sp) + callee_return_pc_offset));
+  ArtMethod* outer_method = *caller_sp;
+
+  if (UNLIKELY(caller_pc == reinterpret_cast<uintptr_t>(GetQuickInstrumentationExitPc()))) {
+    LOG(FATAL_WITHOUT_ABORT) << "Method: " << outer_method->PrettyMethod()
+        << " native pc: " << caller_pc << " Instrumented!";
+    return;
+  }
+
+  const OatQuickMethodHeader* current_code = outer_method->GetOatQuickMethodHeader(caller_pc);
+  CHECK(current_code != nullptr);
+  CHECK(current_code->IsOptimized());
+  uintptr_t native_pc_offset = current_code->NativeQuickPcOffset(caller_pc);
+  CodeInfo code_info = current_code->GetOptimizedCodeInfo();
+  MethodInfo method_info = current_code->GetOptimizedMethodInfo();
+  CodeInfoEncoding encoding = code_info.ExtractEncoding();
+  StackMap stack_map = code_info.GetStackMapForNativePcOffset(native_pc_offset, encoding);
+  CHECK(stack_map.IsValid());
+  uint32_t dex_pc = stack_map.GetDexPc(encoding.stack_map.encoding);
+
+  // Log the outer method and its associated dex file and class table pointer which can be used
+  // to find out if the inlined methods were defined by other dex file(s) or class loader(s).
+  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+  LOG(FATAL_WITHOUT_ABORT) << "Outer: " << outer_method->PrettyMethod()
+      << " native pc: " << caller_pc
+      << " dex pc: " << dex_pc
+      << " dex file: " << outer_method->GetDexFile()->GetLocation()
+      << " class table: " << class_linker->ClassTableForClassLoader(outer_method->GetClassLoader());
+  LOG(FATAL_WITHOUT_ABORT) << "  instruction: " << DumpInstruction(outer_method, dex_pc);
+
+  ArtMethod* caller = outer_method;
+  if (stack_map.HasInlineInfo(encoding.stack_map.encoding)) {
+    InlineInfo inline_info = code_info.GetInlineInfoOf(stack_map, encoding);
+    const InlineInfoEncoding& inline_info_encoding = encoding.inline_info.encoding;
+    size_t depth = inline_info.GetDepth(inline_info_encoding);
+    for (size_t d = 0; d < depth; ++d) {
+      const char* tag = "";
+      dex_pc = inline_info.GetDexPcAtDepth(inline_info_encoding, d);
+      if (inline_info.EncodesArtMethodAtDepth(inline_info_encoding, d)) {
+        tag = "encoded ";
+        caller = inline_info.GetArtMethodAtDepth(inline_info_encoding, d);
+      } else {
+        uint32_t method_index = inline_info.GetMethodIndexAtDepth(inline_info_encoding,
+                                                                  method_info,
+                                                                  d);
+        if (dex_pc == static_cast<uint32_t>(-1)) {
+          tag = "special ";
+          CHECK_EQ(d + 1u, depth);
+          caller = jni::DecodeArtMethod(WellKnownClasses::java_lang_String_charAt);
+          CHECK_EQ(caller->GetDexMethodIndex(), method_index);
+        } else {
+          ObjPtr<mirror::DexCache> dex_cache = caller->GetDexCache();
+          ObjPtr<mirror::ClassLoader> class_loader = caller->GetClassLoader();
+          caller = class_linker->LookupResolvedMethod(method_index, dex_cache, class_loader);
+          CHECK(caller != nullptr);
+        }
+      }
+      LOG(FATAL_WITHOUT_ABORT) << "Inlined method #" << d << ": " << tag << caller->PrettyMethod()
+          << " dex pc: " << dex_pc
+          << " dex file: " << caller->GetDexFile()->GetLocation()
+          << " class table: "
+          << class_linker->ClassTableForClassLoader(outer_method->GetClassLoader());
+      LOG(FATAL_WITHOUT_ABORT) << "  instruction: " << DumpInstruction(caller, dex_pc);
+    }
+  }
+}
+
 // Lazily resolve a method for quick. Called by stub code.
 extern "C" const void* artQuickResolutionTrampoline(
     ArtMethod* called, mirror::Object* receiver, Thread* self, ArtMethod** sp)
@@ -1255,6 +1346,7 @@
           is_range = true;
           break;
         default:
+          DumpB74410240DebugData(sp);
           LOG(FATAL) << "Unexpected call into trampoline: " << instr.DumpString(nullptr);
           UNREACHABLE();
       }