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