xref: /aosp_15_r20/art/test/ti-agent/exceptions_helper.cc (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
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_exceptions {
29*795d594fSAndroid Build Coastguard Worker 
30*795d594fSAndroid Build Coastguard Worker struct ExceptionsData {
31*795d594fSAndroid Build Coastguard Worker   jclass test_klass;
32*795d594fSAndroid Build Coastguard Worker   jclass exception_klass;
33*795d594fSAndroid Build Coastguard Worker   jmethodID exception_event;
34*795d594fSAndroid Build Coastguard Worker   jmethodID exception_catch_event;
35*795d594fSAndroid Build Coastguard Worker };
36*795d594fSAndroid Build Coastguard Worker 
exceptionCB(jvmtiEnv * jvmti,JNIEnv * jnienv,jthread thread,jmethodID throw_method,jlocation throw_location,jobject throwable,jmethodID catch_method,jlocation catch_location)37*795d594fSAndroid Build Coastguard Worker static void exceptionCB(jvmtiEnv* jvmti,
38*795d594fSAndroid Build Coastguard Worker                         JNIEnv* jnienv,
39*795d594fSAndroid Build Coastguard Worker                         jthread thread,
40*795d594fSAndroid Build Coastguard Worker                         jmethodID throw_method,
41*795d594fSAndroid Build Coastguard Worker                         jlocation throw_location,
42*795d594fSAndroid Build Coastguard Worker                         jobject throwable,
43*795d594fSAndroid Build Coastguard Worker                         jmethodID catch_method,
44*795d594fSAndroid Build Coastguard Worker                         jlocation catch_location) {
45*795d594fSAndroid Build Coastguard Worker   ExceptionsData* data = nullptr;
46*795d594fSAndroid Build Coastguard Worker   if (JvmtiErrorToException(jnienv, jvmti,
47*795d594fSAndroid Build Coastguard Worker                             jvmti->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)))) {
48*795d594fSAndroid Build Coastguard Worker     return;
49*795d594fSAndroid Build Coastguard Worker   }
50*795d594fSAndroid Build Coastguard Worker   DCHECK(throwable != nullptr);
51*795d594fSAndroid Build Coastguard Worker   if (!jnienv->IsInstanceOf(throwable, data->exception_klass)) {
52*795d594fSAndroid Build Coastguard Worker     return;
53*795d594fSAndroid Build Coastguard Worker   }
54*795d594fSAndroid Build Coastguard Worker   jthrowable e = jnienv->ExceptionOccurred();
55*795d594fSAndroid Build Coastguard Worker   jnienv->ExceptionClear();
56*795d594fSAndroid Build Coastguard Worker   CHECK(data->exception_event != nullptr);
57*795d594fSAndroid Build Coastguard Worker   jobject throw_method_arg = GetJavaMethod(jvmti, jnienv, throw_method);
58*795d594fSAndroid Build Coastguard Worker   jobject catch_method_arg =
59*795d594fSAndroid Build Coastguard Worker       catch_method != nullptr ? GetJavaMethod(jvmti, jnienv, catch_method) : nullptr;
60*795d594fSAndroid Build Coastguard Worker   jnienv->CallStaticVoidMethod(data->test_klass,
61*795d594fSAndroid Build Coastguard Worker                                data->exception_event,
62*795d594fSAndroid Build Coastguard Worker                                thread,
63*795d594fSAndroid Build Coastguard Worker                                throw_method_arg,
64*795d594fSAndroid Build Coastguard Worker                                static_cast<jlong>(throw_location),
65*795d594fSAndroid Build Coastguard Worker                                throwable,
66*795d594fSAndroid Build Coastguard Worker                                catch_method_arg,
67*795d594fSAndroid Build Coastguard Worker                                static_cast<jlong>(catch_location));
68*795d594fSAndroid Build Coastguard Worker   jnienv->DeleteLocalRef(throw_method_arg);
69*795d594fSAndroid Build Coastguard Worker   if (catch_method_arg != nullptr) {
70*795d594fSAndroid Build Coastguard Worker     jnienv->DeleteLocalRef(catch_method_arg);
71*795d594fSAndroid Build Coastguard Worker   }
72*795d594fSAndroid Build Coastguard Worker   if (e != nullptr) {
73*795d594fSAndroid Build Coastguard Worker     jnienv->Throw(e);
74*795d594fSAndroid Build Coastguard Worker   }
75*795d594fSAndroid Build Coastguard Worker }
76*795d594fSAndroid Build Coastguard Worker 
77*795d594fSAndroid Build Coastguard Worker 
exceptionCatchCB(jvmtiEnv * jvmti,JNIEnv * jnienv,jthread thread,jmethodID catch_method,jlocation catch_location,jobject throwable)78*795d594fSAndroid Build Coastguard Worker static void exceptionCatchCB(jvmtiEnv* jvmti,
79*795d594fSAndroid Build Coastguard Worker                              JNIEnv* jnienv,
80*795d594fSAndroid Build Coastguard Worker                              jthread thread,
81*795d594fSAndroid Build Coastguard Worker                              jmethodID catch_method,
82*795d594fSAndroid Build Coastguard Worker                              jlocation catch_location,
83*795d594fSAndroid Build Coastguard Worker                              jobject throwable) {
84*795d594fSAndroid Build Coastguard Worker   ExceptionsData* data = nullptr;
85*795d594fSAndroid Build Coastguard Worker   if (JvmtiErrorToException(jnienv, jvmti,
86*795d594fSAndroid Build Coastguard Worker                             jvmti->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)))) {
87*795d594fSAndroid Build Coastguard Worker     return;
88*795d594fSAndroid Build Coastguard Worker   }
89*795d594fSAndroid Build Coastguard Worker   if (!jnienv->IsSameObject(data->exception_klass, jnienv->GetObjectClass(throwable))) {
90*795d594fSAndroid Build Coastguard Worker     return;
91*795d594fSAndroid Build Coastguard Worker   }
92*795d594fSAndroid Build Coastguard Worker   jthrowable e = jnienv->ExceptionOccurred();
93*795d594fSAndroid Build Coastguard Worker   jnienv->ExceptionClear();
94*795d594fSAndroid Build Coastguard Worker   CHECK(data->exception_catch_event != nullptr);
95*795d594fSAndroid Build Coastguard Worker   jobject catch_method_arg = GetJavaMethod(jvmti, jnienv, catch_method);
96*795d594fSAndroid Build Coastguard Worker   jnienv->CallStaticVoidMethod(data->test_klass,
97*795d594fSAndroid Build Coastguard Worker                                data->exception_catch_event,
98*795d594fSAndroid Build Coastguard Worker                                thread,
99*795d594fSAndroid Build Coastguard Worker                                catch_method_arg,
100*795d594fSAndroid Build Coastguard Worker                                static_cast<jlong>(catch_location),
101*795d594fSAndroid Build Coastguard Worker                                throwable);
102*795d594fSAndroid Build Coastguard Worker   jnienv->DeleteLocalRef(catch_method_arg);
103*795d594fSAndroid Build Coastguard Worker   if (e != nullptr) {
104*795d594fSAndroid Build Coastguard Worker     jnienv->Throw(e);
105*795d594fSAndroid Build Coastguard Worker   }
106*795d594fSAndroid Build Coastguard Worker }
107*795d594fSAndroid Build Coastguard Worker 
Java_art_Exceptions_setupExceptionTracing(JNIEnv * env,jclass exception,jclass klass,jclass except,jobject exception_event,jobject exception_catch_event)108*795d594fSAndroid Build Coastguard Worker extern "C" JNIEXPORT void JNICALL Java_art_Exceptions_setupExceptionTracing(
109*795d594fSAndroid Build Coastguard Worker     JNIEnv* env,
110*795d594fSAndroid Build Coastguard Worker     [[maybe_unused]] jclass exception,
111*795d594fSAndroid Build Coastguard Worker     jclass klass,
112*795d594fSAndroid Build Coastguard Worker     jclass except,
113*795d594fSAndroid Build Coastguard Worker     jobject exception_event,
114*795d594fSAndroid Build Coastguard Worker     jobject exception_catch_event) {
115*795d594fSAndroid Build Coastguard Worker   ExceptionsData* data = nullptr;
116*795d594fSAndroid Build Coastguard Worker   if (JvmtiErrorToException(env,
117*795d594fSAndroid Build Coastguard Worker                             jvmti_env,
118*795d594fSAndroid Build Coastguard Worker                             jvmti_env->Allocate(sizeof(ExceptionsData),
119*795d594fSAndroid Build Coastguard Worker                                                 reinterpret_cast<unsigned char**>(&data)))) {
120*795d594fSAndroid Build Coastguard Worker     return;
121*795d594fSAndroid Build Coastguard Worker   }
122*795d594fSAndroid Build Coastguard Worker   jvmtiCapabilities caps;
123*795d594fSAndroid Build Coastguard Worker   memset(&caps, 0, sizeof(caps));
124*795d594fSAndroid Build Coastguard Worker   caps.can_generate_exception_events = 1;
125*795d594fSAndroid Build Coastguard Worker   if (JvmtiErrorToException(env, jvmti_env, jvmti_env->AddCapabilities(&caps))) {
126*795d594fSAndroid Build Coastguard Worker     return;
127*795d594fSAndroid Build Coastguard Worker   }
128*795d594fSAndroid Build Coastguard Worker   memset(data, 0, sizeof(ExceptionsData));
129*795d594fSAndroid Build Coastguard Worker   data->test_klass = reinterpret_cast<jclass>(env->NewGlobalRef(klass));
130*795d594fSAndroid Build Coastguard Worker   data->exception_klass = reinterpret_cast<jclass>(env->NewGlobalRef(except));
131*795d594fSAndroid Build Coastguard Worker   data->exception_event =
132*795d594fSAndroid Build Coastguard Worker       exception_event != nullptr ?  env->FromReflectedMethod(exception_event) : nullptr;
133*795d594fSAndroid Build Coastguard Worker   data->exception_catch_event =
134*795d594fSAndroid Build Coastguard Worker       exception_catch_event != nullptr ? env->FromReflectedMethod(exception_catch_event) : nullptr;
135*795d594fSAndroid Build Coastguard Worker 
136*795d594fSAndroid Build Coastguard Worker   ExceptionsData* old_data = nullptr;
137*795d594fSAndroid Build Coastguard Worker   if (JvmtiErrorToException(env, jvmti_env,
138*795d594fSAndroid Build Coastguard Worker                             jvmti_env->GetEnvironmentLocalStorage(
139*795d594fSAndroid Build Coastguard Worker                                 reinterpret_cast<void**>(&old_data)))) {
140*795d594fSAndroid Build Coastguard Worker     return;
141*795d594fSAndroid Build Coastguard Worker   } else if (old_data != nullptr && old_data->test_klass != nullptr) {
142*795d594fSAndroid Build Coastguard Worker     ScopedLocalRef<jclass> rt_exception(env, env->FindClass("java/lang/RuntimeException"));
143*795d594fSAndroid Build Coastguard Worker     env->ThrowNew(rt_exception.get(), "Environment already has local storage set!");
144*795d594fSAndroid Build Coastguard Worker     return;
145*795d594fSAndroid Build Coastguard Worker   }
146*795d594fSAndroid Build Coastguard Worker   if (JvmtiErrorToException(env, jvmti_env, jvmti_env->SetEnvironmentLocalStorage(data))) {
147*795d594fSAndroid Build Coastguard Worker     return;
148*795d594fSAndroid Build Coastguard Worker   }
149*795d594fSAndroid Build Coastguard Worker 
150*795d594fSAndroid Build Coastguard Worker   current_callbacks.Exception = exceptionCB;
151*795d594fSAndroid Build Coastguard Worker   current_callbacks.ExceptionCatch = exceptionCatchCB;
152*795d594fSAndroid Build Coastguard Worker   if (JvmtiErrorToException(env,
153*795d594fSAndroid Build Coastguard Worker                             jvmti_env,
154*795d594fSAndroid Build Coastguard Worker                             jvmti_env->SetEventCallbacks(&current_callbacks,
155*795d594fSAndroid Build Coastguard Worker                                                          sizeof(current_callbacks)))) {
156*795d594fSAndroid Build Coastguard Worker     return;
157*795d594fSAndroid Build Coastguard Worker   }
158*795d594fSAndroid Build Coastguard Worker }
159*795d594fSAndroid Build Coastguard Worker 
Java_art_Exceptions_disableExceptionTracing(JNIEnv * env,jclass klass,jthread thr)160*795d594fSAndroid Build Coastguard Worker extern "C" JNIEXPORT void JNICALL Java_art_Exceptions_disableExceptionTracing(
161*795d594fSAndroid Build Coastguard Worker     JNIEnv* env, [[maybe_unused]] jclass klass, jthread thr) {
162*795d594fSAndroid Build Coastguard Worker   ExceptionsData* data = nullptr;
163*795d594fSAndroid Build Coastguard Worker   if (JvmtiErrorToException(
164*795d594fSAndroid Build Coastguard Worker           env, jvmti_env, jvmti_env->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)))) {
165*795d594fSAndroid Build Coastguard Worker     return;
166*795d594fSAndroid Build Coastguard Worker   }
167*795d594fSAndroid Build Coastguard Worker 
168*795d594fSAndroid Build Coastguard Worker   if (data == nullptr) {
169*795d594fSAndroid Build Coastguard Worker     return;
170*795d594fSAndroid Build Coastguard Worker   }
171*795d594fSAndroid Build Coastguard Worker 
172*795d594fSAndroid Build Coastguard Worker   // Disable Exception and Exception catch events.
173*795d594fSAndroid Build Coastguard Worker   JvmtiErrorToException(
174*795d594fSAndroid Build Coastguard Worker       env,
175*795d594fSAndroid Build Coastguard Worker       jvmti_env,
176*795d594fSAndroid Build Coastguard Worker       jvmti_env->SetEventNotificationMode(JVMTI_DISABLE, JVMTI_EVENT_EXCEPTION, thr));
177*795d594fSAndroid Build Coastguard Worker   JvmtiErrorToException(
178*795d594fSAndroid Build Coastguard Worker       env,
179*795d594fSAndroid Build Coastguard Worker       jvmti_env,
180*795d594fSAndroid Build Coastguard Worker       jvmti_env->SetEventNotificationMode(JVMTI_DISABLE, JVMTI_EVENT_EXCEPTION_CATCH, thr));
181*795d594fSAndroid Build Coastguard Worker 
182*795d594fSAndroid Build Coastguard Worker   env->DeleteGlobalRef(data->test_klass);
183*795d594fSAndroid Build Coastguard Worker   env->DeleteGlobalRef(data->exception_klass);
184*795d594fSAndroid Build Coastguard Worker 
185*795d594fSAndroid Build Coastguard Worker   if (JvmtiErrorToException(env, jvmti_env, jvmti_env->SetEnvironmentLocalStorage(nullptr))) {
186*795d594fSAndroid Build Coastguard Worker     return;
187*795d594fSAndroid Build Coastguard Worker   }
188*795d594fSAndroid Build Coastguard Worker }
189*795d594fSAndroid Build Coastguard Worker 
Java_art_Exceptions_enableExceptionCatchEvent(JNIEnv * env,jclass klass,jthread thr)190*795d594fSAndroid Build Coastguard Worker extern "C" JNIEXPORT void JNICALL Java_art_Exceptions_enableExceptionCatchEvent(
191*795d594fSAndroid Build Coastguard Worker     JNIEnv* env, [[maybe_unused]] jclass klass, jthread thr) {
192*795d594fSAndroid Build Coastguard Worker   JvmtiErrorToException(env,
193*795d594fSAndroid Build Coastguard Worker                         jvmti_env,
194*795d594fSAndroid Build Coastguard Worker                         jvmti_env->SetEventNotificationMode(JVMTI_ENABLE,
195*795d594fSAndroid Build Coastguard Worker                                                             JVMTI_EVENT_EXCEPTION_CATCH,
196*795d594fSAndroid Build Coastguard Worker                                                             thr));
197*795d594fSAndroid Build Coastguard Worker }
198*795d594fSAndroid Build Coastguard Worker 
Java_art_Exceptions_enableExceptionEvent(JNIEnv * env,jclass klass,jthread thr)199*795d594fSAndroid Build Coastguard Worker extern "C" JNIEXPORT void JNICALL Java_art_Exceptions_enableExceptionEvent(
200*795d594fSAndroid Build Coastguard Worker     JNIEnv* env, [[maybe_unused]] jclass klass, jthread thr) {
201*795d594fSAndroid Build Coastguard Worker   JvmtiErrorToException(env,
202*795d594fSAndroid Build Coastguard Worker                         jvmti_env,
203*795d594fSAndroid Build Coastguard Worker                         jvmti_env->SetEventNotificationMode(JVMTI_ENABLE,
204*795d594fSAndroid Build Coastguard Worker                                                             JVMTI_EVENT_EXCEPTION,
205*795d594fSAndroid Build Coastguard Worker                                                             thr));
206*795d594fSAndroid Build Coastguard Worker }
207*795d594fSAndroid Build Coastguard Worker 
Java_art_Exceptions_disableExceptionCatchEvent(JNIEnv * env,jclass klass,jthread thr)208*795d594fSAndroid Build Coastguard Worker extern "C" JNIEXPORT void JNICALL Java_art_Exceptions_disableExceptionCatchEvent(
209*795d594fSAndroid Build Coastguard Worker     JNIEnv* env, [[maybe_unused]] jclass klass, jthread thr) {
210*795d594fSAndroid Build Coastguard Worker   JvmtiErrorToException(env,
211*795d594fSAndroid Build Coastguard Worker                         jvmti_env,
212*795d594fSAndroid Build Coastguard Worker                         jvmti_env->SetEventNotificationMode(JVMTI_DISABLE,
213*795d594fSAndroid Build Coastguard Worker                                                             JVMTI_EVENT_EXCEPTION_CATCH,
214*795d594fSAndroid Build Coastguard Worker                                                             thr));
215*795d594fSAndroid Build Coastguard Worker }
216*795d594fSAndroid Build Coastguard Worker 
Java_art_Exceptions_disableExceptionEvent(JNIEnv * env,jclass klass,jthread thr)217*795d594fSAndroid Build Coastguard Worker extern "C" JNIEXPORT void JNICALL Java_art_Exceptions_disableExceptionEvent(
218*795d594fSAndroid Build Coastguard Worker     JNIEnv* env, [[maybe_unused]] jclass klass, jthread thr) {
219*795d594fSAndroid Build Coastguard Worker   JvmtiErrorToException(env,
220*795d594fSAndroid Build Coastguard Worker                         jvmti_env,
221*795d594fSAndroid Build Coastguard Worker                         jvmti_env->SetEventNotificationMode(JVMTI_DISABLE,
222*795d594fSAndroid Build Coastguard Worker                                                             JVMTI_EVENT_EXCEPTION,
223*795d594fSAndroid Build Coastguard Worker                                                             thr));
224*795d594fSAndroid Build Coastguard Worker }
225*795d594fSAndroid Build Coastguard Worker 
226*795d594fSAndroid Build Coastguard Worker }  // namespace common_exceptions
227*795d594fSAndroid Build Coastguard Worker 
228*795d594fSAndroid Build Coastguard Worker 
229*795d594fSAndroid Build Coastguard Worker }  // namespace art
230