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,jobject exception)112 void JNICALL cbExceptionCatch(jvmtiEnv* jvmti, 113 JNIEnv* env, 114 jthread thr, 115 jmethodID method, 116 [[maybe_unused]] jlocation location, 117 [[maybe_unused]] jobject exception) { 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,jobject exception,jmethodID catch_method,jlocation catch_location)130 void JNICALL cbException(jvmtiEnv* jvmti, 131 JNIEnv* env, 132 jthread thr, 133 jmethodID method, 134 [[maybe_unused]] jlocation location, 135 [[maybe_unused]] jobject exception, 136 [[maybe_unused]] jmethodID catch_method, 137 [[maybe_unused]] jlocation catch_location) { 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,jvalue return_value)163 void JNICALL cbMethodExit(jvmtiEnv* jvmti, 164 JNIEnv* env, 165 jthread thr, 166 jmethodID method, 167 [[maybe_unused]] jboolean was_popped_by_exception, 168 [[maybe_unused]] jvalue return_value) { 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,jlocation location,jclass field_klass,jobject object,jfieldID field,char signature_type,jvalue new_value)181 void JNICALL cbFieldModification(jvmtiEnv* jvmti, 182 JNIEnv* env, 183 jthread thr, 184 [[maybe_unused]] jmethodID method, 185 [[maybe_unused]] jlocation location, 186 [[maybe_unused]] jclass field_klass, 187 [[maybe_unused]] jobject object, 188 jfieldID field, 189 [[maybe_unused]] char signature_type, 190 [[maybe_unused]] jvalue new_value) { 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,jlocation location,jclass field_klass,jobject object,jfieldID field)204 void JNICALL cbFieldAccess(jvmtiEnv* jvmti, 205 JNIEnv* env, 206 jthread thr, 207 [[maybe_unused]] jmethodID method, 208 [[maybe_unused]] jlocation location, 209 jclass field_klass, 210 [[maybe_unused]] jobject object, 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,jboolean was_popped_by_exception)247 void JNICALL cbFramePop(jvmtiEnv* jvmti, 248 JNIEnv* env, 249 jthread thr, 250 [[maybe_unused]] jmethodID method, 251 [[maybe_unused]] jboolean was_popped_by_exception) { 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)283 extern "C" JNIEXPORT void JNICALL Java_art_SuspendEvents_setupTest(JNIEnv* env, 284 [[maybe_unused]] jclass klass) { 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,jint event_num,jobjectArray interesting_names,jthread thr)376 Java_art_SuspendEvents_setupSuspendClassEvent(JNIEnv* env, 377 [[maybe_unused]] jclass klass, 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,jthread thr)411 extern "C" JNIEXPORT void JNICALL Java_art_SuspendEvents_clearSuspendClassEvent( 412 JNIEnv* env, [[maybe_unused]] jclass klass, 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,jobject meth,jlocation loc,jthread thr)434 extern "C" JNIEXPORT void JNICALL Java_art_SuspendEvents_setupSuspendSingleStepAt( 435 JNIEnv* env, [[maybe_unused]] jclass klass, 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,jthread thr)455 extern "C" JNIEXPORT void JNICALL Java_art_SuspendEvents_clearSuspendSingleStepFor( 456 JNIEnv* env, [[maybe_unused]] jclass klass, 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,jint offset,jobject breakpoint_func,jthread thr)472 extern "C" JNIEXPORT void JNICALL Java_art_SuspendEvents_setupSuspendPopFrameEvent( 473 JNIEnv* env, [[maybe_unused]] jclass klass, 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,jthread thr)503 extern "C" JNIEXPORT void JNICALL Java_art_SuspendEvents_clearSuspendPopFrameEvent( 504 JNIEnv* env, [[maybe_unused]] jclass klass , 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,jobject meth,jlocation loc,jthread thr)530 extern "C" JNIEXPORT void JNICALL Java_art_SuspendEvents_setupSuspendBreakpointFor( 531 JNIEnv* env, [[maybe_unused]] jclass klass , 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,jthread thr)555 extern "C" JNIEXPORT void JNICALL Java_art_SuspendEvents_clearSuspendBreakpointFor( 556 JNIEnv* env, [[maybe_unused]] jclass klass , 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,jobject method,jboolean is_catch,jthread thr)579 extern "C" JNIEXPORT void JNICALL Java_art_SuspendEvents_setupSuspendExceptionEvent( 580 JNIEnv* env, [[maybe_unused]] jclass klass , 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,jthread thr)601 extern "C" JNIEXPORT void JNICALL Java_art_SuspendEvents_clearSuspendExceptionEvent( 602 JNIEnv* env, [[maybe_unused]] jclass klass , 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,jobject method,jboolean enter,jthread thr)624 extern "C" JNIEXPORT void JNICALL Java_art_SuspendEvents_setupSuspendMethodEvent( 625 JNIEnv* env, [[maybe_unused]] jclass klass , 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,jthread thr)646 extern "C" JNIEXPORT void JNICALL Java_art_SuspendEvents_clearSuspendMethodEvent( 647 JNIEnv* env, [[maybe_unused]] jclass klass , 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,jclass target_klass,jobject field,jboolean access,jthread thr)670 Java_art_SuspendEvents_setupFieldSuspendFor(JNIEnv* env, 671 [[maybe_unused]] jclass klass, 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,jthread thr)708 extern "C" JNIEXPORT void JNICALL Java_art_SuspendEvents_clearFieldSuspendFor( 709 JNIEnv* env, [[maybe_unused]] jclass klass , 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,jthread thr)746 extern "C" JNIEXPORT void JNICALL Java_art_SuspendEvents_setupWaitForNativeCall( 747 JNIEnv* env, [[maybe_unused]] jclass klass , 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,jthread thr)763 extern "C" JNIEXPORT void JNICALL Java_art_SuspendEvents_clearWaitForNativeCall( 764 JNIEnv* env, [[maybe_unused]] jclass klass , 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,jthread thr)778 Java_art_SuspendEvents_waitForSuspendHit(JNIEnv* env, [[maybe_unused]] jclass klass, 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