1 /*
2 * Copyright (C) 2019 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 "suspend_event_helper.h"
18
19 #include <inttypes.h>
20
21 #include <cstdio>
22 #include <memory>
23 #include <string>
24 #include <vector>
25
26 #include "android-base/logging.h"
27 #include "android-base/stringprintf.h"
28
29 #include "jni.h"
30 #include "jvmti.h"
31 #include "scoped_local_ref.h"
32 #include "scoped_utf_chars.h"
33
34 // Test infrastructure
35 #include "jni_binder.h"
36 #include "jni_helper.h"
37 #include "jvmti_helper.h"
38 #include "test_env.h"
39 #include "ti_macros.h"
40
41 namespace art {
42 namespace common_suspend_event {
43
44 struct TestData {
45 jlocation target_loc;
46 jmethodID target_method;
47 jclass target_klass;
48 jfieldID target_field;
49 jrawMonitorID notify_monitor;
50 jint frame_pop_offset;
51 jmethodID frame_pop_setup_method;
52 std::vector<std::string> interesting_classes;
53 bool hit_location;
54
TestDataart::common_suspend_event::TestData55 TestData(jvmtiEnv* jvmti,
56 JNIEnv* env,
57 jlocation loc,
58 jobject meth,
59 jclass klass,
60 jobject field,
61 jobject setup_meth,
62 jint pop_offset,
63 const std::vector<std::string>&& interesting)
64 : target_loc(loc), target_method(meth != nullptr ? env->FromReflectedMethod(meth) : nullptr),
65 target_klass(reinterpret_cast<jclass>(env->NewGlobalRef(klass))),
66 target_field(field != nullptr ? env->FromReflectedField(field) : nullptr),
67 frame_pop_offset(pop_offset),
68 frame_pop_setup_method(setup_meth != nullptr ? env->FromReflectedMethod(setup_meth)
69 : nullptr),
70 interesting_classes(interesting), hit_location(false) {
71 JvmtiErrorToException(
72 env, jvmti, jvmti->CreateRawMonitor("SuspendStopMonitor", ¬ify_monitor));
73 }
74
PerformSuspendart::common_suspend_event::TestData75 void PerformSuspend(jvmtiEnv* jvmti, JNIEnv* env) {
76 // Wake up the waiting thread.
77 JvmtiErrorToException(env, jvmti, jvmti->RawMonitorEnter(notify_monitor));
78 hit_location = true;
79 JvmtiErrorToException(env, jvmti, jvmti->RawMonitorNotifyAll(notify_monitor));
80 JvmtiErrorToException(env, jvmti, jvmti->RawMonitorExit(notify_monitor));
81 // Suspend ourself
82 jvmti->SuspendThread(nullptr);
83 }
84 };
85
PerformSuspension(jvmtiEnv * jvmti,JNIEnv * env)86 void PerformSuspension(jvmtiEnv* jvmti, JNIEnv* env) {
87 TestData* data;
88 if (JvmtiErrorToException(
89 env,
90 jvmti_env,
91 jvmti->GetThreadLocalStorage(/* thread */ nullptr, reinterpret_cast<void**>(&data)))) {
92 return;
93 }
94 CHECK(data != nullptr);
95 data->PerformSuspend(jvmti, env);
96 }
97
98 void JNICALL
cbSingleStep(jvmtiEnv * jvmti,JNIEnv * env,jthread thr,jmethodID meth,jlocation loc)99 cbSingleStep(jvmtiEnv* jvmti, JNIEnv* env, jthread thr, jmethodID meth, jlocation loc) {
100 TestData* data;
101 if (JvmtiErrorToException(
102 env, jvmti, jvmti->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
103 return;
104 }
105 CHECK(data != nullptr);
106 if (meth != data->target_method || loc != data->target_loc) {
107 return;
108 }
109 data->PerformSuspend(jvmti, env);
110 }
111
cbExceptionCatch(jvmtiEnv * jvmti,JNIEnv * env,jthread thr,jmethodID method,jlocation location ATTRIBUTE_UNUSED,jobject exception ATTRIBUTE_UNUSED)112 void JNICALL cbExceptionCatch(jvmtiEnv* jvmti,
113 JNIEnv* env,
114 jthread thr,
115 jmethodID method,
116 jlocation location ATTRIBUTE_UNUSED,
117 jobject exception ATTRIBUTE_UNUSED) {
118 TestData* data;
119 if (JvmtiErrorToException(
120 env, jvmti, jvmti->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
121 return;
122 }
123 CHECK(data != nullptr);
124 if (method != data->target_method) {
125 return;
126 }
127 data->PerformSuspend(jvmti, env);
128 }
129
cbException(jvmtiEnv * jvmti,JNIEnv * env,jthread thr,jmethodID method,jlocation location ATTRIBUTE_UNUSED,jobject exception ATTRIBUTE_UNUSED,jmethodID catch_method ATTRIBUTE_UNUSED,jlocation catch_location ATTRIBUTE_UNUSED)130 void JNICALL cbException(jvmtiEnv* jvmti,
131 JNIEnv* env,
132 jthread thr,
133 jmethodID method,
134 jlocation location ATTRIBUTE_UNUSED,
135 jobject exception ATTRIBUTE_UNUSED,
136 jmethodID catch_method ATTRIBUTE_UNUSED,
137 jlocation catch_location ATTRIBUTE_UNUSED) {
138 TestData* data;
139 if (JvmtiErrorToException(
140 env, jvmti, jvmti->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
141 return;
142 }
143 CHECK(data != nullptr);
144 if (method != data->target_method) {
145 return;
146 }
147 data->PerformSuspend(jvmti, env);
148 }
149
cbMethodEntry(jvmtiEnv * jvmti,JNIEnv * env,jthread thr,jmethodID method)150 void JNICALL cbMethodEntry(jvmtiEnv* jvmti, JNIEnv* env, jthread thr, jmethodID method) {
151 TestData* data;
152 if (JvmtiErrorToException(
153 env, jvmti, jvmti->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
154 return;
155 }
156 CHECK(data != nullptr);
157 if (method != data->target_method) {
158 return;
159 }
160 data->PerformSuspend(jvmti, env);
161 }
162
cbMethodExit(jvmtiEnv * jvmti,JNIEnv * env,jthread thr,jmethodID method,jboolean was_popped_by_exception ATTRIBUTE_UNUSED,jvalue return_value ATTRIBUTE_UNUSED)163 void JNICALL cbMethodExit(jvmtiEnv* jvmti,
164 JNIEnv* env,
165 jthread thr,
166 jmethodID method,
167 jboolean was_popped_by_exception ATTRIBUTE_UNUSED,
168 jvalue return_value ATTRIBUTE_UNUSED) {
169 TestData* data;
170 if (JvmtiErrorToException(
171 env, jvmti, jvmti->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
172 return;
173 }
174 CHECK(data != nullptr);
175 if (method != data->target_method) {
176 return;
177 }
178 data->PerformSuspend(jvmti, env);
179 }
180
cbFieldModification(jvmtiEnv * jvmti,JNIEnv * env,jthread thr,jmethodID method ATTRIBUTE_UNUSED,jlocation location ATTRIBUTE_UNUSED,jclass field_klass ATTRIBUTE_UNUSED,jobject object ATTRIBUTE_UNUSED,jfieldID field,char signature_type ATTRIBUTE_UNUSED,jvalue new_value ATTRIBUTE_UNUSED)181 void JNICALL cbFieldModification(jvmtiEnv* jvmti,
182 JNIEnv* env,
183 jthread thr,
184 jmethodID method ATTRIBUTE_UNUSED,
185 jlocation location ATTRIBUTE_UNUSED,
186 jclass field_klass ATTRIBUTE_UNUSED,
187 jobject object ATTRIBUTE_UNUSED,
188 jfieldID field,
189 char signature_type ATTRIBUTE_UNUSED,
190 jvalue new_value ATTRIBUTE_UNUSED) {
191 TestData* data;
192 if (JvmtiErrorToException(
193 env, jvmti, jvmti->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
194 return;
195 }
196 CHECK(data != nullptr);
197 if (field != data->target_field) {
198 // TODO What to do here.
199 LOG(FATAL) << "Strange, shouldn't get here!";
200 }
201 data->PerformSuspend(jvmti, env);
202 }
203
cbFieldAccess(jvmtiEnv * jvmti,JNIEnv * env,jthread thr,jmethodID method ATTRIBUTE_UNUSED,jlocation location ATTRIBUTE_UNUSED,jclass field_klass,jobject object ATTRIBUTE_UNUSED,jfieldID field)204 void JNICALL cbFieldAccess(jvmtiEnv* jvmti,
205 JNIEnv* env,
206 jthread thr,
207 jmethodID method ATTRIBUTE_UNUSED,
208 jlocation location ATTRIBUTE_UNUSED,
209 jclass field_klass,
210 jobject object ATTRIBUTE_UNUSED,
211 jfieldID field) {
212 TestData* data;
213 if (JvmtiErrorToException(
214 env, jvmti, jvmti->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
215 return;
216 }
217 CHECK(data != nullptr);
218 if (field != data->target_field || !env->IsSameObject(field_klass, data->target_klass)) {
219 // TODO What to do here.
220 LOG(FATAL) << "Strange, shouldn't get here!";
221 }
222 data->PerformSuspend(jvmti, env);
223 }
224
225 void JNICALL
cbBreakpointHit(jvmtiEnv * jvmti,JNIEnv * env,jthread thr,jmethodID method,jlocation loc)226 cbBreakpointHit(jvmtiEnv* jvmti, JNIEnv* env, jthread thr, jmethodID method, jlocation loc) {
227 TestData* data;
228 if (JvmtiErrorToException(
229 env, jvmti, jvmti->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
230 return;
231 }
232 CHECK(data != nullptr);
233 if (data->frame_pop_setup_method == method) {
234 CHECK(loc == 0) << "We should have stopped at location 0";
235 if (JvmtiErrorToException(env, jvmti, jvmti->NotifyFramePop(thr, data->frame_pop_offset))) {
236 return;
237 }
238 return;
239 }
240 if (method != data->target_method || loc != data->target_loc) {
241 // TODO What to do here.
242 LOG(FATAL) << "Strange, shouldn't get here!";
243 }
244 data->PerformSuspend(jvmti, env);
245 }
246
cbFramePop(jvmtiEnv * jvmti,JNIEnv * env,jthread thr,jmethodID method ATTRIBUTE_UNUSED,jboolean was_popped_by_exception ATTRIBUTE_UNUSED)247 void JNICALL cbFramePop(jvmtiEnv* jvmti,
248 JNIEnv* env,
249 jthread thr,
250 jmethodID method ATTRIBUTE_UNUSED,
251 jboolean was_popped_by_exception ATTRIBUTE_UNUSED) {
252 TestData* data;
253 if (JvmtiErrorToException(
254 env, jvmti, jvmti->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
255 return;
256 }
257 CHECK(data != nullptr);
258 data->PerformSuspend(jvmti, env);
259 }
260
cbClassLoadOrPrepare(jvmtiEnv * jvmti,JNIEnv * env,jthread thr,jclass klass)261 void JNICALL cbClassLoadOrPrepare(jvmtiEnv* jvmti, JNIEnv* env, jthread thr, jclass klass) {
262 TestData* data;
263 if (JvmtiErrorToException(
264 env, jvmti, jvmti->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
265 return;
266 }
267 CHECK(data != nullptr);
268 char* name;
269 if (JvmtiErrorToException(env, jvmti, jvmti->GetClassSignature(klass, &name, nullptr))) {
270 return;
271 }
272 std::string name_str(name);
273 if (JvmtiErrorToException(
274 env, jvmti, jvmti->Deallocate(reinterpret_cast<unsigned char*>(name)))) {
275 return;
276 }
277 if (std::find(data->interesting_classes.cbegin(), data->interesting_classes.cend(), name_str) !=
278 data->interesting_classes.cend()) {
279 data->PerformSuspend(jvmti, env);
280 }
281 }
282
Java_art_SuspendEvents_setupTest(JNIEnv * env,jclass klass ATTRIBUTE_UNUSED)283 extern "C" JNIEXPORT void JNICALL Java_art_SuspendEvents_setupTest(JNIEnv* env,
284 jclass klass ATTRIBUTE_UNUSED) {
285 jvmtiCapabilities caps;
286 memset(&caps, 0, sizeof(caps));
287 // Most of these will already be there but might as well be complete.
288 caps.can_pop_frame = 1;
289 caps.can_force_early_return = 1;
290 caps.can_generate_single_step_events = 1;
291 caps.can_generate_breakpoint_events = 1;
292 caps.can_suspend = 1;
293 caps.can_generate_method_entry_events = 1;
294 caps.can_generate_method_exit_events = 1;
295 caps.can_generate_monitor_events = 1;
296 caps.can_generate_exception_events = 1;
297 caps.can_generate_frame_pop_events = 1;
298 caps.can_generate_field_access_events = 1;
299 caps.can_generate_field_modification_events = 1;
300 caps.can_redefine_classes = 1;
301 if (JvmtiErrorToException(env, jvmti_env, jvmti_env->AddCapabilities(&caps))) {
302 return;
303 }
304 jvmtiEventCallbacks cb;
305 memset(&cb, 0, sizeof(cb));
306 // TODO Add the rest of these.
307 cb.Breakpoint = cbBreakpointHit;
308 cb.SingleStep = cbSingleStep;
309 cb.FieldAccess = cbFieldAccess;
310 cb.FieldModification = cbFieldModification;
311 cb.MethodEntry = cbMethodEntry;
312 cb.MethodExit = cbMethodExit;
313 cb.Exception = cbException;
314 cb.ExceptionCatch = cbExceptionCatch;
315 cb.FramePop = cbFramePop;
316 cb.ClassLoad = cbClassLoadOrPrepare;
317 cb.ClassPrepare = cbClassLoadOrPrepare;
318 JvmtiErrorToException(env, jvmti_env, jvmti_env->SetEventCallbacks(&cb, sizeof(cb)));
319 }
320
DeleteTestData(JNIEnv * env,jthread thr,TestData * data)321 static bool DeleteTestData(JNIEnv* env, jthread thr, TestData* data) {
322 env->DeleteGlobalRef(data->target_klass);
323 if (JvmtiErrorToException(env, jvmti_env, jvmti_env->SetThreadLocalStorage(thr, nullptr))) {
324 return false;
325 }
326 return JvmtiErrorToException(
327 env, jvmti_env, jvmti_env->Deallocate(reinterpret_cast<uint8_t*>(data)));
328 }
329
SetupTestData(JNIEnv * env,jobject meth,jlocation loc,jclass target_klass,jobject field,jobject setup_meth,jint pop_offset,const std::vector<std::string> && interesting_names)330 static TestData* SetupTestData(JNIEnv* env,
331 jobject meth,
332 jlocation loc,
333 jclass target_klass,
334 jobject field,
335 jobject setup_meth,
336 jint pop_offset,
337 const std::vector<std::string>&& interesting_names) {
338 void* data_ptr;
339 TestData* data;
340 if (JvmtiErrorToException(
341 env,
342 jvmti_env,
343 jvmti_env->Allocate(sizeof(TestData), reinterpret_cast<uint8_t**>(&data_ptr)))) {
344 return nullptr;
345 }
346 data = new (data_ptr) TestData(jvmti_env,
347 env,
348 loc,
349 meth,
350 target_klass,
351 field,
352 setup_meth,
353 pop_offset,
354 std::move(interesting_names));
355 if (env->ExceptionCheck()) {
356 env->DeleteGlobalRef(data->target_klass);
357 jvmti_env->Deallocate(reinterpret_cast<uint8_t*>(data));
358 return nullptr;
359 }
360 return data;
361 }
362
SetupTestData(JNIEnv * env,jobject meth,jlocation loc,jclass target_klass,jobject field,jobject setup_meth,jint pop_offset)363 static TestData* SetupTestData(JNIEnv* env,
364 jobject meth,
365 jlocation loc,
366 jclass target_klass,
367 jobject field,
368 jobject setup_meth,
369 jint pop_offset) {
370 std::vector<std::string> empty;
371 return SetupTestData(
372 env, meth, loc, target_klass, field, setup_meth, pop_offset, std::move(empty));
373 }
374
375 extern "C" JNIEXPORT void JNICALL
Java_art_SuspendEvents_setupSuspendClassEvent(JNIEnv * env,jclass klass ATTRIBUTE_UNUSED,jint event_num,jobjectArray interesting_names,jthread thr)376 Java_art_SuspendEvents_setupSuspendClassEvent(JNIEnv* env,
377 jclass klass ATTRIBUTE_UNUSED,
378 jint event_num,
379 jobjectArray interesting_names,
380 jthread thr) {
381 CHECK(event_num == JVMTI_EVENT_CLASS_LOAD || event_num == JVMTI_EVENT_CLASS_PREPARE);
382 std::vector<std::string> names;
383 jint cnt = env->GetArrayLength(interesting_names);
384 for (jint i = 0; i < cnt; i++) {
385 env->PushLocalFrame(1);
386 jstring name_obj = reinterpret_cast<jstring>(env->GetObjectArrayElement(interesting_names, i));
387 const char* name_chr = env->GetStringUTFChars(name_obj, nullptr);
388 names.push_back(std::string(name_chr));
389 env->ReleaseStringUTFChars(name_obj, name_chr);
390 env->PopLocalFrame(nullptr);
391 }
392 TestData* data;
393 if (JvmtiErrorToException(
394 env, jvmti_env, jvmti_env->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
395 return;
396 }
397 CHECK(data == nullptr) << "Data was not cleared!";
398 data = SetupTestData(env, nullptr, 0, nullptr, nullptr, nullptr, 0, std::move(names));
399 if (data == nullptr) {
400 return;
401 }
402 if (JvmtiErrorToException(env, jvmti_env, jvmti_env->SetThreadLocalStorage(thr, data))) {
403 return;
404 }
405 JvmtiErrorToException(
406 env,
407 jvmti_env,
408 jvmti_env->SetEventNotificationMode(JVMTI_ENABLE, static_cast<jvmtiEvent>(event_num), thr));
409 }
410
Java_art_SuspendEvents_clearSuspendClassEvent(JNIEnv * env,jclass klass ATTRIBUTE_UNUSED,jthread thr)411 extern "C" JNIEXPORT void JNICALL Java_art_SuspendEvents_clearSuspendClassEvent(
412 JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jthread thr) {
413 TestData* data;
414 if (JvmtiErrorToException(
415 env, jvmti_env, jvmti_env->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
416 return;
417 }
418 CHECK(data != nullptr);
419 if (JvmtiErrorToException(
420 env,
421 jvmti_env,
422 jvmti_env->SetEventNotificationMode(JVMTI_DISABLE, JVMTI_EVENT_CLASS_LOAD, thr))) {
423 return;
424 }
425 if (JvmtiErrorToException(
426 env,
427 jvmti_env,
428 jvmti_env->SetEventNotificationMode(JVMTI_DISABLE, JVMTI_EVENT_CLASS_PREPARE, thr))) {
429 return;
430 }
431 DeleteTestData(env, thr, data);
432 }
433
Java_art_SuspendEvents_setupSuspendSingleStepAt(JNIEnv * env,jclass klass ATTRIBUTE_UNUSED,jobject meth,jlocation loc,jthread thr)434 extern "C" JNIEXPORT void JNICALL Java_art_SuspendEvents_setupSuspendSingleStepAt(
435 JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jobject meth, jlocation loc, jthread thr) {
436 TestData* data;
437 if (JvmtiErrorToException(
438 env, jvmti_env, jvmti_env->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
439 return;
440 }
441 CHECK(data == nullptr) << "Data was not cleared!";
442 data = SetupTestData(env, meth, loc, nullptr, nullptr, nullptr, 0);
443 if (data == nullptr) {
444 return;
445 }
446 if (JvmtiErrorToException(env, jvmti_env, jvmti_env->SetThreadLocalStorage(thr, data))) {
447 return;
448 }
449 JvmtiErrorToException(
450 env,
451 jvmti_env,
452 jvmti_env->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_SINGLE_STEP, thr));
453 }
454
Java_art_SuspendEvents_clearSuspendSingleStepFor(JNIEnv * env,jclass klass ATTRIBUTE_UNUSED,jthread thr)455 extern "C" JNIEXPORT void JNICALL Java_art_SuspendEvents_clearSuspendSingleStepFor(
456 JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jthread thr) {
457 TestData* data;
458 if (JvmtiErrorToException(
459 env, jvmti_env, jvmti_env->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
460 return;
461 }
462 CHECK(data != nullptr);
463 if (JvmtiErrorToException(
464 env,
465 jvmti_env,
466 jvmti_env->SetEventNotificationMode(JVMTI_DISABLE, JVMTI_EVENT_SINGLE_STEP, thr))) {
467 return;
468 }
469 DeleteTestData(env, thr, data);
470 }
471
Java_art_SuspendEvents_setupSuspendPopFrameEvent(JNIEnv * env,jclass klass ATTRIBUTE_UNUSED,jint offset,jobject breakpoint_func,jthread thr)472 extern "C" JNIEXPORT void JNICALL Java_art_SuspendEvents_setupSuspendPopFrameEvent(
473 JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jint offset, jobject breakpoint_func, jthread thr) {
474 TestData* data;
475 if (JvmtiErrorToException(
476 env, jvmti_env, jvmti_env->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
477 return;
478 }
479 CHECK(data == nullptr) << "Data was not cleared!";
480 data = SetupTestData(env, nullptr, 0, nullptr, nullptr, breakpoint_func, offset);
481 CHECK(data != nullptr);
482 if (JvmtiErrorToException(env, jvmti_env, jvmti_env->SetThreadLocalStorage(thr, data))) {
483 return;
484 }
485 if (JvmtiErrorToException(
486 env,
487 jvmti_env,
488 jvmti_env->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_FRAME_POP, thr))) {
489 return;
490 }
491 if (JvmtiErrorToException(
492 env,
493 jvmti_env,
494 jvmti_env->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_BREAKPOINT, thr))) {
495 return;
496 }
497 if (JvmtiErrorToException(
498 env, jvmti_env, jvmti_env->SetBreakpoint(data->frame_pop_setup_method, 0))) {
499 return;
500 }
501 }
502
Java_art_SuspendEvents_clearSuspendPopFrameEvent(JNIEnv * env,jclass klass ATTRIBUTE_UNUSED,jthread thr)503 extern "C" JNIEXPORT void JNICALL Java_art_SuspendEvents_clearSuspendPopFrameEvent(
504 JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jthread thr) {
505 TestData* data;
506 if (JvmtiErrorToException(
507 env, jvmti_env, jvmti_env->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
508 return;
509 }
510 CHECK(data != nullptr);
511 if (JvmtiErrorToException(
512 env,
513 jvmti_env,
514 jvmti_env->SetEventNotificationMode(JVMTI_DISABLE, JVMTI_EVENT_FRAME_POP, thr))) {
515 return;
516 }
517 if (JvmtiErrorToException(
518 env,
519 jvmti_env,
520 jvmti_env->SetEventNotificationMode(JVMTI_DISABLE, JVMTI_EVENT_BREAKPOINT, thr))) {
521 return;
522 }
523 if (JvmtiErrorToException(
524 env, jvmti_env, jvmti_env->ClearBreakpoint(data->frame_pop_setup_method, 0))) {
525 return;
526 }
527 DeleteTestData(env, thr, data);
528 }
529
Java_art_SuspendEvents_setupSuspendBreakpointFor(JNIEnv * env,jclass klass ATTRIBUTE_UNUSED,jobject meth,jlocation loc,jthread thr)530 extern "C" JNIEXPORT void JNICALL Java_art_SuspendEvents_setupSuspendBreakpointFor(
531 JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jobject meth, jlocation loc, jthread thr) {
532 TestData* data;
533 if (JvmtiErrorToException(
534 env, jvmti_env, jvmti_env->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
535 return;
536 }
537 CHECK(data == nullptr) << "Data was not cleared!";
538 data = SetupTestData(env, meth, loc, nullptr, nullptr, nullptr, 0);
539 if (data == nullptr) {
540 return;
541 }
542 if (JvmtiErrorToException(env, jvmti_env, jvmti_env->SetThreadLocalStorage(thr, data))) {
543 return;
544 }
545 if (JvmtiErrorToException(
546 env,
547 jvmti_env,
548 jvmti_env->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_BREAKPOINT, thr))) {
549 return;
550 }
551 JvmtiErrorToException(
552 env, jvmti_env, jvmti_env->SetBreakpoint(data->target_method, data->target_loc));
553 }
554
Java_art_SuspendEvents_clearSuspendBreakpointFor(JNIEnv * env,jclass klass ATTRIBUTE_UNUSED,jthread thr)555 extern "C" JNIEXPORT void JNICALL Java_art_SuspendEvents_clearSuspendBreakpointFor(
556 JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jthread thr) {
557 TestData* data;
558 if (JvmtiErrorToException(
559 env, jvmti_env, jvmti_env->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
560 return;
561 }
562 CHECK(data != nullptr);
563 if (JvmtiErrorToException(
564 env,
565 jvmti_env,
566 jvmti_env->SetEventNotificationMode(JVMTI_DISABLE, JVMTI_EVENT_BREAKPOINT, thr))) {
567 return;
568 }
569 if (JvmtiErrorToException(
570 env, jvmti_env, jvmti_env->ClearBreakpoint(data->target_method, data->target_loc))) {
571 return;
572 }
573 if (JvmtiErrorToException(env, jvmti_env, jvmti_env->SetThreadLocalStorage(thr, nullptr))) {
574 return;
575 }
576 DeleteTestData(env, thr, data);
577 }
578
Java_art_SuspendEvents_setupSuspendExceptionEvent(JNIEnv * env,jclass klass ATTRIBUTE_UNUSED,jobject method,jboolean is_catch,jthread thr)579 extern "C" JNIEXPORT void JNICALL Java_art_SuspendEvents_setupSuspendExceptionEvent(
580 JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jobject method, jboolean is_catch, jthread thr) {
581 TestData* data;
582 if (JvmtiErrorToException(
583 env, jvmti_env, jvmti_env->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
584 return;
585 }
586 CHECK(data == nullptr) << "Data was not cleared!";
587 data = SetupTestData(env, method, 0, nullptr, nullptr, nullptr, 0);
588 if (data == nullptr) {
589 return;
590 }
591 if (JvmtiErrorToException(env, jvmti_env, jvmti_env->SetThreadLocalStorage(thr, data))) {
592 return;
593 }
594 JvmtiErrorToException(
595 env,
596 jvmti_env,
597 jvmti_env->SetEventNotificationMode(
598 JVMTI_ENABLE, is_catch ? JVMTI_EVENT_EXCEPTION_CATCH : JVMTI_EVENT_EXCEPTION, thr));
599 }
600
Java_art_SuspendEvents_clearSuspendExceptionEvent(JNIEnv * env,jclass klass ATTRIBUTE_UNUSED,jthread thr)601 extern "C" JNIEXPORT void JNICALL Java_art_SuspendEvents_clearSuspendExceptionEvent(
602 JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jthread thr) {
603 TestData* data;
604 if (JvmtiErrorToException(
605 env, jvmti_env, jvmti_env->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
606 return;
607 }
608 CHECK(data != nullptr);
609 if (JvmtiErrorToException(
610 env,
611 jvmti_env,
612 jvmti_env->SetEventNotificationMode(JVMTI_DISABLE, JVMTI_EVENT_EXCEPTION_CATCH, thr))) {
613 return;
614 }
615 if (JvmtiErrorToException(
616 env,
617 jvmti_env,
618 jvmti_env->SetEventNotificationMode(JVMTI_DISABLE, JVMTI_EVENT_EXCEPTION, thr))) {
619 return;
620 }
621 DeleteTestData(env, thr, data);
622 }
623
Java_art_SuspendEvents_setupSuspendMethodEvent(JNIEnv * env,jclass klass ATTRIBUTE_UNUSED,jobject method,jboolean enter,jthread thr)624 extern "C" JNIEXPORT void JNICALL Java_art_SuspendEvents_setupSuspendMethodEvent(
625 JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jobject method, jboolean enter, jthread thr) {
626 TestData* data;
627 if (JvmtiErrorToException(
628 env, jvmti_env, jvmti_env->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
629 return;
630 }
631 CHECK(data == nullptr) << "Data was not cleared!";
632 data = SetupTestData(env, method, 0, nullptr, nullptr, nullptr, 0);
633 if (data == nullptr) {
634 return;
635 }
636 if (JvmtiErrorToException(env, jvmti_env, jvmti_env->SetThreadLocalStorage(thr, data))) {
637 return;
638 }
639 JvmtiErrorToException(
640 env,
641 jvmti_env,
642 jvmti_env->SetEventNotificationMode(
643 JVMTI_ENABLE, enter ? JVMTI_EVENT_METHOD_ENTRY : JVMTI_EVENT_METHOD_EXIT, thr));
644 }
645
Java_art_SuspendEvents_clearSuspendMethodEvent(JNIEnv * env,jclass klass ATTRIBUTE_UNUSED,jthread thr)646 extern "C" JNIEXPORT void JNICALL Java_art_SuspendEvents_clearSuspendMethodEvent(
647 JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jthread thr) {
648 TestData* data;
649 if (JvmtiErrorToException(
650 env, jvmti_env, jvmti_env->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
651 return;
652 }
653 CHECK(data != nullptr);
654 if (JvmtiErrorToException(
655 env,
656 jvmti_env,
657 jvmti_env->SetEventNotificationMode(JVMTI_DISABLE, JVMTI_EVENT_METHOD_EXIT, thr))) {
658 return;
659 }
660 if (JvmtiErrorToException(
661 env,
662 jvmti_env,
663 jvmti_env->SetEventNotificationMode(JVMTI_DISABLE, JVMTI_EVENT_METHOD_ENTRY, thr))) {
664 return;
665 }
666 DeleteTestData(env, thr, data);
667 }
668
669 extern "C" JNIEXPORT void JNICALL
Java_art_SuspendEvents_setupFieldSuspendFor(JNIEnv * env,jclass klass ATTRIBUTE_UNUSED,jclass target_klass,jobject field,jboolean access,jthread thr)670 Java_art_SuspendEvents_setupFieldSuspendFor(JNIEnv* env,
671 jclass klass ATTRIBUTE_UNUSED,
672 jclass target_klass,
673 jobject field,
674 jboolean access,
675 jthread thr) {
676 TestData* data;
677 if (JvmtiErrorToException(
678 env, jvmti_env, jvmti_env->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
679 return;
680 }
681 CHECK(data == nullptr) << "Data was not cleared!";
682 data = SetupTestData(env, nullptr, 0, target_klass, field, nullptr, 0);
683 if (data == nullptr) {
684 return;
685 }
686 if (JvmtiErrorToException(env, jvmti_env, jvmti_env->SetThreadLocalStorage(thr, data))) {
687 return;
688 }
689 if (JvmtiErrorToException(env,
690 jvmti_env,
691 jvmti_env->SetEventNotificationMode(
692 JVMTI_ENABLE,
693 access ? JVMTI_EVENT_FIELD_ACCESS : JVMTI_EVENT_FIELD_MODIFICATION,
694 thr))) {
695 return;
696 }
697 if (access) {
698 JvmtiErrorToException(
699 env, jvmti_env, jvmti_env->SetFieldAccessWatch(data->target_klass, data->target_field));
700 } else {
701 JvmtiErrorToException(
702 env,
703 jvmti_env,
704 jvmti_env->SetFieldModificationWatch(data->target_klass, data->target_field));
705 }
706 }
707
Java_art_SuspendEvents_clearFieldSuspendFor(JNIEnv * env,jclass klass ATTRIBUTE_UNUSED,jthread thr)708 extern "C" JNIEXPORT void JNICALL Java_art_SuspendEvents_clearFieldSuspendFor(
709 JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jthread thr) {
710 TestData* data;
711 if (JvmtiErrorToException(
712 env, jvmti_env, jvmti_env->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
713 return;
714 }
715 CHECK(data != nullptr);
716 if (JvmtiErrorToException(
717 env,
718 jvmti_env,
719 jvmti_env->SetEventNotificationMode(JVMTI_DISABLE, JVMTI_EVENT_FIELD_ACCESS, thr))) {
720 return;
721 }
722 if (JvmtiErrorToException(env,
723 jvmti_env,
724 jvmti_env->SetEventNotificationMode(
725 JVMTI_DISABLE, JVMTI_EVENT_FIELD_MODIFICATION, thr))) {
726 return;
727 }
728 if (JvmtiErrorToException(
729 env,
730 jvmti_env,
731 jvmti_env->ClearFieldModificationWatch(data->target_klass, data->target_field)) &&
732 JvmtiErrorToException(
733 env,
734 jvmti_env,
735 jvmti_env->ClearFieldAccessWatch(data->target_klass, data->target_field))) {
736 return;
737 } else {
738 env->ExceptionClear();
739 }
740 if (JvmtiErrorToException(env, jvmti_env, jvmti_env->SetThreadLocalStorage(thr, nullptr))) {
741 return;
742 }
743 DeleteTestData(env, thr, data);
744 }
745
Java_art_SuspendEvents_setupWaitForNativeCall(JNIEnv * env,jclass klass ATTRIBUTE_UNUSED,jthread thr)746 extern "C" JNIEXPORT void JNICALL Java_art_SuspendEvents_setupWaitForNativeCall(
747 JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jthread thr) {
748 TestData* data;
749 if (JvmtiErrorToException(
750 env, jvmti_env, jvmti_env->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
751 return;
752 }
753 CHECK(data == nullptr) << "Data was not cleared!";
754 data = SetupTestData(env, nullptr, 0, nullptr, nullptr, nullptr, 0);
755 if (data == nullptr) {
756 return;
757 }
758 if (JvmtiErrorToException(env, jvmti_env, jvmti_env->SetThreadLocalStorage(thr, data))) {
759 return;
760 }
761 }
762
Java_art_SuspendEvents_clearWaitForNativeCall(JNIEnv * env,jclass klass ATTRIBUTE_UNUSED,jthread thr)763 extern "C" JNIEXPORT void JNICALL Java_art_SuspendEvents_clearWaitForNativeCall(
764 JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jthread thr) {
765 TestData* data;
766 if (JvmtiErrorToException(
767 env, jvmti_env, jvmti_env->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
768 return;
769 }
770 CHECK(data != nullptr);
771 if (JvmtiErrorToException(env, jvmti_env, jvmti_env->SetThreadLocalStorage(thr, nullptr))) {
772 return;
773 }
774 DeleteTestData(env, thr, data);
775 }
776
777 extern "C" JNIEXPORT void JNICALL
Java_art_SuspendEvents_waitForSuspendHit(JNIEnv * env,jclass klass ATTRIBUTE_UNUSED,jthread thr)778 Java_art_SuspendEvents_waitForSuspendHit(JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jthread thr) {
779 TestData* data;
780 if (JvmtiErrorToException(
781 env, jvmti_env, jvmti_env->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
782 return;
783 }
784 CHECK(data != nullptr);
785 if (JvmtiErrorToException(env, jvmti_env, jvmti_env->RawMonitorEnter(data->notify_monitor))) {
786 return;
787 }
788 while (!data->hit_location) {
789 if (JvmtiErrorToException(
790 env, jvmti_env, jvmti_env->RawMonitorWait(data->notify_monitor, -1))) {
791 return;
792 }
793 }
794 if (JvmtiErrorToException(env, jvmti_env, jvmti_env->RawMonitorExit(data->notify_monitor))) {
795 return;
796 }
797 jint state = 0;
798 while (!JvmtiErrorToException(env, jvmti_env, jvmti_env->GetThreadState(thr, &state)) &&
799 (state & JVMTI_THREAD_STATE_SUSPENDED) == 0) {
800 }
801 }
802 } // namespace common_suspend_event
803 } // namespace art
804