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