Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(172)

Side by Side Diff: base/profiler/win32_stack_frame_unwinder.cc

Issue 1423583002: Stack sampling profiler: handle unloaded and unloading modules (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@lkcr
Patch Set: fix gcc compile Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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 // GetModuleHandleEx() increments the module reference count, which is then
96 // managed and ultimately decremented by ScopedModuleHandle.
97 if (!::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
98 reinterpret_cast<LPCTSTR>(program_counter),
99 &module_handle)) {
100 const DWORD error = ::GetLastError();
101 DCHECK_EQ(ERROR_MOD_NOT_FOUND, static_cast<int>(error));
102 }
103 return ScopedModuleHandle(module_handle);
104 }
105
66 // LeafUnwindBlacklist -------------------------------------------------------- 106 // LeafUnwindBlacklist --------------------------------------------------------
67 107
68 // Records modules that are known to have functions that violate the Microsoft 108 // Records modules that are known to have functions that violate the Microsoft
69 // x64 calling convention and would be dangerous to manually unwind if 109 // 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 110 // 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 111 // been observed in injected third party modules that either do not provide
72 // function unwind information, or do not provide the required function prologue 112 // 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 113 // and epilogue. The former case was observed in several AV products and the
74 // latter in a WndProc function associated with Actual Window 114 // latter in a WndProc function associated with Actual Window
75 // Manager/aimemb64.dll. See https://crbug.com/476422. 115 // Manager/aimemb64.dll. See https://crbug.com/476422.
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
133 173
134 Win32StackFrameUnwinder::UnwindFunctions::~UnwindFunctions() {} 174 Win32StackFrameUnwinder::UnwindFunctions::~UnwindFunctions() {}
135 Win32StackFrameUnwinder::UnwindFunctions::UnwindFunctions() {} 175 Win32StackFrameUnwinder::UnwindFunctions::UnwindFunctions() {}
136 176
137 Win32StackFrameUnwinder::Win32StackFrameUnwinder() 177 Win32StackFrameUnwinder::Win32StackFrameUnwinder()
138 : Win32StackFrameUnwinder(make_scoped_ptr(new Win32UnwindFunctions)) { 178 : Win32StackFrameUnwinder(make_scoped_ptr(new Win32UnwindFunctions)) {
139 } 179 }
140 180
141 Win32StackFrameUnwinder::~Win32StackFrameUnwinder() {} 181 Win32StackFrameUnwinder::~Win32StackFrameUnwinder() {}
142 182
143 bool Win32StackFrameUnwinder::TryUnwind(CONTEXT* context) { 183 bool Win32StackFrameUnwinder::TryUnwind(CONTEXT* context,
184 ScopedModuleHandle* module) {
144 #ifdef _WIN64 185 #ifdef _WIN64
145 CHECK(!at_top_frame_ || unwind_info_present_for_all_frames_); 186 CHECK(!at_top_frame_ || unwind_info_present_for_all_frames_);
146 187
188 ScopedModuleHandle frame_module =
189 unwind_functions_->GetModuleForProgramCounter(context->Rip);
190 // The module may have been unloaded since we recorded the stack. Note that if
191 // this check detects module as valid, it still could be a different module at
192 // the same instruction pointer address (i.e. if the module was unloaded and a
193 // different module loaded in overlapping memory). This should occur extremely
194 // rarely.
195 if (!frame_module.IsValid())
196 return false;
197
147 ULONG64 image_base; 198 ULONG64 image_base;
148 // Try to look up unwind metadata for the current function. 199 // Try to look up unwind metadata for the current function.
149 PRUNTIME_FUNCTION runtime_function = 200 PRUNTIME_FUNCTION runtime_function =
150 unwind_functions_->LookupFunctionEntry(context->Rip, &image_base); 201 unwind_functions_->LookupFunctionEntry(context->Rip, &image_base);
151 202
152 if (runtime_function) { 203 if (runtime_function) {
153 if (!SanityCheckRuntimeFunction(runtime_function, image_base, context->Rip)) 204 if (!SanityCheckRuntimeFunction(runtime_function, image_base, context->Rip))
154 return false; 205 return false;
155 206
156 unwind_functions_->VirtualUnwind(image_base, context->Rip, runtime_function, 207 unwind_functions_->VirtualUnwind(image_base, context->Rip, runtime_function,
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
222 // frame is case 2. But it's possible that the initial frame was case 273 // 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 274 // 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 275 // the weeds. Since we can't be sure, just bail out without
225 // blacklisting the module; chances are we'll later encounter the same 276 // blacklisting the module; chances are we'll later encounter the same
226 // function on a stack with full unwind information. 277 // function on a stack with full unwind information.
227 } 278 }
228 return false; 279 return false;
229 } 280 }
230 } 281 }
231 282
283 module->Set(frame_module.Take());
232 return true; 284 return true;
233 #else 285 #else
234 NOTREACHED(); 286 NOTREACHED();
235 return false; 287 return false;
236 #endif 288 #endif
237 } 289 }
238 290
239 Win32StackFrameUnwinder::Win32StackFrameUnwinder( 291 Win32StackFrameUnwinder::Win32StackFrameUnwinder(
240 scoped_ptr<UnwindFunctions> unwind_functions) 292 scoped_ptr<UnwindFunctions> unwind_functions)
241 : at_top_frame_(true), 293 : at_top_frame_(true),
242 unwind_info_present_for_all_frames_(true), 294 unwind_info_present_for_all_frames_(true),
243 unwind_functions_(unwind_functions.Pass()) { 295 unwind_functions_(unwind_functions.Pass()) {
244 } 296 }
245 297
246 } // namespace base 298 } // namespace base
OLDNEW
« no previous file with comments | « base/profiler/win32_stack_frame_unwinder.h ('k') | base/profiler/win32_stack_frame_unwinder_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698