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_trace {
29
IsInCallback(JNIEnv * env,jvmtiEnv * jvmti,jthread thr)30 static 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
SetInCallback(JNIEnv * env,jvmtiEnv * jvmti,jthread thr,bool val)45 static 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
55 class ScopedCallbackState {
56 public:
ScopedCallbackState(JNIEnv * jnienv,jvmtiEnv * env,jthread thr)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 }
~ScopedCallbackState()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
73 struct 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;
80 jmethodID thread_start;
81 jmethodID thread_end;
82 bool access_watch_on_load;
83 bool modify_watch_on_load;
84 jrawMonitorID trace_mon;
85
GetTestClassart::common_trace::TraceData86 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 }
96 };
97
threadStartCB(jvmtiEnv * jvmti,JNIEnv * jnienv,jthread thread)98 static 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 }
106 ScopedLocalRef<jclass> klass(jnienv, data->GetTestClass(jvmti, jnienv));
107 if (klass.get() == nullptr) {
108 return;
109 }
110 CHECK(data->thread_start != nullptr);
111 jnienv->CallStaticVoidMethod(klass.get(), data->thread_start, thread);
112 }
threadEndCB(jvmtiEnv * jvmti,JNIEnv * jnienv,jthread thread)113 static 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 }
121 ScopedLocalRef<jclass> klass(jnienv, data->GetTestClass(jvmti, jnienv));
122 if (klass.get() == nullptr) {
123 return;
124 }
125 CHECK(data->thread_end != nullptr);
126 jnienv->CallStaticVoidMethod(klass.get(), data->thread_end, thread);
127 }
128
singleStepCB(jvmtiEnv * jvmti,JNIEnv * jnienv,jthread thread,jmethodID method,jlocation location)129 static 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 }
139 if (IsInCallback(jnienv, jvmti, thread)) {
140 return;
141 }
142 ScopedLocalRef<jclass> klass(jnienv, data->GetTestClass(jvmti, jnienv));
143 if (klass.get() == nullptr) {
144 return;
145 }
146 CHECK(data->single_step != nullptr);
147 ScopedCallbackState st(jnienv, jvmti, thread);
148 jobject method_arg = GetJavaMethod(jvmti, jnienv, method);
149 jnienv->CallStaticVoidMethod(klass.get(),
150 data->single_step,
151 thread,
152 method_arg,
153 static_cast<jlong>(location));
154 jnienv->DeleteLocalRef(method_arg);
155 }
156
fieldAccessCB(jvmtiEnv * jvmti,JNIEnv * jnienv,jthread thr,jmethodID method,jlocation location,jclass field_klass,jobject object,jfieldID field)157 static void fieldAccessCB(jvmtiEnv* jvmti,
158 JNIEnv* jnienv,
159 jthread thr,
160 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 }
170 if (IsInCallback(jnienv, jvmti, thr)) {
171 // Don't do callback for either of these to prevent an infinite loop.
172 return;
173 }
174 ScopedLocalRef<jclass> klass(jnienv, data->GetTestClass(jvmti, jnienv));
175 if (klass.get() == nullptr) {
176 return;
177 }
178 CHECK(data->field_access != nullptr);
179 ScopedCallbackState st(jnienv, jvmti, thr);
180 jobject method_arg = GetJavaMethod(jvmti, jnienv, method);
181 jobject field_arg = GetJavaField(jvmti, jnienv, field_klass, field);
182 jnienv->CallStaticVoidMethod(klass.get(),
183 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);
191 }
192
fieldModificationCB(jvmtiEnv * jvmti,JNIEnv * jnienv,jthread thr,jmethodID method,jlocation location,jclass field_klass,jobject object,jfieldID field,char type_char,jvalue new_value)193 static void fieldModificationCB(jvmtiEnv* jvmti,
194 JNIEnv* jnienv,
195 jthread thr,
196 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 }
208 if (IsInCallback(jnienv, jvmti, thr)) {
209 // Don't do callback recursively to prevent an infinite loop.
210 return;
211 }
212 ScopedLocalRef<jclass> klass(jnienv, data->GetTestClass(jvmti, jnienv));
213 if (klass.get() == nullptr) {
214 return;
215 }
216 CHECK(data->field_modify != nullptr);
217 ScopedCallbackState st(jnienv, jvmti, thr);
218 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()) {
222 jnienv->DeleteLocalRef(method_arg);
223 jnienv->DeleteLocalRef(field_arg);
224 return;
225 }
226 jnienv->CallStaticVoidMethod(klass.get(),
227 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);
236 }
237
methodExitCB(jvmtiEnv * jvmti,JNIEnv * jnienv,jthread thr,jmethodID method,jboolean was_popped_by_exception,jvalue return_value)238 static void methodExitCB(jvmtiEnv* jvmti,
239 JNIEnv* jnienv,
240 jthread thr,
241 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 }
249 if (method == data->exit_method ||
250 method == data->enter_method ||
251 IsInCallback(jnienv, jvmti, thr)) {
252 // Don't do callback for either of these to prevent an infinite loop.
253 return;
254 }
255 ScopedLocalRef<jclass> klass(jnienv, data->GetTestClass(jvmti, jnienv));
256 if (klass.get() == nullptr) {
257 return;
258 }
259 CHECK(data->exit_method != nullptr);
260 ScopedCallbackState st(jnienv, jvmti, thr);
261 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()) {
265 return;
266 }
267 jnienv->CallStaticVoidMethod(klass.get(),
268 data->exit_method,
269 method_arg,
270 was_popped_by_exception,
271 result);
272 jnienv->DeleteLocalRef(method_arg);
273 }
274
methodEntryCB(jvmtiEnv * jvmti,JNIEnv * jnienv,jthread thr,jmethodID method)275 static void methodEntryCB(jvmtiEnv* jvmti,
276 JNIEnv* jnienv,
277 jthread thr,
278 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);
285 if (method == data->exit_method ||
286 method == data->enter_method ||
287 IsInCallback(jnienv, jvmti, thr)) {
288 // Don't do callback for either of these to prevent an infinite loop.
289 return;
290 }
291 ScopedLocalRef<jclass> klass(jnienv, data->GetTestClass(jvmti, jnienv));
292 if (klass.get() == nullptr) {
293 return;
294 }
295 ScopedCallbackState st(jnienv, jvmti, thr);
296 jobject method_arg = GetJavaMethod(jvmti, jnienv, method);
297 if (jnienv->ExceptionCheck()) {
298 return;
299 }
300 jnienv->CallStaticVoidMethod(klass.get(), data->enter_method, method_arg);
301 jnienv->DeleteLocalRef(method_arg);
302 }
303
classPrepareCB(jvmtiEnv * jvmti,JNIEnv * jnienv,jthread thr ATTRIBUTE_UNUSED,jclass klass)304 static 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
Java_art_Trace_watchAllFieldAccesses(JNIEnv * env)334 extern "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
Java_art_Trace_watchAllFieldModifications(JNIEnv * env)374 extern "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
GetFieldAndClass(JNIEnv * env,jobject ref_field,jclass * out_klass,jfieldID * out_field)414 static 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
Java_art_Trace_watchFieldModification(JNIEnv * env,jclass trace ATTRIBUTE_UNUSED,jobject field_obj)442 extern "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
Java_art_Trace_watchFieldAccess(JNIEnv * env,jclass trace ATTRIBUTE_UNUSED,jobject field_obj)456 extern "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
Java_art_Trace_enableTracing2(JNIEnv * env,jclass trace ATTRIBUTE_UNUSED,jclass klass,jobject enter,jobject exit,jobject field_access,jobject field_modify,jobject single_step,jobject thread_start,jobject thread_end,jthread thr)469 extern "C" JNIEXPORT void JNICALL Java_art_Trace_enableTracing2(
470 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,
478 jobject thread_start,
479 jobject thread_end,
480 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));
489 if (JvmtiErrorToException(env, jvmti_env,
490 jvmti_env->CreateRawMonitor("Trace monitor", &data->trace_mon))) {
491 return;
492 }
493 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;
499 data->thread_start = thread_start != nullptr ? env->FromReflectedMethod(thread_start) : nullptr;
500 data->thread_end = thread_end != nullptr ? env->FromReflectedMethod(thread_end) : nullptr;
501
502 TraceData* old_data = nullptr;
503 if (JvmtiErrorToException(env, jvmti_env,
504 jvmti_env->GetEnvironmentLocalStorage(
505 reinterpret_cast<void**>(&old_data)))) {
506 return;
507 } else if (old_data != nullptr && old_data->test_klass != nullptr) {
508 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
516 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(¤t_callbacks,
527 sizeof(current_callbacks)))) {
528 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 }
570 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
Java_art_Trace_enableTracing(JNIEnv * env,jclass trace,jclass klass,jobject enter,jobject exit,jobject field_access,jobject field_modify,jobject single_step,jthread thr)588 extern "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;
610 }
611
Java_art_Trace_disableTracing(JNIEnv * env,jclass klass ATTRIBUTE_UNUSED,jthread thr)612 extern "C" JNIEXPORT void JNICALL Java_art_Trace_disableTracing(
613 JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jthread thr) {
614 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 }
623 ScopedLocalRef<jthrowable> err(env, nullptr);
624 // First disable all the events.
625 if (JvmtiErrorToException(env, jvmti_env,
626 jvmti_env->SetEventNotificationMode(JVMTI_DISABLE,
627 JVMTI_EVENT_FIELD_ACCESS,
628 thr))) {
629 env->ExceptionDescribe();
630 err.reset(env->ExceptionOccurred());
631 env->ExceptionClear();
632 }
633 if (JvmtiErrorToException(env, jvmti_env,
634 jvmti_env->SetEventNotificationMode(JVMTI_DISABLE,
635 JVMTI_EVENT_FIELD_MODIFICATION,
636 thr))) {
637 env->ExceptionDescribe();
638 err.reset(env->ExceptionOccurred());
639 env->ExceptionClear();
640 }
641 if (JvmtiErrorToException(env, jvmti_env,
642 jvmti_env->SetEventNotificationMode(JVMTI_DISABLE,
643 JVMTI_EVENT_METHOD_ENTRY,
644 thr))) {
645 env->ExceptionDescribe();
646 err.reset(env->ExceptionOccurred());
647 env->ExceptionClear();
648 }
649 if (JvmtiErrorToException(env, jvmti_env,
650 jvmti_env->SetEventNotificationMode(JVMTI_DISABLE,
651 JVMTI_EVENT_METHOD_EXIT,
652 thr))) {
653 env->ExceptionDescribe();
654 err.reset(env->ExceptionOccurred());
655 env->ExceptionClear();
656 }
657 if (JvmtiErrorToException(env, jvmti_env,
658 jvmti_env->SetEventNotificationMode(JVMTI_DISABLE,
659 JVMTI_EVENT_SINGLE_STEP,
660 thr))) {
661 env->ExceptionDescribe();
662 err.reset(env->ExceptionOccurred());
663 env->ExceptionClear();
664 }
665 if (JvmtiErrorToException(env, jvmti_env,
666 jvmti_env->RawMonitorEnter(data->trace_mon))) {
667 return;
668 }
669 // 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 }
680 }
681
682 } // namespace common_trace
683
684
685 } // namespace art
686