blob: 11e1c157577af7b2ddf6bd3194b16fe55a3a7389 [file] [log] [blame]
Alex Lightd0d65962017-06-30 11:13:33 -07001/*
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
26namespace art {
27
28namespace common_trace {
29
Alex Light4ae4e7e2017-12-14 10:04:06 -080030static bool IsInCallback(JNIEnv* env, jvmtiEnv *jvmti, jthread thr) {
31 void* data;
32 ScopedLocalRef<jthrowable> exc(env, env->ExceptionOccurred());
33 env->ExceptionClear();
34 jvmti->GetThreadLocalStorage(thr, &data);
35 if (exc.get() != nullptr) {
36 env->Throw(exc.get());
37 }
38 if (data == nullptr) {
39 return false;
40 } else {
41 return true;
42 }
43}
44
45static void SetInCallback(JNIEnv* env, jvmtiEnv *jvmti, jthread thr, bool val) {
46 ScopedLocalRef<jthrowable> exc(env, env->ExceptionOccurred());
47 env->ExceptionClear();
48 jvmti->SetThreadLocalStorage(thr, (val ? reinterpret_cast<void*>(0x1)
49 : reinterpret_cast<void*>(0x0)));
50 if (exc.get() != nullptr) {
51 env->Throw(exc.get());
52 }
53}
54
55class ScopedCallbackState {
56 public:
57 ScopedCallbackState(JNIEnv* jnienv, jvmtiEnv* env, jthread thr)
58 : jnienv_(jnienv), env_(env), thr_(thr) {
59 CHECK(!IsInCallback(jnienv_, env_, thr_));
60 SetInCallback(jnienv_, env_, thr_, true);
61 }
62 ~ScopedCallbackState() {
63 CHECK(IsInCallback(jnienv_, env_, thr_));
64 SetInCallback(jnienv_, env_, thr_, false);
65 }
66
67 private:
68 JNIEnv* jnienv_;
69 jvmtiEnv* env_;
70 jthread thr_;
71};
72
Alex Lightd0d65962017-06-30 11:13:33 -070073struct TraceData {
74 jclass test_klass;
75 jmethodID enter_method;
76 jmethodID exit_method;
77 jmethodID field_access;
78 jmethodID field_modify;
79 jmethodID single_step;
Alex Lightdf132402017-09-29 12:54:33 -070080 jmethodID thread_start;
81 jmethodID thread_end;
Alex Lightd0d65962017-06-30 11:13:33 -070082 bool access_watch_on_load;
83 bool modify_watch_on_load;
Alex Light2743d752017-12-05 10:36:12 -080084 jrawMonitorID trace_mon;
85
86 jclass GetTestClass(jvmtiEnv* jvmti, JNIEnv* env) {
87 if (JvmtiErrorToException(env, jvmti, jvmti->RawMonitorEnter(trace_mon))) {
88 return nullptr;
89 }
90 jclass out = reinterpret_cast<jclass>(env->NewLocalRef(test_klass));
91 if (JvmtiErrorToException(env, jvmti, jvmti->RawMonitorExit(trace_mon))) {
92 return nullptr;
93 }
94 return out;
95 }
Alex Lightd0d65962017-06-30 11:13:33 -070096};
97
Alex Lightdf132402017-09-29 12:54:33 -070098static void threadStartCB(jvmtiEnv* jvmti,
99 JNIEnv* jnienv,
100 jthread thread) {
101 TraceData* data = nullptr;
102 if (JvmtiErrorToException(jnienv, jvmti,
103 jvmti->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)))) {
104 return;
105 }
Alex Light2743d752017-12-05 10:36:12 -0800106 ScopedLocalRef<jclass> klass(jnienv, data->GetTestClass(jvmti, jnienv));
107 if (klass.get() == nullptr) {
108 return;
109 }
Alex Lightdf132402017-09-29 12:54:33 -0700110 CHECK(data->thread_start != nullptr);
Alex Light2743d752017-12-05 10:36:12 -0800111 jnienv->CallStaticVoidMethod(klass.get(), data->thread_start, thread);
Alex Lightdf132402017-09-29 12:54:33 -0700112}
113static void threadEndCB(jvmtiEnv* jvmti,
114 JNIEnv* jnienv,
115 jthread thread) {
116 TraceData* data = nullptr;
117 if (JvmtiErrorToException(jnienv, jvmti,
118 jvmti->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)))) {
119 return;
120 }
Alex Light2743d752017-12-05 10:36:12 -0800121 ScopedLocalRef<jclass> klass(jnienv, data->GetTestClass(jvmti, jnienv));
122 if (klass.get() == nullptr) {
123 return;
124 }
Alex Lightdf132402017-09-29 12:54:33 -0700125 CHECK(data->thread_end != nullptr);
Alex Light2743d752017-12-05 10:36:12 -0800126 jnienv->CallStaticVoidMethod(klass.get(), data->thread_end, thread);
Alex Lightdf132402017-09-29 12:54:33 -0700127}
128
Alex Lightd0d65962017-06-30 11:13:33 -0700129static void singleStepCB(jvmtiEnv* jvmti,
130 JNIEnv* jnienv,
131 jthread thread,
132 jmethodID method,
133 jlocation location) {
134 TraceData* data = nullptr;
135 if (JvmtiErrorToException(jnienv, jvmti,
136 jvmti->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)))) {
137 return;
138 }
Alex Light4ae4e7e2017-12-14 10:04:06 -0800139 if (IsInCallback(jnienv, jvmti, thread)) {
Alex Lightd0d65962017-06-30 11:13:33 -0700140 return;
141 }
Alex Light2743d752017-12-05 10:36:12 -0800142 ScopedLocalRef<jclass> klass(jnienv, data->GetTestClass(jvmti, jnienv));
143 if (klass.get() == nullptr) {
144 return;
145 }
Alex Lightd0d65962017-06-30 11:13:33 -0700146 CHECK(data->single_step != nullptr);
Alex Light4ae4e7e2017-12-14 10:04:06 -0800147 ScopedCallbackState st(jnienv, jvmti, thread);
Alex Lightd0d65962017-06-30 11:13:33 -0700148 jobject method_arg = GetJavaMethod(jvmti, jnienv, method);
Alex Light2743d752017-12-05 10:36:12 -0800149 jnienv->CallStaticVoidMethod(klass.get(),
Alex Lightd0d65962017-06-30 11:13:33 -0700150 data->single_step,
151 thread,
152 method_arg,
153 static_cast<jlong>(location));
154 jnienv->DeleteLocalRef(method_arg);
Alex Lightd0d65962017-06-30 11:13:33 -0700155}
156
157static void fieldAccessCB(jvmtiEnv* jvmti,
158 JNIEnv* jnienv,
Alex Light4ae4e7e2017-12-14 10:04:06 -0800159 jthread thr,
Alex Lightd0d65962017-06-30 11:13:33 -0700160 jmethodID method,
161 jlocation location,
162 jclass field_klass,
163 jobject object,
164 jfieldID field) {
165 TraceData* data = nullptr;
166 if (JvmtiErrorToException(jnienv, jvmti,
167 jvmti->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)))) {
168 return;
169 }
Alex Light4ae4e7e2017-12-14 10:04:06 -0800170 if (IsInCallback(jnienv, jvmti, thr)) {
Alex Lightd0d65962017-06-30 11:13:33 -0700171 // Don't do callback for either of these to prevent an infinite loop.
172 return;
173 }
Alex Light2743d752017-12-05 10:36:12 -0800174 ScopedLocalRef<jclass> klass(jnienv, data->GetTestClass(jvmti, jnienv));
175 if (klass.get() == nullptr) {
176 return;
177 }
Alex Lightd0d65962017-06-30 11:13:33 -0700178 CHECK(data->field_access != nullptr);
Alex Light4ae4e7e2017-12-14 10:04:06 -0800179 ScopedCallbackState st(jnienv, jvmti, thr);
Alex Lightd0d65962017-06-30 11:13:33 -0700180 jobject method_arg = GetJavaMethod(jvmti, jnienv, method);
181 jobject field_arg = GetJavaField(jvmti, jnienv, field_klass, field);
Alex Light2743d752017-12-05 10:36:12 -0800182 jnienv->CallStaticVoidMethod(klass.get(),
Alex Lightd0d65962017-06-30 11:13:33 -0700183 data->field_access,
184 method_arg,
185 static_cast<jlong>(location),
186 field_klass,
187 object,
188 field_arg);
189 jnienv->DeleteLocalRef(method_arg);
190 jnienv->DeleteLocalRef(field_arg);
Alex Lightd0d65962017-06-30 11:13:33 -0700191}
192
193static void fieldModificationCB(jvmtiEnv* jvmti,
194 JNIEnv* jnienv,
Alex Light4ae4e7e2017-12-14 10:04:06 -0800195 jthread thr,
Alex Lightd0d65962017-06-30 11:13:33 -0700196 jmethodID method,
197 jlocation location,
198 jclass field_klass,
199 jobject object,
200 jfieldID field,
201 char type_char,
202 jvalue new_value) {
203 TraceData* data = nullptr;
204 if (JvmtiErrorToException(jnienv, jvmti,
205 jvmti->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)))) {
206 return;
207 }
Alex Light4ae4e7e2017-12-14 10:04:06 -0800208 if (IsInCallback(jnienv, jvmti, thr)) {
Alex Lightd0d65962017-06-30 11:13:33 -0700209 // Don't do callback recursively to prevent an infinite loop.
210 return;
211 }
Alex Light2743d752017-12-05 10:36:12 -0800212 ScopedLocalRef<jclass> klass(jnienv, data->GetTestClass(jvmti, jnienv));
213 if (klass.get() == nullptr) {
214 return;
215 }
Alex Lightd0d65962017-06-30 11:13:33 -0700216 CHECK(data->field_modify != nullptr);
Alex Light4ae4e7e2017-12-14 10:04:06 -0800217 ScopedCallbackState st(jnienv, jvmti, thr);
Alex Lightd0d65962017-06-30 11:13:33 -0700218 jobject method_arg = GetJavaMethod(jvmti, jnienv, method);
219 jobject field_arg = GetJavaField(jvmti, jnienv, field_klass, field);
220 jobject value = GetJavaValueByType(jnienv, type_char, new_value);
221 if (jnienv->ExceptionCheck()) {
Alex Lightd0d65962017-06-30 11:13:33 -0700222 jnienv->DeleteLocalRef(method_arg);
223 jnienv->DeleteLocalRef(field_arg);
224 return;
225 }
Alex Light2743d752017-12-05 10:36:12 -0800226 jnienv->CallStaticVoidMethod(klass.get(),
Alex Lightd0d65962017-06-30 11:13:33 -0700227 data->field_modify,
228 method_arg,
229 static_cast<jlong>(location),
230 field_klass,
231 object,
232 field_arg,
233 value);
234 jnienv->DeleteLocalRef(method_arg);
235 jnienv->DeleteLocalRef(field_arg);
Alex Lightd0d65962017-06-30 11:13:33 -0700236}
237
238static void methodExitCB(jvmtiEnv* jvmti,
239 JNIEnv* jnienv,
Alex Light4ae4e7e2017-12-14 10:04:06 -0800240 jthread thr,
Alex Lightd0d65962017-06-30 11:13:33 -0700241 jmethodID method,
242 jboolean was_popped_by_exception,
243 jvalue return_value) {
244 TraceData* data = nullptr;
245 if (JvmtiErrorToException(jnienv, jvmti,
246 jvmti->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)))) {
247 return;
248 }
Alex Light4ae4e7e2017-12-14 10:04:06 -0800249 if (method == data->exit_method ||
250 method == data->enter_method ||
251 IsInCallback(jnienv, jvmti, thr)) {
Alex Lightd0d65962017-06-30 11:13:33 -0700252 // Don't do callback for either of these to prevent an infinite loop.
253 return;
254 }
Alex Light2743d752017-12-05 10:36:12 -0800255 ScopedLocalRef<jclass> klass(jnienv, data->GetTestClass(jvmti, jnienv));
256 if (klass.get() == nullptr) {
257 return;
258 }
Alex Lightd0d65962017-06-30 11:13:33 -0700259 CHECK(data->exit_method != nullptr);
Alex Light4ae4e7e2017-12-14 10:04:06 -0800260 ScopedCallbackState st(jnienv, jvmti, thr);
Alex Lightd0d65962017-06-30 11:13:33 -0700261 jobject method_arg = GetJavaMethod(jvmti, jnienv, method);
262 jobject result =
263 was_popped_by_exception ? nullptr : GetJavaValue(jvmti, jnienv, method, return_value);
264 if (jnienv->ExceptionCheck()) {
Alex Lightd0d65962017-06-30 11:13:33 -0700265 return;
266 }
Alex Light2743d752017-12-05 10:36:12 -0800267 jnienv->CallStaticVoidMethod(klass.get(),
Alex Lightd0d65962017-06-30 11:13:33 -0700268 data->exit_method,
269 method_arg,
270 was_popped_by_exception,
271 result);
272 jnienv->DeleteLocalRef(method_arg);
Alex Lightd0d65962017-06-30 11:13:33 -0700273}
274
275static void methodEntryCB(jvmtiEnv* jvmti,
276 JNIEnv* jnienv,
Alex Light4ae4e7e2017-12-14 10:04:06 -0800277 jthread thr,
Alex Lightd0d65962017-06-30 11:13:33 -0700278 jmethodID method) {
279 TraceData* data = nullptr;
280 if (JvmtiErrorToException(jnienv, jvmti,
281 jvmti->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)))) {
282 return;
283 }
284 CHECK(data->enter_method != nullptr);
Alex Light4ae4e7e2017-12-14 10:04:06 -0800285 if (method == data->exit_method ||
286 method == data->enter_method ||
287 IsInCallback(jnienv, jvmti, thr)) {
Alex Lightd0d65962017-06-30 11:13:33 -0700288 // Don't do callback for either of these to prevent an infinite loop.
289 return;
290 }
Alex Light2743d752017-12-05 10:36:12 -0800291 ScopedLocalRef<jclass> klass(jnienv, data->GetTestClass(jvmti, jnienv));
292 if (klass.get() == nullptr) {
293 return;
294 }
Alex Light4ae4e7e2017-12-14 10:04:06 -0800295 ScopedCallbackState st(jnienv, jvmti, thr);
Alex Lightd0d65962017-06-30 11:13:33 -0700296 jobject method_arg = GetJavaMethod(jvmti, jnienv, method);
297 if (jnienv->ExceptionCheck()) {
298 return;
299 }
Alex Light2743d752017-12-05 10:36:12 -0800300 jnienv->CallStaticVoidMethod(klass.get(), data->enter_method, method_arg);
Alex Lightd0d65962017-06-30 11:13:33 -0700301 jnienv->DeleteLocalRef(method_arg);
Alex Lightd0d65962017-06-30 11:13:33 -0700302}
303
304static void classPrepareCB(jvmtiEnv* jvmti,
305 JNIEnv* jnienv,
306 jthread thr ATTRIBUTE_UNUSED,
307 jclass klass) {
308 TraceData* data = nullptr;
309 if (JvmtiErrorToException(jnienv, jvmti,
310 jvmti->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)))) {
311 return;
312 }
313 if (data->access_watch_on_load || data->modify_watch_on_load) {
314 jint nfields;
315 jfieldID* fields;
316 if (JvmtiErrorToException(jnienv, jvmti, jvmti->GetClassFields(klass, &nfields, &fields))) {
317 return;
318 }
319 for (jint i = 0; i < nfields; i++) {
320 jfieldID f = fields[i];
321 // Ignore errors
322 if (data->access_watch_on_load) {
323 jvmti->SetFieldAccessWatch(klass, f);
324 }
325
326 if (data->modify_watch_on_load) {
327 jvmti->SetFieldModificationWatch(klass, f);
328 }
329 }
330 jvmti->Deallocate(reinterpret_cast<unsigned char*>(fields));
331 }
332}
333
334extern "C" JNIEXPORT void JNICALL Java_art_Trace_watchAllFieldAccesses(JNIEnv* env) {
335 TraceData* data = nullptr;
336 if (JvmtiErrorToException(
337 env, jvmti_env, jvmti_env->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)))) {
338 return;
339 }
340 data->access_watch_on_load = true;
341 // We need the classPrepareCB to watch new fields as the classes are loaded/prepared.
342 if (JvmtiErrorToException(env,
343 jvmti_env,
344 jvmti_env->SetEventNotificationMode(JVMTI_ENABLE,
345 JVMTI_EVENT_CLASS_PREPARE,
346 nullptr))) {
347 return;
348 }
349 jint nklasses;
350 jclass* klasses;
351 if (JvmtiErrorToException(env, jvmti_env, jvmti_env->GetLoadedClasses(&nklasses, &klasses))) {
352 return;
353 }
354 for (jint i = 0; i < nklasses; i++) {
355 jclass k = klasses[i];
356
357 jint nfields;
358 jfieldID* fields;
359 jvmtiError err = jvmti_env->GetClassFields(k, &nfields, &fields);
360 if (err == JVMTI_ERROR_CLASS_NOT_PREPARED) {
361 continue;
362 } else if (JvmtiErrorToException(env, jvmti_env, err)) {
363 jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(klasses));
364 return;
365 }
366 for (jint j = 0; j < nfields; j++) {
367 jvmti_env->SetFieldAccessWatch(k, fields[j]);
368 }
369 jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(fields));
370 }
371 jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(klasses));
372}
373
374extern "C" JNIEXPORT void JNICALL Java_art_Trace_watchAllFieldModifications(JNIEnv* env) {
375 TraceData* data = nullptr;
376 if (JvmtiErrorToException(
377 env, jvmti_env, jvmti_env->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)))) {
378 return;
379 }
380 data->modify_watch_on_load = true;
381 // We need the classPrepareCB to watch new fields as the classes are loaded/prepared.
382 if (JvmtiErrorToException(env,
383 jvmti_env,
384 jvmti_env->SetEventNotificationMode(JVMTI_ENABLE,
385 JVMTI_EVENT_CLASS_PREPARE,
386 nullptr))) {
387 return;
388 }
389 jint nklasses;
390 jclass* klasses;
391 if (JvmtiErrorToException(env, jvmti_env, jvmti_env->GetLoadedClasses(&nklasses, &klasses))) {
392 return;
393 }
394 for (jint i = 0; i < nklasses; i++) {
395 jclass k = klasses[i];
396
397 jint nfields;
398 jfieldID* fields;
399 jvmtiError err = jvmti_env->GetClassFields(k, &nfields, &fields);
400 if (err == JVMTI_ERROR_CLASS_NOT_PREPARED) {
401 continue;
402 } else if (JvmtiErrorToException(env, jvmti_env, err)) {
403 jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(klasses));
404 return;
405 }
406 for (jint j = 0; j < nfields; j++) {
407 jvmti_env->SetFieldModificationWatch(k, fields[j]);
408 }
409 jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(fields));
410 }
411 jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(klasses));
412}
413
414static bool GetFieldAndClass(JNIEnv* env,
415 jobject ref_field,
416 jclass* out_klass,
417 jfieldID* out_field) {
418 *out_field = env->FromReflectedField(ref_field);
419 if (env->ExceptionCheck()) {
420 return false;
421 }
422 jclass field_klass = env->FindClass("java/lang/reflect/Field");
423 if (env->ExceptionCheck()) {
424 return false;
425 }
426 jmethodID get_declaring_class_method =
427 env->GetMethodID(field_klass, "getDeclaringClass", "()Ljava/lang/Class;");
428 if (env->ExceptionCheck()) {
429 env->DeleteLocalRef(field_klass);
430 return false;
431 }
432 *out_klass = static_cast<jclass>(env->CallObjectMethod(ref_field, get_declaring_class_method));
433 if (env->ExceptionCheck()) {
434 *out_klass = nullptr;
435 env->DeleteLocalRef(field_klass);
436 return false;
437 }
438 env->DeleteLocalRef(field_klass);
439 return true;
440}
441
442extern "C" JNIEXPORT void JNICALL Java_art_Trace_watchFieldModification(
443 JNIEnv* env,
444 jclass trace ATTRIBUTE_UNUSED,
445 jobject field_obj) {
446 jfieldID field;
447 jclass klass;
448 if (!GetFieldAndClass(env, field_obj, &klass, &field)) {
449 return;
450 }
451
452 JvmtiErrorToException(env, jvmti_env, jvmti_env->SetFieldModificationWatch(klass, field));
453 env->DeleteLocalRef(klass);
454}
455
456extern "C" JNIEXPORT void JNICALL Java_art_Trace_watchFieldAccess(
457 JNIEnv* env,
458 jclass trace ATTRIBUTE_UNUSED,
459 jobject field_obj) {
460 jfieldID field;
461 jclass klass;
462 if (!GetFieldAndClass(env, field_obj, &klass, &field)) {
463 return;
464 }
465 JvmtiErrorToException(env, jvmti_env, jvmti_env->SetFieldAccessWatch(klass, field));
466 env->DeleteLocalRef(klass);
467}
468
Alex Lightdf132402017-09-29 12:54:33 -0700469extern "C" JNIEXPORT void JNICALL Java_art_Trace_enableTracing2(
Alex Lightd0d65962017-06-30 11:13:33 -0700470 JNIEnv* env,
471 jclass trace ATTRIBUTE_UNUSED,
472 jclass klass,
473 jobject enter,
474 jobject exit,
475 jobject field_access,
476 jobject field_modify,
477 jobject single_step,
Alex Lightdf132402017-09-29 12:54:33 -0700478 jobject thread_start,
479 jobject thread_end,
Alex Lightd0d65962017-06-30 11:13:33 -0700480 jthread thr) {
481 TraceData* data = nullptr;
482 if (JvmtiErrorToException(env,
483 jvmti_env,
484 jvmti_env->Allocate(sizeof(TraceData),
485 reinterpret_cast<unsigned char**>(&data)))) {
486 return;
487 }
488 memset(data, 0, sizeof(TraceData));
Alex Light2743d752017-12-05 10:36:12 -0800489 if (JvmtiErrorToException(env, jvmti_env,
490 jvmti_env->CreateRawMonitor("Trace monitor", &data->trace_mon))) {
491 return;
492 }
Alex Lightd0d65962017-06-30 11:13:33 -0700493 data->test_klass = reinterpret_cast<jclass>(env->NewGlobalRef(klass));
494 data->enter_method = enter != nullptr ? env->FromReflectedMethod(enter) : nullptr;
495 data->exit_method = exit != nullptr ? env->FromReflectedMethod(exit) : nullptr;
496 data->field_access = field_access != nullptr ? env->FromReflectedMethod(field_access) : nullptr;
497 data->field_modify = field_modify != nullptr ? env->FromReflectedMethod(field_modify) : nullptr;
498 data->single_step = single_step != nullptr ? env->FromReflectedMethod(single_step) : nullptr;
Alex Lightdf132402017-09-29 12:54:33 -0700499 data->thread_start = thread_start != nullptr ? env->FromReflectedMethod(thread_start) : nullptr;
500 data->thread_end = thread_end != nullptr ? env->FromReflectedMethod(thread_end) : nullptr;
Alex Lightd0d65962017-06-30 11:13:33 -0700501
Alex Lightadce6a02017-08-02 17:12:53 -0700502 TraceData* old_data = nullptr;
503 if (JvmtiErrorToException(env, jvmti_env,
504 jvmti_env->GetEnvironmentLocalStorage(
505 reinterpret_cast<void**>(&old_data)))) {
Alex Lightd0d65962017-06-30 11:13:33 -0700506 return;
Alex Lightadce6a02017-08-02 17:12:53 -0700507 } else if (old_data != nullptr && old_data->test_klass != nullptr) {
Alex Lightd0d65962017-06-30 11:13:33 -0700508 ScopedLocalRef<jclass> rt_exception(env, env->FindClass("java/lang/RuntimeException"));
509 env->ThrowNew(rt_exception.get(), "Environment already has local storage set!");
510 return;
511 }
512 if (JvmtiErrorToException(env, jvmti_env, jvmti_env->SetEnvironmentLocalStorage(data))) {
513 return;
514 }
515
Alex Light9e7859c2018-04-05 13:49:43 -0700516 current_callbacks.MethodEntry = methodEntryCB;
517 current_callbacks.MethodExit = methodExitCB;
518 current_callbacks.FieldAccess = fieldAccessCB;
519 current_callbacks.FieldModification = fieldModificationCB;
520 current_callbacks.ClassPrepare = classPrepareCB;
521 current_callbacks.SingleStep = singleStepCB;
522 current_callbacks.ThreadStart = threadStartCB;
523 current_callbacks.ThreadEnd = threadEndCB;
524 if (JvmtiErrorToException(env,
525 jvmti_env,
526 jvmti_env->SetEventCallbacks(&current_callbacks,
527 sizeof(current_callbacks)))) {
Alex Lightd0d65962017-06-30 11:13:33 -0700528 return;
529 }
530 if (enter != nullptr &&
531 JvmtiErrorToException(env,
532 jvmti_env,
533 jvmti_env->SetEventNotificationMode(JVMTI_ENABLE,
534 JVMTI_EVENT_METHOD_ENTRY,
535 thr))) {
536 return;
537 }
538 if (exit != nullptr &&
539 JvmtiErrorToException(env,
540 jvmti_env,
541 jvmti_env->SetEventNotificationMode(JVMTI_ENABLE,
542 JVMTI_EVENT_METHOD_EXIT,
543 thr))) {
544 return;
545 }
546 if (field_access != nullptr &&
547 JvmtiErrorToException(env,
548 jvmti_env,
549 jvmti_env->SetEventNotificationMode(JVMTI_ENABLE,
550 JVMTI_EVENT_FIELD_ACCESS,
551 thr))) {
552 return;
553 }
554 if (field_modify != nullptr &&
555 JvmtiErrorToException(env,
556 jvmti_env,
557 jvmti_env->SetEventNotificationMode(JVMTI_ENABLE,
558 JVMTI_EVENT_FIELD_MODIFICATION,
559 thr))) {
560 return;
561 }
562 if (single_step != nullptr &&
563 JvmtiErrorToException(env,
564 jvmti_env,
565 jvmti_env->SetEventNotificationMode(JVMTI_ENABLE,
566 JVMTI_EVENT_SINGLE_STEP,
567 thr))) {
568 return;
569 }
Alex Lightdf132402017-09-29 12:54:33 -0700570 if (thread_start != nullptr &&
571 JvmtiErrorToException(env,
572 jvmti_env,
573 jvmti_env->SetEventNotificationMode(JVMTI_ENABLE,
574 JVMTI_EVENT_THREAD_START,
575 thr))) {
576 return;
577 }
578 if (thread_end != nullptr &&
579 JvmtiErrorToException(env,
580 jvmti_env,
581 jvmti_env->SetEventNotificationMode(JVMTI_ENABLE,
582 JVMTI_EVENT_THREAD_END,
583 thr))) {
584 return;
585 }
586}
587
588extern "C" JNIEXPORT void JNICALL Java_art_Trace_enableTracing(
589 JNIEnv* env,
590 jclass trace,
591 jclass klass,
592 jobject enter,
593 jobject exit,
594 jobject field_access,
595 jobject field_modify,
596 jobject single_step,
597 jthread thr) {
598 Java_art_Trace_enableTracing2(env,
599 trace,
600 klass,
601 enter,
602 exit,
603 field_access,
604 field_modify,
605 single_step,
606 /* thread_start */ nullptr,
607 /* thread_end */ nullptr,
608 thr);
609 return;
Alex Lightd0d65962017-06-30 11:13:33 -0700610}
611
612extern "C" JNIEXPORT void JNICALL Java_art_Trace_disableTracing(
613 JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jthread thr) {
Alex Lightadce6a02017-08-02 17:12:53 -0700614 TraceData* data = nullptr;
615 if (JvmtiErrorToException(
616 env, jvmti_env, jvmti_env->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)))) {
617 return;
618 }
619 // If data is null then we haven't ever enabled tracing so we don't need to do anything.
620 if (data == nullptr || data->test_klass == nullptr) {
621 return;
622 }
Alex Light2743d752017-12-05 10:36:12 -0800623 ScopedLocalRef<jthrowable> err(env, nullptr);
624 // First disable all the events.
Alex Lightd0d65962017-06-30 11:13:33 -0700625 if (JvmtiErrorToException(env, jvmti_env,
626 jvmti_env->SetEventNotificationMode(JVMTI_DISABLE,
627 JVMTI_EVENT_FIELD_ACCESS,
628 thr))) {
Alex Light2743d752017-12-05 10:36:12 -0800629 env->ExceptionDescribe();
630 err.reset(env->ExceptionOccurred());
631 env->ExceptionClear();
Alex Lightd0d65962017-06-30 11:13:33 -0700632 }
633 if (JvmtiErrorToException(env, jvmti_env,
634 jvmti_env->SetEventNotificationMode(JVMTI_DISABLE,
635 JVMTI_EVENT_FIELD_MODIFICATION,
636 thr))) {
Alex Light2743d752017-12-05 10:36:12 -0800637 env->ExceptionDescribe();
638 err.reset(env->ExceptionOccurred());
639 env->ExceptionClear();
Alex Lightd0d65962017-06-30 11:13:33 -0700640 }
641 if (JvmtiErrorToException(env, jvmti_env,
642 jvmti_env->SetEventNotificationMode(JVMTI_DISABLE,
643 JVMTI_EVENT_METHOD_ENTRY,
644 thr))) {
Alex Light2743d752017-12-05 10:36:12 -0800645 env->ExceptionDescribe();
646 err.reset(env->ExceptionOccurred());
647 env->ExceptionClear();
Alex Lightd0d65962017-06-30 11:13:33 -0700648 }
649 if (JvmtiErrorToException(env, jvmti_env,
650 jvmti_env->SetEventNotificationMode(JVMTI_DISABLE,
651 JVMTI_EVENT_METHOD_EXIT,
652 thr))) {
Alex Light2743d752017-12-05 10:36:12 -0800653 env->ExceptionDescribe();
654 err.reset(env->ExceptionOccurred());
655 env->ExceptionClear();
Alex Lightd0d65962017-06-30 11:13:33 -0700656 }
657 if (JvmtiErrorToException(env, jvmti_env,
658 jvmti_env->SetEventNotificationMode(JVMTI_DISABLE,
659 JVMTI_EVENT_SINGLE_STEP,
660 thr))) {
Alex Light2743d752017-12-05 10:36:12 -0800661 env->ExceptionDescribe();
662 err.reset(env->ExceptionOccurred());
663 env->ExceptionClear();
664 }
665 if (JvmtiErrorToException(env, jvmti_env,
666 jvmti_env->RawMonitorEnter(data->trace_mon))) {
Alex Lightd0d65962017-06-30 11:13:33 -0700667 return;
668 }
Alex Light2743d752017-12-05 10:36:12 -0800669 // Clear test_klass so we know this isn't being used
670 env->DeleteGlobalRef(data->test_klass);
671 data->test_klass = nullptr;
672 if (JvmtiErrorToException(env,
673 jvmti_env,
674 jvmti_env->RawMonitorExit(data->trace_mon))) {
675 return;
676 }
677 if (err.get() != nullptr) {
678 env->Throw(err.get());
679 }
Alex Lightd0d65962017-06-30 11:13:33 -0700680}
681
682} // namespace common_trace
683
684
685} // namespace art