1 /**************************************************************************
2 *
3 * Copyright 2007-2009 VMware, Inc.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 *
24 **************************************************************************/
25
26
27 #include <assert.h>
28 #include <stdarg.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <wchar.h>
33 #include <vector>
34
35 #include "os.hpp"
36 #include "trace_ostream.hpp"
37 #include "trace_writer.hpp"
38 #include "trace_format.hpp"
39
40 namespace trace {
41
42
Writer()43 Writer::Writer() :
44 call_no(0)
45 {
46 m_file = nullptr;
47 }
48
~Writer()49 Writer::~Writer()
50 {
51 close();
52 }
53
54 void
close(void)55 Writer::close(void) {
56 delete m_file;
57 m_file = nullptr;
58 }
59
60 bool
open(const char * filename,unsigned semanticVersion,const Properties & properties)61 Writer::open(const char *filename,
62 unsigned semanticVersion,
63 const Properties &properties)
64 {
65 close();
66
67 m_file = createSnappyStream(filename);
68 if (!m_file) {
69 return false;
70 }
71
72 call_no = 0;
73 functions.clear();
74 structs.clear();
75 enums.clear();
76 bitmasks.clear();
77 frames.clear();
78
79 _writeUInt(TRACE_VERSION);
80
81 assert(semanticVersion <= TRACE_VERSION);
82 _writeUInt(semanticVersion);
83
84 beginProperties();
85 for (auto & kv : properties) {
86 writeProperty(kv.first.c_str(), kv.second.c_str());
87 }
88 endProperties();
89
90 return true;
91 }
92
93 void inline
_write(const void * sBuffer,size_t dwBytesToWrite)94 Writer::_write(const void *sBuffer, size_t dwBytesToWrite) {
95 m_file->write(sBuffer, dwBytesToWrite);
96 }
97
98 void inline
_writeByte(char c)99 Writer::_writeByte(char c) {
100 _write(&c, 1);
101 }
102
103 void inline
_writeUInt(unsigned long long value)104 Writer::_writeUInt(unsigned long long value) {
105 char buf[2 * sizeof value];
106 unsigned len;
107
108 len = 0;
109 do {
110 assert(len < sizeof buf);
111 buf[len] = 0x80 | (value & 0x7f);
112 value >>= 7;
113 ++len;
114 } while (value);
115
116 assert(len);
117 buf[len - 1] &= 0x7f;
118
119 _write(buf, len);
120 }
121
122 void inline
_writeFloat(float value)123 Writer::_writeFloat(float value) {
124 static_assert(sizeof value == 4, "float is not 4 bytes");
125 _write((const char *)&value, sizeof value);
126 }
127
128 void inline
_writeDouble(double value)129 Writer::_writeDouble(double value) {
130 static_assert(sizeof value == 8, "double is not 8 bytes");
131 _write((const char *)&value, sizeof value);
132 }
133
134 void inline
_writeString(const char * str)135 Writer::_writeString(const char *str) {
136 size_t len = strlen(str);
137 _writeUInt(len);
138 _write(str, len);
139 }
140
lookup(std::vector<bool> & map,size_t index)141 inline bool lookup(std::vector<bool> &map, size_t index) {
142 if (index >= map.size()) {
143 map.resize(index + 1);
144 return false;
145 } else {
146 return map[index];
147 }
148 }
149
beginBacktrace(unsigned num_frames)150 void Writer::beginBacktrace(unsigned num_frames) {
151 if (num_frames) {
152 _writeByte(trace::CALL_BACKTRACE);
153 _writeUInt(num_frames);
154 }
155 }
156
writeStackFrame(const RawStackFrame * frame)157 void Writer::writeStackFrame(const RawStackFrame *frame) {
158 _writeUInt(frame->id);
159 if (!lookup(frames, frame->id)) {
160 if (frame->module != NULL) {
161 _writeByte(trace::BACKTRACE_MODULE);
162 _writeString(frame->module);
163 }
164 if (frame->function != NULL) {
165 _writeByte(trace::BACKTRACE_FUNCTION);
166 _writeString(frame->function);
167 }
168 if (frame->filename != NULL) {
169 _writeByte(trace::BACKTRACE_FILENAME);
170 _writeString(frame->filename);
171 }
172 if (frame->linenumber >= 0) {
173 _writeByte(trace::BACKTRACE_LINENUMBER);
174 _writeUInt(frame->linenumber);
175 }
176 if (frame->offset >= 0) {
177 _writeByte(trace::BACKTRACE_OFFSET);
178 _writeUInt(frame->offset);
179 }
180 _writeByte(trace::BACKTRACE_END);
181 frames[frame->id] = true;
182 }
183 }
184
185 void
writeFlags(unsigned flags)186 Writer::writeFlags(unsigned flags) {
187 if (flags) {
188 _writeByte(trace::CALL_FLAGS);
189 _writeUInt(flags);
190 }
191 }
192
193 void
writeProperty(const char * name,const char * value)194 Writer::writeProperty(const char *name, const char *value)
195 {
196 assert(name);
197 assert(strlen(name));
198 assert(value);
199 _writeString(name);
200 _writeString(value);
201 }
202
203 void
endProperties(void)204 Writer::endProperties(void)
205 {
206 _writeUInt(0); // zero-length string
207 }
208
beginEnter(const FunctionSig * sig,unsigned thread_id)209 unsigned Writer::beginEnter(const FunctionSig *sig, unsigned thread_id) {
210 _writeByte(trace::EVENT_ENTER);
211 _writeUInt(thread_id);
212 _writeUInt(sig->id);
213 if (!lookup(functions, sig->id)) {
214 _writeString(sig->name);
215 _writeUInt(sig->num_args);
216 for (unsigned i = 0; i < sig->num_args; ++i) {
217 _writeString(sig->arg_names[i]);
218 }
219 functions[sig->id] = true;
220 }
221
222 return call_no++;
223 }
224
endEnter(void)225 void Writer::endEnter(void) {
226 _writeByte(trace::CALL_END);
227 }
228
beginLeave(unsigned call)229 void Writer::beginLeave(unsigned call) {
230 _writeByte(trace::EVENT_LEAVE);
231 _writeUInt(call);
232 }
233
endLeave(void)234 void Writer::endLeave(void) {
235 _writeByte(trace::CALL_END);
236 }
237
beginArg(unsigned index)238 void Writer::beginArg(unsigned index) {
239 _writeByte(trace::CALL_ARG);
240 _writeUInt(index);
241 }
242
beginReturn(void)243 void Writer::beginReturn(void) {
244 _writeByte(trace::CALL_RET);
245 }
246
beginArray(size_t length)247 void Writer::beginArray(size_t length) {
248 _writeByte(trace::TYPE_ARRAY);
249 _writeUInt(length);
250 }
251
beginStruct(const StructSig * sig)252 void Writer::beginStruct(const StructSig *sig) {
253 _writeByte(trace::TYPE_STRUCT);
254 _writeUInt(sig->id);
255 if (!lookup(structs, sig->id)) {
256 _writeString(sig->name);
257 _writeUInt(sig->num_members);
258 for (unsigned i = 0; i < sig->num_members; ++i) {
259 _writeString(sig->member_names[i]);
260 }
261 structs[sig->id] = true;
262 }
263 }
264
beginRepr(void)265 void Writer::beginRepr(void) {
266 _writeByte(trace::TYPE_REPR);
267 }
268
writeBool(bool value)269 void Writer::writeBool(bool value) {
270 _writeByte(value ? trace::TYPE_TRUE : trace::TYPE_FALSE);
271 }
272
writeSInt(signed long long value)273 void Writer::writeSInt(signed long long value) {
274 if (value < 0) {
275 _writeByte(trace::TYPE_SINT);
276 _writeUInt(-value);
277 } else {
278 _writeByte(trace::TYPE_UINT);
279 _writeUInt(value);
280 }
281 }
282
writeUInt(unsigned long long value)283 void Writer::writeUInt(unsigned long long value) {
284 _writeByte(trace::TYPE_UINT);
285 _writeUInt(value);
286 }
287
writeFloat(float value)288 void Writer::writeFloat(float value) {
289 _writeByte(trace::TYPE_FLOAT);
290 _writeFloat(value);
291 }
292
writeDouble(double value)293 void Writer::writeDouble(double value) {
294 _writeByte(trace::TYPE_DOUBLE);
295 _writeDouble(value);
296 }
297
writeString(const char * str)298 void Writer::writeString(const char *str) {
299 if (!str) {
300 Writer::writeNull();
301 return;
302 }
303 _writeByte(trace::TYPE_STRING);
304 _writeString(str);
305 }
306
writeString(const char * str,size_t len)307 void Writer::writeString(const char *str, size_t len) {
308 if (!str) {
309 Writer::writeNull();
310 return;
311 }
312 _writeByte(trace::TYPE_STRING);
313 _writeUInt(len);
314 _write(str, len);
315 }
316
writeWString(const wchar_t * str,size_t len)317 void Writer::writeWString(const wchar_t *str, size_t len) {
318 if (!str) {
319 Writer::writeNull();
320 return;
321 }
322 _writeByte(trace::TYPE_WSTRING);
323 _writeUInt(len);
324 for (size_t i = 0; i < len; ++i) {
325 _writeUInt(str[i]);
326 }
327 }
328
writeWString(const wchar_t * str)329 void Writer::writeWString(const wchar_t *str) {
330 if (!str) {
331 Writer::writeNull();
332 return;
333 }
334 size_t len = wcslen(str);
335 writeWString(str, len);
336 }
337
writeBlob(const void * data,size_t size)338 void Writer::writeBlob(const void *data, size_t size) {
339 if (!data) {
340 Writer::writeNull();
341 return;
342 }
343 _writeByte(trace::TYPE_BLOB);
344 _writeUInt(size);
345 if (size) {
346 _write(data, size);
347 }
348 }
349
writeEnum(const EnumSig * sig,signed long long value)350 void Writer::writeEnum(const EnumSig *sig, signed long long value) {
351 _writeByte(trace::TYPE_ENUM);
352 _writeUInt(sig->id);
353 if (!lookup(enums, sig->id)) {
354 _writeUInt(sig->num_values);
355 for (unsigned i = 0; i < sig->num_values; ++i) {
356 _writeString(sig->values[i].name);
357 writeSInt(sig->values[i].value);
358 }
359 enums[sig->id] = true;
360 }
361 writeSInt(value);
362 }
363
writeBitmask(const BitmaskSig * sig,unsigned long long value)364 void Writer::writeBitmask(const BitmaskSig *sig, unsigned long long value) {
365 _writeByte(trace::TYPE_BITMASK);
366 _writeUInt(sig->id);
367 if (!lookup(bitmasks, sig->id)) {
368 _writeUInt(sig->num_flags);
369 for (unsigned i = 0; i < sig->num_flags; ++i) {
370 if (i != 0 && sig->flags[i].value == 0) {
371 os::log("apitrace: warning: sig %s is zero but is not first flag\n", sig->flags[i].name);
372 }
373 _writeString(sig->flags[i].name);
374 _writeUInt(sig->flags[i].value);
375 }
376 bitmasks[sig->id] = true;
377 }
378 _writeUInt(value);
379 }
380
writeNull(void)381 void Writer::writeNull(void) {
382 _writeByte(trace::TYPE_NULL);
383 }
384
writePointer(unsigned long long addr)385 void Writer::writePointer(unsigned long long addr) {
386 if (!addr) {
387 Writer::writeNull();
388 return;
389 }
390 _writeByte(trace::TYPE_OPAQUE);
391 _writeUInt(addr);
392 }
393
394
395 } /* namespace trace */
396
397