1*635a8641SAndroid Build Coastguard Worker // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2*635a8641SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*635a8641SAndroid Build Coastguard Worker // found in the LICENSE file.
4*635a8641SAndroid Build Coastguard Worker
5*635a8641SAndroid Build Coastguard Worker #include "base/debug/profiler.h"
6*635a8641SAndroid Build Coastguard Worker
7*635a8641SAndroid Build Coastguard Worker #include <string>
8*635a8641SAndroid Build Coastguard Worker
9*635a8641SAndroid Build Coastguard Worker #include "base/debug/debugging_buildflags.h"
10*635a8641SAndroid Build Coastguard Worker #include "base/process/process_handle.h"
11*635a8641SAndroid Build Coastguard Worker #include "base/strings/string_number_conversions.h"
12*635a8641SAndroid Build Coastguard Worker #include "base/strings/string_util.h"
13*635a8641SAndroid Build Coastguard Worker #include "build/build_config.h"
14*635a8641SAndroid Build Coastguard Worker
15*635a8641SAndroid Build Coastguard Worker #if defined(OS_WIN)
16*635a8641SAndroid Build Coastguard Worker #include "base/win/current_module.h"
17*635a8641SAndroid Build Coastguard Worker #include "base/win/pe_image.h"
18*635a8641SAndroid Build Coastguard Worker #endif // defined(OS_WIN)
19*635a8641SAndroid Build Coastguard Worker
20*635a8641SAndroid Build Coastguard Worker // TODO(peria): Enable profiling on Windows.
21*635a8641SAndroid Build Coastguard Worker #if BUILDFLAG(ENABLE_PROFILING) && !defined(NO_TCMALLOC) && !defined(OS_WIN)
22*635a8641SAndroid Build Coastguard Worker #include "third_party/tcmalloc/gperftools-2.0/chromium/src/gperftools/profiler.h"
23*635a8641SAndroid Build Coastguard Worker #endif
24*635a8641SAndroid Build Coastguard Worker
25*635a8641SAndroid Build Coastguard Worker namespace base {
26*635a8641SAndroid Build Coastguard Worker namespace debug {
27*635a8641SAndroid Build Coastguard Worker
28*635a8641SAndroid Build Coastguard Worker // TODO(peria): Enable profiling on Windows.
29*635a8641SAndroid Build Coastguard Worker #if BUILDFLAG(ENABLE_PROFILING) && !defined(NO_TCMALLOC) && !defined(OS_WIN)
30*635a8641SAndroid Build Coastguard Worker
31*635a8641SAndroid Build Coastguard Worker static int profile_count = 0;
32*635a8641SAndroid Build Coastguard Worker
StartProfiling(const std::string & name)33*635a8641SAndroid Build Coastguard Worker void StartProfiling(const std::string& name) {
34*635a8641SAndroid Build Coastguard Worker ++profile_count;
35*635a8641SAndroid Build Coastguard Worker std::string full_name(name);
36*635a8641SAndroid Build Coastguard Worker std::string pid = IntToString(GetCurrentProcId());
37*635a8641SAndroid Build Coastguard Worker std::string count = IntToString(profile_count);
38*635a8641SAndroid Build Coastguard Worker ReplaceSubstringsAfterOffset(&full_name, 0, "{pid}", pid);
39*635a8641SAndroid Build Coastguard Worker ReplaceSubstringsAfterOffset(&full_name, 0, "{count}", count);
40*635a8641SAndroid Build Coastguard Worker ProfilerStart(full_name.c_str());
41*635a8641SAndroid Build Coastguard Worker }
42*635a8641SAndroid Build Coastguard Worker
StopProfiling()43*635a8641SAndroid Build Coastguard Worker void StopProfiling() {
44*635a8641SAndroid Build Coastguard Worker ProfilerFlush();
45*635a8641SAndroid Build Coastguard Worker ProfilerStop();
46*635a8641SAndroid Build Coastguard Worker }
47*635a8641SAndroid Build Coastguard Worker
FlushProfiling()48*635a8641SAndroid Build Coastguard Worker void FlushProfiling() {
49*635a8641SAndroid Build Coastguard Worker ProfilerFlush();
50*635a8641SAndroid Build Coastguard Worker }
51*635a8641SAndroid Build Coastguard Worker
BeingProfiled()52*635a8641SAndroid Build Coastguard Worker bool BeingProfiled() {
53*635a8641SAndroid Build Coastguard Worker return ProfilingIsEnabledForAllThreads();
54*635a8641SAndroid Build Coastguard Worker }
55*635a8641SAndroid Build Coastguard Worker
RestartProfilingAfterFork()56*635a8641SAndroid Build Coastguard Worker void RestartProfilingAfterFork() {
57*635a8641SAndroid Build Coastguard Worker ProfilerRegisterThread();
58*635a8641SAndroid Build Coastguard Worker }
59*635a8641SAndroid Build Coastguard Worker
IsProfilingSupported()60*635a8641SAndroid Build Coastguard Worker bool IsProfilingSupported() {
61*635a8641SAndroid Build Coastguard Worker return true;
62*635a8641SAndroid Build Coastguard Worker }
63*635a8641SAndroid Build Coastguard Worker
64*635a8641SAndroid Build Coastguard Worker #else
65*635a8641SAndroid Build Coastguard Worker
66*635a8641SAndroid Build Coastguard Worker void StartProfiling(const std::string& name) {
67*635a8641SAndroid Build Coastguard Worker }
68*635a8641SAndroid Build Coastguard Worker
69*635a8641SAndroid Build Coastguard Worker void StopProfiling() {
70*635a8641SAndroid Build Coastguard Worker }
71*635a8641SAndroid Build Coastguard Worker
72*635a8641SAndroid Build Coastguard Worker void FlushProfiling() {
73*635a8641SAndroid Build Coastguard Worker }
74*635a8641SAndroid Build Coastguard Worker
75*635a8641SAndroid Build Coastguard Worker bool BeingProfiled() {
76*635a8641SAndroid Build Coastguard Worker return false;
77*635a8641SAndroid Build Coastguard Worker }
78*635a8641SAndroid Build Coastguard Worker
79*635a8641SAndroid Build Coastguard Worker void RestartProfilingAfterFork() {
80*635a8641SAndroid Build Coastguard Worker }
81*635a8641SAndroid Build Coastguard Worker
82*635a8641SAndroid Build Coastguard Worker bool IsProfilingSupported() {
83*635a8641SAndroid Build Coastguard Worker return false;
84*635a8641SAndroid Build Coastguard Worker }
85*635a8641SAndroid Build Coastguard Worker
86*635a8641SAndroid Build Coastguard Worker #endif
87*635a8641SAndroid Build Coastguard Worker
88*635a8641SAndroid Build Coastguard Worker #if !defined(OS_WIN)
89*635a8641SAndroid Build Coastguard Worker
GetProfilerReturnAddrResolutionFunc()90*635a8641SAndroid Build Coastguard Worker ReturnAddressLocationResolver GetProfilerReturnAddrResolutionFunc() {
91*635a8641SAndroid Build Coastguard Worker return nullptr;
92*635a8641SAndroid Build Coastguard Worker }
93*635a8641SAndroid Build Coastguard Worker
GetProfilerDynamicFunctionEntryHookFunc()94*635a8641SAndroid Build Coastguard Worker DynamicFunctionEntryHook GetProfilerDynamicFunctionEntryHookFunc() {
95*635a8641SAndroid Build Coastguard Worker return nullptr;
96*635a8641SAndroid Build Coastguard Worker }
97*635a8641SAndroid Build Coastguard Worker
GetProfilerAddDynamicSymbolFunc()98*635a8641SAndroid Build Coastguard Worker AddDynamicSymbol GetProfilerAddDynamicSymbolFunc() {
99*635a8641SAndroid Build Coastguard Worker return nullptr;
100*635a8641SAndroid Build Coastguard Worker }
101*635a8641SAndroid Build Coastguard Worker
GetProfilerMoveDynamicSymbolFunc()102*635a8641SAndroid Build Coastguard Worker MoveDynamicSymbol GetProfilerMoveDynamicSymbolFunc() {
103*635a8641SAndroid Build Coastguard Worker return nullptr;
104*635a8641SAndroid Build Coastguard Worker }
105*635a8641SAndroid Build Coastguard Worker
106*635a8641SAndroid Build Coastguard Worker #else // defined(OS_WIN)
107*635a8641SAndroid Build Coastguard Worker
108*635a8641SAndroid Build Coastguard Worker namespace {
109*635a8641SAndroid Build Coastguard Worker
110*635a8641SAndroid Build Coastguard Worker struct FunctionSearchContext {
111*635a8641SAndroid Build Coastguard Worker const char* name;
112*635a8641SAndroid Build Coastguard Worker FARPROC function;
113*635a8641SAndroid Build Coastguard Worker };
114*635a8641SAndroid Build Coastguard Worker
115*635a8641SAndroid Build Coastguard Worker // Callback function to PEImage::EnumImportChunks.
FindResolutionFunctionInImports(const base::win::PEImage & image,const char * module_name,PIMAGE_THUNK_DATA unused_name_table,PIMAGE_THUNK_DATA import_address_table,PVOID cookie)116*635a8641SAndroid Build Coastguard Worker bool FindResolutionFunctionInImports(
117*635a8641SAndroid Build Coastguard Worker const base::win::PEImage &image, const char* module_name,
118*635a8641SAndroid Build Coastguard Worker PIMAGE_THUNK_DATA unused_name_table, PIMAGE_THUNK_DATA import_address_table,
119*635a8641SAndroid Build Coastguard Worker PVOID cookie) {
120*635a8641SAndroid Build Coastguard Worker FunctionSearchContext* context =
121*635a8641SAndroid Build Coastguard Worker reinterpret_cast<FunctionSearchContext*>(cookie);
122*635a8641SAndroid Build Coastguard Worker
123*635a8641SAndroid Build Coastguard Worker DCHECK(context);
124*635a8641SAndroid Build Coastguard Worker DCHECK(!context->function);
125*635a8641SAndroid Build Coastguard Worker
126*635a8641SAndroid Build Coastguard Worker // Our import address table contains pointers to the functions we import
127*635a8641SAndroid Build Coastguard Worker // at this point. Let's retrieve the first such function and use it to
128*635a8641SAndroid Build Coastguard Worker // find the module this import was resolved to by the loader.
129*635a8641SAndroid Build Coastguard Worker const wchar_t* function_in_module =
130*635a8641SAndroid Build Coastguard Worker reinterpret_cast<const wchar_t*>(import_address_table->u1.Function);
131*635a8641SAndroid Build Coastguard Worker
132*635a8641SAndroid Build Coastguard Worker // Retrieve the module by a function in the module.
133*635a8641SAndroid Build Coastguard Worker const DWORD kFlags = GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
134*635a8641SAndroid Build Coastguard Worker GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT;
135*635a8641SAndroid Build Coastguard Worker HMODULE module = NULL;
136*635a8641SAndroid Build Coastguard Worker if (!::GetModuleHandleEx(kFlags, function_in_module, &module)) {
137*635a8641SAndroid Build Coastguard Worker // This can happen if someone IAT patches us to a thunk.
138*635a8641SAndroid Build Coastguard Worker return true;
139*635a8641SAndroid Build Coastguard Worker }
140*635a8641SAndroid Build Coastguard Worker
141*635a8641SAndroid Build Coastguard Worker // See whether this module exports the function we're looking for.
142*635a8641SAndroid Build Coastguard Worker FARPROC exported_func = ::GetProcAddress(module, context->name);
143*635a8641SAndroid Build Coastguard Worker if (exported_func != NULL) {
144*635a8641SAndroid Build Coastguard Worker // We found it, return the function and terminate the enumeration.
145*635a8641SAndroid Build Coastguard Worker context->function = exported_func;
146*635a8641SAndroid Build Coastguard Worker return false;
147*635a8641SAndroid Build Coastguard Worker }
148*635a8641SAndroid Build Coastguard Worker
149*635a8641SAndroid Build Coastguard Worker // Keep going.
150*635a8641SAndroid Build Coastguard Worker return true;
151*635a8641SAndroid Build Coastguard Worker }
152*635a8641SAndroid Build Coastguard Worker
153*635a8641SAndroid Build Coastguard Worker template <typename FunctionType>
FindFunctionInImports(const char * function_name)154*635a8641SAndroid Build Coastguard Worker FunctionType FindFunctionInImports(const char* function_name) {
155*635a8641SAndroid Build Coastguard Worker base::win::PEImage image(CURRENT_MODULE());
156*635a8641SAndroid Build Coastguard Worker
157*635a8641SAndroid Build Coastguard Worker FunctionSearchContext ctx = { function_name, NULL };
158*635a8641SAndroid Build Coastguard Worker image.EnumImportChunks(FindResolutionFunctionInImports, &ctx);
159*635a8641SAndroid Build Coastguard Worker
160*635a8641SAndroid Build Coastguard Worker return reinterpret_cast<FunctionType>(ctx.function);
161*635a8641SAndroid Build Coastguard Worker }
162*635a8641SAndroid Build Coastguard Worker
163*635a8641SAndroid Build Coastguard Worker } // namespace
164*635a8641SAndroid Build Coastguard Worker
GetProfilerReturnAddrResolutionFunc()165*635a8641SAndroid Build Coastguard Worker ReturnAddressLocationResolver GetProfilerReturnAddrResolutionFunc() {
166*635a8641SAndroid Build Coastguard Worker return FindFunctionInImports<ReturnAddressLocationResolver>(
167*635a8641SAndroid Build Coastguard Worker "ResolveReturnAddressLocation");
168*635a8641SAndroid Build Coastguard Worker }
169*635a8641SAndroid Build Coastguard Worker
GetProfilerDynamicFunctionEntryHookFunc()170*635a8641SAndroid Build Coastguard Worker DynamicFunctionEntryHook GetProfilerDynamicFunctionEntryHookFunc() {
171*635a8641SAndroid Build Coastguard Worker return FindFunctionInImports<DynamicFunctionEntryHook>(
172*635a8641SAndroid Build Coastguard Worker "OnDynamicFunctionEntry");
173*635a8641SAndroid Build Coastguard Worker }
174*635a8641SAndroid Build Coastguard Worker
GetProfilerAddDynamicSymbolFunc()175*635a8641SAndroid Build Coastguard Worker AddDynamicSymbol GetProfilerAddDynamicSymbolFunc() {
176*635a8641SAndroid Build Coastguard Worker return FindFunctionInImports<AddDynamicSymbol>(
177*635a8641SAndroid Build Coastguard Worker "AddDynamicSymbol");
178*635a8641SAndroid Build Coastguard Worker }
179*635a8641SAndroid Build Coastguard Worker
GetProfilerMoveDynamicSymbolFunc()180*635a8641SAndroid Build Coastguard Worker MoveDynamicSymbol GetProfilerMoveDynamicSymbolFunc() {
181*635a8641SAndroid Build Coastguard Worker return FindFunctionInImports<MoveDynamicSymbol>(
182*635a8641SAndroid Build Coastguard Worker "MoveDynamicSymbol");
183*635a8641SAndroid Build Coastguard Worker }
184*635a8641SAndroid Build Coastguard Worker
185*635a8641SAndroid Build Coastguard Worker #endif // defined(OS_WIN)
186*635a8641SAndroid Build Coastguard Worker
187*635a8641SAndroid Build Coastguard Worker } // namespace debug
188*635a8641SAndroid Build Coastguard Worker } // namespace base
189