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_flags.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/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 bool IsBinaryInstrumented() { 91 return false; 92 } 93 94 ReturnAddressLocationResolver GetProfilerReturnAddrResolutionFunc() { 95 return NULL; 96 } 97 98 DynamicFunctionEntryHook GetProfilerDynamicFunctionEntryHookFunc() { 99 return NULL; 100 } 101 102 AddDynamicSymbol GetProfilerAddDynamicSymbolFunc() { 103 return NULL; 104 } 105 106 MoveDynamicSymbol GetProfilerMoveDynamicSymbolFunc() { 107 return NULL; 108 } 109 110 #else // defined(OS_WIN) 111 112 bool IsBinaryInstrumented() { 113 enum InstrumentationCheckState { 114 UNINITIALIZED, 115 INSTRUMENTED_IMAGE, 116 NON_INSTRUMENTED_IMAGE, 117 }; 118 119 static InstrumentationCheckState state = UNINITIALIZED; 120 121 if (state == UNINITIALIZED) { 122 base::win::PEImage image(CURRENT_MODULE()); 123 124 // Check to be sure our image is structured as we'd expect. 125 DCHECK(image.VerifyMagic()); 126 127 // Syzygy-instrumented binaries contain a PE image section named ".thunks", 128 // and all Syzygy-modified binaries contain the ".syzygy" image section. 129 // This is a very fast check, as it only looks at the image header. 130 if ((image.GetImageSectionHeaderByName(".thunks") != NULL) && 131 (image.GetImageSectionHeaderByName(".syzygy") != NULL)) { 132 state = INSTRUMENTED_IMAGE; 133 } else { 134 state = NON_INSTRUMENTED_IMAGE; 135 } 136 } 137 DCHECK(state != UNINITIALIZED); 138 139 return state == INSTRUMENTED_IMAGE; 140 } 141 142 namespace { 143 144 struct FunctionSearchContext { 145 const char* name; 146 FARPROC function; 147 }; 148 149 // Callback function to PEImage::EnumImportChunks. 150 bool FindResolutionFunctionInImports( 151 const base::win::PEImage &image, const char* module_name, 152 PIMAGE_THUNK_DATA unused_name_table, PIMAGE_THUNK_DATA import_address_table, 153 PVOID cookie) { 154 FunctionSearchContext* context = 155 reinterpret_cast<FunctionSearchContext*>(cookie); 156 157 DCHECK(context); 158 DCHECK(!context->function); 159 160 // Our import address table contains pointers to the functions we import 161 // at this point. Let's retrieve the first such function and use it to 162 // find the module this import was resolved to by the loader. 163 const wchar_t* function_in_module = 164 reinterpret_cast<const wchar_t*>(import_address_table->u1.Function); 165 166 // Retrieve the module by a function in the module. 167 const DWORD kFlags = GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | 168 GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT; 169 HMODULE module = NULL; 170 if (!::GetModuleHandleEx(kFlags, function_in_module, &module)) { 171 // This can happen if someone IAT patches us to a thunk. 172 return true; 173 } 174 175 // See whether this module exports the function we're looking for. 176 FARPROC exported_func = ::GetProcAddress(module, context->name); 177 if (exported_func != NULL) { 178 // We found it, return the function and terminate the enumeration. 179 context->function = exported_func; 180 return false; 181 } 182 183 // Keep going. 184 return true; 185 } 186 187 template <typename FunctionType> 188 FunctionType FindFunctionInImports(const char* function_name) { 189 if (!IsBinaryInstrumented()) 190 return NULL; 191 192 base::win::PEImage image(CURRENT_MODULE()); 193 194 FunctionSearchContext ctx = { function_name, NULL }; 195 image.EnumImportChunks(FindResolutionFunctionInImports, &ctx); 196 197 return reinterpret_cast<FunctionType>(ctx.function); 198 } 199 200 } // namespace 201 202 ReturnAddressLocationResolver GetProfilerReturnAddrResolutionFunc() { 203 return FindFunctionInImports<ReturnAddressLocationResolver>( 204 "ResolveReturnAddressLocation"); 205 } 206 207 DynamicFunctionEntryHook GetProfilerDynamicFunctionEntryHookFunc() { 208 return FindFunctionInImports<DynamicFunctionEntryHook>( 209 "OnDynamicFunctionEntry"); 210 } 211 212 AddDynamicSymbol GetProfilerAddDynamicSymbolFunc() { 213 return FindFunctionInImports<AddDynamicSymbol>( 214 "AddDynamicSymbol"); 215 } 216 217 MoveDynamicSymbol GetProfilerMoveDynamicSymbolFunc() { 218 return FindFunctionInImports<MoveDynamicSymbol>( 219 "MoveDynamicSymbol"); 220 } 221 222 #endif // defined(OS_WIN) 223 224 } // namespace debug 225 } // namespace base 226