Chromium Code Reviews| 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/win32_stack_frame_unwinder.h" | 5 #include "base/profiler/win32_stack_frame_unwinder.h" |
| 6 | 6 |
| 7 #include <windows.h> | |
| 8 | |
| 7 #include "base/containers/hash_tables.h" | 9 #include "base/containers/hash_tables.h" |
| 8 #include "base/memory/singleton.h" | 10 #include "base/memory/singleton.h" |
| 9 #include "base/stl_util.h" | 11 #include "base/stl_util.h" |
| 10 | 12 |
| 11 namespace base { | 13 namespace base { |
| 12 | 14 |
| 13 // Win32UnwindFunctions ------------------------------------------------------- | 15 // Win32UnwindFunctions ------------------------------------------------------- |
| 14 | 16 |
| 17 const HMODULE ModuleHandleTraits::kNonNullModuleForTesting = | |
| 18 reinterpret_cast<HMODULE>(static_cast<uintptr_t>(-1)); | |
| 19 | |
| 20 // static | |
| 21 bool ModuleHandleTraits::CloseHandle(HMODULE handle) { | |
| 22 if (handle == kNonNullModuleForTesting) | |
| 23 return true; | |
| 24 | |
| 25 return ::FreeLibrary(handle) != 0; | |
| 26 } | |
| 27 | |
| 28 // static | |
| 29 bool ModuleHandleTraits::IsHandleValid(HMODULE handle) { | |
| 30 return handle != nullptr; | |
| 31 } | |
| 32 | |
| 33 // static | |
| 34 HMODULE ModuleHandleTraits::NullHandle() { | |
| 35 return nullptr; | |
| 36 } | |
| 37 | |
| 15 namespace { | 38 namespace { |
| 16 | 39 |
| 17 // Implements the UnwindFunctions interface for the corresponding Win32 | 40 // Implements the UnwindFunctions interface for the corresponding Win32 |
| 18 // functions. | 41 // functions. |
| 19 class Win32UnwindFunctions : public Win32StackFrameUnwinder::UnwindFunctions { | 42 class Win32UnwindFunctions : public Win32StackFrameUnwinder::UnwindFunctions { |
| 20 public: | 43 public: |
| 21 Win32UnwindFunctions(); | 44 Win32UnwindFunctions(); |
| 22 ~Win32UnwindFunctions() override; | 45 ~Win32UnwindFunctions() override; |
| 23 | 46 |
| 24 PRUNTIME_FUNCTION LookupFunctionEntry(DWORD64 program_counter, | 47 PRUNTIME_FUNCTION LookupFunctionEntry(DWORD64 program_counter, |
| 25 PDWORD64 image_base) override; | 48 PDWORD64 image_base) override; |
| 26 | 49 |
| 27 void VirtualUnwind(DWORD64 image_base, | 50 void VirtualUnwind(DWORD64 image_base, |
| 28 DWORD64 program_counter, | 51 DWORD64 program_counter, |
| 29 PRUNTIME_FUNCTION runtime_function, | 52 PRUNTIME_FUNCTION runtime_function, |
| 30 CONTEXT* context) override; | 53 CONTEXT* context) override; |
| 31 | 54 |
| 55 ScopedModuleHandle GetModuleForProgramCounter( | |
| 56 DWORD64 program_counter) override; | |
| 57 | |
| 32 private: | 58 private: |
| 33 DISALLOW_COPY_AND_ASSIGN(Win32UnwindFunctions); | 59 DISALLOW_COPY_AND_ASSIGN(Win32UnwindFunctions); |
| 34 }; | 60 }; |
| 35 | 61 |
| 36 Win32UnwindFunctions::Win32UnwindFunctions() {} | 62 Win32UnwindFunctions::Win32UnwindFunctions() {} |
| 37 Win32UnwindFunctions::~Win32UnwindFunctions() {} | 63 Win32UnwindFunctions::~Win32UnwindFunctions() {} |
| 38 | 64 |
| 39 PRUNTIME_FUNCTION Win32UnwindFunctions::LookupFunctionEntry( | 65 PRUNTIME_FUNCTION Win32UnwindFunctions::LookupFunctionEntry( |
| 40 DWORD64 program_counter, | 66 DWORD64 program_counter, |
| 41 PDWORD64 image_base) { | 67 PDWORD64 image_base) { |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 56 ULONG64 establisher_frame; | 82 ULONG64 establisher_frame; |
| 57 KNONVOLATILE_CONTEXT_POINTERS nvcontext = {}; | 83 KNONVOLATILE_CONTEXT_POINTERS nvcontext = {}; |
| 58 RtlVirtualUnwind(UNW_FLAG_NHANDLER, image_base, program_counter, | 84 RtlVirtualUnwind(UNW_FLAG_NHANDLER, image_base, program_counter, |
| 59 runtime_function, context, &handler_data, | 85 runtime_function, context, &handler_data, |
| 60 &establisher_frame, &nvcontext); | 86 &establisher_frame, &nvcontext); |
| 61 #else | 87 #else |
| 62 NOTREACHED(); | 88 NOTREACHED(); |
| 63 #endif | 89 #endif |
| 64 } | 90 } |
| 65 | 91 |
| 92 ScopedModuleHandle Win32UnwindFunctions::GetModuleForProgramCounter( | |
| 93 DWORD64 program_counter) { | |
| 94 HMODULE module_handle = nullptr; | |
| 95 if (!::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, | |
| 96 reinterpret_cast<LPCTSTR>(program_counter), | |
| 97 &module_handle)) { | |
| 98 const DWORD error = ::GetLastError(); | |
| 99 DCHECK_EQ(ERROR_MOD_NOT_FOUND, static_cast<int>(error)); | |
| 100 } | |
| 101 return ScopedModuleHandle(module_handle); | |
| 102 } | |
| 103 | |
| 66 // LeafUnwindBlacklist -------------------------------------------------------- | 104 // LeafUnwindBlacklist -------------------------------------------------------- |
| 67 | 105 |
| 68 // Records modules that are known to have functions that violate the Microsoft | 106 // Records modules that are known to have functions that violate the Microsoft |
| 69 // x64 calling convention and would be dangerous to manually unwind if | 107 // x64 calling convention and would be dangerous to manually unwind if |
| 70 // encountered as the last frame on the call stack. Functions like these have | 108 // encountered as the last frame on the call stack. Functions like these have |
| 71 // been observed in injected third party modules that either do not provide | 109 // been observed in injected third party modules that either do not provide |
| 72 // function unwind information, or do not provide the required function prologue | 110 // function unwind information, or do not provide the required function prologue |
| 73 // and epilogue. The former case was observed in several AV products and the | 111 // and epilogue. The former case was observed in several AV products and the |
| 74 // latter in a WndProc function associated with Actual Window | 112 // latter in a WndProc function associated with Actual Window |
| 75 // Manager/aimemb64.dll. See https://crbug.com/476422. | 113 // Manager/aimemb64.dll. See https://crbug.com/476422. |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 133 | 171 |
| 134 Win32StackFrameUnwinder::UnwindFunctions::~UnwindFunctions() {} | 172 Win32StackFrameUnwinder::UnwindFunctions::~UnwindFunctions() {} |
| 135 Win32StackFrameUnwinder::UnwindFunctions::UnwindFunctions() {} | 173 Win32StackFrameUnwinder::UnwindFunctions::UnwindFunctions() {} |
| 136 | 174 |
| 137 Win32StackFrameUnwinder::Win32StackFrameUnwinder() | 175 Win32StackFrameUnwinder::Win32StackFrameUnwinder() |
| 138 : Win32StackFrameUnwinder(make_scoped_ptr(new Win32UnwindFunctions)) { | 176 : Win32StackFrameUnwinder(make_scoped_ptr(new Win32UnwindFunctions)) { |
| 139 } | 177 } |
| 140 | 178 |
| 141 Win32StackFrameUnwinder::~Win32StackFrameUnwinder() {} | 179 Win32StackFrameUnwinder::~Win32StackFrameUnwinder() {} |
| 142 | 180 |
| 143 bool Win32StackFrameUnwinder::TryUnwind(CONTEXT* context) { | 181 bool Win32StackFrameUnwinder::TryUnwind(CONTEXT* context, |
| 182 ScopedModuleHandle* module) { | |
| 144 #ifdef _WIN64 | 183 #ifdef _WIN64 |
| 145 CHECK(!at_top_frame_ || unwind_info_present_for_all_frames_); | 184 CHECK(!at_top_frame_ || unwind_info_present_for_all_frames_); |
| 146 | 185 |
| 186 ScopedModuleHandle frame_module = | |
| 187 unwind_functions_->GetModuleForProgramCounter(context->Rip); | |
| 188 // The module may have been unloaded since we recorded the stack. | |
| 189 if (!frame_module.IsValid()) | |
| 190 return false; | |
|
cpu_(ooo_6.6-7.5)
2015/10/29 21:22:19
we should note that the module at that address cou
Mike Wittman
2015/10/29 23:23:28
Done.
| |
| 191 | |
| 147 ULONG64 image_base; | 192 ULONG64 image_base; |
| 148 // Try to look up unwind metadata for the current function. | 193 // Try to look up unwind metadata for the current function. |
| 149 PRUNTIME_FUNCTION runtime_function = | 194 PRUNTIME_FUNCTION runtime_function = |
| 150 unwind_functions_->LookupFunctionEntry(context->Rip, &image_base); | 195 unwind_functions_->LookupFunctionEntry(context->Rip, &image_base); |
| 151 | 196 |
| 152 if (runtime_function) { | 197 if (runtime_function) { |
| 153 if (!SanityCheckRuntimeFunction(runtime_function, image_base, context->Rip)) | 198 if (!SanityCheckRuntimeFunction(runtime_function, image_base, context->Rip)) |
| 154 return false; | 199 return false; |
| 155 | 200 |
| 156 unwind_functions_->VirtualUnwind(image_base, context->Rip, runtime_function, | 201 unwind_functions_->VirtualUnwind(image_base, context->Rip, runtime_function, |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 222 // frame is case 2. But it's possible that the initial frame was case | 267 // frame is case 2. But it's possible that the initial frame was case |
| 223 // 2 but hadn't been blacklisted yet, and we've started to go off into | 268 // 2 but hadn't been blacklisted yet, and we've started to go off into |
| 224 // the weeds. Since we can't be sure, just bail out without | 269 // the weeds. Since we can't be sure, just bail out without |
| 225 // blacklisting the module; chances are we'll later encounter the same | 270 // blacklisting the module; chances are we'll later encounter the same |
| 226 // function on a stack with full unwind information. | 271 // function on a stack with full unwind information. |
| 227 } | 272 } |
| 228 return false; | 273 return false; |
| 229 } | 274 } |
| 230 } | 275 } |
| 231 | 276 |
| 277 module->Set(frame_module.Take()); | |
| 232 return true; | 278 return true; |
| 233 #else | 279 #else |
| 234 NOTREACHED(); | 280 NOTREACHED(); |
| 235 return false; | 281 return false; |
| 236 #endif | 282 #endif |
| 237 } | 283 } |
| 238 | 284 |
| 239 Win32StackFrameUnwinder::Win32StackFrameUnwinder( | 285 Win32StackFrameUnwinder::Win32StackFrameUnwinder( |
| 240 scoped_ptr<UnwindFunctions> unwind_functions) | 286 scoped_ptr<UnwindFunctions> unwind_functions) |
| 241 : at_top_frame_(true), | 287 : at_top_frame_(true), |
| 242 unwind_info_present_for_all_frames_(true), | 288 unwind_info_present_for_all_frames_(true), |
| 243 unwind_functions_(unwind_functions.Pass()) { | 289 unwind_functions_(unwind_functions.Pass()) { |
| 244 } | 290 } |
| 245 | 291 |
| 246 } // namespace base | 292 } // namespace base |
| OLD | NEW |