1 : // Copyright 2012 Google Inc.
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 : #ifndef SYZYGY_TRACE_PROTOCOL_CALL_TRACE_DEFS_H_
16 : #define SYZYGY_TRACE_PROTOCOL_CALL_TRACE_DEFS_H_
17 :
18 : #include <windows.h>
19 : #include <wmistr.h>
20 : #include <evntrace.h> // NOLINT - wmistr must precede envtrace.h
21 : #include <vector>
22 :
23 : #include "base/basictypes.h"
24 : #include "base/string_piece.h"
25 :
26 : // ID for the call trace provider.
27 m : extern const GUID kCallTraceProvider;
28 :
29 : // Class of trace provider events.
30 m : extern const GUID kCallTraceEventClass;
31 :
32 : // GUID for the kernel trace control interface.
33 m : extern const GUID kSystemTraceControlGuid;
34 :
35 : // This is the absolute minimum number of buffers we will allow, across all
36 : // CPUs.
37 m : extern const size_t kMinEtwBuffers;
38 :
39 : // This is the minimum number of buffers per CPU we'll allow.
40 m : extern const size_t kMinEtwBuffersPerProcessor;
41 :
42 : // Max buffers will be min buffers * kEtwBufferMultiplier.
43 m : extern const size_t kEtwBufferMultiplier;
44 :
45 : // The set of flags to use when logging trace events via ETW.
46 m : extern const int kDefaultEtwTraceFlags;
47 :
48 : // The set of flags to use when logging kernel events via ETW.
49 m : extern const int kDefaultEtwKernelFlags;
50 :
51 : // RPC protocol and endpoint.
52 m : extern const char* const kSyzygyRpcInstanceIdEnvVar;
53 m : void GetSyzygyCallTraceRpcProtocol(std::wstring* protocol);
54 m : void GetSyzygyCallTraceRpcEndpoint(const base::StringPiece16& id,
55 m : std::wstring* endpoint);
56 m : void GetSyzygyCallTraceRpcMutexName(const base::StringPiece16& id,
57 m : std::wstring* mutex_name);
58 m : void GetSyzygyCallTraceRpcEventName(const base::StringPiece16& id,
59 m : std::wstring* event_name);
60 :
61 : // This must be bumped anytime the file format is changed.
62 m : enum {
63 m : TRACE_VERSION_HI = 1,
64 m : TRACE_VERSION_LO = 2,
65 m : };
66 :
67 m : enum TraceEventType {
68 : // Header prefix for a "page" of call trace events.
69 m : TRACE_PAGE_HEADER,
70 : // The actual events are below.
71 m : TRACE_PROCESS_STARTED = 10,
72 m : TRACE_PROCESS_ENDED,
73 m : TRACE_ENTER_EVENT,
74 m : TRACE_EXIT_EVENT,
75 m : TRACE_PROCESS_ATTACH_EVENT,
76 m : TRACE_PROCESS_DETACH_EVENT,
77 m : TRACE_THREAD_ATTACH_EVENT,
78 m : TRACE_THREAD_DETACH_EVENT,
79 m : TRACE_MODULE_EVENT,
80 m : TRACE_BATCH_ENTER,
81 m : TRACE_BATCH_INVOCATION,
82 m : TRACE_THREAD_NAME,
83 m : TRACE_BASIC_BLOCK_FREQUENCY,
84 m : };
85 :
86 : // All traces are emitted at this trace level.
87 m : const UCHAR CALL_TRACE_LEVEL = TRACE_LEVEL_INFORMATION;
88 :
89 m : enum TraceEventFlags {
90 : // Trace function entry.
91 m : TRACE_FLAG_ENTER = 0x0001,
92 : // Trace function exit.
93 m : TRACE_FLAG_EXIT = 0x0002,
94 : // Capture stack traces on entry and exit.
95 m : TRACE_FLAG_STACK_TRACES = 0x0004,
96 : // Trace DLL load/unload events.
97 m : TRACE_FLAG_LOAD_EVENTS = 0x0008,
98 : // Trace DLL thread events.
99 m : TRACE_FLAG_THREAD_EVENTS = 0x0010,
100 : // Batch entry traces.
101 m : TRACE_FLAG_BATCH_ENTER = 0x0020,
102 m : };
103 :
104 : // Max depth of stack trace captured on entry/exit.
105 m : const size_t kMaxTraceDepth = 32;
106 :
107 m : typedef const void* RetAddr;
108 m : typedef const void* FuncAddr;
109 m : typedef const void* ModuleAddr;
110 m : typedef DWORD ArgumentWord;
111 m : typedef DWORD RetValueWord;
112 m : typedef void* SessionHandle;
113 :
114 : // A prefix for each trace record on disk.
115 m : struct RecordPrefix {
116 : // The timestamp of the trace event.
117 m : uint32 timestamp;
118 :
119 : // The size of the record, in bytes;
120 m : uint32 size;
121 :
122 : // The type of trace record. Will be a value from the TraceEventType
123 : // enumeration.
124 m : uint16 type;
125 :
126 : // If the call trace service aggregates all trace records to a single
127 : // file, instead of a file per process, then it's possible that a
128 : // single file could contain traces produced by multiple versions of
129 : // the client library.
130 m : struct {
131 m : uint8 hi;
132 m : uint8 lo;
133 m : } version;
134 m : };
135 :
136 m : COMPILE_ASSERT(sizeof(RecordPrefix) == 12, record_prefix_size_is_12);
137 :
138 : // This structure is written at the beginning of a call trace file. If the
139 : // format of this trace file changes the server version must be increased.
140 m : struct TraceFileHeader {
141 : // Everything in this header up to and including the header_size field should
142 : // not be changed in order, layout or alignment. This allows the beginning of
143 : // the header to be read across all trace file versions. If adding a new
144 : // fixed length field, do so immediately prior to blob_data. If adding a new
145 : // variable length field, append it to blob data updating the comment below,
146 : // and both the reading and writing of TraceFileHeader.
147 :
148 : // The "magic-number" identifying this as a Syzygy call-trace file.
149 : // In a valid trace file this will be "SZGY".
150 m : typedef char Signature[4];
151 :
152 : // A canonical value for the signature.
153 m : static const Signature kSignatureValue;
154 :
155 : // A signature is at the start of the trace file header.
156 m : Signature signature;
157 :
158 : // The version of the call trace service which recorded this trace file.
159 m : struct {
160 m : uint16 lo;
161 m : uint16 hi;
162 m : } server_version;
163 :
164 : // The number of bytes in the header. This is the size of this structure
165 : // plus the length of the blob.
166 m : uint32 header_size;
167 :
168 : // The block size used when writing the file to disk. The header and
169 : // all segments are padded and byte aligned to this block size.
170 m : uint32 block_size;
171 :
172 : // The id of the process being traced.
173 m : uint32 process_id;
174 :
175 : // The timestamp (in ticks) when this trace file was created.
176 m : uint32 timestamp;
177 :
178 : // The base address at which the executable module was loaded when the
179 : // trace file was created.
180 m : uint32 module_base_address;
181 :
182 : // The size of the executable module.
183 m : uint32 module_size;
184 :
185 : // The checksum of the executable module.
186 m : uint32 module_checksum;
187 :
188 : // The timestamp of the executable module.
189 m : uint32 module_time_date_stamp;
190 :
191 : // System information.
192 m : OSVERSIONINFOEX os_version_info;
193 m : SYSTEM_INFO system_info;
194 m : MEMORYSTATUSEX memory_status;
195 :
196 : // The header is required to store multiple variable length fields. We do
197 : // this via a blob mechanism. The header contains a single binary blob at the
198 : // end, whose length in bytes) is encoded via blob_length.
199 : //
200 : // Currently, the header stores the following variable length fields (in
201 : // the order indicated):
202 : //
203 : // 1. The path to the instrumented module, a NULL terminated wide string.
204 : // 2. The command line for the process, a NULL terminated wide string.
205 : // 3. The environment string for the process, an array of wide chars
206 : // terminated by a double NULL (individual environment variables are
207 : // separated by single NULLs).
208 :
209 : // This stores the variable length data, concatenated. This should be pointer
210 : // aligned so that PODs with alignment constraints embedded in the blob can be
211 : // read directly from a header loaded into memory.
212 m : uint8 blob_data[1];
213 m : };
214 :
215 : // Written at the beginning of a call trace file segment. Each call trace file
216 : // segment has a length, which on-disk is rounded up to the block_size, as
217 : // recorded in the TraceFileHeader. Within a call trace segment, there are one
218 : // or more records, each prefixed with a RecordPrefix, which describes the
219 : // length and type of the data to follow.
220 m : struct TraceFileSegmentHeader {
221 : // Type identifiers used for these headers.
222 m : enum { kTypeId = TRACE_PAGE_HEADER };
223 :
224 : // The identity of the thread that is reporting in this segment
225 : // of the trace file.
226 m : uint32 thread_id;
227 :
228 : // The number of data bytes in this segment of the trace file. This
229 : // value does not include the size of the record prefix nor the size
230 : // of the segment header.
231 m : uint32 segment_length;
232 m : };
233 :
234 : // The structure traced on function entry or exit.
235 m : template<int TypeId>
236 m : struct TraceEnterExitEventDataTempl {
237 m : enum { kTypeId = TypeId };
238 m : size_t depth;
239 m : FuncAddr function;
240 m : union {
241 m : ArgumentWord args[4];
242 m : RetValueWord retval;
243 m : };
244 m : size_t num_traces;
245 m : RetAddr traces[kMaxTraceDepth];
246 m : };
247 :
248 m : typedef TraceEnterExitEventDataTempl<TRACE_ENTER_EVENT> TraceEnterEventData;
249 m : typedef TraceEnterExitEventDataTempl<TRACE_EXIT_EVENT> TraceExitEventData;
250 :
251 : // For backward source compatibilty.
252 m : typedef TraceEnterEventData TraceEnterExitEventData;
253 :
254 : // The structure written for each loaded module when module event tracing is
255 : // enabled.
256 m : struct TraceModuleData {
257 m : ModuleAddr module_base_addr;
258 m : size_t module_base_size;
259 m : uint32 module_checksum;
260 m : uint32 module_time_date_stamp;
261 m : wchar_t module_name[256];
262 m : wchar_t module_exe[MAX_PATH];
263 m : };
264 :
265 : // This is for storing environment string information. Each environment string
266 : // consists of a pair of strings, the key and the value. Certain special
267 : // strings have empty keys.
268 m : typedef std::vector<std::pair<std::wstring, std::wstring>>
269 m : TraceEnvironmentStrings;
270 :
271 : // Describes the system information and environment in which a process is
272 : // running.
273 m : struct TraceSystemInfo {
274 m : OSVERSIONINFOEX os_version_info;
275 m : SYSTEM_INFO system_info;
276 m : MEMORYSTATUSEX memory_status;
277 m : TraceEnvironmentStrings environment_strings;
278 m : };
279 :
280 m : struct FuncCall {
281 m : union {
282 m : DWORD tick_count;
283 m : DWORD ticks_ago;
284 m : };
285 m : FuncAddr function;
286 m : };
287 :
288 : // The structure traced for batch entry traces.
289 m : struct TraceBatchEnterData {
290 m : enum { kTypeId = TRACE_BATCH_ENTER };
291 :
292 : // The thread ID from which these traces originate. This can differ
293 : // from the logging thread ID when a process exits, and the exiting
294 : // thread flushes the trace buffers from its expired brethren.
295 m : DWORD thread_id;
296 :
297 : // Number of function entries.
298 m : size_t num_calls;
299 :
300 : // Back-to-back function calls, one for each entry.
301 m : FuncCall calls[1];
302 m : };
303 :
304 : // This is the data recorded for each distinct caller/function
305 : // pair by the profiler.
306 m : struct InvocationInfo {
307 m : RetAddr caller;
308 m : FuncAddr function;
309 m : size_t num_calls;
310 m : uint64 cycles_min;
311 m : uint64 cycles_max;
312 m : uint64 cycles_sum;
313 m : };
314 :
315 m : struct TraceBatchInvocationInfo {
316 m : enum { kTypeId = TRACE_BATCH_INVOCATION };
317 :
318 : // TODO(siggi): Perhaps the batch should carry the time resolution for
319 : // the invocation data?
320 :
321 : // Back to back entries, as many as our enclosing record's size allows for.
322 m : InvocationInfo invocations[1];
323 m : };
324 :
325 m : struct TraceThreadNameInfo {
326 m : enum { kTypeId = TRACE_THREAD_NAME };
327 : // In fact as many as our enclosing record's size allows for,
328 : // zero terminated.
329 m : char thread_name[1];
330 m : };
331 :
332 m : struct TraceBasicBlockFrequencyData {
333 m : enum { kTypeId = TRACE_BASIC_BLOCK_FREQUENCY };
334 :
335 : // This is used to tie the data to a particular module, which has already
336 : // been reported via a TraceModuleData struct.
337 m : ModuleAddr module_base_addr;
338 m : size_t module_base_size;
339 m : uint32 module_checksum;
340 m : uint32 module_time_date_stamp;
341 :
342 : // The size of the frequency reports: 1, 2 or 4 bytes.
343 m : uint32 frequency_size;
344 : // The number of basic blocks being reported. It is up to the instrumentation
345 : // to output any other metadata that is required to map an index to a basic
346 : // block address. (Typically, the OMAP data is sufficient for this.)
347 m : uint32 num_basic_blocks;
348 :
349 : // In fact, there are frequency_size * num_basic_blocks bytes that follow.
350 m : uint8 frequency_data[1];
351 m : };
352 :
353 : #endif // SYZYGY_TRACE_PROTOCOL_CALL_TRACE_DEFS_H_
|