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", &notify_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