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.
5 #include "base/debug/profiler.h"
9 #include "base/process/process_handle.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "base/strings/string_util.h"
14 #include "base/win/pe_image.h"
15 #endif // defined(OS_WIN)
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"
25 // TODO(peria): Enable profiling on Windows.
26 #if defined(ENABLE_PROFILING) && !defined(NO_TCMALLOC) && !defined(OS_WIN)
28 static int profile_count
= 0;
30 void StartProfiling(const std::string
& name
) {
32 std::string
full_name(name
);
33 std::string pid
= IntToString(GetCurrentProcId());
34 std::string count
= IntToString(profile_count
);
35 ReplaceSubstringsAfterOffset(&full_name
, 0, "{pid}", pid
);
36 ReplaceSubstringsAfterOffset(&full_name
, 0, "{count}", count
);
37 ProfilerStart(full_name
.c_str());
40 void StopProfiling() {
45 void FlushProfiling() {
49 bool BeingProfiled() {
50 return ProfilingIsEnabledForAllThreads();
53 void RestartProfilingAfterFork() {
54 ProfilerRegisterThread();
59 void StartProfiling(const std::string
& name
) {
62 void StopProfiling() {
65 void FlushProfiling() {
68 bool BeingProfiled() {
72 void RestartProfilingAfterFork() {
79 bool IsBinaryInstrumented() {
83 ReturnAddressLocationResolver
GetProfilerReturnAddrResolutionFunc() {
87 DynamicFunctionEntryHook
GetProfilerDynamicFunctionEntryHookFunc() {
91 AddDynamicSymbol
GetProfilerAddDynamicSymbolFunc() {
95 MoveDynamicSymbol
GetProfilerMoveDynamicSymbolFunc() {
99 #else // defined(OS_WIN)
101 // http://blogs.msdn.com/oldnewthing/archive/2004/10/25/247180.aspx
102 extern "C" IMAGE_DOS_HEADER __ImageBase
;
104 bool IsBinaryInstrumented() {
105 enum InstrumentationCheckState
{
108 NON_INSTRUMENTED_IMAGE
,
111 static InstrumentationCheckState state
= UNINITIALIZED
;
113 if (state
== UNINITIALIZED
) {
114 HMODULE this_module
= reinterpret_cast<HMODULE
>(&__ImageBase
);
115 base::win::PEImage
image(this_module
);
117 // Check to be sure our image is structured as we'd expect.
118 DCHECK(image
.VerifyMagic());
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
;
127 state
= NON_INSTRUMENTED_IMAGE
;
130 DCHECK(state
!= UNINITIALIZED
);
132 return state
== INSTRUMENTED_IMAGE
;
137 struct FunctionSearchContext
{
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
,
147 FunctionSearchContext
* context
=
148 reinterpret_cast<FunctionSearchContext
*>(cookie
);
150 DCHECK_NE(static_cast<FunctionSearchContext
*>(NULL
), context
);
151 DCHECK_EQ(static_cast<FARPROC
>(NULL
), context
->function
);
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
);
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.
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
;
180 template <typename FunctionType
>
181 FunctionType
FindFunctionInImports(const char* function_name
) {
182 if (!IsBinaryInstrumented())
185 HMODULE this_module
= reinterpret_cast<HMODULE
>(&__ImageBase
);
186 base::win::PEImage
image(this_module
);
188 FunctionSearchContext ctx
= { function_name
, NULL
};
189 image
.EnumImportChunks(FindResolutionFunctionInImports
, &ctx
);
191 return reinterpret_cast<FunctionType
>(ctx
.function
);
196 ReturnAddressLocationResolver
GetProfilerReturnAddrResolutionFunc() {
197 return FindFunctionInImports
<ReturnAddressLocationResolver
>(
198 "ResolveReturnAddressLocation");
201 DynamicFunctionEntryHook
GetProfilerDynamicFunctionEntryHookFunc() {
202 return FindFunctionInImports
<DynamicFunctionEntryHook
>(
203 "OnDynamicFunctionEntry");
206 AddDynamicSymbol
GetProfilerAddDynamicSymbolFunc() {
207 return FindFunctionInImports
<AddDynamicSymbol
>(
211 MoveDynamicSymbol
GetProfilerMoveDynamicSymbolFunc() {
212 return FindFunctionInImports
<MoveDynamicSymbol
>(
213 "MoveDynamicSymbol");
216 #endif // defined(OS_WIN)