summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Matt Gilbride <mattgilbride@google.com> 2024-09-19 10:17:56 +0000
committer Matt Gilbride <mattgilbride@google.com> 2024-10-22 10:47:23 +0000
commit88f65e236865ccade279316f710c51784e56c452 (patch)
treedbe5a860fe1da6b68624e0e2c5b4a0fcb4f11c47
parent466a0114469f6a03ba1b4a927d994cffbaae6366 (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.aconfig9
-rw-r--r--runtime/native/dalvik_system_VMDebug.cc78
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) {