| 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> | 7 #include <windows.h> |
| 8 | 8 |
| 9 #include "base/containers/hash_tables.h" | 9 #include "base/containers/hash_tables.h" |
| 10 #include "base/memory/singleton.h" | 10 #include "base/memory/singleton.h" |
| (...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 152 blacklisted_modules_.insert(module); | 152 blacklisted_modules_.insert(module); |
| 153 } | 153 } |
| 154 | 154 |
| 155 LeafUnwindBlacklist::LeafUnwindBlacklist() {} | 155 LeafUnwindBlacklist::LeafUnwindBlacklist() {} |
| 156 LeafUnwindBlacklist::~LeafUnwindBlacklist() {} | 156 LeafUnwindBlacklist::~LeafUnwindBlacklist() {} |
| 157 | 157 |
| 158 } // namespace | 158 } // namespace |
| 159 | 159 |
| 160 // Win32StackFrameUnwinder ---------------------------------------------------- | 160 // Win32StackFrameUnwinder ---------------------------------------------------- |
| 161 | 161 |
| 162 // hipis0e011b8.dll from McAfee Host Intrusion Prevention has been observed to | |
| 163 // provide a pointer to a bogus RUNTIME_FUNCTION structure. This function checks | |
| 164 // that the values in the structure look plausible. | |
| 165 bool SanityCheckRuntimeFunction(PRUNTIME_FUNCTION runtime_function, | |
| 166 ULONG64 image_base, | |
| 167 DWORD64 program_counter) { | |
| 168 const DWORD64 program_counter_offset = program_counter - image_base; | |
| 169 return (runtime_function->BeginAddress <= runtime_function->EndAddress && | |
| 170 program_counter_offset >= runtime_function->BeginAddress && | |
| 171 program_counter_offset <= runtime_function->EndAddress); | |
| 172 } | |
| 173 | |
| 174 Win32StackFrameUnwinder::UnwindFunctions::~UnwindFunctions() {} | 162 Win32StackFrameUnwinder::UnwindFunctions::~UnwindFunctions() {} |
| 175 Win32StackFrameUnwinder::UnwindFunctions::UnwindFunctions() {} | 163 Win32StackFrameUnwinder::UnwindFunctions::UnwindFunctions() {} |
| 176 | 164 |
| 177 Win32StackFrameUnwinder::Win32StackFrameUnwinder() | 165 Win32StackFrameUnwinder::Win32StackFrameUnwinder() |
| 178 : Win32StackFrameUnwinder(make_scoped_ptr(new Win32UnwindFunctions)) { | 166 : Win32StackFrameUnwinder(make_scoped_ptr(new Win32UnwindFunctions)) { |
| 179 } | 167 } |
| 180 | 168 |
| 181 Win32StackFrameUnwinder::~Win32StackFrameUnwinder() {} | 169 Win32StackFrameUnwinder::~Win32StackFrameUnwinder() {} |
| 182 | 170 |
| 183 bool Win32StackFrameUnwinder::TryUnwind(CONTEXT* context, | 171 bool Win32StackFrameUnwinder::TryUnwind(CONTEXT* context, |
| 184 ScopedModuleHandle* module) { | 172 ScopedModuleHandle* module) { |
| 185 #ifdef _WIN64 | 173 #ifdef _WIN64 |
| 186 CHECK(!at_top_frame_ || unwind_info_present_for_all_frames_); | 174 CHECK(!at_top_frame_ || unwind_info_present_for_all_frames_); |
| 187 | 175 |
| 188 ScopedModuleHandle frame_module = | 176 ScopedModuleHandle frame_module = |
| 189 unwind_functions_->GetModuleForProgramCounter(context->Rip); | 177 unwind_functions_->GetModuleForProgramCounter(context->Rip); |
| 190 // The module may have been unloaded since we recorded the stack. Note that if | 178 if (!frame_module.IsValid()) { |
| 191 // this check detects module as valid, it still could be a different module at | 179 // There's no loaded module containing the instruction pointer. This can be |
| 192 // the same instruction pointer address (i.e. if the module was unloaded and a | 180 // due to executing code that is not in a module. In particular, |
| 193 // different module loaded in overlapping memory). This should occur extremely | 181 // runtime-generated code associated with third-party injected DLLs |
| 194 // rarely. | 182 // typically is not in a module. It can also be due to the the module having |
| 195 if (!frame_module.IsValid()) | 183 // been unloaded since we recorded the stack. In the latter case the |
| 184 // function unwind information was part of the unloaded module, so it's not |
| 185 // possible to unwind further. |
| 186 // |
| 187 // If a module was found, it's still theoretically possible for the detected |
| 188 // module module to be different than the one that was loaded when the stack |
| 189 // was copied (i.e. if the module was unloaded and a different module loaded |
| 190 // in overlapping memory). This likely would cause a crash, but has not been |
| 191 // observed in practice. |
| 196 return false; | 192 return false; |
| 193 } |
| 197 | 194 |
| 198 ULONG64 image_base; | 195 ULONG64 image_base; |
| 199 // Try to look up unwind metadata for the current function. | 196 // Try to look up unwind metadata for the current function. |
| 200 PRUNTIME_FUNCTION runtime_function = | 197 PRUNTIME_FUNCTION runtime_function = |
| 201 unwind_functions_->LookupFunctionEntry(context->Rip, &image_base); | 198 unwind_functions_->LookupFunctionEntry(context->Rip, &image_base); |
| 202 | 199 |
| 203 if (runtime_function) { | 200 if (runtime_function) { |
| 204 if (!SanityCheckRuntimeFunction(runtime_function, image_base, context->Rip)) | |
| 205 return false; | |
| 206 | |
| 207 unwind_functions_->VirtualUnwind(image_base, context->Rip, runtime_function, | 201 unwind_functions_->VirtualUnwind(image_base, context->Rip, runtime_function, |
| 208 context); | 202 context); |
| 209 at_top_frame_ = false; | 203 at_top_frame_ = false; |
| 210 } else { | 204 } else { |
| 211 // RtlLookupFunctionEntry didn't find unwind information. This could mean | 205 // RtlLookupFunctionEntry didn't find unwind information. This could mean |
| 212 // the code at the instruction pointer is in: | 206 // the code at the instruction pointer is in: |
| 213 // | 207 // |
| 214 // 1. a true leaf function (i.e. a function that neither calls a function, | 208 // 1. a true leaf function (i.e. a function that neither calls a function, |
| 215 // nor allocates any stack space itself) in which case the return | 209 // nor allocates any stack space itself) in which case the return |
| 216 // address is at RSP, or | 210 // address is at RSP, or |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 289 } | 283 } |
| 290 | 284 |
| 291 Win32StackFrameUnwinder::Win32StackFrameUnwinder( | 285 Win32StackFrameUnwinder::Win32StackFrameUnwinder( |
| 292 scoped_ptr<UnwindFunctions> unwind_functions) | 286 scoped_ptr<UnwindFunctions> unwind_functions) |
| 293 : at_top_frame_(true), | 287 : at_top_frame_(true), |
| 294 unwind_info_present_for_all_frames_(true), | 288 unwind_info_present_for_all_frames_(true), |
| 295 unwind_functions_(unwind_functions.Pass()) { | 289 unwind_functions_(unwind_functions.Pass()) { |
| 296 } | 290 } |
| 297 | 291 |
| 298 } // namespace base | 292 } // namespace base |
| OLD | NEW |