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