1 /* Copyright (C) 2016 The Android Open Source Project 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 3 * 4 * This file implements interfaces from the file jvmti.h. This implementation 5 * is licensed under the same terms as the file jvmti.h. The 6 * copyright and license information for the file jvmti.h follows. 7 * 8 * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. 9 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 10 * 11 * This code is free software; you can redistribute it and/or modify it 12 * under the terms of the GNU General Public License version 2 only, as 13 * published by the Free Software Foundation. Oracle designates this 14 * particular file as subject to the "Classpath" exception as provided 15 * by Oracle in the LICENSE file that accompanied this code. 16 * 17 * This code is distributed in the hope that it will be useful, but WITHOUT 18 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 19 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 20 * version 2 for more details (a copy is included in the LICENSE file that 21 * accompanied this code). 22 * 23 * You should have received a copy of the GNU General Public License version 24 * 2 along with this work; if not, write to the Free Software Foundation, 25 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 26 * 27 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 28 * or visit www.oracle.com if you need additional information or have any 29 * questions. 30 */ 31 32 #include "ti_stack.h" 33 34 #include <algorithm> 35 #include <list> 36 #include <unordered_map> 37 #include <vector> 38 39 #include "art_field-inl.h" 40 #include "art_method-inl.h" 41 #include "art_jvmti.h" 42 #include "base/bit_utils.h" 43 #include "base/enums.h" 44 #include "base/mutex.h" 45 #include "dex_file.h" 46 #include "dex_file_annotations.h" 47 #include "handle_scope-inl.h" 48 #include "jni_env_ext.h" 49 #include "jni_internal.h" 50 #include "mirror/class.h" 51 #include "mirror/dex_cache.h" 52 #include "scoped_thread_state_change-inl.h" 53 #include "ScopedLocalRef.h" 54 #include "stack.h" 55 #include "thread-inl.h" 56 #include "thread_list.h" 57 #include "thread_pool.h" 58 #include "well_known_classes.h" 59 60 namespace openjdkjvmti { 61 62 struct GetStackTraceVisitor : public art::StackVisitor { 63 GetStackTraceVisitor(art::Thread* thread_in, 64 size_t start_, 65 size_t stop_) 66 : StackVisitor(thread_in, nullptr, StackVisitor::StackWalkKind::kIncludeInlinedFrames), 67 start(start_), 68 stop(stop_) {} 69 70 bool VisitFrame() REQUIRES_SHARED(art::Locks::mutator_lock_) { 71 art::ArtMethod* m = GetMethod(); 72 if (m->IsRuntimeMethod()) { 73 return true; 74 } 75 76 if (start == 0) { 77 m = m->GetInterfaceMethodIfProxy(art::kRuntimePointerSize); 78 jmethodID id = art::jni::EncodeArtMethod(m); 79 80 uint32_t dex_pc = GetDexPc(false); 81 jlong dex_location = (dex_pc == art::DexFile::kDexNoIndex) ? -1 : static_cast<jlong>(dex_pc); 82 83 jvmtiFrameInfo info = { id, dex_location }; 84 frames.push_back(info); 85 86 if (stop == 1) { 87 return false; // We're done. 88 } else if (stop > 0) { 89 stop--; 90 } 91 } else { 92 start--; 93 } 94 95 return true; 96 } 97 98 std::vector<jvmtiFrameInfo> frames; 99 size_t start; 100 size_t stop; 101 }; 102 103 struct GetStackTraceClosure : public art::Closure { 104 public: 105 GetStackTraceClosure(size_t start, size_t stop) 106 : start_input(start), 107 stop_input(stop), 108 start_result(0), 109 stop_result(0) {} 110 111 void Run(art::Thread* self) OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) { 112 GetStackTraceVisitor visitor(self, start_input, stop_input); 113 visitor.WalkStack(false); 114 115 frames.swap(visitor.frames); 116 start_result = visitor.start; 117 stop_result = visitor.stop; 118 } 119 120 const size_t start_input; 121 const size_t stop_input; 122 123 std::vector<jvmtiFrameInfo> frames; 124 size_t start_result; 125 size_t stop_result; 126 }; 127 128 static jvmtiError TranslateFrameVector(const std::vector<jvmtiFrameInfo>& frames, 129 jint start_depth, 130 size_t start_result, 131 jint max_frame_count, 132 jvmtiFrameInfo* frame_buffer, 133 jint* count_ptr) { 134 size_t collected_frames = frames.size(); 135 136 // Assume we're here having collected something. 137 DCHECK_GT(max_frame_count, 0); 138 139 // Frames from the top. 140 if (start_depth >= 0) { 141 if (start_result != 0) { 142 // Not enough frames. 143 return ERR(ILLEGAL_ARGUMENT); 144 } 145 DCHECK_LE(collected_frames, static_cast<size_t>(max_frame_count)); 146 if (frames.size() > 0) { 147 memcpy(frame_buffer, frames.data(), collected_frames * sizeof(jvmtiFrameInfo)); 148 } 149 *count_ptr = static_cast<jint>(frames.size()); 150 return ERR(NONE); 151 } 152 153 // Frames from the bottom. 154 if (collected_frames < static_cast<size_t>(-start_depth)) { 155 return ERR(ILLEGAL_ARGUMENT); 156 } 157 158 size_t count = std::min(static_cast<size_t>(-start_depth), static_cast<size_t>(max_frame_count)); 159 memcpy(frame_buffer, 160 &frames.data()[collected_frames + start_depth], 161 count * sizeof(jvmtiFrameInfo)); 162 *count_ptr = static_cast<jint>(count); 163 return ERR(NONE); 164 } 165 166 static jvmtiError GetThread(JNIEnv* env, jthread java_thread, art::Thread** thread) { 167 if (java_thread == nullptr) { 168 *thread = art::Thread::Current(); 169 if (*thread == nullptr) { 170 // GetStackTrace can only be run during the live phase, so the current thread should be 171 // attached and thus available. Getting a null for current means we're starting up or 172 // dying. 173 return ERR(WRONG_PHASE); 174 } 175 } else { 176 if (!env->IsInstanceOf(java_thread, art::WellKnownClasses::java_lang_Thread)) { 177 return ERR(INVALID_THREAD); 178 } 179 180 // TODO: Need non-aborting call here, to return JVMTI_ERROR_INVALID_THREAD. 181 art::ScopedObjectAccess soa(art::Thread::Current()); 182 art::MutexLock mu(soa.Self(), *art::Locks::thread_list_lock_); 183 *thread = art::Thread::FromManagedThread(soa, java_thread); 184 if (*thread == nullptr) { 185 return ERR(THREAD_NOT_ALIVE); 186 } 187 } 188 return ERR(NONE); 189 } 190 191 jvmtiError StackUtil::GetStackTrace(jvmtiEnv* jvmti_env ATTRIBUTE_UNUSED, 192 jthread java_thread, 193 jint start_depth, 194 jint max_frame_count, 195 jvmtiFrameInfo* frame_buffer, 196 jint* count_ptr) { 197 art::Thread* thread; 198 jvmtiError thread_error = GetThread(art::Thread::Current()->GetJniEnv(), java_thread, &thread); 199 if (thread_error != ERR(NONE)) { 200 return thread_error; 201 } 202 DCHECK(thread != nullptr); 203 204 art::ThreadState state = thread->GetState(); 205 if (state == art::ThreadState::kStarting || 206 state == art::ThreadState::kTerminated || 207 thread->IsStillStarting()) { 208 return ERR(THREAD_NOT_ALIVE); 209 } 210 211 if (max_frame_count < 0) { 212 return ERR(ILLEGAL_ARGUMENT); 213 } 214 if (frame_buffer == nullptr || count_ptr == nullptr) { 215 return ERR(NULL_POINTER); 216 } 217 218 if (max_frame_count == 0) { 219 *count_ptr = 0; 220 return ERR(NONE); 221 } 222 223 GetStackTraceClosure closure(start_depth >= 0 ? static_cast<size_t>(start_depth) : 0, 224 start_depth >= 0 ? static_cast<size_t>(max_frame_count) : 0); 225 thread->RequestSynchronousCheckpoint(&closure); 226 227 return TranslateFrameVector(closure.frames, 228 start_depth, 229 closure.start_result, 230 max_frame_count, 231 frame_buffer, 232 count_ptr); 233 } 234 235 struct GetAllStackTraceClosure : public art::Closure { 236 public: 237 explicit GetAllStackTraceClosure(size_t stop) 238 : start_input(0), 239 stop_input(stop), 240 frames_lock("GetAllStackTraceGuard", art::LockLevel::kAbortLock), 241 start_result(0), 242 stop_result(0) {} 243 244 void Run(art::Thread* self) 245 OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) REQUIRES(!frames_lock) { 246 // self should be live here (so it could be suspended). No need to filter. 247 248 art::Thread* current = art::Thread::Current(); 249 std::vector<jvmtiFrameInfo> self_frames; 250 251 GetStackTraceVisitor visitor(self, start_input, stop_input); 252 visitor.WalkStack(false); 253 254 self_frames.swap(visitor.frames); 255 256 art::MutexLock mu(current, frames_lock); 257 frames.emplace(self, self_frames); 258 } 259 260 const size_t start_input; 261 const size_t stop_input; 262 263 art::Mutex frames_lock; 264 std::unordered_map<art::Thread*, std::vector<jvmtiFrameInfo>> frames GUARDED_BY(frames_lock); 265 size_t start_result; 266 size_t stop_result; 267 }; 268 269 270 271 jvmtiError StackUtil::GetAllStackTraces(jvmtiEnv* env, 272 jint max_frame_count, 273 jvmtiStackInfo** stack_info_ptr, 274 jint* thread_count_ptr) { 275 if (max_frame_count < 0) { 276 return ERR(ILLEGAL_ARGUMENT); 277 } 278 if (stack_info_ptr == nullptr || thread_count_ptr == nullptr) { 279 return ERR(NULL_POINTER); 280 } 281 282 283 art::Thread* current = art::Thread::Current(); 284 art::ScopedObjectAccess soa(current); // Now we know we have the shared lock. 285 art::ScopedThreadSuspension sts(current, art::kWaitingForDebuggerSuspension); 286 art::ScopedSuspendAll ssa("GetAllStackTraces"); 287 288 std::vector<art::Thread*> threads; 289 std::vector<std::vector<jvmtiFrameInfo>> frames; 290 { 291 std::list<art::Thread*> thread_list; 292 { 293 art::MutexLock mu(current, *art::Locks::thread_list_lock_); 294 thread_list = art::Runtime::Current()->GetThreadList()->GetList(); 295 } 296 297 for (art::Thread* thread : thread_list) { 298 // Skip threads that are still starting. 299 if (thread->IsStillStarting()) { 300 continue; 301 } 302 303 GetStackTraceClosure closure(0u, static_cast<size_t>(max_frame_count)); 304 thread->RequestSynchronousCheckpoint(&closure); 305 306 threads.push_back(thread); 307 frames.emplace_back(); 308 frames.back().swap(closure.frames); 309 } 310 } 311 312 // Convert the data into our output format. Note: we need to keep the threads suspended, 313 // as we need to access them for their peers. 314 315 // Note: we use an array of jvmtiStackInfo for convenience. The spec says we need to 316 // allocate one big chunk for this and the actual frames, which means we need 317 // to either be conservative or rearrange things later (the latter is implemented). 318 std::unique_ptr<jvmtiStackInfo[]> stack_info_array(new jvmtiStackInfo[frames.size()]); 319 std::vector<std::unique_ptr<jvmtiFrameInfo[]>> frame_infos; 320 frame_infos.reserve(frames.size()); 321 322 // Now run through and add data for each thread. 323 size_t sum_frames = 0; 324 for (size_t index = 0; index < frames.size(); ++index) { 325 jvmtiStackInfo& stack_info = stack_info_array.get()[index]; 326 memset(&stack_info, 0, sizeof(jvmtiStackInfo)); 327 328 art::Thread* self = threads[index]; 329 const std::vector<jvmtiFrameInfo>& thread_frames = frames[index]; 330 331 // For the time being, set the thread to null. We don't have good ScopedLocalRef 332 // infrastructure. 333 DCHECK(self->GetPeerFromOtherThread() != nullptr); 334 stack_info.thread = nullptr; 335 stack_info.state = JVMTI_THREAD_STATE_SUSPENDED; 336 337 size_t collected_frames = thread_frames.size(); 338 if (max_frame_count == 0 || collected_frames == 0) { 339 stack_info.frame_count = 0; 340 stack_info.frame_buffer = nullptr; 341 continue; 342 } 343 DCHECK_LE(collected_frames, static_cast<size_t>(max_frame_count)); 344 345 jvmtiFrameInfo* frame_info = new jvmtiFrameInfo[collected_frames]; 346 frame_infos.emplace_back(frame_info); 347 348 jint count; 349 jvmtiError translate_result = TranslateFrameVector(thread_frames, 350 0, 351 0, 352 static_cast<jint>(collected_frames), 353 frame_info, 354 &count); 355 DCHECK(translate_result == JVMTI_ERROR_NONE); 356 stack_info.frame_count = static_cast<jint>(collected_frames); 357 stack_info.frame_buffer = frame_info; 358 sum_frames += static_cast<size_t>(count); 359 } 360 361 // No errors, yet. Now put it all into an output buffer. 362 size_t rounded_stack_info_size = art::RoundUp(sizeof(jvmtiStackInfo) * frames.size(), 363 alignof(jvmtiFrameInfo)); 364 size_t chunk_size = rounded_stack_info_size + sum_frames * sizeof(jvmtiFrameInfo); 365 unsigned char* chunk_data; 366 jvmtiError alloc_result = env->Allocate(chunk_size, &chunk_data); 367 if (alloc_result != ERR(NONE)) { 368 return alloc_result; 369 } 370 371 jvmtiStackInfo* stack_info = reinterpret_cast<jvmtiStackInfo*>(chunk_data); 372 // First copy in all the basic data. 373 memcpy(stack_info, stack_info_array.get(), sizeof(jvmtiStackInfo) * frames.size()); 374 375 // Now copy the frames and fix up the pointers. 376 jvmtiFrameInfo* frame_info = reinterpret_cast<jvmtiFrameInfo*>( 377 chunk_data + rounded_stack_info_size); 378 for (size_t i = 0; i < frames.size(); ++i) { 379 jvmtiStackInfo& old_stack_info = stack_info_array.get()[i]; 380 jvmtiStackInfo& new_stack_info = stack_info[i]; 381 382 jthread thread_peer = current->GetJniEnv()->AddLocalReference<jthread>( 383 threads[i]->GetPeerFromOtherThread()); 384 new_stack_info.thread = thread_peer; 385 386 if (old_stack_info.frame_count > 0) { 387 // Only copy when there's data - leave the nullptr alone. 388 size_t frames_size = static_cast<size_t>(old_stack_info.frame_count) * sizeof(jvmtiFrameInfo); 389 memcpy(frame_info, old_stack_info.frame_buffer, frames_size); 390 new_stack_info.frame_buffer = frame_info; 391 frame_info += old_stack_info.frame_count; 392 } 393 } 394 395 *stack_info_ptr = stack_info; 396 *thread_count_ptr = static_cast<jint>(frames.size()); 397 398 return ERR(NONE); 399 } 400 401 jvmtiError StackUtil::GetThreadListStackTraces(jvmtiEnv* env, 402 jint thread_count, 403 const jthread* thread_list, 404 jint max_frame_count, 405 jvmtiStackInfo** stack_info_ptr) { 406 if (max_frame_count < 0) { 407 return ERR(ILLEGAL_ARGUMENT); 408 } 409 if (thread_count < 0) { 410 return ERR(ILLEGAL_ARGUMENT); 411 } 412 if (thread_count == 0) { 413 *stack_info_ptr = nullptr; 414 return ERR(NONE); 415 } 416 if (stack_info_ptr == nullptr || stack_info_ptr == nullptr) { 417 return ERR(NULL_POINTER); 418 } 419 420 art::Thread* current = art::Thread::Current(); 421 art::ScopedObjectAccess soa(current); // Now we know we have the shared lock. 422 423 // Decode all threads to raw pointers. Put them into a handle scope to avoid any moving GC bugs. 424 art::VariableSizedHandleScope hs(current); 425 std::vector<art::Handle<art::mirror::Object>> handles; 426 for (jint i = 0; i != thread_count; ++i) { 427 if (thread_list[i] == nullptr) { 428 return ERR(INVALID_THREAD); 429 } 430 if (!soa.Env()->IsInstanceOf(thread_list[i], art::WellKnownClasses::java_lang_Thread)) { 431 return ERR(INVALID_THREAD); 432 } 433 handles.push_back(hs.NewHandle(soa.Decode<art::mirror::Object>(thread_list[i]))); 434 } 435 436 std::vector<art::Thread*> threads; 437 std::vector<size_t> thread_list_indices; 438 std::vector<std::vector<jvmtiFrameInfo>> frames; 439 440 { 441 art::ScopedThreadSuspension sts(current, art::kWaitingForDebuggerSuspension); 442 art::ScopedSuspendAll ssa("GetThreadListStackTraces"); 443 444 { 445 std::list<art::Thread*> art_thread_list; 446 { 447 art::MutexLock mu(current, *art::Locks::thread_list_lock_); 448 art_thread_list = art::Runtime::Current()->GetThreadList()->GetList(); 449 } 450 451 for (art::Thread* thread : art_thread_list) { 452 if (thread->IsStillStarting()) { 453 // Skip this. We can't get the jpeer, and if it is for a thread in the thread_list, 454 // we'll just report STARTING. 455 continue; 456 } 457 458 // Get the peer, and check whether we know it. 459 art::ObjPtr<art::mirror::Object> peer = thread->GetPeerFromOtherThread(); 460 for (size_t index = 0; index != handles.size(); ++index) { 461 if (peer == handles[index].Get()) { 462 // Found the thread. 463 GetStackTraceClosure closure(0u, static_cast<size_t>(max_frame_count)); 464 thread->RequestSynchronousCheckpoint(&closure); 465 466 threads.push_back(thread); 467 thread_list_indices.push_back(index); 468 frames.emplace_back(); 469 frames.back().swap(closure.frames); 470 471 continue; 472 } 473 } 474 475 // Must be not started, or dead. We'll deal with it at the end. 476 } 477 } 478 } 479 480 // Convert the data into our output format. 481 482 // Note: we use an array of jvmtiStackInfo for convenience. The spec says we need to 483 // allocate one big chunk for this and the actual frames, which means we need 484 // to either be conservative or rearrange things later (the latter is implemented). 485 std::unique_ptr<jvmtiStackInfo[]> stack_info_array(new jvmtiStackInfo[frames.size()]); 486 std::vector<std::unique_ptr<jvmtiFrameInfo[]>> frame_infos; 487 frame_infos.reserve(frames.size()); 488 489 // Now run through and add data for each thread. 490 size_t sum_frames = 0; 491 for (size_t index = 0; index < frames.size(); ++index) { 492 jvmtiStackInfo& stack_info = stack_info_array.get()[index]; 493 memset(&stack_info, 0, sizeof(jvmtiStackInfo)); 494 495 art::Thread* self = threads[index]; 496 const std::vector<jvmtiFrameInfo>& thread_frames = frames[index]; 497 498 // For the time being, set the thread to null. We don't have good ScopedLocalRef 499 // infrastructure. 500 DCHECK(self->GetPeerFromOtherThread() != nullptr); 501 stack_info.thread = nullptr; 502 stack_info.state = JVMTI_THREAD_STATE_SUSPENDED; 503 504 size_t collected_frames = thread_frames.size(); 505 if (max_frame_count == 0 || collected_frames == 0) { 506 stack_info.frame_count = 0; 507 stack_info.frame_buffer = nullptr; 508 continue; 509 } 510 DCHECK_LE(collected_frames, static_cast<size_t>(max_frame_count)); 511 512 jvmtiFrameInfo* frame_info = new jvmtiFrameInfo[collected_frames]; 513 frame_infos.emplace_back(frame_info); 514 515 jint count; 516 jvmtiError translate_result = TranslateFrameVector(thread_frames, 517 0, 518 0, 519 static_cast<jint>(collected_frames), 520 frame_info, 521 &count); 522 DCHECK(translate_result == JVMTI_ERROR_NONE); 523 stack_info.frame_count = static_cast<jint>(collected_frames); 524 stack_info.frame_buffer = frame_info; 525 sum_frames += static_cast<size_t>(count); 526 } 527 528 // No errors, yet. Now put it all into an output buffer. Note that this is not frames.size(), 529 // potentially. 530 size_t rounded_stack_info_size = art::RoundUp(sizeof(jvmtiStackInfo) * thread_count, 531 alignof(jvmtiFrameInfo)); 532 size_t chunk_size = rounded_stack_info_size + sum_frames * sizeof(jvmtiFrameInfo); 533 unsigned char* chunk_data; 534 jvmtiError alloc_result = env->Allocate(chunk_size, &chunk_data); 535 if (alloc_result != ERR(NONE)) { 536 return alloc_result; 537 } 538 539 jvmtiStackInfo* stack_info = reinterpret_cast<jvmtiStackInfo*>(chunk_data); 540 jvmtiFrameInfo* frame_info = reinterpret_cast<jvmtiFrameInfo*>( 541 chunk_data + rounded_stack_info_size); 542 543 for (size_t i = 0; i < static_cast<size_t>(thread_count); ++i) { 544 // Check whether we found a running thread for this. 545 // Note: For simplicity, and with the expectation that the list is usually small, use a simple 546 // search. (The list is *not* sorted!) 547 auto it = std::find(thread_list_indices.begin(), thread_list_indices.end(), i); 548 if (it == thread_list_indices.end()) { 549 // No native thread. Must be new or dead. We need to fill out the stack info now. 550 // (Need to read the Java "started" field to know whether this is starting or terminated.) 551 art::ObjPtr<art::mirror::Object> peer = soa.Decode<art::mirror::Object>(thread_list[i]); 552 art::ObjPtr<art::mirror::Class> klass = peer->GetClass(); 553 art::ArtField* started_field = klass->FindDeclaredInstanceField("started", "Z"); 554 CHECK(started_field != nullptr); 555 bool started = started_field->GetBoolean(peer) != 0; 556 constexpr jint kStartedState = JVMTI_JAVA_LANG_THREAD_STATE_NEW; 557 constexpr jint kTerminatedState = JVMTI_THREAD_STATE_TERMINATED | 558 JVMTI_JAVA_LANG_THREAD_STATE_TERMINATED; 559 stack_info[i].thread = reinterpret_cast<JNIEnv*>(soa.Env())->NewLocalRef(thread_list[i]); 560 stack_info[i].state = started ? kTerminatedState : kStartedState; 561 stack_info[i].frame_count = 0; 562 stack_info[i].frame_buffer = nullptr; 563 } else { 564 // Had a native thread and frames. 565 size_t f_index = it - thread_list_indices.begin(); 566 567 jvmtiStackInfo& old_stack_info = stack_info_array.get()[f_index]; 568 jvmtiStackInfo& new_stack_info = stack_info[i]; 569 570 memcpy(&new_stack_info, &old_stack_info, sizeof(jvmtiStackInfo)); 571 new_stack_info.thread = reinterpret_cast<JNIEnv*>(soa.Env())->NewLocalRef(thread_list[i]); 572 if (old_stack_info.frame_count > 0) { 573 // Only copy when there's data - leave the nullptr alone. 574 size_t frames_size = 575 static_cast<size_t>(old_stack_info.frame_count) * sizeof(jvmtiFrameInfo); 576 memcpy(frame_info, old_stack_info.frame_buffer, frames_size); 577 new_stack_info.frame_buffer = frame_info; 578 frame_info += old_stack_info.frame_count; 579 } 580 } 581 } 582 583 * stack_info_ptr = stack_info; 584 585 return ERR(NONE); 586 } 587 588 // Walks up the stack counting Java frames. This is not StackVisitor::ComputeNumFrames, as 589 // runtime methods and transitions must not be counted. 590 struct GetFrameCountVisitor : public art::StackVisitor { 591 explicit GetFrameCountVisitor(art::Thread* thread) 592 : art::StackVisitor(thread, nullptr, art::StackVisitor::StackWalkKind::kIncludeInlinedFrames), 593 count(0) {} 594 595 bool VisitFrame() REQUIRES_SHARED(art::Locks::mutator_lock_) { 596 art::ArtMethod* m = GetMethod(); 597 const bool do_count = !(m == nullptr || m->IsRuntimeMethod()); 598 if (do_count) { 599 count++; 600 } 601 return true; 602 } 603 604 size_t count; 605 }; 606 607 struct GetFrameCountClosure : public art::Closure { 608 public: 609 GetFrameCountClosure() : count(0) {} 610 611 void Run(art::Thread* self) OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) { 612 GetFrameCountVisitor visitor(self); 613 visitor.WalkStack(false); 614 615 count = visitor.count; 616 } 617 618 size_t count; 619 }; 620 621 jvmtiError StackUtil::GetFrameCount(jvmtiEnv* env ATTRIBUTE_UNUSED, 622 jthread java_thread, 623 jint* count_ptr) { 624 art::Thread* thread; 625 jvmtiError thread_error = GetThread(art::Thread::Current()->GetJniEnv(), java_thread, &thread); 626 if (thread_error != ERR(NONE)) { 627 return thread_error; 628 } 629 DCHECK(thread != nullptr); 630 631 if (count_ptr == nullptr) { 632 return ERR(NULL_POINTER); 633 } 634 635 GetFrameCountClosure closure; 636 thread->RequestSynchronousCheckpoint(&closure); 637 638 *count_ptr = closure.count; 639 return ERR(NONE); 640 } 641 642 // Walks up the stack 'n' callers, when used with Thread::WalkStack. 643 struct GetLocationVisitor : public art::StackVisitor { 644 GetLocationVisitor(art::Thread* thread, size_t n_in) 645 : art::StackVisitor(thread, nullptr, art::StackVisitor::StackWalkKind::kIncludeInlinedFrames), 646 n(n_in), 647 count(0), 648 caller(nullptr), 649 caller_dex_pc(0) {} 650 651 bool VisitFrame() REQUIRES_SHARED(art::Locks::mutator_lock_) { 652 art::ArtMethod* m = GetMethod(); 653 const bool do_count = !(m == nullptr || m->IsRuntimeMethod()); 654 if (do_count) { 655 DCHECK(caller == nullptr); 656 if (count == n) { 657 caller = m; 658 caller_dex_pc = GetDexPc(false); 659 return false; 660 } 661 count++; 662 } 663 return true; 664 } 665 666 const size_t n; 667 size_t count; 668 art::ArtMethod* caller; 669 uint32_t caller_dex_pc; 670 }; 671 672 struct GetLocationClosure : public art::Closure { 673 public: 674 explicit GetLocationClosure(size_t n_in) : n(n_in), method(nullptr), dex_pc(0) {} 675 676 void Run(art::Thread* self) OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) { 677 GetLocationVisitor visitor(self, n); 678 visitor.WalkStack(false); 679 680 method = visitor.caller; 681 dex_pc = visitor.caller_dex_pc; 682 } 683 684 const size_t n; 685 art::ArtMethod* method; 686 uint32_t dex_pc; 687 }; 688 689 jvmtiError StackUtil::GetFrameLocation(jvmtiEnv* env ATTRIBUTE_UNUSED, 690 jthread java_thread, 691 jint depth, 692 jmethodID* method_ptr, 693 jlocation* location_ptr) { 694 art::Thread* thread; 695 jvmtiError thread_error = GetThread(art::Thread::Current()->GetJniEnv(), java_thread, &thread); 696 if (thread_error != ERR(NONE)) { 697 return thread_error; 698 } 699 DCHECK(thread != nullptr); 700 701 if (depth < 0) { 702 return ERR(ILLEGAL_ARGUMENT); 703 } 704 if (method_ptr == nullptr || location_ptr == nullptr) { 705 return ERR(NULL_POINTER); 706 } 707 708 GetLocationClosure closure(static_cast<size_t>(depth)); 709 thread->RequestSynchronousCheckpoint(&closure); 710 711 if (closure.method == nullptr) { 712 return ERR(NO_MORE_FRAMES); 713 } 714 715 *method_ptr = art::jni::EncodeArtMethod(closure.method); 716 if (closure.method->IsNative()) { 717 *location_ptr = -1; 718 } else { 719 if (closure.dex_pc == art::DexFile::kDexNoIndex) { 720 return ERR(INTERNAL); 721 } 722 *location_ptr = static_cast<jlocation>(closure.dex_pc); 723 } 724 725 return ERR(NONE); 726 } 727 728 } // namespace openjdkjvmti 729