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/hash_tables.h"
32 : #include "base/synchronization/lock.h"
33 : #include "base/threading/thread_local.h"
34 : #include "syzygy/agent/common/dll_notifications.h"
35 : #include "syzygy/agent/common/entry_frame.h"
36 : #include "syzygy/agent/common/thread_state.h"
37 : #include "syzygy/agent/profiler/symbol_map.h"
38 : #include "syzygy/trace/client/rpc_session.h"
39 :
40 : // Assembly instrumentation stubs to handle function entry and exit.
41 : extern "C" void _cdecl _indirect_penter();
42 : extern "C" void _cdecl _indirect_penter_dllmain();
43 : extern "C" void _cdecl _indirect_penter_inside_function();
44 : extern void pexit();
45 :
46 : // Add a symbol to the dynamic symbol store.
47 : // @param address the start address of the new symbol.
48 : // @param length the length of the new symbol.
49 : // @param name the name of the new symbol, this string is not necessarily
50 : // zero terminated.
51 : // @paran name_len the length of @p name.
52 : extern "C" void WINAPI AddSymbol(const void* address, size_t length,
53 : const char* name, size_t name_len);
54 :
55 : // Moves a symbol in the dynamic symbol store.
56 : // @param old_address the previous start address of the moved symbol.
57 : // @param new_address the new start address of the moved symbol.
58 : extern "C" void WINAPI MoveSymbol(const void* old_address,
59 : const void* new_address);
60 :
61 : namespace agent {
62 : namespace profiler {
63 :
64 : // There's a single instance of this class.
65 : class Profiler {
66 : public:
67 : static void WINAPI DllMainEntryHook(EntryFrame* entry_frame,
68 : FuncAddr function,
69 : uint64 cycles);
70 :
71 : static void WINAPI FunctionEntryHook(EntryFrame* entry_frame,
72 : FuncAddr function,
73 : uint64 cycles);
74 :
75 : static void WINAPI OnV8FunctionEntry(FuncAddr function,
76 : RetAddr* return_addr_location,
77 : uint64 cycles);
78 :
79 : // Adds a symbol to the dynamic symbol store.
80 : // @param address the start address of the new symbol.
81 : // @param length the length of the new symbol.
82 : // @param name the name of the new symbol, this string is not necessarily
83 : // zero terminated.
84 : // @paran name_len the length of @p name.
85 : void AddSymbol(const void* address, size_t length,
86 : const char* name, size_t name_len);
87 :
88 : // Moves a symbol in the dynamic symbol store.
89 : // @param old_address the previous start address of the moved symbol.
90 : // @param new_address the new start address of the moved symbol.
91 : void MoveSymbol(const void* old_address, const void* new_address);
92 :
93 : // Resolves a return address location to a thunk's stashed original
94 : // location if a thunk is involved.
95 : // @param pc_location an address on stack where a return address is stored.
96 : // @returns the address where the profiler stashed the original return address
97 : // if *(@p pc_location) refers to a thunk, otherwise @p pc_location.
98 : // @note this function must be able to resolve through thunks that belong
99 : // to other threads, as e.g. V8 will traverse all stacks that are using
100 : // V8 during garbage collection.
101 : RetAddr* ResolveReturnAddressLocation(RetAddr* pc_location);
102 :
103 : // Called when a thread is terminating.
104 : void OnThreadDetach();
105 :
106 : // Retrieves the profiler singleton instance.
107 E : static Profiler& instance() { return instance_; }
108 :
109 : private:
110 : Profiler();
111 : ~Profiler();
112 :
113 : // Called form DllMainEntryHook.
114 : void OnModuleEntry(EntryFrame* entry_frame,
115 : FuncAddr function,
116 : uint64 cycles);
117 :
118 : // Callbacks from ThreadState.
119 : void OnPageAdded(const void* page);
120 : void OnPageRemoved(const void* page);
121 :
122 : // Called on a first chance exception declaring thread name.
123 : void OnThreadName(const base::StringPiece& thread_name);
124 :
125 : // Our vectored exception handler that takes care
126 : // of capturing thread name debug exceptions.
127 : static LONG CALLBACK ExceptionHandler(EXCEPTION_POINTERS* ex_info);
128 :
129 : class ThreadState;
130 :
131 : // Sink for DLL load/unload event notifications.
132 : void OnDllEvent(agent::common::DllNotificationWatcher::EventType type,
133 : HMODULE module,
134 : size_t module_size,
135 : const base::StringPiece16& dll_path,
136 : const base::StringPiece16& dll_base_name);
137 :
138 : ThreadState* CreateFirstThreadStateAndSession();
139 : ThreadState* GetOrAllocateThreadState();
140 : ThreadState* GetOrAllocateThreadStateImpl();
141 : ThreadState* GetThreadState() const;
142 : void FreeThreadState();
143 :
144 : // The RPC session we're logging to/through.
145 : trace::client::RpcSession session_;
146 :
147 : // Protects pages_ and logged_modules_.
148 : base::Lock lock_;
149 :
150 : // The dynamic symbol map.
151 : SymbolMap symbol_map_;
152 :
153 : // Contains the thunk pages in lexical order.
154 : typedef std::vector<const void*> PageVector;
155 : PageVector pages_; // Under lock_.
156 :
157 : // Contains the set of modules we've seen and logged.
158 : typedef base::hash_set<HMODULE> ModuleSet;
159 : ModuleSet logged_modules_; // Under lock_.
160 :
161 : // A helper to manage the life-cycle of the ThreadState instances allocated
162 : // by this agent.
163 : agent::common::ThreadStateManager thread_state_manager_;
164 :
165 : // Stores our vectored exception handler registration handle.
166 : void* handler_registration_;
167 :
168 : // To keep track of modules added after initialization.
169 : agent::common::DllNotificationWatcher dll_watcher_;
170 :
171 : // This points to our per-thread state.
172 : mutable base::ThreadLocalPointer<ThreadState> tls_;
173 :
174 : // The instance all profiling goes through.
175 : static Profiler instance_;
176 : };
177 :
178 : } // namespace profiler
179 : } // namespace agent
180 :
181 : #endif // SYZYGY_AGENT_PROFILER_PROFILER_H_
|