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 |