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