Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / base / debug / profiler.cc
blob924c7693eb52e8d1b3d2d295d931a7ffe3857f6f
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/debug/profiler.h"
7 #include <string>
9 #include "base/process/process_handle.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "base/strings/string_util.h"
13 #if defined(OS_WIN)
14 #include "base/win/pe_image.h"
15 #endif // defined(OS_WIN)
17 // TODO(peria): Enable profiling on Windows.
18 #if defined(ENABLE_PROFILING) && !defined(NO_TCMALLOC) && !defined(OS_WIN)
19 #include "third_party/tcmalloc/chromium/src/gperftools/profiler.h"
20 #endif
22 namespace base {
23 namespace debug {
25 // TODO(peria): Enable profiling on Windows.
26 #if defined(ENABLE_PROFILING) && !defined(NO_TCMALLOC) && !defined(OS_WIN)
28 static int profile_count = 0;
30 void StartProfiling(const std::string& name) {
31 ++profile_count;
32 std::string full_name(name);
33 std::string pid = IntToString(GetCurrentProcId());
34 std::string count = IntToString(profile_count);
35 ReplaceSubstringsAfterOffset(&full_name, 0, "{pid}", pid);
36 ReplaceSubstringsAfterOffset(&full_name, 0, "{count}", count);
37 ProfilerStart(full_name.c_str());
40 void StopProfiling() {
41 ProfilerFlush();
42 ProfilerStop();
45 void FlushProfiling() {
46 ProfilerFlush();
49 bool BeingProfiled() {
50 return ProfilingIsEnabledForAllThreads();
53 void RestartProfilingAfterFork() {
54 ProfilerRegisterThread();
57 #else
59 void StartProfiling(const std::string& name) {
62 void StopProfiling() {
65 void FlushProfiling() {
68 bool BeingProfiled() {
69 return false;
72 void RestartProfilingAfterFork() {
75 #endif
77 #if !defined(OS_WIN)
79 bool IsBinaryInstrumented() {
80 return false;
83 ReturnAddressLocationResolver GetProfilerReturnAddrResolutionFunc() {
84 return NULL;
87 DynamicFunctionEntryHook GetProfilerDynamicFunctionEntryHookFunc() {
88 return NULL;
91 AddDynamicSymbol GetProfilerAddDynamicSymbolFunc() {
92 return NULL;
95 MoveDynamicSymbol GetProfilerMoveDynamicSymbolFunc() {
96 return NULL;
99 #else // defined(OS_WIN)
101 // http://blogs.msdn.com/oldnewthing/archive/2004/10/25/247180.aspx
102 extern "C" IMAGE_DOS_HEADER __ImageBase;
104 bool IsBinaryInstrumented() {
105 enum InstrumentationCheckState {
106 UNINITIALIZED,
107 INSTRUMENTED_IMAGE,
108 NON_INSTRUMENTED_IMAGE,
111 static InstrumentationCheckState state = UNINITIALIZED;
113 if (state == UNINITIALIZED) {
114 HMODULE this_module = reinterpret_cast<HMODULE>(&__ImageBase);
115 base::win::PEImage image(this_module);
117 // Check to be sure our image is structured as we'd expect.
118 DCHECK(image.VerifyMagic());
120 // Syzygy-instrumented binaries contain a PE image section named ".thunks",
121 // and all Syzygy-modified binaries contain the ".syzygy" image section.
122 // This is a very fast check, as it only looks at the image header.
123 if ((image.GetImageSectionHeaderByName(".thunks") != NULL) &&
124 (image.GetImageSectionHeaderByName(".syzygy") != NULL)) {
125 state = INSTRUMENTED_IMAGE;
126 } else {
127 state = NON_INSTRUMENTED_IMAGE;
130 DCHECK(state != UNINITIALIZED);
132 return state == INSTRUMENTED_IMAGE;
135 namespace {
137 struct FunctionSearchContext {
138 const char* name;
139 FARPROC function;
142 // Callback function to PEImage::EnumImportChunks.
143 bool FindResolutionFunctionInImports(
144 const base::win::PEImage &image, const char* module_name,
145 PIMAGE_THUNK_DATA unused_name_table, PIMAGE_THUNK_DATA import_address_table,
146 PVOID cookie) {
147 FunctionSearchContext* context =
148 reinterpret_cast<FunctionSearchContext*>(cookie);
150 DCHECK_NE(static_cast<FunctionSearchContext*>(NULL), context);
151 DCHECK_EQ(static_cast<FARPROC>(NULL), context->function);
153 // Our import address table contains pointers to the functions we import
154 // at this point. Let's retrieve the first such function and use it to
155 // find the module this import was resolved to by the loader.
156 const wchar_t* function_in_module =
157 reinterpret_cast<const wchar_t*>(import_address_table->u1.Function);
159 // Retrieve the module by a function in the module.
160 const DWORD kFlags = GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
161 GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT;
162 HMODULE module = NULL;
163 if (!::GetModuleHandleEx(kFlags, function_in_module, &module)) {
164 // This can happen if someone IAT patches us to a thunk.
165 return true;
168 // See whether this module exports the function we're looking for.
169 FARPROC exported_func = ::GetProcAddress(module, context->name);
170 if (exported_func != NULL) {
171 // We found it, return the function and terminate the enumeration.
172 context->function = exported_func;
173 return false;
176 // Keep going.
177 return true;
180 template <typename FunctionType>
181 FunctionType FindFunctionInImports(const char* function_name) {
182 if (!IsBinaryInstrumented())
183 return NULL;
185 HMODULE this_module = reinterpret_cast<HMODULE>(&__ImageBase);
186 base::win::PEImage image(this_module);
188 FunctionSearchContext ctx = { function_name, NULL };
189 image.EnumImportChunks(FindResolutionFunctionInImports, &ctx);
191 return reinterpret_cast<FunctionType>(ctx.function);
194 } // namespace
196 ReturnAddressLocationResolver GetProfilerReturnAddrResolutionFunc() {
197 return FindFunctionInImports<ReturnAddressLocationResolver>(
198 "ResolveReturnAddressLocation");
201 DynamicFunctionEntryHook GetProfilerDynamicFunctionEntryHookFunc() {
202 return FindFunctionInImports<DynamicFunctionEntryHook>(
203 "OnDynamicFunctionEntry");
206 AddDynamicSymbol GetProfilerAddDynamicSymbolFunc() {
207 return FindFunctionInImports<AddDynamicSymbol>(
208 "AddDynamicSymbol");
211 MoveDynamicSymbol GetProfilerMoveDynamicSymbolFunc() {
212 return FindFunctionInImports<MoveDynamicSymbol>(
213 "MoveDynamicSymbol");
216 #endif // defined(OS_WIN)
218 } // namespace debug
219 } // namespace base