]> git.cworth.org Git - apitrace/blob - log.cpp
Basic Linux/GLX tracing support.
[apitrace] / log.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 <stdarg.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31
32 #ifdef WIN32
33 #include <windows.h>
34 #endif
35
36 #include <zlib.h>
37
38 #include "log.hpp"
39
40
41 #ifdef WIN32
42 #ifndef PATH_MAX
43 #define PATH_MAX _MAX_PATH
44 #endif
45 #ifndef snprintf
46 #define snprintf _snprintf
47 #endif
48 #ifndef vsnprintf
49 #define vsnprintf _vsnprintf
50 #endif
51 #endif /* WIN32 */
52
53 #ifndef PATH_MAX
54 #define PATH_MAX 1024
55 #endif
56
57 namespace Log {
58
59
60 static gzFile g_gzFile = NULL;
61 static char g_szFileName[PATH_MAX];
62
63 #if WIN32
64 static CRITICAL_SECTION CriticalSection;
65 #endif /* WIN32 */
66
67 static void _Close(void) {
68     if(g_gzFile != NULL) {
69         gzclose(g_gzFile);
70         g_gzFile = NULL;
71 #if WIN32
72         DeleteCriticalSection(&CriticalSection);
73 #endif
74     }
75 }
76
77 static void _Open(const char *szName, const char *szExtension) {
78     _Close();
79     
80     static unsigned dwCounter = 0;
81
82     char szProcessPath[PATH_MAX];
83     char *lpProcessName;
84     char *lpProcessExt;
85
86 #ifdef WIN32
87     GetModuleFileNameA(NULL, szProcessPath, sizeof(szProcessPath)/sizeof(szProcessPath[0]));
88
89     lpProcessName = strrchr(szProcessPath, '\\');
90     lpProcessName = lpProcessName ? lpProcessName + 1 : szProcessPath;
91     lpProcessExt = strrchr(lpProcessName, '.');
92     if(lpProcessExt)
93         *lpProcessExt = '\0';
94 #else
95     // http://stackoverflow.com/questions/1023306/finding-current-executables-path-without-proc-self-exe
96     lpProcessName = "";
97 #endif
98
99     for(;;) {
100         FILE *file;
101         
102         if(dwCounter)
103             snprintf(g_szFileName, PATH_MAX, "%s.%s.%u.%s.gz", lpProcessName, szName, dwCounter, szExtension);
104         else
105             snprintf(g_szFileName, PATH_MAX, "%s.%s.%s.gz", lpProcessName, szName, szExtension);
106         
107         file = fopen(g_szFileName, "rb");
108         if(file == NULL)
109             break;
110         
111         fclose(file);
112         
113         ++dwCounter;
114     }
115
116     g_gzFile = gzopen(g_szFileName, "wb");
117 #ifdef WIN32
118     InitializeCriticalSection(&CriticalSection);
119 #endif
120 }
121
122 static inline void _ReOpen(void) {
123     /* XXX */
124 }
125
126 static inline void Write(const char *sBuffer, size_t dwBytesToWrite) {
127     if(g_gzFile == NULL)
128         return;
129     
130     gzwrite(g_gzFile, sBuffer, dwBytesToWrite);
131 }
132
133 static inline void Write(const char *szText) {
134     Write(szText, strlen(szText));
135 }
136
137 static inline void Write(char c) 
138 {
139     Write(&c, 1);
140 }
141
142 static inline void
143 WriteF(const char *format, ...) 
144 {
145     char szBuffer[4096];
146     va_list ap;
147     va_start(ap, format);
148     vsnprintf(szBuffer, sizeof(szBuffer), format, ap);
149     va_end(ap);
150     Write(szBuffer);
151 }
152
153 static inline void 
154 Escape(char c) 
155 {
156     switch(c) {
157     case '&':
158         Write("&amp;");
159         break;
160     case '<':
161         Write("&lt;");
162         break;
163     case '>':
164         Write("&gt;");
165         break;
166     case '"':
167         Write("&quot;");
168         break;
169     case '\'':
170         Write("&apos;");
171         break;
172     default:
173         Write(c);
174     }
175 }
176
177 static inline void 
178 Escape(const char *s)
179 {
180     unsigned char c;
181     while((c = *s++) != 0) {
182         Escape(c);
183     }
184 }
185
186 static inline void
187 EscapeF(const char *format, ...)
188 {
189     char szBuffer[4096];
190     va_list ap;
191     va_start(ap, format);
192     vsnprintf(szBuffer, sizeof(szBuffer), format, ap);
193     va_end(ap);
194     Escape(szBuffer);
195 }
196
197 static inline void 
198 Indent(unsigned level) {
199     for(unsigned i = 0; i < level; ++i)
200         Write("\t");
201 }
202
203 static inline void 
204 NewLine(void) {
205     Write("\r\n");
206 }
207
208 static inline void 
209 Tag(const char *name) {
210     Write("<");
211     Write(name);
212     Write("/>");
213 }
214
215 static inline void 
216 BeginTag(const char *name) {
217     Write("<");
218     Write(name);
219     Write(">");
220 }
221
222 static inline void 
223 BeginTag(const char *name, 
224          const char *attr1, const char *value1) {
225     Write("<");
226     Write(name);
227     Write(" ");
228     Write(attr1);
229     Write("=\"");
230     Escape(value1);
231     Write("\">");
232 }
233
234 static inline void 
235 BeginTag(const char *name, 
236          const char *attr1, const char *value1,
237          const char *attr2, const char *value2) {
238     Write("<");
239     Write(name);
240     Write(" ");
241     Write(attr1);
242     Write("=\"");
243     Escape(value1);
244     Write("\" ");
245     Write(attr2);
246     Write("=\"");
247     Escape(value2);
248     Write("\">");
249 }
250
251 static inline void 
252 BeginTag(const char *name, 
253               const char *attr1, const char *value1,
254               const char *attr2, const char *value2,
255               const char *attr3, const char *value3) {
256     Write("<");
257     Write(name);
258     Write(" ");
259     Write(attr1);
260     Write("=\"");
261     Escape(value1);
262     Write("\" ");
263     Write(attr2);
264     Write("=\"");
265     Escape(value2);
266     Write("\" ");
267     Write(attr3);
268     Write("=\"");
269     Escape(value3);
270     Write("\">");
271 }
272
273 static inline void
274 EndTag(const char *name) {
275     Write("</");
276     Write(name);
277     Write(">");
278 }
279
280 void Open(const char *name) {
281     _Open(name, "xml");
282     Write("<?xml version='1.0' encoding='UTF-8'?>");
283     NewLine();
284     Write("<?xml-stylesheet type='text/xsl' href='apitrace.xsl'?>");
285     NewLine();
286     BeginTag("trace");
287     NewLine();
288 }
289
290 void ReOpen(void) {
291     _ReOpen();
292 }
293
294 void Close(void) {
295     EndTag("trace");
296     NewLine();
297     _Close();
298 }
299
300 void Text(const char *text) {
301     Escape(text);
302 }
303
304 void TextF(const char *format, ...) {
305     char szBuffer[4096];
306     va_list ap;
307     va_start(ap, format);
308     vsnprintf(szBuffer, sizeof(szBuffer), format, ap);
309     va_end(ap);
310     Escape(szBuffer);
311 }
312
313 void BeginCall(const char *function) {
314 #ifdef WIN32
315     EnterCriticalSection(&CriticalSection); 
316 #endif
317     Indent(1);
318     BeginTag("call", "name", function);
319     NewLine();
320 }
321
322 void EndCall(void) {
323     Indent(1);
324     EndTag("call");
325     NewLine();
326     gzflush(g_gzFile, Z_SYNC_FLUSH);
327 #ifdef WIN32
328     LeaveCriticalSection(&CriticalSection); 
329 #endif
330 }
331
332 void BeginArg(const char *type, const char *name) {
333     Indent(2);
334     BeginTag("arg", "type", type, "name", name);
335 }
336
337 void EndArg(void) {
338     EndTag("arg");
339     NewLine();
340 }
341
342 void BeginReturn(const char *type) {
343     Indent(2);
344     BeginTag("ret", "type", type);
345 }
346
347 void EndReturn(void) {
348     EndTag("ret");
349     NewLine();
350 }
351
352 void BeginElement(const char *type, const char *name) {
353     BeginTag("elem", "type", type, "name", name);
354 }
355
356 void BeginElement(const char *type) {
357     BeginTag("elem", "type", type);
358 }
359
360 void EndElement(void) {
361     EndTag("elem");
362 }
363
364 void BeginReference(const char *type, const void *addr) {
365     char saddr[256];
366     snprintf(saddr, sizeof(saddr), "%p", addr);
367     BeginTag("ref", "type", type, "addr", saddr);
368 }
369
370 void EndReference(void) {
371     EndTag("ref");
372 }
373
374 void DumpString(const char *str) {
375     const unsigned char *p = (const unsigned char *)str;
376     if (!str) {
377         Write("NULL");
378         return;
379     }
380     Write("\"");
381     unsigned char c;
382     while((c = *p++) != 0) {
383         if(c == '\"')
384             Write("\\\"");
385         else if(c == '\\')
386             Write("\\\\");
387         else if(c >= 0x20 && c <= 0x7e)
388             Write(c);
389         else if(c == '\t')
390             Write("&#09;");
391         else if(c == '\r')
392             Write("&#13;");
393         else if(c == '\n')
394             Write("&#10;");
395         else {
396             unsigned char octal0 = c & 0x7;
397             unsigned char octal1 = (c >> 3) & 0x7;
398             unsigned char octal2 = (c >> 3) & 0x7;
399             if(octal2)
400                 WriteF("\\%u%u%u", octal2, octal1, octal0);
401             else if(octal1)
402                 WriteF("\\%u%u", octal1, octal0);
403             else
404                 WriteF("\\%u", octal0);
405         }
406     }
407     Write("\"");
408 }
409
410 void DumpWString(const wchar_t *str) {
411     const wchar_t *p = str;
412     if (!str) {
413         Write("NULL");
414         return;
415     }
416     Write("L\"");
417     wchar_t c;
418     while((c = *p++) != 0) {
419         if(c == '\"')
420             Write("\\\"");
421         else if(c == '\\')
422             Write("\\\\");
423         else if(c >= 0x20 && c <= 0x7e)
424             Write((char)c);
425         else if(c == '\t')
426             Write("&#09;");
427         else if(c == '\r')
428             Write("&#13;");
429         else if(c == '\n')
430             Write("&#10;");
431         else {
432             unsigned octal0 = c & 0x7;
433             unsigned octal1 = (c >> 3) & 0x7;
434             unsigned octal2 = (c >> 3) & 0x7;
435             if(octal2)
436                 WriteF("\\%u%u%u", octal2, octal1, octal0);
437             else if(octal1)
438                 WriteF("\\%u%u", octal1, octal0);
439             else
440                 WriteF("\\%u", octal0);
441         }
442     }
443     Write("\"");
444 }
445
446 } /* namespace Log */