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 : // The runtime portion of a basic-block counting agent. This is responsible for
16 : // initializing the RPC connection and per-thread counter buffering on
17 : // demand as necessary as well as saturation incrementing the appropriate
18 : // counter when requested.
19 : //
20 : // The instrumenter can be used to inject a run-time dependency on this
21 : // library as well as to add the appropriate entry-hook code.
22 : // For details on the implementation, see basic_block_entry.cc.
23 :
24 : #ifndef SYZYGY_AGENT_BASIC_BLOCK_ENTRY_BASIC_BLOCK_ENTRY_H_
25 : #define SYZYGY_AGENT_BASIC_BLOCK_ENTRY_BASIC_BLOCK_ENTRY_H_
26 :
27 : #include <windows.h>
28 : #include <winnt.h>
29 : #include <vector>
30 :
31 : #include "base/lazy_instance.h"
32 : #include "base/win/pe_image.h"
33 : #include "syzygy/agent/common/thread_state.h"
34 : #include "syzygy/common/indexed_frequency_data.h"
35 : #include "syzygy/trace/client/rpc_session.h"
36 :
37 m : namespace agent {
38 m : namespace basic_block_entry {
39 :
40 : // The basic-block counting agent.
41 : // @note: There's a single instance of this class.
42 : // TODO(sebmarchand): Rename this class to BasicBlockAgent (or something
43 : // similar) as this is used by various modes of instrumentation (basic block
44 : // entry counting, basic block arc counts, jump table entry counts, etc).
45 m : class BasicBlockEntry {
46 m : public:
47 m : typedef ::common::IndexedFrequencyData IndexedFrequencyData;
48 m : typedef ::agent::common::ThreadStateManager ThreadStateManager;
49 :
50 : // Forward declaration.
51 m : struct BasicBlockIndexedFrequencyData;
52 :
53 : // The size in DWORD of the buffer. We choose a multiple of memory page size.
54 m : static const size_t kBufferSize = 4096;
55 : // The number of entries in the simulated branch predictor cache.
56 m : static const size_t kPredictorCacheSize = 4096;
57 :
58 : // This structure describes the contents of the stack above a call to
59 : // BasicBlockEntry::IncrementIndexedFreqDataHook. A pointer to this structure
60 : // will be given to the IncrementIndexedFreqDataHook by
61 : // _increment_indexed_freq_data.
62 m : struct IncrementIndexedFreqDataFrame;
63 :
64 : // This structure describes the contents of the stack above a call to
65 : // BasicBlockEntry::DllMainEntryHook(). A pointer to this structure will
66 : // be given to the DllMainEntryHook by _indirect_penter_dllmain.
67 m : struct DllMainEntryFrame;
68 :
69 : // This structure describes the contents of the stack above a call to
70 : // BasicBlockEntry::ExeMainEntryHook(). A pointer to this structure will
71 : // be given to the ExeMainEntryHook by _indirect_penter_exemain.
72 m : struct ExeMainEntryFrame;
73 :
74 : // Retrieves the basic block entry singleton instance.
75 m : static BasicBlockEntry* Instance();
76 :
77 : // Called from _increment_indexed_freq_data().
78 m : static void WINAPI IncrementIndexedFreqDataHook(
79 m : IncrementIndexedFreqDataFrame* entry_frame);
80 :
81 : // Called from _branch_enter.
82 m : static void WINAPI BranchEnterHook(
83 m : IncrementIndexedFreqDataFrame* entry_frame);
84 :
85 : // Called from _branch_enter_buffered.
86 m : static void WINAPI BranchEnterBufferedHook(
87 m : IncrementIndexedFreqDataFrame* entry_frame);
88 :
89 : // Called from _branch_exit.
90 m : static void WINAPI BranchExitHook(
91 m : IncrementIndexedFreqDataFrame* entry_frame);
92 :
93 : // Called from _function_enter_slotX.
94 m : template<int S>
95 m : static inline void __fastcall FunctionEnterHookSlot(
96 m : IndexedFrequencyData* module_data);
97 :
98 : // Called from _branch_enter_slotX.
99 m : template<int S>
100 m : static inline void __fastcall BranchEnterHookSlot(uint32 index);
101 :
102 : // Called from _branch_enter_buffered_slotX.
103 m : template<int S>
104 m : static inline void __fastcall BranchEnterBufferedHookSlot(uint32 index);
105 :
106 : // Called from _branch_exit_slotX.
107 m : template<int S>
108 m : static inline void __fastcall BranchExitHookSlot(uint32 index);
109 :
110 : // Called from _indirect_penter_dllmain.
111 m : static void WINAPI DllMainEntryHook(DllMainEntryFrame* entry_frame);
112 :
113 : // Called from _indirect_penter_exemain.
114 m : static void WINAPI ExeMainEntryHook(ExeMainEntryFrame* entry_frame);
115 :
116 m : protected:
117 : // This class defines the per-thread-per-instrumented-module state managed
118 : // by this agent.
119 m : class ThreadState;
120 m : friend class ThreadState;
121 :
122 : // Make sure the LazyInstance can be created.
123 m : friend struct base::DefaultLazyInstanceTraits<BasicBlockEntry>;
124 :
125 m : BasicBlockEntry();
126 m : ~BasicBlockEntry();
127 :
128 : // Initializes the given frequency data element.
129 m : bool InitializeFrequencyData(IndexedFrequencyData* data);
130 :
131 : // Handles EXE startup on ExeMainEntryHook and DLL_PROCESS_ATTACH messages
132 : // received by DllMainEntryHook().
133 m : void OnProcessAttach(IndexedFrequencyData* module_data);
134 :
135 : // Handles DLL_THREAD_DETACH and DLL_PROCESS_DETACH messages received by
136 : // DllMainEntryHook().
137 m : void OnThreadDetach(IndexedFrequencyData* module_data);
138 :
139 : // Registers the module containing @p addr with the call_trace_service.
140 m : void RegisterModule(const void* addr);
141 :
142 : // Register a TLS slot for this module.
143 m : void RegisterFastPathSlot(IndexedFrequencyData* module_data,
144 m : unsigned int slot);
145 :
146 : // Unregister a TLS slot for this module.
147 m : void UnregisterFastPathSlot(IndexedFrequencyData* module_data,
148 m : unsigned int slot);
149 :
150 : // Create the local thread state for the current thread. This should only
151 : // be called if the local thread state has not already been created.
152 m : ThreadState* CreateThreadState(IndexedFrequencyData* module_data);
153 :
154 : // Returns the local thread state for the current thread. If the thread state
155 : // is unavailable, this function returns NULL.
156 m : static ThreadState* GetThreadState(IndexedFrequencyData* module_data);
157 :
158 : // Returns the local thread state for the current thread (when instrumented
159 : // with fast-path).
160 m : template<int S>
161 m : static ThreadState* GetThreadStateSlot();
162 :
163 : // Registered thread local specific slot.
164 m : uint32 registered_slots_;
165 :
166 : // The RPC session we're logging to/through.
167 m : trace::client::RpcSession session_;
168 :
169 : // A helper to manage the life-cycle of the ThreadState instances allocated
170 : // by this agent.
171 m : ThreadStateManager thread_state_manager_;
172 :
173 : // The trace file segment we're writing module events to. The frequency data
174 : // goes to specially allocated segments that we don't explicitly keep track
175 : // of, but rather that we let live until the client gets torn down.
176 m : trace::client::TraceFileSegment segment_; // Under lock_.
177 :
178 : // Global lock to avoid concurrent segment_ update.
179 m : base::Lock lock_;
180 m : };
181 :
182 : // This structure contains the BasicBlockEntry IndexedFrequencyData specifics
183 : // information.
184 m : struct BasicBlockEntry::BasicBlockIndexedFrequencyData {
185 : // The indexed frequency data information common for all agents.
186 m : ::common::IndexedFrequencyData module_data;
187 :
188 : // The TLS slot associated with this module (if any). This allows for the
189 : // frequency trace data to be managed on a per-thread basis, if desired by the
190 : // agent. The TLS index is initialized to TLS_OUT_OF_INDEXES by the
191 : // instrumenter.
192 m : DWORD tls_index;
193 :
194 : // The FS slot associated with this module (if any). This allows for the
195 : // frequency trace data to be managed on a per-thread basis, if desired by the
196 : // agent. An unused slot is initialized to zero by the instrumenter, otherwise
197 : // it is initialized to a slot index between 1 and 4.
198 m : DWORD fs_slot;
199 m : };
200 :
201 m : } // namespace basic_block_entry
202 m : } // namespace agent
203 :
204 : #endif // SYZYGY_AGENT_BASIC_BLOCK_ENTRY_BASIC_BLOCK_ENTRY_H_
|