1d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light/* 2d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light * Copyright (C) 2017 The Android Open Source Project 3d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light * 4d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light * Licensed under the Apache License, Version 2.0 (the "License"); 5d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light * you may not use this file except in compliance with the License. 6d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light * You may obtain a copy of the License at 7d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light * 8d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light * http://www.apache.org/licenses/LICENSE-2.0 9d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light * 10d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light * Unless required by applicable law or agreed to in writing, software 11d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light * distributed under the License is distributed on an "AS IS" BASIS, 12d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light * See the License for the specific language governing permissions and 14d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light * limitations under the License. 15d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light */ 16d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light 17d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light#include "common_helper.h" 18d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light 19d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light#include "jni.h" 20d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light#include "jvmti.h" 21d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light 22d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light#include "jvmti_helper.h" 23d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light#include "scoped_local_ref.h" 24d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light#include "test_env.h" 25d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light 26d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Lightnamespace art { 27d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light 28d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Lightnamespace common_breakpoint { 29d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light 30d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Lightstruct BreakpointData { 31d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light jclass test_klass; 32d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light jmethodID breakpoint_method; 33d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light bool in_callback; 34d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light bool allow_recursive; 35d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light}; 36d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light 37d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Lightextern "C" void breakpointCB(jvmtiEnv* jvmti, 38d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light JNIEnv* jnienv, 39d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light jthread thread, 40d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light jmethodID method, 41d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light jlocation location) { 42d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light BreakpointData* data = nullptr; 43d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light if (JvmtiErrorToException(jnienv, jvmti, 44d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light jvmti->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)))) { 45d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light return; 46d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light } 47d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light if (data->in_callback && !data->allow_recursive) { 48d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light return; 49d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light } 50d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light data->in_callback = true; 51d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light jobject method_arg = GetJavaMethod(jvmti, jnienv, method); 52d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light jnienv->CallStaticVoidMethod(data->test_klass, 53d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light data->breakpoint_method, 54d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light thread, 55d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light method_arg, 56d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light static_cast<jlong>(location)); 57d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light jnienv->DeleteLocalRef(method_arg); 58d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light data->in_callback = false; 59d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light} 60d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light 61d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Lightextern "C" JNIEXPORT jobjectArray JNICALL Java_art_Breakpoint_getLineNumberTableNative( 62d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light JNIEnv* env, 63d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light jclass k ATTRIBUTE_UNUSED, 64d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light jobject target) { 65d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light jmethodID method = env->FromReflectedMethod(target); 66d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light if (env->ExceptionCheck()) { 67d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light return nullptr; 68d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light } 69d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light jint nlines; 70d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light jvmtiLineNumberEntry* lines = nullptr; 71d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light if (JvmtiErrorToException(env, jvmti_env, 72d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light jvmti_env->GetLineNumberTable(method, &nlines, &lines))) { 73d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light return nullptr; 74d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light } 75d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light jintArray lines_array = env->NewIntArray(nlines); 76d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light if (env->ExceptionCheck()) { 77d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(lines)); 78d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light return nullptr; 79d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light } 80d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light jlongArray locs_array = env->NewLongArray(nlines); 81d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light if (env->ExceptionCheck()) { 82d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(lines)); 83d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light return nullptr; 84d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light } 85d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light ScopedLocalRef<jclass> object_class(env, env->FindClass("java/lang/Object")); 86d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light if (env->ExceptionCheck()) { 87d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(lines)); 88d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light return nullptr; 89d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light } 90d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light jobjectArray ret = env->NewObjectArray(2, object_class.get(), nullptr); 91d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light if (env->ExceptionCheck()) { 92d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(lines)); 93d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light return nullptr; 94d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light } 95d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light jint* temp_lines = env->GetIntArrayElements(lines_array, /*isCopy*/nullptr); 96d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light jlong* temp_locs = env->GetLongArrayElements(locs_array, /*isCopy*/nullptr); 97d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light for (jint i = 0; i < nlines; i++) { 98d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light temp_lines[i] = lines[i].line_number; 99d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light temp_locs[i] = lines[i].start_location; 100d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light } 101d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light env->ReleaseIntArrayElements(lines_array, temp_lines, 0); 102d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light env->ReleaseLongArrayElements(locs_array, temp_locs, 0); 103d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light env->SetObjectArrayElement(ret, 0, locs_array); 104d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light env->SetObjectArrayElement(ret, 1, lines_array); 105d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(lines)); 106d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light return ret; 107d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light} 108d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light 109d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Lightextern "C" JNIEXPORT jlong JNICALL Java_art_Breakpoint_getStartLocation(JNIEnv* env, 110d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light jclass k ATTRIBUTE_UNUSED, 111d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light jobject target) { 112d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light jmethodID method = env->FromReflectedMethod(target); 113d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light if (env->ExceptionCheck()) { 114d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light return 0; 115d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light } 116d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light jlong start = 0; 117d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light jlong end = end; 118d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light JvmtiErrorToException(env, jvmti_env, jvmti_env->GetMethodLocation(method, &start, &end)); 119d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light return start; 120d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light} 121d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light 122d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Lightextern "C" JNIEXPORT void JNICALL Java_art_Breakpoint_clearBreakpoint(JNIEnv* env, 123d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light jclass k ATTRIBUTE_UNUSED, 124d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light jobject target, 125d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light jlocation location) { 126d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light jmethodID method = env->FromReflectedMethod(target); 127d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light if (env->ExceptionCheck()) { 128d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light return; 129d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light } 130d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light JvmtiErrorToException(env, jvmti_env, jvmti_env->ClearBreakpoint(method, location)); 131d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light} 132d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light 133d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Lightextern "C" JNIEXPORT void JNICALL Java_art_Breakpoint_setBreakpoint(JNIEnv* env, 134d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light jclass k ATTRIBUTE_UNUSED, 135d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light jobject target, 136d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light jlocation location) { 137d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light jmethodID method = env->FromReflectedMethod(target); 138d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light if (env->ExceptionCheck()) { 139d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light return; 140d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light } 141d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light JvmtiErrorToException(env, jvmti_env, jvmti_env->SetBreakpoint(method, location)); 142d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light} 143d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light 144d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Lightextern "C" JNIEXPORT void JNICALL Java_art_Breakpoint_startBreakpointWatch( 145d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light JNIEnv* env, 146d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light jclass k ATTRIBUTE_UNUSED, 147d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light jclass method_klass, 148d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light jobject method, 149d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light jboolean allow_recursive, 150d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light jthread thr) { 151d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light BreakpointData* data = nullptr; 152d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light if (JvmtiErrorToException(env, 153d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light jvmti_env, 154d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light jvmti_env->Allocate(sizeof(BreakpointData), 155d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light reinterpret_cast<unsigned char**>(&data)))) { 156d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light return; 157d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light } 158d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light memset(data, 0, sizeof(BreakpointData)); 159d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light data->test_klass = reinterpret_cast<jclass>(env->NewGlobalRef(method_klass)); 160d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light data->breakpoint_method = env->FromReflectedMethod(method); 161d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light data->in_callback = false; 162d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light data->allow_recursive = allow_recursive; 163d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light 164d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light void* old_data = nullptr; 165d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light if (JvmtiErrorToException(env, jvmti_env, jvmti_env->GetEnvironmentLocalStorage(&old_data))) { 166d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light return; 167d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light } else if (old_data != nullptr) { 168d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light ScopedLocalRef<jclass> rt_exception(env, env->FindClass("java/lang/RuntimeException")); 169d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light env->ThrowNew(rt_exception.get(), "Environment already has local storage set!"); 170d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light return; 171d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light } 172d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light if (JvmtiErrorToException(env, jvmti_env, jvmti_env->SetEnvironmentLocalStorage(data))) { 173d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light return; 174d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light } 175d3782f304acee54273f551c52f547539c8f4a78bAlex Light current_callbacks.Breakpoint = breakpointCB; 176d3782f304acee54273f551c52f547539c8f4a78bAlex Light if (JvmtiErrorToException(env, 177d3782f304acee54273f551c52f547539c8f4a78bAlex Light jvmti_env, 178d3782f304acee54273f551c52f547539c8f4a78bAlex Light jvmti_env->SetEventCallbacks(¤t_callbacks, 179d3782f304acee54273f551c52f547539c8f4a78bAlex Light sizeof(current_callbacks)))) { 180d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light return; 181d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light } 182d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light if (JvmtiErrorToException(env, 183d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light jvmti_env, 184d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light jvmti_env->SetEventNotificationMode(JVMTI_ENABLE, 185d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light JVMTI_EVENT_BREAKPOINT, 186d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light thr))) { 187d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light return; 188d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light } 189d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light} 190d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light 191d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Lightextern "C" JNIEXPORT void JNICALL Java_art_Breakpoint_stopBreakpointWatch( 192d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light JNIEnv* env, 193d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light jclass k ATTRIBUTE_UNUSED, 194d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light jthread thr) { 195d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light if (JvmtiErrorToException(env, jvmti_env, 196d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light jvmti_env->SetEventNotificationMode(JVMTI_DISABLE, 197d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light JVMTI_EVENT_BREAKPOINT, 198d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light thr))) { 199d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light return; 200d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light } 201d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light} 202d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light 203d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light} // namespace common_breakpoint 204d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light 205d0d6596dd85e6fdd7c82c242fbc050f611ad3b09Alex Light} // namespace art 206