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

Side by Side Diff: base/profiler/native_stack_sampler_win.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
« no previous file with comments | « base/profiler/native_stack_sampler_posix.cc ('k') | base/profiler/stack_sampling_profiler.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 <objbase.h> 5 #include <objbase.h>
6 #include <windows.h> 6 #include <windows.h>
7 #include <winternl.h> 7 #include <winternl.h>
8 8
9 #include <cstdlib> 9 #include <cstdlib>
10 #include <map> 10 #include <map>
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after
133 const void** end = reinterpret_cast<const void**>( 133 const void** end = reinterpret_cast<const void**>(
134 reinterpret_cast<char*>(stack_copy) + (top - bottom)); 134 reinterpret_cast<char*>(stack_copy) + (top - bottom));
135 for (const void** loc = start; loc < end; ++loc) 135 for (const void** loc = start; loc < end; ++loc)
136 RewritePointerIfInOriginalStack(top, bottom, stack_copy, loc); 136 RewritePointerIfInOriginalStack(top, bottom, stack_copy, loc);
137 #endif 137 #endif
138 } 138 }
139 139
140 // Walks the stack represented by |context| from the current frame downwards, 140 // Walks the stack represented by |context| from the current frame downwards,
141 // recording the instruction pointers for each frame in |instruction_pointers|. 141 // recording the instruction pointers for each frame in |instruction_pointers|.
142 int RecordStack(CONTEXT* context, int max_stack_size, 142 int RecordStack(CONTEXT* context, int max_stack_size,
143 const void* instruction_pointers[]) { 143 const void* instruction_pointers[],
144 ScopedModuleHandle modules[]) {
144 #ifdef _WIN64 145 #ifdef _WIN64
145 Win32StackFrameUnwinder frame_unwinder; 146 Win32StackFrameUnwinder frame_unwinder;
146 int i = 0; 147 int i = 0;
147 for (; (i < max_stack_size) && context->Rip; ++i) { 148 for (; (i < max_stack_size) && context->Rip; ++i) {
148 instruction_pointers[i] = reinterpret_cast<const void*>(context->Rip); 149 instruction_pointers[i] = reinterpret_cast<const void*>(context->Rip);
149 if (!frame_unwinder.TryUnwind(context)) 150 if (!frame_unwinder.TryUnwind(context, &modules[i]))
150 return i + 1; 151 return i + 1;
151 } 152 }
152 return i; 153 return i;
153 #else 154 #else
154 return 0; 155 return 0;
155 #endif 156 #endif
156 } 157 }
157 158
158 // Fills in |module_handles| corresponding to the pointers to code in
159 // |addresses|. The module handles are returned with reference counts
160 // incremented and should be freed with FreeModuleHandles. See note in
161 // SuspendThreadAndRecordStack for why |addresses| and |module_handles| are
162 // arrays.
163 void FindModuleHandlesForAddresses(const void* const addresses[],
164 HMODULE module_handles[], int stack_depth) {
165 for (int i = 0; i < stack_depth; ++i) {
166 HMODULE module_handle = NULL;
167 if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
168 reinterpret_cast<LPCTSTR>(addresses[i]),
169 &module_handle)) {
170 // HMODULE actually represents the base address of the module, so we can
171 // use it directly as an address.
172 DCHECK_LE(reinterpret_cast<const void*>(module_handle), addresses[i]);
173 module_handles[i] = module_handle;
174 }
175 }
176 }
177
178 // Frees the modules handles returned by FindModuleHandlesForAddresses. See note
179 // in SuspendThreadAndRecordStack for why |module_handles| is an array.
180 void FreeModuleHandles(int stack_depth, HMODULE module_handles[]) {
181 for (int i = 0; i < stack_depth; ++i) {
182 if (module_handles[i])
183 ::FreeLibrary(module_handles[i]);
184 }
185 }
186
187 // Gets the unique build ID for a module. Windows build IDs are created by a 159 // Gets the unique build ID for a module. Windows build IDs are created by a
188 // concatenation of a GUID and AGE fields found in the headers of a module. The 160 // concatenation of a GUID and AGE fields found in the headers of a module. The
189 // GUID is stored in the first 16 bytes and the AGE is stored in the last 4 161 // GUID is stored in the first 16 bytes and the AGE is stored in the last 4
190 // bytes. Returns the empty string if the function fails to get the build ID. 162 // bytes. Returns the empty string if the function fails to get the build ID.
191 // 163 //
192 // Example: 164 // Example:
193 // dumpbin chrome.exe /headers | find "Format:" 165 // dumpbin chrome.exe /headers | find "Format:"
194 // ... Format: RSDS, {16B2A428-1DED-442E-9A36-FCE8CBD29726}, 10, ... 166 // ... Format: RSDS, {16B2A428-1DED-442E-9A36-FCE8CBD29726}, 10, ...
195 // 167 //
196 // The resulting buildID string of this instance of chrome.exe is 168 // The resulting buildID string of this instance of chrome.exe is
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after
293 // IMPORTANT NOTE: No allocations from the default heap may occur in the 265 // IMPORTANT NOTE: No allocations from the default heap may occur in the
294 // ScopedSuspendThread scope, including indirectly via use of DCHECK/CHECK or 266 // ScopedSuspendThread scope, including indirectly via use of DCHECK/CHECK or
295 // other logging statements. Otherwise this code can deadlock on heap locks in 267 // other logging statements. Otherwise this code can deadlock on heap locks in
296 // the default heap acquired by the target thread before it was suspended. This 268 // the default heap acquired by the target thread before it was suspended. This
297 // is why we pass instruction pointers as preallocated arrays. 269 // is why we pass instruction pointers as preallocated arrays.
298 int SuspendThreadAndRecordStack(HANDLE thread_handle, 270 int SuspendThreadAndRecordStack(HANDLE thread_handle,
299 const void* base_address, 271 const void* base_address,
300 void* stack_copy_buffer, 272 void* stack_copy_buffer,
301 size_t stack_copy_buffer_size, 273 size_t stack_copy_buffer_size,
302 int max_stack_size, 274 int max_stack_size,
303 const void* instruction_pointers[]) { 275 const void* instruction_pointers[],
276 ScopedModuleHandle modules[],
277 NativeStackSamplerTestDelegate* test_delegate) {
304 CONTEXT thread_context = {0}; 278 CONTEXT thread_context = {0};
305 thread_context.ContextFlags = CONTEXT_FULL; 279 thread_context.ContextFlags = CONTEXT_FULL;
306 // The stack bounds are saved to uintptr_ts for use outside 280 // The stack bounds are saved to uintptr_ts for use outside
307 // ScopedSuspendThread, as the thread's memory is not safe to dereference 281 // ScopedSuspendThread, as the thread's memory is not safe to dereference
308 // beyond that point. 282 // beyond that point.
309 const uintptr_t top = reinterpret_cast<uintptr_t>(base_address); 283 const uintptr_t top = reinterpret_cast<uintptr_t>(base_address);
310 uintptr_t bottom = 0u; 284 uintptr_t bottom = 0u;
311 285
312 { 286 {
313 ScopedSuspendThread suspend_thread(thread_handle); 287 ScopedSuspendThread suspend_thread(thread_handle);
314 288
315 if (!suspend_thread.was_successful()) 289 if (!suspend_thread.was_successful())
316 return 0; 290 return 0;
317 291
318 if (!::GetThreadContext(thread_handle, &thread_context)) 292 if (!::GetThreadContext(thread_handle, &thread_context))
319 return 0; 293 return 0;
320 #if defined(_WIN64) 294 #if defined(_WIN64)
321 bottom = thread_context.Rsp; 295 bottom = thread_context.Rsp;
322 #else 296 #else
323 bottom = thread_context.Esp; 297 bottom = thread_context.Esp;
324 #endif 298 #endif
325 299
326 if ((top - bottom) > stack_copy_buffer_size) 300 if ((top - bottom) > stack_copy_buffer_size)
327 return 0; 301 return 0;
328 302
329 std::memcpy(stack_copy_buffer, reinterpret_cast<const void*>(bottom), 303 std::memcpy(stack_copy_buffer, reinterpret_cast<const void*>(bottom),
330 top - bottom); 304 top - bottom);
331 } 305 }
332 306
307 if (test_delegate)
308 test_delegate->OnPreStackWalk();
309
333 RewritePointersToStackMemory(top, bottom, &thread_context, stack_copy_buffer); 310 RewritePointersToStackMemory(top, bottom, &thread_context, stack_copy_buffer);
334 311
335 return RecordStack(&thread_context, max_stack_size, instruction_pointers); 312 return RecordStack(&thread_context, max_stack_size, instruction_pointers,
313 modules);
336 } 314 }
337 315
338 // NativeStackSamplerWin ------------------------------------------------------ 316 // NativeStackSamplerWin ------------------------------------------------------
339 317
340 class NativeStackSamplerWin : public NativeStackSampler { 318 class NativeStackSamplerWin : public NativeStackSampler {
341 public: 319 public:
342 explicit NativeStackSamplerWin(win::ScopedHandle thread_handle); 320 NativeStackSamplerWin(win::ScopedHandle thread_handle,
321 NativeStackSamplerTestDelegate* test_delegate);
343 ~NativeStackSamplerWin() override; 322 ~NativeStackSamplerWin() override;
344 323
345 // StackSamplingProfiler::NativeStackSampler: 324 // StackSamplingProfiler::NativeStackSampler:
346 void ProfileRecordingStarting( 325 void ProfileRecordingStarting(
347 std::vector<StackSamplingProfiler::Module>* modules) override; 326 std::vector<StackSamplingProfiler::Module>* modules) override;
348 void RecordStackSample(StackSamplingProfiler::Sample* sample) override; 327 void RecordStackSample(StackSamplingProfiler::Sample* sample) override;
349 void ProfileRecordingStopped() override; 328 void ProfileRecordingStopped() override;
350 329
351 private: 330 private:
352 enum { 331 enum {
(...skipping 13 matching lines...) Expand all
366 // Gets the index for the Module corresponding to |module_handle| in 345 // Gets the index for the Module corresponding to |module_handle| in
367 // |modules|, adding it if it's not already present. Returns 346 // |modules|, adding it if it's not already present. Returns
368 // StackSamplingProfiler::Frame::kUnknownModuleIndex if no Module can be 347 // StackSamplingProfiler::Frame::kUnknownModuleIndex if no Module can be
369 // determined for |module|. 348 // determined for |module|.
370 size_t GetModuleIndex(HMODULE module_handle, 349 size_t GetModuleIndex(HMODULE module_handle,
371 std::vector<StackSamplingProfiler::Module>* modules); 350 std::vector<StackSamplingProfiler::Module>* modules);
372 351
373 // Copies the stack information represented by |instruction_pointers| into 352 // Copies the stack information represented by |instruction_pointers| into
374 // |sample| and |modules|. 353 // |sample| and |modules|.
375 void CopyToSample(const void* const instruction_pointers[], 354 void CopyToSample(const void* const instruction_pointers[],
376 const HMODULE module_handles[], 355 const ScopedModuleHandle module_handles[],
377 int stack_depth, 356 int stack_depth,
378 StackSamplingProfiler::Sample* sample, 357 StackSamplingProfiler::Sample* sample,
379 std::vector<StackSamplingProfiler::Module>* modules); 358 std::vector<StackSamplingProfiler::Module>* modules);
380 359
381 win::ScopedHandle thread_handle_; 360 win::ScopedHandle thread_handle_;
382 361
362 NativeStackSamplerTestDelegate* const test_delegate_;
363
383 // The stack base address corresponding to |thread_handle_|. 364 // The stack base address corresponding to |thread_handle_|.
384 const void* const thread_stack_base_address_; 365 const void* const thread_stack_base_address_;
385 366
386 // Buffer to use for copies of the stack. We use the same buffer for all the 367 // Buffer to use for copies of the stack. We use the same buffer for all the
387 // samples to avoid the overhead of multiple allocations and frees. 368 // samples to avoid the overhead of multiple allocations and frees.
388 const scoped_ptr<unsigned char[]> stack_copy_buffer_; 369 const scoped_ptr<unsigned char[]> stack_copy_buffer_;
389 370
390 // Weak. Points to the modules associated with the profile being recorded 371 // Weak. Points to the modules associated with the profile being recorded
391 // between ProfileRecordingStarting() and ProfileRecordingStopped(). 372 // between ProfileRecordingStarting() and ProfileRecordingStopped().
392 std::vector<StackSamplingProfiler::Module>* current_modules_; 373 std::vector<StackSamplingProfiler::Module>* current_modules_;
393 374
394 // Maps a module handle to the corresponding Module's index within 375 // Maps a module handle to the corresponding Module's index within
395 // current_modules_. 376 // current_modules_.
396 std::map<HMODULE, size_t> profile_module_index_; 377 std::map<HMODULE, size_t> profile_module_index_;
397 378
398 DISALLOW_COPY_AND_ASSIGN(NativeStackSamplerWin); 379 DISALLOW_COPY_AND_ASSIGN(NativeStackSamplerWin);
399 }; 380 };
400 381
401 NativeStackSamplerWin::NativeStackSamplerWin(win::ScopedHandle thread_handle) 382 NativeStackSamplerWin::NativeStackSamplerWin(
402 : thread_handle_(thread_handle.Take()), 383 win::ScopedHandle thread_handle,
384 NativeStackSamplerTestDelegate* test_delegate)
385 : thread_handle_(thread_handle.Take()), test_delegate_(test_delegate),
403 thread_stack_base_address_( 386 thread_stack_base_address_(
404 GetThreadEnvironmentBlock(thread_handle_.Get())->Tib.StackBase), 387 GetThreadEnvironmentBlock(thread_handle_.Get())->Tib.StackBase),
405 stack_copy_buffer_(new unsigned char[kStackCopyBufferSize]) { 388 stack_copy_buffer_(new unsigned char[kStackCopyBufferSize]) {
406 } 389 }
407 390
408 NativeStackSamplerWin::~NativeStackSamplerWin() { 391 NativeStackSamplerWin::~NativeStackSamplerWin() {
409 } 392 }
410 393
411 void NativeStackSamplerWin::ProfileRecordingStarting( 394 void NativeStackSamplerWin::ProfileRecordingStarting(
412 std::vector<StackSamplingProfiler::Module>* modules) { 395 std::vector<StackSamplingProfiler::Module>* modules) {
413 current_modules_ = modules; 396 current_modules_ = modules;
414 profile_module_index_.clear(); 397 profile_module_index_.clear();
415 } 398 }
416 399
417 void NativeStackSamplerWin::RecordStackSample( 400 void NativeStackSamplerWin::RecordStackSample(
418 StackSamplingProfiler::Sample* sample) { 401 StackSamplingProfiler::Sample* sample) {
419 DCHECK(current_modules_); 402 DCHECK(current_modules_);
420 403
421 if (!stack_copy_buffer_) 404 if (!stack_copy_buffer_)
422 return; 405 return;
423 406
424 const int max_stack_size = 64; 407 const int max_stack_size = 64;
425 const void* instruction_pointers[max_stack_size] = {0}; 408 const void* instruction_pointers[max_stack_size] = {0};
426 HMODULE module_handles[max_stack_size] = {0}; 409 ScopedModuleHandle modules[max_stack_size];
427 410
428 int stack_depth = SuspendThreadAndRecordStack(thread_handle_.Get(), 411 int stack_depth = SuspendThreadAndRecordStack(thread_handle_.Get(),
429 thread_stack_base_address_, 412 thread_stack_base_address_,
430 stack_copy_buffer_.get(), 413 stack_copy_buffer_.get(),
431 kStackCopyBufferSize, 414 kStackCopyBufferSize,
432 max_stack_size, 415 max_stack_size,
433 instruction_pointers); 416 instruction_pointers,
434 FindModuleHandlesForAddresses(instruction_pointers, module_handles, 417 modules,
435 stack_depth); 418 test_delegate_);
436 CopyToSample(instruction_pointers, module_handles, stack_depth, sample, 419 CopyToSample(instruction_pointers, modules, stack_depth, sample,
437 current_modules_); 420 current_modules_);
438 FreeModuleHandles(stack_depth, module_handles);
439 } 421 }
440 422
441 void NativeStackSamplerWin::ProfileRecordingStopped() { 423 void NativeStackSamplerWin::ProfileRecordingStopped() {
442 current_modules_ = nullptr; 424 current_modules_ = nullptr;
443 } 425 }
444 426
445 // static 427 // static
446 bool NativeStackSamplerWin::GetModuleForHandle( 428 bool NativeStackSamplerWin::GetModuleForHandle(
447 HMODULE module_handle, 429 HMODULE module_handle,
448 StackSamplingProfiler::Module* module) { 430 StackSamplingProfiler::Module* module) {
(...skipping 28 matching lines...) Expand all
477 modules->push_back(module); 459 modules->push_back(module);
478 loc = profile_module_index_.insert(std::make_pair( 460 loc = profile_module_index_.insert(std::make_pair(
479 module_handle, modules->size() - 1)).first; 461 module_handle, modules->size() - 1)).first;
480 } 462 }
481 463
482 return loc->second; 464 return loc->second;
483 } 465 }
484 466
485 void NativeStackSamplerWin::CopyToSample( 467 void NativeStackSamplerWin::CopyToSample(
486 const void* const instruction_pointers[], 468 const void* const instruction_pointers[],
487 const HMODULE module_handles[], 469 const ScopedModuleHandle module_handles[],
488 int stack_depth, 470 int stack_depth,
489 StackSamplingProfiler::Sample* sample, 471 StackSamplingProfiler::Sample* sample,
490 std::vector<StackSamplingProfiler::Module>* module) { 472 std::vector<StackSamplingProfiler::Module>* modules) {
491 sample->clear(); 473 sample->clear();
492 sample->reserve(stack_depth); 474 sample->reserve(stack_depth);
493 475
494 for (int i = 0; i < stack_depth; ++i) { 476 for (int i = 0; i < stack_depth; ++i) {
495 sample->push_back(StackSamplingProfiler::Frame( 477 sample->push_back(StackSamplingProfiler::Frame(
496 reinterpret_cast<uintptr_t>(instruction_pointers[i]), 478 reinterpret_cast<uintptr_t>(instruction_pointers[i]),
497 GetModuleIndex(module_handles[i], module))); 479 GetModuleIndex(module_handles[i].Get(), modules)));
498 } 480 }
499 } 481 }
500 482
501 } // namespace 483 } // namespace
502 484
503 scoped_ptr<NativeStackSampler> NativeStackSampler::Create( 485 scoped_ptr<NativeStackSampler> NativeStackSampler::Create(
504 PlatformThreadId thread_id) { 486 PlatformThreadId thread_id,
487 NativeStackSamplerTestDelegate* test_delegate) {
505 #if _WIN64 488 #if _WIN64
506 // Get the thread's handle. 489 // Get the thread's handle.
507 HANDLE thread_handle = ::OpenThread( 490 HANDLE thread_handle = ::OpenThread(
508 THREAD_GET_CONTEXT | THREAD_SUSPEND_RESUME | THREAD_QUERY_INFORMATION, 491 THREAD_GET_CONTEXT | THREAD_SUSPEND_RESUME | THREAD_QUERY_INFORMATION,
509 FALSE, 492 FALSE,
510 thread_id); 493 thread_id);
511 494
512 if (thread_handle) { 495 if (thread_handle) {
513 return scoped_ptr<NativeStackSampler>(new NativeStackSamplerWin( 496 return scoped_ptr<NativeStackSampler>(new NativeStackSamplerWin(
514 win::ScopedHandle(thread_handle))); 497 win::ScopedHandle(thread_handle),
498 test_delegate));
515 } 499 }
516 #endif 500 #endif
517 return scoped_ptr<NativeStackSampler>(); 501 return scoped_ptr<NativeStackSampler>();
518 } 502 }
519 503
520 } // namespace base 504 } // namespace base
OLDNEW
« no previous file with comments | « base/profiler/native_stack_sampler_posix.cc ('k') | base/profiler/stack_sampling_profiler.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698