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