Home | History | Annotate | Download | only in debug
      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