summaryrefslogtreecommitdiff
path: root/chromium/base/profiler/native_stack_sampler_win.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/base/profiler/native_stack_sampler_win.cc')
-rw-r--r--chromium/base/profiler/native_stack_sampler_win.cc224
1 files changed, 93 insertions, 131 deletions
diff --git a/chromium/base/profiler/native_stack_sampler_win.cc b/chromium/base/profiler/native_stack_sampler_win.cc
index b53197d0dc7..b9b1773e896 100644
--- a/chromium/base/profiler/native_stack_sampler_win.cc
+++ b/chromium/base/profiler/native_stack_sampler_win.cc
@@ -4,8 +4,9 @@
#include "base/profiler/native_stack_sampler.h"
-#include <objbase.h>
#include <windows.h>
+
+#include <objbase.h>
#include <stddef.h>
#include <winternl.h>
@@ -20,6 +21,8 @@
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/profiler/win32_stack_frame_unwinder.h"
+#include "base/stl_util.h"
+#include "base/strings/string16.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
@@ -29,6 +32,12 @@
namespace base {
+using Frame = StackSamplingProfiler::Frame;
+using InternalFrame = StackSamplingProfiler::InternalFrame;
+using Module = StackSamplingProfiler::Module;
+using InternalModule = StackSamplingProfiler::InternalModule;
+using ProfileBuilder = StackSamplingProfiler::ProfileBuilder;
+
// Stack recording functions --------------------------------------------------
namespace {
@@ -59,21 +68,18 @@ const TEB* GetThreadEnvironmentBlock(HANDLE thread_handle) {
};
using NtQueryInformationThreadFunction =
- NTSTATUS (WINAPI*)(HANDLE, THREAD_INFORMATION_CLASS, PVOID, ULONG,
- PULONG);
+ NTSTATUS(WINAPI*)(HANDLE, THREAD_INFORMATION_CLASS, PVOID, ULONG, PULONG);
- const NtQueryInformationThreadFunction nt_query_information_thread =
- reinterpret_cast<NtQueryInformationThreadFunction>(
- ::GetProcAddress(::GetModuleHandle(L"ntdll.dll"),
- "NtQueryInformationThread"));
+ const auto nt_query_information_thread =
+ reinterpret_cast<NtQueryInformationThreadFunction>(::GetProcAddress(
+ ::GetModuleHandle(L"ntdll.dll"), "NtQueryInformationThread"));
if (!nt_query_information_thread)
return nullptr;
THREAD_BASIC_INFORMATION basic_info = {0};
- NTSTATUS status =
- nt_query_information_thread(thread_handle, ThreadBasicInformation,
- &basic_info, sizeof(THREAD_BASIC_INFORMATION),
- nullptr);
+ NTSTATUS status = nt_query_information_thread(
+ thread_handle, ThreadBasicInformation, &basic_info,
+ sizeof(THREAD_BASIC_INFORMATION), nullptr);
if (status != 0)
return nullptr;
@@ -83,9 +89,11 @@ const TEB* GetThreadEnvironmentBlock(HANDLE thread_handle) {
#if defined(_WIN64)
// If the value at |pointer| points to the original stack, rewrite it to point
// to the corresponding location in the copied stack.
-void RewritePointerIfInOriginalStack(uintptr_t top, uintptr_t bottom,
- void* stack_copy, const void** pointer) {
- const uintptr_t value = reinterpret_cast<uintptr_t>(*pointer);
+void RewritePointerIfInOriginalStack(uintptr_t top,
+ uintptr_t bottom,
+ void* stack_copy,
+ const void** pointer) {
+ const auto value = reinterpret_cast<uintptr_t>(*pointer);
if (value >= bottom && value < top) {
*pointer = reinterpret_cast<const void*>(
static_cast<unsigned char*>(stack_copy) + (value - bottom));
@@ -122,23 +130,17 @@ void CopyMemoryFromStack(void* to, const void* from, size_t length)
// Note: this function must not access memory in the original stack as it may
// have been changed or deallocated by this point. This is why |top| and
// |bottom| are passed as uintptr_t.
-void RewritePointersToStackMemory(uintptr_t top, uintptr_t bottom,
- CONTEXT* context, void* stack_copy) {
+void RewritePointersToStackMemory(uintptr_t top,
+ uintptr_t bottom,
+ CONTEXT* context,
+ void* stack_copy) {
#if defined(_WIN64)
- DWORD64 CONTEXT::* const nonvolatile_registers[] = {
- &CONTEXT::R12,
- &CONTEXT::R13,
- &CONTEXT::R14,
- &CONTEXT::R15,
- &CONTEXT::Rdi,
- &CONTEXT::Rsi,
- &CONTEXT::Rbx,
- &CONTEXT::Rbp,
- &CONTEXT::Rsp
- };
+ DWORD64 CONTEXT::*const nonvolatile_registers[] = {
+ &CONTEXT::R12, &CONTEXT::R13, &CONTEXT::R14, &CONTEXT::R15, &CONTEXT::Rdi,
+ &CONTEXT::Rsi, &CONTEXT::Rbx, &CONTEXT::Rbp, &CONTEXT::Rsp};
// Rewrite pointers in the context.
- for (size_t i = 0; i < arraysize(nonvolatile_registers); ++i) {
+ for (size_t i = 0; i < size(nonvolatile_registers); ++i) {
DWORD64* const reg = &(context->*nonvolatile_registers[i]);
RewritePointerIfInOriginalStack(top, bottom, stack_copy,
reinterpret_cast<const void**>(reg));
@@ -159,8 +161,7 @@ struct RecordedFrame {
RecordedFrame(RecordedFrame&& other)
: instruction_pointer(other.instruction_pointer),
- module(std::move(other.module)) {
- }
+ module(std::move(other.module)) {}
RecordedFrame& operator=(RecordedFrame&& other) {
instruction_pointer = other.instruction_pointer;
@@ -220,14 +221,14 @@ std::string GetBuildIDForModule(HMODULE module_handle) {
DWORD age;
win::PEImage(module_handle).GetDebugId(&guid, &age, /* pdb_file= */ nullptr);
const int kGUIDSize = 39;
- std::wstring build_id;
+ string16 build_id;
int result =
::StringFromGUID2(guid, WriteInto(&build_id, kGUIDSize), kGUIDSize);
if (result != kGUIDSize)
return std::string();
RemoveChars(build_id, L"{}-", &build_id);
build_id += StringPrintf(L"%d", age);
- return WideToUTF8(build_id);
+ return UTF16ToUTF8(build_id);
}
// ScopedDisablePriorityBoost -------------------------------------------------
@@ -315,8 +316,7 @@ ScopedSuspendThread::~ScopedSuspendThread() {
bool PointsToGuardPage(uintptr_t stack_pointer) {
MEMORY_BASIC_INFORMATION memory_info;
SIZE_T result = ::VirtualQuery(reinterpret_cast<LPCVOID>(stack_pointer),
- &memory_info,
- sizeof(memory_info));
+ &memory_info, sizeof(memory_info));
return result != 0 && (memory_info.Protect & PAGE_GUARD);
}
@@ -333,8 +333,7 @@ void SuspendThreadAndRecordStack(
void* stack_copy_buffer,
size_t stack_copy_buffer_size,
std::vector<RecordedFrame>* stack,
- NativeStackSampler::AnnotateCallback annotator,
- StackSamplingProfiler::Sample* sample,
+ ProfileBuilder* profile_builder,
NativeStackSamplerTestDelegate* test_delegate) {
DCHECK(stack->empty());
@@ -343,7 +342,7 @@ void SuspendThreadAndRecordStack(
// The stack bounds are saved to uintptr_ts for use outside
// ScopedSuspendThread, as the thread's memory is not safe to dereference
// beyond that point.
- const uintptr_t top = reinterpret_cast<uintptr_t>(base_address);
+ const auto top = reinterpret_cast<uintptr_t>(base_address);
uintptr_t bottom = 0u;
{
@@ -369,7 +368,7 @@ void SuspendThreadAndRecordStack(
if (PointsToGuardPage(bottom))
return;
- (*annotator)(sample);
+ profile_builder->RecordAnnotations();
CopyMemoryFromStack(stack_copy_buffer,
reinterpret_cast<const void*>(bottom), top - bottom);
@@ -388,163 +387,126 @@ void SuspendThreadAndRecordStack(
class NativeStackSamplerWin : public NativeStackSampler {
public:
NativeStackSamplerWin(win::ScopedHandle thread_handle,
- AnnotateCallback annotator,
NativeStackSamplerTestDelegate* test_delegate);
~NativeStackSamplerWin() override;
// StackSamplingProfiler::NativeStackSampler:
- void ProfileRecordingStarting(
- std::vector<StackSamplingProfiler::Module>* modules) override;
- void RecordStackSample(StackBuffer* stack_buffer,
- StackSamplingProfiler::Sample* sample) override;
- void ProfileRecordingStopped(StackBuffer* stack_buffer) override;
+ void ProfileRecordingStarting() override;
+ std::vector<InternalFrame> RecordStackFrames(
+ StackBuffer* stack_buffer,
+ ProfileBuilder* profile_builder) override;
private:
// Attempts to query the module filename, base address, and id for
- // |module_handle|, and store them in |module|. Returns true if it succeeded.
- static bool GetModuleForHandle(HMODULE module_handle,
- StackSamplingProfiler::Module* module);
-
- // Gets the index for the Module corresponding to |module_handle| in
- // |modules|, adding it if it's not already present. Returns
- // StackSamplingProfiler::Frame::kUnknownModuleIndex if no Module can be
- // determined for |module|.
- size_t GetModuleIndex(HMODULE module_handle,
- std::vector<StackSamplingProfiler::Module>* modules);
-
- // Copies the information represented by |stack| into |sample| and |modules|.
- void CopyToSample(const std::vector<RecordedFrame>& stack,
- StackSamplingProfiler::Sample* sample,
- std::vector<StackSamplingProfiler::Module>* modules);
+ // |module_handle|, and returns them in an InternalModule object.
+ static InternalModule GetModuleForHandle(HMODULE module_handle);
- win::ScopedHandle thread_handle_;
+ // Creates a set of internal frames with the information represented by
+ // |stack|.
+ std::vector<InternalFrame> CreateInternalFrames(
+ const std::vector<RecordedFrame>& stack);
- const AnnotateCallback annotator_;
+ win::ScopedHandle thread_handle_;
NativeStackSamplerTestDelegate* const test_delegate_;
// The stack base address corresponding to |thread_handle_|.
const void* const thread_stack_base_address_;
- // Weak. Points to the modules associated with the profile being recorded
- // between ProfileRecordingStarting() and ProfileRecordingStopped().
- std::vector<StackSamplingProfiler::Module>* current_modules_;
-
- // Maps a module handle to the corresponding Module's index within
- // current_modules_.
- std::map<HMODULE, size_t> profile_module_index_;
+ // The internal module objects, indexed by the module handle.
+ std::map<HMODULE, InternalModule> module_cache_;
DISALLOW_COPY_AND_ASSIGN(NativeStackSamplerWin);
};
NativeStackSamplerWin::NativeStackSamplerWin(
win::ScopedHandle thread_handle,
- AnnotateCallback annotator,
NativeStackSamplerTestDelegate* test_delegate)
: thread_handle_(thread_handle.Take()),
- annotator_(annotator),
test_delegate_(test_delegate),
thread_stack_base_address_(
- GetThreadEnvironmentBlock(thread_handle_.Get())->Tib.StackBase) {
- DCHECK(annotator_);
-}
+ GetThreadEnvironmentBlock(thread_handle_.Get())->Tib.StackBase) {}
-NativeStackSamplerWin::~NativeStackSamplerWin() {
-}
+NativeStackSamplerWin::~NativeStackSamplerWin() {}
-void NativeStackSamplerWin::ProfileRecordingStarting(
- std::vector<StackSamplingProfiler::Module>* modules) {
- current_modules_ = modules;
- profile_module_index_.clear();
+void NativeStackSamplerWin::ProfileRecordingStarting() {
+ module_cache_.clear();
}
-void NativeStackSamplerWin::RecordStackSample(
+std::vector<InternalFrame> NativeStackSamplerWin::RecordStackFrames(
StackBuffer* stack_buffer,
- StackSamplingProfiler::Sample* sample) {
+ ProfileBuilder* profile_builder) {
DCHECK(stack_buffer);
- DCHECK(current_modules_);
std::vector<RecordedFrame> stack;
SuspendThreadAndRecordStack(thread_handle_.Get(), thread_stack_base_address_,
stack_buffer->buffer(), stack_buffer->size(),
- &stack, annotator_, sample, test_delegate_);
- CopyToSample(stack, sample, current_modules_);
-}
+ &stack, profile_builder, test_delegate_);
-void NativeStackSamplerWin::ProfileRecordingStopped(StackBuffer* stack_buffer) {
- current_modules_ = nullptr;
+ return CreateInternalFrames(stack);
}
// static
-bool NativeStackSamplerWin::GetModuleForHandle(
- HMODULE module_handle,
- StackSamplingProfiler::Module* module) {
+InternalModule NativeStackSamplerWin::GetModuleForHandle(
+ HMODULE module_handle) {
wchar_t module_name[MAX_PATH];
DWORD result_length =
- GetModuleFileName(module_handle, module_name, arraysize(module_name));
+ ::GetModuleFileName(module_handle, module_name, size(module_name));
if (result_length == 0)
- return false;
+ return InternalModule();
- module->filename = base::FilePath(module_name);
+ const std::string& module_id = GetBuildIDForModule(module_handle);
+ if (module_id.empty())
+ return InternalModule();
- module->base_address = reinterpret_cast<uintptr_t>(module_handle);
+ return InternalModule(reinterpret_cast<uintptr_t>(module_handle), module_id,
+ FilePath(module_name));
+}
- module->id = GetBuildIDForModule(module_handle);
- if (module->id.empty())
- return false;
+std::vector<InternalFrame> NativeStackSamplerWin::CreateInternalFrames(
+ const std::vector<RecordedFrame>& stack) {
+ std::vector<InternalFrame> internal_frames;
+ internal_frames.reserve(stack.size());
- return true;
-}
+ for (const auto& frame : stack) {
+ auto frame_ip = reinterpret_cast<uintptr_t>(frame.instruction_pointer);
-size_t NativeStackSamplerWin::GetModuleIndex(
- HMODULE module_handle,
- std::vector<StackSamplingProfiler::Module>* modules) {
- if (!module_handle)
- return StackSamplingProfiler::Frame::kUnknownModuleIndex;
-
- auto loc = profile_module_index_.find(module_handle);
- if (loc == profile_module_index_.end()) {
- StackSamplingProfiler::Module module;
- if (!GetModuleForHandle(module_handle, &module))
- return StackSamplingProfiler::Frame::kUnknownModuleIndex;
- modules->push_back(module);
- loc = profile_module_index_.insert(std::make_pair(
- module_handle, modules->size() - 1)).first;
- }
+ HMODULE module_handle = frame.module.Get();
+ if (!module_handle) {
+ internal_frames.emplace_back(frame_ip, InternalModule());
+ continue;
+ }
- return loc->second;
-}
+ auto loc = module_cache_.find(module_handle);
+ if (loc != module_cache_.end()) {
+ internal_frames.emplace_back(frame_ip, loc->second);
+ continue;
+ }
-void NativeStackSamplerWin::CopyToSample(
- const std::vector<RecordedFrame>& stack,
- StackSamplingProfiler::Sample* sample,
- std::vector<StackSamplingProfiler::Module>* modules) {
- sample->frames.clear();
- sample->frames.reserve(stack.size());
-
- for (const RecordedFrame& frame : stack) {
- sample->frames.push_back(StackSamplingProfiler::Frame(
- reinterpret_cast<uintptr_t>(frame.instruction_pointer),
- GetModuleIndex(frame.module.Get(), modules)));
+ InternalModule internal_module = GetModuleForHandle(module_handle);
+ if (internal_module.is_valid)
+ module_cache_.insert(std::make_pair(module_handle, internal_module));
+
+ internal_frames.emplace_back(frame_ip, std::move(internal_module));
}
+
+ return internal_frames;
}
} // namespace
std::unique_ptr<NativeStackSampler> NativeStackSampler::Create(
PlatformThreadId thread_id,
- AnnotateCallback annotator,
NativeStackSamplerTestDelegate* test_delegate) {
#if _WIN64
// Get the thread's handle.
HANDLE thread_handle = ::OpenThread(
THREAD_GET_CONTEXT | THREAD_SUSPEND_RESUME | THREAD_QUERY_INFORMATION,
- FALSE,
- thread_id);
+ FALSE, thread_id);
if (thread_handle) {
return std::unique_ptr<NativeStackSampler>(new NativeStackSamplerWin(
- win::ScopedHandle(thread_handle), annotator, test_delegate));
+ win::ScopedHandle(thread_handle), test_delegate));
}
#endif
return std::unique_ptr<NativeStackSampler>();