| Index: base/debug/profiler.cc
|
| diff --git a/base/debug/profiler.cc b/base/debug/profiler.cc
|
| index b14120416eaf247da03592e2ffdc040b8090d6ef..825aa3828b06eaa66a67a1c909964721b07d5f0e 100644
|
| --- a/base/debug/profiler.cc
|
| +++ b/base/debug/profiler.cc
|
| @@ -1,177 +1,217 @@
|
| -// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -#include "base/debug/profiler.h"
|
| -
|
| -#include <string>
|
| -
|
| -#include "base/process_util.h"
|
| -#include "base/strings/string_util.h"
|
| -#include "base/strings/stringprintf.h"
|
| -
|
| -#if defined(OS_WIN)
|
| -#include "base/win/pe_image.h"
|
| -#endif // defined(OS_WIN)
|
| -
|
| -#if defined(ENABLE_PROFILING) && !defined(NO_TCMALLOC)
|
| -#include "third_party/tcmalloc/chromium/src/gperftools/profiler.h"
|
| -#endif
|
| -
|
| -namespace base {
|
| -namespace debug {
|
| -
|
| -#if defined(ENABLE_PROFILING) && !defined(NO_TCMALLOC)
|
| -
|
| -static int profile_count = 0;
|
| -
|
| -void StartProfiling(const std::string& name) {
|
| - ++profile_count;
|
| - std::string full_name(name);
|
| - std::string pid = StringPrintf("%d", GetCurrentProcId());
|
| - std::string count = StringPrintf("%d", profile_count);
|
| - ReplaceSubstringsAfterOffset(&full_name, 0, "{pid}", pid);
|
| - ReplaceSubstringsAfterOffset(&full_name, 0, "{count}", count);
|
| - ProfilerStart(full_name.c_str());
|
| -}
|
| -
|
| -void StopProfiling() {
|
| - ProfilerFlush();
|
| - ProfilerStop();
|
| -}
|
| -
|
| -void FlushProfiling() {
|
| - ProfilerFlush();
|
| -}
|
| -
|
| -bool BeingProfiled() {
|
| - return ProfilingIsEnabledForAllThreads();
|
| -}
|
| -
|
| -void RestartProfilingAfterFork() {
|
| - ProfilerRegisterThread();
|
| -}
|
| -
|
| -#else
|
| -
|
| -void StartProfiling(const std::string& name) {
|
| -}
|
| -
|
| -void StopProfiling() {
|
| -}
|
| -
|
| -void FlushProfiling() {
|
| -}
|
| -
|
| -bool BeingProfiled() {
|
| - return false;
|
| -}
|
| -
|
| -void RestartProfilingAfterFork() {
|
| -}
|
| -
|
| -#endif
|
| -
|
| -#if !defined(OS_WIN)
|
| -
|
| -bool IsBinaryInstrumented() {
|
| - return false;
|
| -}
|
| -
|
| -ReturnAddressLocationResolver GetProfilerReturnAddrResolutionFunc() {
|
| - return NULL;
|
| -}
|
| -
|
| -#else // defined(OS_WIN)
|
| -
|
| -// http://blogs.msdn.com/oldnewthing/archive/2004/10/25/247180.aspx
|
| -extern "C" IMAGE_DOS_HEADER __ImageBase;
|
| -
|
| -bool IsBinaryInstrumented() {
|
| - enum InstrumentationCheckState {
|
| - UNINITIALIZED,
|
| - INSTRUMENTED_IMAGE,
|
| - NON_INSTRUMENTED_IMAGE,
|
| - };
|
| -
|
| - static InstrumentationCheckState state = UNINITIALIZED;
|
| -
|
| - if (state == UNINITIALIZED) {
|
| - HMODULE this_module = reinterpret_cast<HMODULE>(&__ImageBase);
|
| - base::win::PEImage image(this_module);
|
| -
|
| - // Check to be sure our image is structured as we'd expect.
|
| - DCHECK(image.VerifyMagic());
|
| -
|
| - // Syzygy-instrumented binaries contain a PE image section named ".thunks",
|
| - // and all Syzygy-modified binaries contain the ".syzygy" image section.
|
| - // This is a very fast check, as it only looks at the image header.
|
| - if ((image.GetImageSectionHeaderByName(".thunks") != NULL) &&
|
| - (image.GetImageSectionHeaderByName(".syzygy") != NULL)) {
|
| - state = INSTRUMENTED_IMAGE;
|
| - } else {
|
| - state = NON_INSTRUMENTED_IMAGE;
|
| - }
|
| - }
|
| - DCHECK(state != UNINITIALIZED);
|
| -
|
| - return state == INSTRUMENTED_IMAGE;
|
| -}
|
| -
|
| -// Callback function to PEImage::EnumImportChunks.
|
| -static bool FindResolutionFunctionInImports(
|
| - const base::win::PEImage &image, const char* module_name,
|
| - PIMAGE_THUNK_DATA unused_name_table, PIMAGE_THUNK_DATA import_address_table,
|
| - PVOID cookie) {
|
| - // Our import address table contains pointers to the functions we import
|
| - // at this point. Let's retrieve the first such function and use it to
|
| - // find the module this import was resolved to by the loader.
|
| - const wchar_t* function_in_module =
|
| - reinterpret_cast<const wchar_t*>(import_address_table->u1.Function);
|
| -
|
| - // Retrieve the module by a function in the module.
|
| - const DWORD kFlags = GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
|
| - GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT;
|
| - HMODULE module = NULL;
|
| - if (!::GetModuleHandleEx(kFlags, function_in_module, &module)) {
|
| - // This can happen if someone IAT patches us to a thunk.
|
| - return true;
|
| - }
|
| -
|
| - // See whether this module exports the function we're looking for.
|
| - ReturnAddressLocationResolver exported_func =
|
| - reinterpret_cast<ReturnAddressLocationResolver>(
|
| - ::GetProcAddress(module, "ResolveReturnAddressLocation"));
|
| -
|
| - if (exported_func != NULL) {
|
| - ReturnAddressLocationResolver* resolver_func =
|
| - reinterpret_cast<ReturnAddressLocationResolver*>(cookie);
|
| - DCHECK(resolver_func != NULL);
|
| - DCHECK(*resolver_func == NULL);
|
| -
|
| - // We found it, return the function and terminate the enumeration.
|
| - *resolver_func = exported_func;
|
| - return false;
|
| - }
|
| -
|
| - // Keep going.
|
| - return true;
|
| -}
|
| -
|
| -ReturnAddressLocationResolver GetProfilerReturnAddrResolutionFunc() {
|
| - if (!IsBinaryInstrumented())
|
| - return NULL;
|
| -
|
| - HMODULE this_module = reinterpret_cast<HMODULE>(&__ImageBase);
|
| - base::win::PEImage image(this_module);
|
| -
|
| - ReturnAddressLocationResolver resolver_func = NULL;
|
| - image.EnumImportChunks(FindResolutionFunctionInImports, &resolver_func);
|
| -
|
| - return resolver_func;
|
| -}
|
| -
|
| -#endif // defined(OS_WIN)
|
| -
|
| -} // namespace debug
|
| -} // namespace base
|
| +// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "base/debug/profiler.h"
|
| +
|
| +#include <string>
|
| +
|
| +#include "base/process_util.h"
|
| +#include "base/strings/string_util.h"
|
| +#include "base/strings/stringprintf.h"
|
| +
|
| +#if defined(OS_WIN)
|
| +#include "base/win/pe_image.h"
|
| +#endif // defined(OS_WIN)
|
| +
|
| +#if defined(ENABLE_PROFILING) && !defined(NO_TCMALLOC)
|
| +#include "third_party/tcmalloc/chromium/src/gperftools/profiler.h"
|
| +#endif
|
| +
|
| +namespace base {
|
| +namespace debug {
|
| +
|
| +#if defined(ENABLE_PROFILING) && !defined(NO_TCMALLOC)
|
| +
|
| +static int profile_count = 0;
|
| +
|
| +void StartProfiling(const std::string& name) {
|
| + ++profile_count;
|
| + std::string full_name(name);
|
| + std::string pid = StringPrintf("%d", GetCurrentProcId());
|
| + std::string count = StringPrintf("%d", profile_count);
|
| + ReplaceSubstringsAfterOffset(&full_name, 0, "{pid}", pid);
|
| + ReplaceSubstringsAfterOffset(&full_name, 0, "{count}", count);
|
| + ProfilerStart(full_name.c_str());
|
| +}
|
| +
|
| +void StopProfiling() {
|
| + ProfilerFlush();
|
| + ProfilerStop();
|
| +}
|
| +
|
| +void FlushProfiling() {
|
| + ProfilerFlush();
|
| +}
|
| +
|
| +bool BeingProfiled() {
|
| + return ProfilingIsEnabledForAllThreads();
|
| +}
|
| +
|
| +void RestartProfilingAfterFork() {
|
| + ProfilerRegisterThread();
|
| +}
|
| +
|
| +#else
|
| +
|
| +void StartProfiling(const std::string& name) {
|
| +}
|
| +
|
| +void StopProfiling() {
|
| +}
|
| +
|
| +void FlushProfiling() {
|
| +}
|
| +
|
| +bool BeingProfiled() {
|
| + return false;
|
| +}
|
| +
|
| +void RestartProfilingAfterFork() {
|
| +}
|
| +
|
| +#endif
|
| +
|
| +#if !defined(OS_WIN)
|
| +
|
| +bool IsBinaryInstrumented() {
|
| + return false;
|
| +}
|
| +
|
| +ReturnAddressLocationResolver GetProfilerReturnAddrResolutionFunc() {
|
| + return NULL;
|
| +}
|
| +
|
| +DynamicFunctionEntryHook GetProfilerDynamicFunctionEntryHookFunc() {
|
| + return NULL;
|
| +}
|
| +
|
| +AddDynamicSymbol GetProfilerAddDynamicSymbolFunc() {
|
| + return NULL;
|
| +}
|
| +
|
| +MoveDynamicSymbol GetProfilerMoveDynamicSymbolFunc() {
|
| + return NULL;
|
| +}
|
| +
|
| +#else // defined(OS_WIN)
|
| +
|
| +// http://blogs.msdn.com/oldnewthing/archive/2004/10/25/247180.aspx
|
| +extern "C" IMAGE_DOS_HEADER __ImageBase;
|
| +
|
| +bool IsBinaryInstrumented() {
|
| + enum InstrumentationCheckState {
|
| + UNINITIALIZED,
|
| + INSTRUMENTED_IMAGE,
|
| + NON_INSTRUMENTED_IMAGE,
|
| + };
|
| +
|
| + static InstrumentationCheckState state = UNINITIALIZED;
|
| +
|
| + if (state == UNINITIALIZED) {
|
| + HMODULE this_module = reinterpret_cast<HMODULE>(&__ImageBase);
|
| + base::win::PEImage image(this_module);
|
| +
|
| + // Check to be sure our image is structured as we'd expect.
|
| + DCHECK(image.VerifyMagic());
|
| +
|
| + // Syzygy-instrumented binaries contain a PE image section named ".thunks",
|
| + // and all Syzygy-modified binaries contain the ".syzygy" image section.
|
| + // This is a very fast check, as it only looks at the image header.
|
| + if ((image.GetImageSectionHeaderByName(".thunks") != NULL) &&
|
| + (image.GetImageSectionHeaderByName(".syzygy") != NULL)) {
|
| + state = INSTRUMENTED_IMAGE;
|
| + } else {
|
| + state = NON_INSTRUMENTED_IMAGE;
|
| + }
|
| + }
|
| + DCHECK(state != UNINITIALIZED);
|
| +
|
| + return state == INSTRUMENTED_IMAGE;
|
| +}
|
| +
|
| +namespace {
|
| +
|
| +struct FunctionSearchContext {
|
| + const char* name;
|
| + FARPROC function;
|
| +};
|
| +
|
| +// Callback function to PEImage::EnumImportChunks.
|
| +bool FindResolutionFunctionInImports(
|
| + const base::win::PEImage &image, const char* module_name,
|
| + PIMAGE_THUNK_DATA unused_name_table, PIMAGE_THUNK_DATA import_address_table,
|
| + PVOID cookie) {
|
| + FunctionSearchContext* context =
|
| + reinterpret_cast<FunctionSearchContext*>(cookie);
|
| +
|
| + DCHECK_NE(static_cast<FunctionSearchContext*>(NULL), context);
|
| + DCHECK_EQ(static_cast<FARPROC>(NULL), context->function);
|
| +
|
| + // Our import address table contains pointers to the functions we import
|
| + // at this point. Let's retrieve the first such function and use it to
|
| + // find the module this import was resolved to by the loader.
|
| + const wchar_t* function_in_module =
|
| + reinterpret_cast<const wchar_t*>(import_address_table->u1.Function);
|
| +
|
| + // Retrieve the module by a function in the module.
|
| + const DWORD kFlags = GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
|
| + GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT;
|
| + HMODULE module = NULL;
|
| + if (!::GetModuleHandleEx(kFlags, function_in_module, &module)) {
|
| + // This can happen if someone IAT patches us to a thunk.
|
| + return true;
|
| + }
|
| +
|
| + // See whether this module exports the function we're looking for.
|
| + FARPROC exported_func = ::GetProcAddress(module, context->name);
|
| + if (exported_func != NULL) {
|
| + // We found it, return the function and terminate the enumeration.
|
| + context->function = exported_func;
|
| + return false;
|
| + }
|
| +
|
| + // Keep going.
|
| + return true;
|
| +}
|
| +
|
| +template <typename FunctionType>
|
| +FunctionType FindFunctionInImports(const char* function_name) {
|
| + if (!IsBinaryInstrumented())
|
| + return NULL;
|
| +
|
| + HMODULE this_module = reinterpret_cast<HMODULE>(&__ImageBase);
|
| + base::win::PEImage image(this_module);
|
| +
|
| + FunctionSearchContext ctx = { function_name, NULL };
|
| + image.EnumImportChunks(FindResolutionFunctionInImports, &ctx);
|
| +
|
| + return reinterpret_cast<FunctionType>(ctx.function);
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +ReturnAddressLocationResolver GetProfilerReturnAddrResolutionFunc() {
|
| + return FindFunctionInImports<ReturnAddressLocationResolver>(
|
| + "ResolveReturnAddressLocation");
|
| +}
|
| +
|
| +DynamicFunctionEntryHook GetProfilerDynamicFunctionEntryHookFunc() {
|
| + return FindFunctionInImports<DynamicFunctionEntryHook>(
|
| + "OnDynamicFunctionEntry");
|
| +}
|
| +
|
| +AddDynamicSymbol GetProfilerAddDynamicSymbolFunc() {
|
| + return FindFunctionInImports<AddDynamicSymbol>(
|
| + "AddDynamicSymbol");
|
| +}
|
| +
|
| +MoveDynamicSymbol GetProfilerMoveDynamicSymbolFunc() {
|
| + return FindFunctionInImports<MoveDynamicSymbol>(
|
| + "MoveDynamicSymbol");
|
| +}
|
| +
|
| +#endif // defined(OS_WIN)
|
| +
|
| +} // namespace debug
|
| +} // namespace base
|
|
|