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 "common_helper.h"
18
19 #include "jni.h"
20 #include "jvmti.h"
21
22 #include "jvmti_helper.h"
23 #include "scoped_local_ref.h"
24 #include "test_env.h"
25
26 namespace art {
27
28 namespace common_exceptions {
29
30 struct ExceptionsData {
31 jclass test_klass;
32 jclass exception_klass;
33 jmethodID exception_event;
34 jmethodID exception_catch_event;
35 };
36
exceptionCB(jvmtiEnv * jvmti,JNIEnv * jnienv,jthread thread,jmethodID throw_method,jlocation throw_location,jobject throwable,jmethodID catch_method,jlocation catch_location)37 static void exceptionCB(jvmtiEnv* jvmti,
38 JNIEnv* jnienv,
39 jthread thread,
40 jmethodID throw_method,
41 jlocation throw_location,
42 jobject throwable,
43 jmethodID catch_method,
44 jlocation catch_location) {
45 ExceptionsData* data = nullptr;
46 if (JvmtiErrorToException(jnienv, jvmti,
47 jvmti->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)))) {
48 return;
49 }
50 DCHECK(throwable != nullptr);
51 if (!jnienv->IsInstanceOf(throwable, data->exception_klass)) {
52 return;
53 }
54 jthrowable e = jnienv->ExceptionOccurred();
55 jnienv->ExceptionClear();
56 CHECK(data->exception_event != nullptr);
57 jobject throw_method_arg = GetJavaMethod(jvmti, jnienv, throw_method);
58 jobject catch_method_arg =
59 catch_method != nullptr ? GetJavaMethod(jvmti, jnienv, catch_method) : nullptr;
60 jnienv->CallStaticVoidMethod(data->test_klass,
61 data->exception_event,
62 thread,
63 throw_method_arg,
64 static_cast<jlong>(throw_location),
65 throwable,
66 catch_method_arg,
67 static_cast<jlong>(catch_location));
68 jnienv->DeleteLocalRef(throw_method_arg);
69 if (catch_method_arg != nullptr) {
70 jnienv->DeleteLocalRef(catch_method_arg);
71 }
72 if (e != nullptr) {
73 jnienv->Throw(e);
74 }
75 }
76
77
exceptionCatchCB(jvmtiEnv * jvmti,JNIEnv * jnienv,jthread thread,jmethodID catch_method,jlocation catch_location,jobject throwable)78 static void exceptionCatchCB(jvmtiEnv* jvmti,
79 JNIEnv* jnienv,
80 jthread thread,
81 jmethodID catch_method,
82 jlocation catch_location,
83 jobject throwable) {
84 ExceptionsData* data = nullptr;
85 if (JvmtiErrorToException(jnienv, jvmti,
86 jvmti->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)))) {
87 return;
88 }
89 if (!jnienv->IsSameObject(data->exception_klass, jnienv->GetObjectClass(throwable))) {
90 return;
91 }
92 jthrowable e = jnienv->ExceptionOccurred();
93 jnienv->ExceptionClear();
94 CHECK(data->exception_catch_event != nullptr);
95 jobject catch_method_arg = GetJavaMethod(jvmti, jnienv, catch_method);
96 jnienv->CallStaticVoidMethod(data->test_klass,
97 data->exception_catch_event,
98 thread,
99 catch_method_arg,
100 static_cast<jlong>(catch_location),
101 throwable);
102 jnienv->DeleteLocalRef(catch_method_arg);
103 if (e != nullptr) {
104 jnienv->Throw(e);
105 }
106 }
107
Java_art_Exceptions_setupExceptionTracing(JNIEnv * env,jclass exception ATTRIBUTE_UNUSED,jclass klass,jclass except,jobject exception_event,jobject exception_catch_event)108 extern "C" JNIEXPORT void JNICALL Java_art_Exceptions_setupExceptionTracing(
109 JNIEnv* env,
110 jclass exception ATTRIBUTE_UNUSED,
111 jclass klass,
112 jclass except,
113 jobject exception_event,
114 jobject exception_catch_event) {
115 ExceptionsData* data = nullptr;
116 if (JvmtiErrorToException(env,
117 jvmti_env,
118 jvmti_env->Allocate(sizeof(ExceptionsData),
119 reinterpret_cast<unsigned char**>(&data)))) {
120 return;
121 }
122 jvmtiCapabilities caps;
123 memset(&caps, 0, sizeof(caps));
124 caps.can_generate_exception_events = 1;
125 if (JvmtiErrorToException(env, jvmti_env, jvmti_env->AddCapabilities(&caps))) {
126 return;
127 }
128 memset(data, 0, sizeof(ExceptionsData));
129 data->test_klass = reinterpret_cast<jclass>(env->NewGlobalRef(klass));
130 data->exception_klass = reinterpret_cast<jclass>(env->NewGlobalRef(except));
131 data->exception_event =
132 exception_event != nullptr ? env->FromReflectedMethod(exception_event) : nullptr;
133 data->exception_catch_event =
134 exception_catch_event != nullptr ? env->FromReflectedMethod(exception_catch_event) : nullptr;
135
136 ExceptionsData* old_data = nullptr;
137 if (JvmtiErrorToException(env, jvmti_env,
138 jvmti_env->GetEnvironmentLocalStorage(
139 reinterpret_cast<void**>(&old_data)))) {
140 return;
141 } else if (old_data != nullptr && old_data->test_klass != nullptr) {
142 ScopedLocalRef<jclass> rt_exception(env, env->FindClass("java/lang/RuntimeException"));
143 env->ThrowNew(rt_exception.get(), "Environment already has local storage set!");
144 return;
145 }
146 if (JvmtiErrorToException(env, jvmti_env, jvmti_env->SetEnvironmentLocalStorage(data))) {
147 return;
148 }
149
150 current_callbacks.Exception = exceptionCB;
151 current_callbacks.ExceptionCatch = exceptionCatchCB;
152 if (JvmtiErrorToException(env,
153 jvmti_env,
154 jvmti_env->SetEventCallbacks(¤t_callbacks,
155 sizeof(current_callbacks)))) {
156 return;
157 }
158 }
159
Java_art_Exceptions_enableExceptionCatchEvent(JNIEnv * env,jclass klass ATTRIBUTE_UNUSED,jthread thr)160 extern "C" JNIEXPORT void JNICALL Java_art_Exceptions_enableExceptionCatchEvent(
161 JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jthread thr) {
162 JvmtiErrorToException(env,
163 jvmti_env,
164 jvmti_env->SetEventNotificationMode(JVMTI_ENABLE,
165 JVMTI_EVENT_EXCEPTION_CATCH,
166 thr));
167 }
168
Java_art_Exceptions_enableExceptionEvent(JNIEnv * env,jclass klass ATTRIBUTE_UNUSED,jthread thr)169 extern "C" JNIEXPORT void JNICALL Java_art_Exceptions_enableExceptionEvent(
170 JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jthread thr) {
171 JvmtiErrorToException(env,
172 jvmti_env,
173 jvmti_env->SetEventNotificationMode(JVMTI_ENABLE,
174 JVMTI_EVENT_EXCEPTION,
175 thr));
176 }
177
Java_art_Exceptions_disableExceptionCatchEvent(JNIEnv * env,jclass klass ATTRIBUTE_UNUSED,jthread thr)178 extern "C" JNIEXPORT void JNICALL Java_art_Exceptions_disableExceptionCatchEvent(
179 JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jthread thr) {
180 JvmtiErrorToException(env,
181 jvmti_env,
182 jvmti_env->SetEventNotificationMode(JVMTI_DISABLE,
183 JVMTI_EVENT_EXCEPTION_CATCH,
184 thr));
185 }
186
Java_art_Exceptions_disableExceptionEvent(JNIEnv * env,jclass klass ATTRIBUTE_UNUSED,jthread thr)187 extern "C" JNIEXPORT void JNICALL Java_art_Exceptions_disableExceptionEvent(
188 JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jthread thr) {
189 JvmtiErrorToException(env,
190 jvmti_env,
191 jvmti_env->SetEventNotificationMode(JVMTI_DISABLE,
192 JVMTI_EVENT_EXCEPTION,
193 thr));
194 }
195
196 } // namespace common_exceptions
197
198
199 } // namespace art
200