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/process/process_handle.h" 10 #include "base/strings/string_util.h" 11 #include "base/strings/stringprintf.h" 12 13 #if defined(OS_WIN) 14 #include "base/win/pe_image.h" 15 #endif // defined(OS_WIN) 16 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 21 22 namespace base { 23 namespace debug { 24 25 // TODO(peria): Enable profiling on Windows. 26 #if defined(ENABLE_PROFILING) && !defined(NO_TCMALLOC) && !defined(OS_WIN) 27 28 static int profile_count = 0; 29 30 void StartProfiling(const std::string& name) { 31 ++profile_count; 32 std::string full_name(name); 33 std::string pid = StringPrintf("%d", GetCurrentProcId()); 34 std::string count = StringPrintf("%d", profile_count); 35 ReplaceSubstringsAfterOffset(&full_name, 0, "{pid}", pid); 36 ReplaceSubstringsAfterOffset(&full_name, 0, "{count}", count); 37 ProfilerStart(full_name.c_str()); 38 } 39 40 void StopProfiling() { 41 ProfilerFlush(); 42 ProfilerStop(); 43 } 44 45 void FlushProfiling() { 46 ProfilerFlush(); 47 } 48 49 bool BeingProfiled() { 50 return ProfilingIsEnabledForAllThreads(); 51 } 52 53 void RestartProfilingAfterFork() { 54 ProfilerRegisterThread(); 55 } 56 57 #else 58 59 void StartProfiling(const std::string& name) { 60 } 61 62 void StopProfiling() { 63 } 64 65 void FlushProfiling() { 66 } 67 68 bool BeingProfiled() { 69 return false; 70 } 71 72 void RestartProfilingAfterFork() { 73 } 74 75 #endif 76 77 #if !defined(OS_WIN) 78 79 bool IsBinaryInstrumented() { 80 return false; 81 } 82 83 ReturnAddressLocationResolver GetProfilerReturnAddrResolutionFunc() { 84 return NULL; 85 } 86 87 DynamicFunctionEntryHook GetProfilerDynamicFunctionEntryHookFunc() { 88 return NULL; 89 } 90 91 AddDynamicSymbol GetProfilerAddDynamicSymbolFunc() { 92 return NULL; 93 } 94 95 MoveDynamicSymbol GetProfilerMoveDynamicSymbolFunc() { 96 return NULL; 97 } 98 99 #else // defined(OS_WIN) 100 101 // http://blogs.msdn.com/oldnewthing/archive/2004/10/25/247180.aspx 102 extern "C" IMAGE_DOS_HEADER __ImageBase; 103 104 bool IsBinaryInstrumented() { 105 enum InstrumentationCheckState { 106 UNINITIALIZED, 107 INSTRUMENTED_IMAGE, 108 NON_INSTRUMENTED_IMAGE, 109 }; 110 111 static InstrumentationCheckState state = UNINITIALIZED; 112 113 if (state == UNINITIALIZED) { 114 HMODULE this_module = reinterpret_cast<HMODULE>(&__ImageBase); 115 base::win::PEImage image(this_module); 116 117 // Check to be sure our image is structured as we'd expect. 118 DCHECK(image.VerifyMagic()); 119 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; 128 } 129 } 130 DCHECK(state != UNINITIALIZED); 131 132 return state == INSTRUMENTED_IMAGE; 133 } 134 135 namespace { 136 137 struct FunctionSearchContext { 138 const char* name; 139 FARPROC function; 140 }; 141 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); 149 150 DCHECK_NE(static_cast<FunctionSearchContext*>(NULL), context); 151 DCHECK_EQ(static_cast<FARPROC>(NULL), context->function); 152 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); 158 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; 166 } 167 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; 174 } 175 176 // Keep going. 177 return true; 178 } 179 180 template <typename FunctionType> 181 FunctionType FindFunctionInImports(const char* function_name) { 182 if (!IsBinaryInstrumented()) 183 return NULL; 184 185 HMODULE this_module = reinterpret_cast<HMODULE>(&__ImageBase); 186 base::win::PEImage image(this_module); 187 188 FunctionSearchContext ctx = { function_name, NULL }; 189 image.EnumImportChunks(FindResolutionFunctionInImports, &ctx); 190 191 return reinterpret_cast<FunctionType>(ctx.function); 192 } 193 194 } // namespace 195 196 ReturnAddressLocationResolver GetProfilerReturnAddrResolutionFunc() { 197 return FindFunctionInImports<ReturnAddressLocationResolver>( 198 "ResolveReturnAddressLocation"); 199 } 200 201 DynamicFunctionEntryHook GetProfilerDynamicFunctionEntryHookFunc() { 202 return FindFunctionInImports<DynamicFunctionEntryHook>( 203 "OnDynamicFunctionEntry"); 204 } 205 206 AddDynamicSymbol GetProfilerAddDynamicSymbolFunc() { 207 return FindFunctionInImports<AddDynamicSymbol>( 208 "AddDynamicSymbol"); 209 } 210 211 MoveDynamicSymbol GetProfilerMoveDynamicSymbolFunc() { 212 return FindFunctionInImports<MoveDynamicSymbol>( 213 "MoveDynamicSymbol"); 214 } 215 216 #endif // defined(OS_WIN) 217 218 } // namespace debug 219 } // namespace base 220