| Index: base/profiler/win32_stack_frame_unwinder.cc
|
| diff --git a/base/profiler/win32_stack_frame_unwinder.cc b/base/profiler/win32_stack_frame_unwinder.cc
|
| index 2f09e8e88750e15340c9445e3d00c499f2c8276c..2c0689136234839aa513a976c1d2db9b30a7dfde 100644
|
| --- a/base/profiler/win32_stack_frame_unwinder.cc
|
| +++ b/base/profiler/win32_stack_frame_unwinder.cc
|
| @@ -4,6 +4,8 @@
|
|
|
| #include "base/profiler/win32_stack_frame_unwinder.h"
|
|
|
| +#include <windows.h>
|
| +
|
| #include "base/containers/hash_tables.h"
|
| #include "base/memory/singleton.h"
|
| #include "base/stl_util.h"
|
| @@ -12,6 +14,27 @@ namespace base {
|
|
|
| // Win32UnwindFunctions -------------------------------------------------------
|
|
|
| +const HMODULE ModuleHandleTraits::kNonNullModuleForTesting =
|
| + reinterpret_cast<HMODULE>(static_cast<uintptr_t>(-1));
|
| +
|
| +// static
|
| +bool ModuleHandleTraits::CloseHandle(HMODULE handle) {
|
| + if (handle == kNonNullModuleForTesting)
|
| + return true;
|
| +
|
| + return ::FreeLibrary(handle) != 0;
|
| +}
|
| +
|
| +// static
|
| +bool ModuleHandleTraits::IsHandleValid(HMODULE handle) {
|
| + return handle != nullptr;
|
| +}
|
| +
|
| +// static
|
| +HMODULE ModuleHandleTraits::NullHandle() {
|
| + return nullptr;
|
| +}
|
| +
|
| namespace {
|
|
|
| // Implements the UnwindFunctions interface for the corresponding Win32
|
| @@ -29,6 +52,9 @@ public:
|
| PRUNTIME_FUNCTION runtime_function,
|
| CONTEXT* context) override;
|
|
|
| + ScopedModuleHandle GetModuleForProgramCounter(
|
| + DWORD64 program_counter) override;
|
| +
|
| private:
|
| DISALLOW_COPY_AND_ASSIGN(Win32UnwindFunctions);
|
| };
|
| @@ -63,6 +89,20 @@ void Win32UnwindFunctions::VirtualUnwind(DWORD64 image_base,
|
| #endif
|
| }
|
|
|
| +ScopedModuleHandle Win32UnwindFunctions::GetModuleForProgramCounter(
|
| + DWORD64 program_counter) {
|
| + HMODULE module_handle = nullptr;
|
| + // GetModuleHandleEx() increments the module reference count, which is then
|
| + // managed and ultimately decremented by ScopedModuleHandle.
|
| + if (!::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
|
| + reinterpret_cast<LPCTSTR>(program_counter),
|
| + &module_handle)) {
|
| + const DWORD error = ::GetLastError();
|
| + DCHECK_EQ(ERROR_MOD_NOT_FOUND, static_cast<int>(error));
|
| + }
|
| + return ScopedModuleHandle(module_handle);
|
| +}
|
| +
|
| // LeafUnwindBlacklist --------------------------------------------------------
|
|
|
| // Records modules that are known to have functions that violate the Microsoft
|
| @@ -140,10 +180,21 @@ Win32StackFrameUnwinder::Win32StackFrameUnwinder()
|
|
|
| Win32StackFrameUnwinder::~Win32StackFrameUnwinder() {}
|
|
|
| -bool Win32StackFrameUnwinder::TryUnwind(CONTEXT* context) {
|
| +bool Win32StackFrameUnwinder::TryUnwind(CONTEXT* context,
|
| + ScopedModuleHandle* module) {
|
| #ifdef _WIN64
|
| CHECK(!at_top_frame_ || unwind_info_present_for_all_frames_);
|
|
|
| + ScopedModuleHandle frame_module =
|
| + unwind_functions_->GetModuleForProgramCounter(context->Rip);
|
| + // The module may have been unloaded since we recorded the stack. Note that if
|
| + // this check detects module as valid, it still could be a different module at
|
| + // the same instruction pointer address (i.e. if the module was unloaded and a
|
| + // different module loaded in overlapping memory). This should occur extremely
|
| + // rarely.
|
| + if (!frame_module.IsValid())
|
| + return false;
|
| +
|
| ULONG64 image_base;
|
| // Try to look up unwind metadata for the current function.
|
| PRUNTIME_FUNCTION runtime_function =
|
| @@ -229,6 +280,7 @@ bool Win32StackFrameUnwinder::TryUnwind(CONTEXT* context) {
|
| }
|
| }
|
|
|
| + module->Set(frame_module.Take());
|
| return true;
|
| #else
|
| NOTREACHED();
|
|
|