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