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