1 : // Copyright 2012 Google Inc. All Rights Reserved.
2 : //
3 : // Licensed under the Apache License, Version 2.0 (the "License");
4 : // you may not use this file except in compliance with the License.
5 : // You may obtain a copy of the License at
6 : //
7 : // http://www.apache.org/licenses/LICENSE-2.0
8 : //
9 : // Unless required by applicable law or agreed to in writing, software
10 : // distributed under the License is distributed on an "AS IS" BASIS,
11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : // See the License for the specific language governing permissions and
13 : // limitations under the License.
14 : //
15 : // A hierarchical profiler, indended for use with the Syzygy function level
16 : // instrumenter. The Syzygy instrumented provides a function entry hook, and
17 : // this implementation uses a shadow stack with return address swizzling to
18 : // get an exit hook.
19 : // The profiler uses RDTSC as wall clock, which makes it unsuitable for
20 : // profiling on systems with CPUs prior to AMD Barcelona/Phenom, or older
21 : // Intel processors, see e.g. http://en.wikipedia.org/wiki/Time_Stamp_Counter
22 : // for the low down details.
23 :
24 : #ifndef SYZYGY_AGENT_PROFILER_PROFILER_H_
25 : #define SYZYGY_AGENT_PROFILER_PROFILER_H_
26 :
27 : #include <windows.h>
28 : #include <winnt.h>
29 : #include <vector>
30 :
31 : #include "base/synchronization/lock.h"
32 : #include "base/threading/thread_local.h"
33 : #include "syzygy/agent/common/dll_notifications.h"
34 : #include "syzygy/agent/common/entry_frame.h"
35 : #include "syzygy/agent/common/thread_state.h"
36 : #include "syzygy/agent/profiler/symbol_map.h"
37 : #include "syzygy/trace/client/rpc_session.h"
38 :
39 : // Assembly instrumentation stubs to handle function entry and exit.
40 : extern "C" void _cdecl _indirect_penter();
41 : extern "C" void _cdecl _indirect_penter_dllmain();
42 : extern "C" void _cdecl _indirect_penter_inside_function();
43 : extern void pexit();
44 :
45 : // Add a symbol to the dynamic symbol store.
46 : // @param address the start address of the new symbol.
47 : // @param length the length of the new symbol.
48 : // @param name the name of the new symbol, this string is not necessarily
49 : // zero terminated.
50 : // @paran name_len the length of @p name.
51 : extern "C" void WINAPI AddSymbol(const void* address, size_t length,
52 : const char* name, size_t name_len);
53 :
54 : // Moves a symbol in the dynamic symbol store.
55 : // @param old_address the previous start address of the moved symbol.
56 : // @param new_address the new start address of the moved symbol.
57 : extern "C" void WINAPI MoveSymbol(const void* old_address,
58 : const void* new_address);
59 :
60 : namespace agent {
61 : namespace profiler {
62 :
63 : // There's a single instance of this class.
64 : class Profiler {
65 : public:
66 : static void WINAPI DllMainEntryHook(EntryFrame* entry_frame,
67 : FuncAddr function,
68 : uint64 cycles);
69 :
70 : static void WINAPI FunctionEntryHook(EntryFrame* entry_frame,
71 : FuncAddr function,
72 : uint64 cycles);
73 :
74 : static void WINAPI OnV8FunctionEntry(FuncAddr function,
75 : RetAddr* return_addr_location,
76 : uint64 cycles);
77 :
78 : // Adds a symbol to the dynamic symbol store.
79 : // @param address the start address of the new symbol.
80 : // @param length the length of the new symbol.
81 : // @param name the name of the new symbol, this string is not necessarily
82 : // zero terminated.
83 : // @paran name_len the length of @p name.
84 : void AddSymbol(const void* address, size_t length,
85 : const char* name, size_t name_len);
86 :
87 : // Moves a symbol in the dynamic symbol store.
88 : // @param old_address the previous start address of the moved symbol.
89 : // @param new_address the new start address of the moved symbol.
90 : void MoveSymbol(const void* old_address, const void* new_address);
91 :
92 : // Resolves a return address location to a thunk's stashed original
93 : // location if a thunk is involved.
94 : // @param pc_location an address on stack where a return address is stored.
95 : // @returns the address where the profiler stashed the original return address
96 : // if *(@p pc_location) refers to a thunk, otherwise @p pc_location.
97 : // @note this function must be able to resolve through thunks that belong
98 : // to other threads, as e.g. V8 will traverse all stacks that are using
99 : // V8 during garbage collection.
100 : RetAddr* ResolveReturnAddressLocation(RetAddr* pc_location);
101 :
102 : // Called when a thread is terminating.
103 : void OnThreadDetach();
104 :
105 : // Retrieves the profiler singleton instance.
106 E : static Profiler& instance() { return instance_; }
107 :
108 : private:
109 : Profiler();
110 : ~Profiler();
111 :
112 : // Called form DllMainEntryHook.
113 : void OnModuleEntry(EntryFrame* entry_frame,
114 : FuncAddr function,
115 : uint64 cycles);
116 :
117 : // Callbacks from ThreadState.
118 : void OnPageAdded(const void* page);
119 : void OnPageRemoved(const void* page);
120 :
121 : // Called on a first chance exception declaring thread name.
122 : void OnThreadName(const base::StringPiece& thread_name);
123 :
124 : // Our vectored exception handler that takes care
125 : // of capturing thread name debug exceptions.
126 : static LONG CALLBACK ExceptionHandler(EXCEPTION_POINTERS* ex_info);
127 :
128 : class ThreadState;
129 :
130 : // Sink for DLL load/unload event notifications.
131 : void OnDllEvent(agent::common::DllNotificationWatcher::EventType type,
132 : HMODULE module,
133 : size_t module_size,
134 : const base::StringPiece16& dll_path,
135 : const base::StringPiece16& dll_base_name);
136 :
137 : ThreadState* CreateFirstThreadStateAndSession();
138 : ThreadState* GetOrAllocateThreadState();
139 : ThreadState* GetOrAllocateThreadStateImpl();
140 : ThreadState* GetThreadState() const;
141 : void FreeThreadState();
142 :
143 : // The RPC session we're logging to/through.
144 : trace::client::RpcSession session_;
145 :
146 : // Protects pages_ and logged_modules_.
147 : base::Lock lock_;
148 :
149 : // The dynamic symbol map.
150 : SymbolMap symbol_map_;
151 :
152 : // Contains the thunk pages in lexical order.
153 : typedef std::vector<const void*> PageVector;
154 : PageVector pages_; // Under lock_.
155 :
156 : // Contains the set of modules we've seen and logged.
157 : typedef base::hash_set<HMODULE> ModuleSet;
158 : ModuleSet logged_modules_; // Under lock_.
159 :
160 : // A helper to manage the life-cycle of the ThreadState instances allocated
161 : // by this agent.
162 : agent::common::ThreadStateManager thread_state_manager_;
163 :
164 : // Stores our vectored exception handler registration handle.
165 : void* handler_registration_;
166 :
167 : // To keep track of modules added after initialization.
168 : agent::common::DllNotificationWatcher dll_watcher_;
169 :
170 : // This points to our per-thread state.
171 : mutable base::ThreadLocalPointer<ThreadState> tls_;
172 :
173 : // The instance all profiling goes through.
174 : static Profiler instance_;
175 : };
176 :
177 : } // namespace profiler
178 : } // namespace agent
179 :
180 : #endif // SYZYGY_AGENT_PROFILER_PROFILER_H_
|