diff options
author | 2024-09-19 10:17:56 +0000 | |
---|---|---|
committer | 2024-10-22 10:47:23 +0000 | |
commit | 88f65e236865ccade279316f710c51784e56c452 (patch) | |
tree | dbe5a860fe1da6b68624e0e2c5b4a0fcb4f11c47 | |
parent | 466a0114469f6a03ba1b4a927d994cffbaae6366 (diff) |
Add VMDebug_getExecutableMethodFileOffsetsNative
Adds a method that, given a Java/Kotlin method, fetches the ODEX file,
offset of that file within the running process, and offset of the
method within that file.
The mechanism works only for AOT compiled methods for now, but can
later be expanded to provide similar info for JIT compiled methods.
Bug: 372925025
Test: TH
Flag: com.android.art.flags.executable_method_file_offsets
Change-Id: I0598b8602d81416f602b186f9f313ec55cfc3e8d
-rw-r--r-- | build/flags/art-flags.aconfig | 9 | ||||
-rw-r--r-- | runtime/native/dalvik_system_VMDebug.cc | 78 |
2 files changed, 85 insertions, 2 deletions
diff --git a/build/flags/art-flags.aconfig b/build/flags/art-flags.aconfig index e38f62a0ae..35ac49ed0b 100644 --- a/build/flags/art-flags.aconfig +++ b/build/flags/art-flags.aconfig @@ -34,3 +34,12 @@ flag { is_fixed_read_only: true is_exported: false } + +flag { + namespace: "art_performance" + name: "executable_method_file_offsets" + is_exported: true + description: "This flag includes the API for getting the compiled native executable offset info for a java method" + bug: "296108553" + is_fixed_read_only: true +} diff --git a/runtime/native/dalvik_system_VMDebug.cc b/runtime/native/dalvik_system_VMDebug.cc index 11d2898c3c..9d7a12c783 100644 --- a/runtime/native/dalvik_system_VMDebug.cc +++ b/runtime/native/dalvik_system_VMDebug.cc @@ -21,8 +21,6 @@ #include <sstream> -#include "nativehelper/jni_macros.h" - #include "base/file_utils.h" #include "base/histogram-inl.h" #include "base/time_utils.h" @@ -30,6 +28,8 @@ #include "class_root-inl.h" #include "common_throws.h" #include "debugger.h" +#include "dex/class_accessor-inl.h" +#include "dex/descriptors_names.h" #include "gc/space/bump_pointer_space.h" #include "gc/space/dlmalloc_space.h" #include "gc/space/large_object_space.h" @@ -42,10 +42,14 @@ #include "mirror/array-alloc-inl.h" #include "mirror/array-inl.h" #include "mirror/class.h" +#include "mirror/executable-inl.h" #include "mirror/object_array-alloc-inl.h" #include "native_util.h" +#include "nativehelper/jni_macros.h" #include "nativehelper/scoped_local_ref.h" #include "nativehelper/scoped_utf_chars.h" +#include "nativehelper/utils.h" +#include "oat/oat_quick_method_header.h" #include "scoped_fast_native_object_access-inl.h" #include "string_array_utils.h" #include "thread-inl.h" @@ -312,6 +316,72 @@ static jlong VMDebug_countInstancesOfClass(JNIEnv* env, return count; } +static jobject VMDebug_getExecutableMethodFileOffsetsNative(JNIEnv* env, + jclass, + jobject javaMethod) { + ScopedObjectAccess soa(env); + ObjPtr<mirror::Executable> m = soa.Decode<mirror::Executable>(javaMethod); + if (m == nullptr) { + soa.Self()->ThrowNewExceptionF("Ljava/lang/RuntimeException;", + "Could not find mirror::Executable for supplied jobject"); + return nullptr; + } + + ObjPtr<mirror::Class> c = m->GetDeclaringClass(); + if (c == nullptr) { + soa.Self()->ThrowNewExceptionF("Ljava/lang/RuntimeException;", + "Could not find mirror::Class for supplied jobject"); + return nullptr; + } + + ArtMethod* art_method = m->GetArtMethod(); + auto oat_method_quick_code = + reinterpret_cast<const uint8_t*>(art_method->GetOatMethodQuickCode(kRuntimePointerSize)); + + if (oat_method_quick_code == nullptr) { + LOG(ERROR) << "No OatMethodQuickCode for method " << art_method->PrettyMethod(); + return nullptr; + } + + const OatDexFile* oat_dex_file = c->GetDexFile().GetOatDexFile(); + if (oat_dex_file == nullptr) { + soa.Self()->ThrowNewExceptionF("Ljava/lang/RuntimeException;", "Could not find oat_dex_file"); + return nullptr; + } + + const OatFile* oat_file = oat_dex_file->GetOatFile(); + if (oat_file == nullptr) { + soa.Self()->ThrowNewExceptionF("Ljava/lang/RuntimeException;", "Could not find oat_file"); + return nullptr; + } + + std::string error_msg; + const uint8_t* elf_begin = oat_file->ComputeElfBegin(&error_msg); + if (elf_begin == nullptr) { + soa.Self()->ThrowNewExceptionF( + "Ljava/lang/RuntimeException;", "Could not find elf_begin: %s", error_msg.c_str()); + return nullptr; + } + + size_t adjusted_offset = oat_method_quick_code - elf_begin; + + ScopedLocalRef<jstring> odex_path = CREATE_UTF_OR_RETURN(env, oat_file->GetLocation()); + auto odex_offset = reinterpret_cast64<jlong>(elf_begin); + auto method_offset = static_cast<jlong>(adjusted_offset); + + ScopedLocalRef<jclass> clazz(env, + env->FindClass("dalvik/system/VMDebug$ExecutableMethodFileOffsets")); + if (clazz == nullptr) { + soa.Self()->ThrowNewExceptionF( + "Ljava/lang/RuntimeException;", + "Could not find dalvik/system/VMDebug$ExecutableMethodFileOffsets"); + return nullptr; + } + + jmethodID constructor_id = env->GetMethodID(clazz.get(), "<init>", "(Ljava/lang/String;JJ)V"); + return env->NewObject(clazz.get(), constructor_id, odex_path.get(), odex_offset, method_offset); +} + static jlongArray VMDebug_countInstancesOfClasses(JNIEnv* env, jclass, jobjectArray javaClasses, @@ -638,6 +708,10 @@ static JNINativeMethod gMethods[] = { NATIVE_METHOD(VMDebug, stopLowOverheadTraceImpl, "()V"), NATIVE_METHOD(VMDebug, dumpLowOverheadTraceImpl, "(Ljava/lang/String;)V"), NATIVE_METHOD(VMDebug, dumpLowOverheadTraceFdImpl, "(I)V"), + NATIVE_METHOD( + VMDebug, + getExecutableMethodFileOffsetsNative, + "(Ljava/lang/reflect/Method;)Ldalvik/system/VMDebug$ExecutableMethodFileOffsets;"), }; void register_dalvik_system_VMDebug(JNIEnv* env) { |