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