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/lazy_instance.h"
33 : #include "base/synchronization/lock.h"
34 : #include "base/threading/thread_local.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 m : extern "C" void _cdecl _indirect_penter();
42 m : extern "C" void _cdecl _indirect_penter_dllmain();
43 m : extern "C" void _cdecl _indirect_penter_inside_function();
44 m : 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 m : extern "C" void WINAPI AddSymbol(const void* address, size_t length,
53 m : 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 m : extern "C" void WINAPI MoveSymbol(const void* old_address,
59 m : const void* new_address);
60 :
61 m : namespace agent {
62 m : namespace profiler {
63 :
64 : // There's a single instance of this class.
65 m : class Profiler {
66 m : public:
67 m : static void WINAPI DllMainEntryHook(EntryFrame* entry_frame,
68 m : FuncAddr function,
69 m : uint64 cycles);
70 :
71 m : static void WINAPI FunctionEntryHook(EntryFrame* entry_frame,
72 m : FuncAddr function,
73 m : uint64 cycles);
74 :
75 m : static void WINAPI OnV8FunctionEntry(FuncAddr function,
76 m : RetAddr* return_addr_location,
77 m : 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 m : void AddSymbol(const void* address, size_t length,
86 m : 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 m : 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 m : RetAddr* ResolveReturnAddressLocation(RetAddr* pc_location);
102 :
103 : // Retrieves the profiler singleton instance.
104 m : static Profiler* Instance();
105 :
106 : // Called when a thread is terminating.
107 m : void OnThreadDetach();
108 :
109 m : private:
110 : // Make sure the LazyInstance can be created.
111 m : friend struct base::DefaultLazyInstanceTraits<Profiler>;
112 :
113 m : Profiler();
114 m : ~Profiler();
115 :
116 : // Called form DllMainEntryHook.
117 m : void OnModuleEntry(EntryFrame* entry_frame,
118 m : FuncAddr function,
119 m : uint64 cycles);
120 :
121 : // Callbacks from ThreadState.
122 m : void OnPageAdded(const void* page);
123 m : void OnPageRemoved(const void* page);
124 :
125 : // Called on a first chance exception declaring thread name.
126 m : void OnThreadName(const base::StringPiece& thread_name);
127 :
128 : // Our vectored exception handler that takes care
129 : // of capturing thread name debug exceptions.
130 m : static LONG CALLBACK ExceptionHandler(EXCEPTION_POINTERS* ex_info);
131 :
132 m : class ThreadState;
133 :
134 m : ThreadState* CreateFirstThreadStateAndSession();
135 m : ThreadState* GetOrAllocateThreadState();
136 m : ThreadState* GetOrAllocateThreadStateImpl();
137 m : ThreadState* GetThreadState() const;
138 m : void FreeThreadState();
139 :
140 : // The RPC session we're logging to/through.
141 m : trace::client::RpcSession session_;
142 :
143 : // Protects pages_ and logged_modules_.
144 m : base::Lock lock_;
145 :
146 : // The dynamic symbol map.
147 m : SymbolMap symbol_map_;
148 :
149 : // Contains the thunk pages in lexical order.
150 m : typedef std::vector<const void*> PageVector;
151 m : PageVector pages_; // Under lock_.
152 :
153 : // Contains the set of modules we've seen and logged.
154 m : typedef base::hash_set<HMODULE> ModuleSet;
155 m : ModuleSet logged_modules_; // Under lock_.
156 :
157 : // A helper to manage the life-cycle of the ThreadState instances allocated
158 : // by this agent.
159 m : agent::common::ThreadStateManager thread_state_manager_;
160 :
161 : // Stores our vectored exception handler registration handle.
162 m : void* handler_registration_;
163 :
164 : // This points to our per-thread state.
165 m : mutable base::ThreadLocalPointer<ThreadState> tls_;
166 m : };
167 :
168 m : } // namespace profiler
169 m : } // namespace agent
170 :
171 : #endif // SYZYGY_AGENT_PROFILER_PROFILER_H_
|