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 |