]> git.cworth.org Git - apitrace/blob - common/trace_writer.cpp
Cleanup the backtrace representation.
[apitrace] / common / trace_writer.cpp
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 <vector>
33
34 #include "os.hpp"
35 #include "trace_file.hpp"
36 #include "trace_writer.hpp"
37 #include "trace_format.hpp"
38 #include "trace_backtrace.hpp"
39
40 namespace trace {
41
42
43 Writer::Writer() :
44     call_no(0)
45 {
46     m_file = File::createSnappy();
47     close();
48 }
49
50 Writer::~Writer()
51 {
52     close();
53     delete m_file;
54     m_file = NULL;
55 }
56
57 void
58 Writer::close(void) {
59     m_file->close();
60 }
61
62 bool
63 Writer::open(const char *filename) {
64     close();
65
66     if (!m_file->open(filename, File::Write)) {
67         return false;
68     }
69
70     call_no = 0;
71     functions.clear();
72     structs.clear();
73     enums.clear();
74     bitmasks.clear();
75
76     _writeUInt(TRACE_VERSION);
77
78     return true;
79 }
80
81 void inline
82 Writer::_write(const void *sBuffer, size_t dwBytesToWrite) {
83     m_file->write(sBuffer, dwBytesToWrite);
84 }
85
86 void inline
87 Writer::_writeByte(char c) {
88     _write(&c, 1);
89 }
90
91 void inline
92 Writer::_writeUInt(unsigned long long value) {
93     char buf[2 * sizeof value];
94     unsigned len;
95
96     len = 0;
97     do {
98         assert(len < sizeof buf);
99         buf[len] = 0x80 | (value & 0x7f);
100         value >>= 7;
101         ++len;
102     } while (value);
103
104     assert(len);
105     buf[len - 1] &= 0x7f;
106
107     _write(buf, len);
108 }
109
110 void inline
111 Writer::_writeFloat(float value) {
112     assert(sizeof value == 4);
113     _write((const char *)&value, sizeof value);
114 }
115
116 void inline
117 Writer::_writeDouble(double value) {
118     assert(sizeof value == 8);
119     _write((const char *)&value, sizeof value);
120 }
121
122 void inline
123 Writer::_writeString(const char *str) {
124     size_t len = strlen(str);
125     _writeUInt(len);
126     _write(str, len);
127 }
128
129 inline bool lookup(std::vector<bool> &map, size_t index) {
130     if (index >= map.size()) {
131         map.resize(index + 1);
132         return false;
133     } else {
134         return map[index];
135     }
136 }
137
138 void Writer::beginBacktrace(unsigned num_frames) {
139     if (num_frames) {
140         _writeByte(trace::CALL_BACKTRACE);
141         _writeUInt(num_frames);
142     }
143 }
144
145 void Writer::writeStackFrame(const RawStackFrame &frame) {
146     if (frame.module != NULL) {
147         _writeByte(trace::BACKTRACE_MODULE);
148         _writeString(frame.module);
149     }
150     if (frame.function != NULL) {
151         _writeByte(trace::BACKTRACE_FUNCTION);
152         _writeString(frame.function);
153     }
154     if (frame.filename != NULL) {
155         _writeByte(trace::BACKTRACE_FILENAME);
156         _writeString(frame.filename);
157     }
158     if (frame.linenumber >= 0) {
159         _writeByte(trace::BACKTRACE_LINENUMBER);
160         _writeUInt(frame.linenumber);
161     }
162     if (frame.offset >= 0) {
163         _writeByte(trace::BACKTRACE_OFFSET);
164         _writeUInt(frame.offset);
165     }
166     _writeByte(trace::BACKTRACE_END);
167 }
168
169 unsigned Writer::beginEnter(const FunctionSig *sig, unsigned thread_id) {
170     _writeByte(trace::EVENT_ENTER);
171     _writeUInt(thread_id);
172     _writeUInt(sig->id);
173     if (!lookup(functions, sig->id)) {
174         _writeString(sig->name);
175         _writeUInt(sig->num_args);
176         for (unsigned i = 0; i < sig->num_args; ++i) {
177             _writeString(sig->arg_names[i]);
178         }
179         functions[sig->id] = true;
180     }
181
182     return call_no++;
183 }
184
185 void Writer::endEnter(void) {
186     _writeByte(trace::CALL_END);
187 }
188
189 void Writer::beginLeave(unsigned call) {
190     _writeByte(trace::EVENT_LEAVE);
191     _writeUInt(call);
192 }
193
194 void Writer::endLeave(void) {
195     _writeByte(trace::CALL_END);
196 }
197
198 void Writer::beginArg(unsigned index) {
199     _writeByte(trace::CALL_ARG);
200     _writeUInt(index);
201 }
202
203 void Writer::beginReturn(void) {
204     _writeByte(trace::CALL_RET);
205 }
206
207 void Writer::beginArray(size_t length) {
208     _writeByte(trace::TYPE_ARRAY);
209     _writeUInt(length);
210 }
211
212 void Writer::beginStruct(const StructSig *sig) {
213     _writeByte(trace::TYPE_STRUCT);
214     _writeUInt(sig->id);
215     if (!lookup(structs, sig->id)) {
216         _writeString(sig->name);
217         _writeUInt(sig->num_members);
218         for (unsigned i = 0; i < sig->num_members; ++i) {
219             _writeString(sig->member_names[i]);
220         }
221         structs[sig->id] = true;
222     }
223 }
224
225 void Writer::beginRepr(void) {
226     _writeByte(trace::TYPE_REPR);
227 }
228
229 void Writer::writeBool(bool value) {
230     _writeByte(value ? trace::TYPE_TRUE : trace::TYPE_FALSE);
231 }
232
233 void Writer::writeSInt(signed long long value) {
234     if (value < 0) {
235         _writeByte(trace::TYPE_SINT);
236         _writeUInt(-value);
237     } else {
238         _writeByte(trace::TYPE_UINT);
239         _writeUInt(value);
240     }
241 }
242
243 void Writer::writeUInt(unsigned long long value) {
244     _writeByte(trace::TYPE_UINT);
245     _writeUInt(value);
246 }
247
248 void Writer::writeFloat(float value) {
249     _writeByte(trace::TYPE_FLOAT);
250     _writeFloat(value);
251 }
252
253 void Writer::writeDouble(double value) {
254     _writeByte(trace::TYPE_DOUBLE);
255     _writeDouble(value);
256 }
257
258 void Writer::writeString(const char *str) {
259     if (!str) {
260         Writer::writeNull();
261         return;
262     }
263     _writeByte(trace::TYPE_STRING);
264     _writeString(str);
265 }
266
267 void Writer::writeString(const char *str, size_t len) {
268     if (!str) {
269         Writer::writeNull();
270         return;
271     }
272     _writeByte(trace::TYPE_STRING);
273     _writeUInt(len);
274     _write(str, len);
275 }
276
277 void Writer::writeWString(const wchar_t *str) {
278     if (!str) {
279         Writer::writeNull();
280         return;
281     }
282     _writeByte(trace::TYPE_STRING);
283     _writeString("<wide-string>");
284 }
285
286 void Writer::writeBlob(const void *data, size_t size) {
287     if (!data) {
288         Writer::writeNull();
289         return;
290     }
291     _writeByte(trace::TYPE_BLOB);
292     _writeUInt(size);
293     if (size) {
294         _write(data, size);
295     }
296 }
297
298 void Writer::writeEnum(const EnumSig *sig, signed long long value) {
299     _writeByte(trace::TYPE_ENUM);
300     _writeUInt(sig->id);
301     if (!lookup(enums, sig->id)) {
302         _writeUInt(sig->num_values);
303         for (unsigned i = 0; i < sig->num_values; ++i) {
304             _writeString(sig->values[i].name);
305             writeSInt(sig->values[i].value);
306         }
307         enums[sig->id] = true;
308     }
309     writeSInt(value);
310 }
311
312 void Writer::writeBitmask(const BitmaskSig *sig, unsigned long long value) {
313     _writeByte(trace::TYPE_BITMASK);
314     _writeUInt(sig->id);
315     if (!lookup(bitmasks, sig->id)) {
316         _writeUInt(sig->num_flags);
317         for (unsigned i = 0; i < sig->num_flags; ++i) {
318             if (i != 0 && sig->flags[i].value == 0) {
319                 os::log("apitrace: warning: sig %s is zero but is not first flag\n", sig->flags[i].name);
320             }
321             _writeString(sig->flags[i].name);
322             _writeUInt(sig->flags[i].value);
323         }
324         bitmasks[sig->id] = true;
325     }
326     _writeUInt(value);
327 }
328
329 void Writer::writeNull(void) {
330     _writeByte(trace::TYPE_NULL);
331 }
332
333 void Writer::writePointer(unsigned long long addr) {
334     if (!addr) {
335         Writer::writeNull();
336         return;
337     }
338     _writeByte(trace::TYPE_OPAQUE);
339     _writeUInt(addr);
340 }
341
342
343 } /* namespace trace */
344