]> git.cworth.org Git - apitrace/blob - trace_write.cpp
Merge branch 'trace-editing'
[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 static unsigned call_no = 0;
152
153 inline bool lookup(std::vector<bool> &map, size_t index) {
154     if (index >= map.size()) {
155         map.resize(index + 1);
156         return false;
157     } else {
158         return map[index];
159     }
160 }
161
162 static std::vector<bool> functions;
163 static std::vector<bool> structs;
164 static std::vector<bool> enums;
165 static std::vector<bool> bitmasks;
166
167
168 void Close(void) {
169     _Close();
170     call_no = 0;
171     functions = std::vector<bool>();
172     structs = std::vector<bool>();
173     enums = std::vector<bool>();
174     bitmasks = std::vector<bool>();
175 }
176
177 unsigned BeginEnter(const FunctionSig &function) {
178     OS::AcquireMutex();
179     Open();
180     WriteByte(Trace::EVENT_ENTER);
181     WriteUInt(function.id);
182     if (!lookup(functions, function.id)) {
183         WriteString(function.name);
184         WriteUInt(function.num_args);
185         for (unsigned i = 0; i < function.num_args; ++i) {
186             WriteString(function.args[i]);
187         }
188         functions[function.id] = true;
189     }
190     return call_no++;
191 }
192
193 void EndEnter(void) {
194     WriteByte(Trace::CALL_END);
195     gzflush(g_gzFile, Z_SYNC_FLUSH);
196     OS::ReleaseMutex();
197 }
198
199 void BeginLeave(unsigned call) {
200     OS::AcquireMutex();
201     WriteByte(Trace::EVENT_LEAVE);
202     WriteUInt(call);
203 }
204
205 void EndLeave(void) {
206     WriteByte(Trace::CALL_END);
207     gzflush(g_gzFile, Z_SYNC_FLUSH);
208     OS::ReleaseMutex();
209 }
210
211 void BeginArg(unsigned index) {
212     WriteByte(Trace::CALL_ARG);
213     WriteUInt(index);
214 }
215
216 void BeginReturn(void) {
217     WriteByte(Trace::CALL_RET);
218 }
219
220 void BeginArray(size_t length) {
221     WriteByte(Trace::TYPE_ARRAY);
222     WriteUInt(length);
223 }
224
225 void BeginStruct(const StructSig *sig) {
226     WriteByte(Trace::TYPE_STRUCT);
227     WriteUInt(sig->id);
228     if (!lookup(structs, sig->id)) {
229         WriteString(sig->name);
230         WriteUInt(sig->num_members);
231         for (unsigned i = 0; i < sig->num_members; ++i) {
232             WriteString(sig->members[i]);
233         }
234         structs[sig->id] = true;
235     }
236 }
237
238 void LiteralBool(bool value) {
239     WriteByte(value ? Trace::TYPE_TRUE : Trace::TYPE_FALSE);
240 }
241
242 void LiteralSInt(signed long long value) {
243     if (value < 0) {
244         WriteByte(Trace::TYPE_SINT);
245         WriteUInt(-value);
246     } else {
247         WriteByte(Trace::TYPE_UINT);
248         WriteUInt(value);
249     }
250 }
251
252 void LiteralUInt(unsigned long long value) {
253     WriteByte(Trace::TYPE_UINT);
254     WriteUInt(value);
255 }
256
257 void LiteralFloat(float value) {
258     WriteByte(Trace::TYPE_FLOAT);
259     WriteFloat(value);
260 }
261
262 void LiteralFloat(double value) {
263     WriteByte(Trace::TYPE_DOUBLE);
264     WriteDouble(value);
265 }
266
267 void LiteralString(const char *str) {
268     if (!str) {
269         LiteralNull();
270         return;
271     }
272     WriteByte(Trace::TYPE_STRING);
273     WriteString(str);
274 }
275
276 void LiteralString(const char *str, size_t len) {
277     if (!str) {
278         LiteralNull();
279         return;
280     }
281     WriteByte(Trace::TYPE_STRING);
282     WriteUInt(len);
283     Write(str, len);
284 }
285
286 void LiteralWString(const wchar_t *str) {
287     if (!str) {
288         LiteralNull();
289         return;
290     }
291     WriteByte(Trace::TYPE_STRING);
292     WriteString("<wide-string>");
293 }
294
295 void LiteralBlob(const void *data, size_t size) {
296     if (!data) {
297         LiteralNull();
298         return;
299     }
300     WriteByte(Trace::TYPE_BLOB);
301     WriteUInt(size);
302     if (size) {
303         Write(data, size);
304     }
305 }
306
307 void LiteralEnum(const EnumSig *sig) {
308     WriteByte(Trace::TYPE_ENUM);
309     WriteUInt(sig->id);
310     if (!lookup(enums, sig->id)) {
311         WriteString(sig->name);
312         LiteralSInt(sig->value);
313         enums[sig->id] = true;
314     }
315 }
316
317 void LiteralBitmask(const BitmaskSig &bitmask, unsigned long long value) {
318     WriteByte(Trace::TYPE_BITMASK);
319     WriteUInt(bitmask.id);
320     if (!lookup(bitmasks, bitmask.id)) {
321         WriteUInt(bitmask.count);
322         for (unsigned i = 0; i < bitmask.count; ++i) {
323             if (i != 0 && bitmask.values[i].value == 0) {
324                 OS::DebugMessage("apitrace: bitmask %s is zero but is not first flag\n", bitmask.values[i].name);
325             }
326             WriteString(bitmask.values[i].name);
327             WriteUInt(bitmask.values[i].value);
328         }
329         bitmasks[bitmask.id] = true;
330     }
331     WriteUInt(value);
332 }
333
334 void LiteralNull(void) {
335     WriteByte(Trace::TYPE_NULL);
336 }
337
338 void LiteralOpaque(const void *addr) {
339     if (!addr) {
340         LiteralNull();
341         return;
342     }
343     WriteByte(Trace::TYPE_OPAQUE);
344     WriteUInt((size_t)addr);
345 }
346
347 void Abort(void) {
348     Close();
349     OS::Abort();
350 }
351
352 } /* namespace Trace */
353
354
355 #ifdef _WIN32
356
357 #if 0
358 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) {
359     switch(fdwReason) {
360     case DLL_PROCESS_ATTACH:
361     case DLL_THREAD_ATTACH:
362         return TRUE;
363     case DLL_THREAD_DETACH:
364         return TRUE;
365     case DLL_PROCESS_DETACH:
366         Trace::Close();
367         return TRUE;
368     }
369     (void)hinstDLL;
370     (void)lpvReserved;
371     return TRUE;
372 }
373 #endif
374
375 #else
376
377 static void _uninit(void) __attribute__((destructor));
378 static void _uninit(void) {
379     Trace::Close();
380 }
381
382 #endif