| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "base/profiler/native_stack_sampler.h" | 5 #include "base/profiler/native_stack_sampler.h" |
| 6 | 6 |
| 7 #include <objbase.h> | 7 #include <objbase.h> |
| 8 #include <windows.h> | 8 #include <windows.h> |
| 9 #include <stddef.h> | 9 #include <stddef.h> |
| 10 #include <winternl.h> | 10 #include <winternl.h> |
| (...skipping 308 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 319 return result != 0 && (memory_info.Protect & PAGE_GUARD); | 319 return result != 0 && (memory_info.Protect & PAGE_GUARD); |
| 320 } | 320 } |
| 321 | 321 |
| 322 // Suspends the thread with |thread_handle|, copies its stack and resumes the | 322 // Suspends the thread with |thread_handle|, copies its stack and resumes the |
| 323 // thread, then records the stack frames and associated modules into |stack|. | 323 // thread, then records the stack frames and associated modules into |stack|. |
| 324 // | 324 // |
| 325 // IMPORTANT NOTE: No allocations from the default heap may occur in the | 325 // IMPORTANT NOTE: No allocations from the default heap may occur in the |
| 326 // ScopedSuspendThread scope, including indirectly via use of DCHECK/CHECK or | 326 // ScopedSuspendThread scope, including indirectly via use of DCHECK/CHECK or |
| 327 // other logging statements. Otherwise this code can deadlock on heap locks in | 327 // other logging statements. Otherwise this code can deadlock on heap locks in |
| 328 // the default heap acquired by the target thread before it was suspended. | 328 // the default heap acquired by the target thread before it was suspended. |
| 329 void SuspendThreadAndRecordStack( | 329 NativeStackSampler::ThreadState SuspendThreadAndRecordStack( |
| 330 HANDLE thread_handle, | 330 HANDLE thread_handle, |
| 331 const void* base_address, | 331 const void* base_address, |
| 332 void* stack_copy_buffer, | 332 void* stack_copy_buffer, |
| 333 size_t stack_copy_buffer_size, | 333 size_t stack_copy_buffer_size, |
| 334 std::vector<RecordedFrame>* stack, | 334 std::vector<RecordedFrame>* stack, |
| 335 NativeStackSampler::AnnotateCallback annotator, | 335 NativeStackSampler::AnnotateCallback annotator, |
| 336 StackSamplingProfiler::Sample* sample, | 336 StackSamplingProfiler::Sample* sample, |
| 337 NativeStackSamplerTestDelegate* test_delegate) { | 337 NativeStackSamplerTestDelegate* test_delegate) { |
| 338 DCHECK(stack->empty()); | 338 DCHECK(stack->empty()); |
| 339 | 339 |
| 340 CONTEXT thread_context = {0}; | 340 CONTEXT thread_context = {0}; |
| 341 thread_context.ContextFlags = CONTEXT_FULL; | 341 thread_context.ContextFlags = CONTEXT_FULL; |
| 342 // The stack bounds are saved to uintptr_ts for use outside | 342 // The stack bounds are saved to uintptr_ts for use outside |
| 343 // ScopedSuspendThread, as the thread's memory is not safe to dereference | 343 // ScopedSuspendThread, as the thread's memory is not safe to dereference |
| 344 // beyond that point. | 344 // beyond that point. |
| 345 const uintptr_t top = reinterpret_cast<uintptr_t>(base_address); | 345 const uintptr_t top = reinterpret_cast<uintptr_t>(base_address); |
| 346 uintptr_t bottom = 0u; | 346 uintptr_t bottom = 0u; |
| 347 | 347 |
| 348 { | 348 { |
| 349 ScopedSuspendThread suspend_thread(thread_handle); | 349 ScopedSuspendThread suspend_thread(thread_handle); |
| 350 | 350 |
| 351 if (!suspend_thread.was_successful()) | 351 if (!suspend_thread.was_successful()) |
| 352 return; | 352 return NativeStackSampler::THREAD_UNSUSPENDABLE; |
| 353 | 353 |
| 354 if (!::GetThreadContext(thread_handle, &thread_context)) | 354 if (!::GetThreadContext(thread_handle, &thread_context)) |
| 355 return; | 355 return NativeStackSampler::THREAD_NO_INFO; |
| 356 |
| 356 #if defined(_WIN64) | 357 #if defined(_WIN64) |
| 357 bottom = thread_context.Rsp; | 358 bottom = thread_context.Rsp; |
| 358 #else | 359 #else |
| 359 bottom = thread_context.Esp; | 360 bottom = thread_context.Esp; |
| 360 #endif | 361 #endif |
| 361 | 362 |
| 362 if ((top - bottom) > stack_copy_buffer_size) | 363 if ((top - bottom) > stack_copy_buffer_size) |
| 363 return; | 364 return NativeStackSampler::THREAD_STACK_TOO_BIG; |
| 364 | 365 |
| 365 // Dereferencing a pointer in the guard page in a thread that doesn't own | 366 // Dereferencing a pointer in the guard page in a thread that doesn't own |
| 366 // the stack results in a STATUS_GUARD_PAGE_VIOLATION exception and a crash. | 367 // the stack results in a STATUS_GUARD_PAGE_VIOLATION exception and a crash. |
| 367 // This occurs very rarely, but reliably over the population. | 368 // This occurs very rarely, but reliably over the population. |
| 368 if (PointsToGuardPage(bottom)) | 369 if (PointsToGuardPage(bottom)) |
| 369 return; | 370 return NativeStackSampler::THREAD_INACCESSIBLE; |
| 370 | 371 |
| 371 (*annotator)(sample); | 372 (*annotator)(sample); |
| 372 | 373 |
| 373 CopyMemoryFromStack(stack_copy_buffer, | 374 CopyMemoryFromStack(stack_copy_buffer, |
| 374 reinterpret_cast<const void*>(bottom), top - bottom); | 375 reinterpret_cast<const void*>(bottom), top - bottom); |
| 375 } | 376 } |
| 376 | 377 |
| 377 if (test_delegate) | 378 if (test_delegate) |
| 378 test_delegate->OnPreStackWalk(); | 379 test_delegate->OnPreStackWalk(); |
| 379 | 380 |
| 380 RewritePointersToStackMemory(top, bottom, &thread_context, stack_copy_buffer); | 381 RewritePointersToStackMemory(top, bottom, &thread_context, stack_copy_buffer); |
| 381 | 382 |
| 382 RecordStack(&thread_context, stack); | 383 RecordStack(&thread_context, stack); |
| 384 return NativeStackSampler::THREAD_RUNNING; |
| 383 } | 385 } |
| 384 | 386 |
| 385 // NativeStackSamplerWin ------------------------------------------------------ | 387 // NativeStackSamplerWin ------------------------------------------------------ |
| 386 | 388 |
| 387 class NativeStackSamplerWin : public NativeStackSampler { | 389 class NativeStackSamplerWin : public NativeStackSampler { |
| 388 public: | 390 public: |
| 389 NativeStackSamplerWin(win::ScopedHandle thread_handle, | 391 NativeStackSamplerWin(win::ScopedHandle thread_handle, |
| 390 AnnotateCallback annotator, | 392 AnnotateCallback annotator, |
| 391 NativeStackSamplerTestDelegate* test_delegate); | 393 NativeStackSamplerTestDelegate* test_delegate); |
| 392 ~NativeStackSamplerWin() override; | 394 ~NativeStackSamplerWin() override; |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 470 profile_module_index_.clear(); | 472 profile_module_index_.clear(); |
| 471 } | 473 } |
| 472 | 474 |
| 473 void NativeStackSamplerWin::RecordStackSample( | 475 void NativeStackSamplerWin::RecordStackSample( |
| 474 StackSamplingProfiler::Sample* sample) { | 476 StackSamplingProfiler::Sample* sample) { |
| 475 DCHECK(current_modules_); | 477 DCHECK(current_modules_); |
| 476 | 478 |
| 477 if (!stack_copy_buffer_) | 479 if (!stack_copy_buffer_) |
| 478 return; | 480 return; |
| 479 | 481 |
| 482 if (thread_state() == THREAD_EXITED) |
| 483 return; |
| 484 |
| 480 std::vector<RecordedFrame> stack; | 485 std::vector<RecordedFrame> stack; |
| 481 SuspendThreadAndRecordStack(thread_handle_.Get(), thread_stack_base_address_, | 486 set_thread_state(SuspendThreadAndRecordStack( |
| 482 stack_copy_buffer_.get(), kStackCopyBufferSize, | 487 thread_handle_.Get(), thread_stack_base_address_, |
| 483 &stack, annotator_, sample, test_delegate_); | 488 stack_copy_buffer_.get(), kStackCopyBufferSize, &stack, annotator_, |
| 489 sample, test_delegate_)); |
| 484 CopyToSample(stack, sample, current_modules_); | 490 CopyToSample(stack, sample, current_modules_); |
| 491 |
| 492 if (test_delegate_) |
| 493 test_delegate_->OnPostRecordSample(thread_state()); |
| 485 } | 494 } |
| 486 | 495 |
| 487 void NativeStackSamplerWin::ProfileRecordingStopped() { | 496 void NativeStackSamplerWin::ProfileRecordingStopped() { |
| 488 current_modules_ = nullptr; | 497 current_modules_ = nullptr; |
| 489 } | 498 } |
| 490 | 499 |
| 491 // static | 500 // static |
| 492 bool NativeStackSamplerWin::GetModuleForHandle( | 501 bool NativeStackSamplerWin::GetModuleForHandle( |
| 493 HMODULE module_handle, | 502 HMODULE module_handle, |
| 494 StackSamplingProfiler::Module* module) { | 503 StackSamplingProfiler::Module* module) { |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 557 | 566 |
| 558 if (thread_handle) { | 567 if (thread_handle) { |
| 559 return std::unique_ptr<NativeStackSampler>(new NativeStackSamplerWin( | 568 return std::unique_ptr<NativeStackSampler>(new NativeStackSamplerWin( |
| 560 win::ScopedHandle(thread_handle), annotator, test_delegate)); | 569 win::ScopedHandle(thread_handle), annotator, test_delegate)); |
| 561 } | 570 } |
| 562 #endif | 571 #endif |
| 563 return std::unique_ptr<NativeStackSampler>(); | 572 return std::unique_ptr<NativeStackSampler>(); |
| 564 } | 573 } |
| 565 | 574 |
| 566 } // namespace base | 575 } // namespace base |
| OLD | NEW |