1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include <dlfcn.h> 18 #include <inttypes.h> 19 20 #include <cstdio> 21 #include <memory> 22 23 #include "android-base/stringprintf.h" 24 #include "jni.h" 25 #include "jvmti.h" 26 27 // Test infrastructure 28 #include "jni_binder.h" 29 #include "jvmti_helper.h" 30 #include "scoped_local_ref.h" 31 #include "test_env.h" 32 33 namespace art { 34 namespace Test986NativeBind { 35 36 static void doUpPrintCall(JNIEnv* env, const char* function) { 37 ScopedLocalRef<jclass> klass(env, env->FindClass("art/Test986")); 38 jmethodID targetMethod = env->GetStaticMethodID(klass.get(), function, "()V"); 39 env->CallStaticVoidMethod(klass.get(), targetMethod); 40 } 41 42 extern "C" JNIEXPORT void JNICALL Java_art_Test986_00024Transform_sayHi__( 43 JNIEnv* env, jclass klass ATTRIBUTE_UNUSED) { 44 doUpPrintCall(env, "doSayHi"); 45 } 46 47 extern "C" JNIEXPORT void JNICALL Java_art_Test986_00024Transform_sayHi2( 48 JNIEnv* env, jclass klass ATTRIBUTE_UNUSED) { 49 doUpPrintCall(env, "doSayHi2"); 50 } 51 52 extern "C" JNIEXPORT void JNICALL NoReallySayGoodbye(JNIEnv* env, jclass klass ATTRIBUTE_UNUSED) { 53 doUpPrintCall(env, "doSayBye"); 54 } 55 56 static void doJvmtiMethodBind(jvmtiEnv* jvmtienv ATTRIBUTE_UNUSED, 57 JNIEnv* env, 58 jthread thread ATTRIBUTE_UNUSED, 59 jmethodID m, 60 void* address, 61 /*out*/void** out_address) { 62 ScopedLocalRef<jclass> method_class(env, env->FindClass("java/lang/reflect/Method")); 63 ScopedLocalRef<jobject> method_obj(env, env->ToReflectedMethod(method_class.get(), m, false)); 64 Dl_info addr_info; 65 if (dladdr(address, &addr_info) == 0 || addr_info.dli_sname == nullptr) { 66 ScopedLocalRef<jclass> exception_class(env, env->FindClass("java/lang/Exception")); 67 env->ThrowNew(exception_class.get(), "dladdr failure!"); 68 return; 69 } 70 ScopedLocalRef<jstring> sym_name(env, env->NewStringUTF(addr_info.dli_sname)); 71 ScopedLocalRef<jclass> klass(env, env->FindClass("art/Test986")); 72 jmethodID upcallMethod = env->GetStaticMethodID( 73 klass.get(), 74 "doNativeMethodBind", 75 "(Ljava/lang/reflect/Method;Ljava/lang/String;)Ljava/lang/String;"); 76 if (env->ExceptionCheck()) { 77 return; 78 } 79 ScopedLocalRef<jstring> new_symbol(env, 80 reinterpret_cast<jstring>( 81 env->CallStaticObjectMethod(klass.get(), 82 upcallMethod, 83 method_obj.get(), 84 sym_name.get()))); 85 const char* new_symbol_chars = env->GetStringUTFChars(new_symbol.get(), nullptr); 86 if (strcmp(new_symbol_chars, addr_info.dli_sname) != 0) { 87 *out_address = dlsym(RTLD_DEFAULT, new_symbol_chars); 88 if (*out_address == nullptr) { 89 ScopedLocalRef<jclass> exception_class(env, env->FindClass("java/lang/Exception")); 90 env->ThrowNew(exception_class.get(), "dlsym failure!"); 91 return; 92 } 93 } 94 env->ReleaseStringUTFChars(new_symbol.get(), new_symbol_chars); 95 } 96 97 extern "C" JNIEXPORT void JNICALL Java_art_Test986_setupNativeBindNotify( 98 JNIEnv* env ATTRIBUTE_UNUSED, jclass klass ATTRIBUTE_UNUSED) { 99 jvmtiEventCallbacks cb; 100 memset(&cb, 0, sizeof(cb)); 101 cb.NativeMethodBind = doJvmtiMethodBind; 102 jvmti_env->SetEventCallbacks(&cb, sizeof(cb)); 103 } 104 105 extern "C" JNIEXPORT void JNICALL Java_art_Test986_setNativeBindNotify( 106 JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jboolean enable) { 107 jvmtiError res = jvmti_env->SetEventNotificationMode(enable ? JVMTI_ENABLE : JVMTI_DISABLE, 108 JVMTI_EVENT_NATIVE_METHOD_BIND, 109 nullptr); 110 if (res != JVMTI_ERROR_NONE) { 111 JvmtiErrorToException(env, jvmti_env, res); 112 } 113 } 114 115 extern "C" JNIEXPORT void JNICALL Java_art_Test986_rebindTransformClass( 116 JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jclass k) { 117 JNINativeMethod m[2]; 118 m[0].name = "sayHi"; 119 m[0].signature = "()V"; 120 m[0].fnPtr = reinterpret_cast<void*>(Java_art_Test986_00024Transform_sayHi__); 121 m[1].name = "sayHi2"; 122 m[1].signature = "()V"; 123 m[1].fnPtr = reinterpret_cast<void*>(Java_art_Test986_00024Transform_sayHi2); 124 env->RegisterNatives(k, m, 2); 125 } 126 127 } // namespace Test986NativeBind 128 } // namespace art 129