]> git.cworth.org Git - apitrace/blob - common/os_win32.cpp
Use skiplist-based FastCallSet within trace::CallSet
[apitrace] / common / os_win32.cpp
1 /**************************************************************************
2  *
3  * Copyright 2010 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 #include <windows.h>
27
28 #include <assert.h>
29 #include <string.h>
30 #include <stdio.h>
31
32 #include <string>
33
34 #include "os.hpp"
35 #include "os_string.hpp"
36
37
38 namespace os {
39
40
41 String
42 getProcessName(void)
43 {
44     String path;
45     size_t size = MAX_PATH;
46     char *buf = path.buf(size);
47
48     DWORD nWritten = GetModuleFileNameA(NULL, buf, size);
49     (void)nWritten;
50
51     path.truncate();
52
53     return path;
54 }
55
56 String
57 getCurrentDir(void)
58 {
59     String path;
60     size_t size = MAX_PATH;
61     char *buf = path.buf(size);
62     
63     DWORD ret = GetCurrentDirectoryA(size, buf);
64     (void)ret;
65     
66     buf[size - 1] = 0;
67     path.truncate();
68
69     return path;
70 }
71
72 bool
73 String::exists(void) const
74 {
75     DWORD attrs = GetFileAttributesA(str());
76     return attrs != INVALID_FILE_ATTRIBUTES;
77 }
78
79 bool
80 copyFile(const String &srcFileName, const String &dstFileName, bool override)
81 {
82     return CopyFileA(srcFileName, dstFileName, !override);
83 }
84
85 bool
86 removeFile(const String &srcFilename)
87 {
88     return DeleteFileA(srcFilename);
89 }
90
91 /**
92  * Determine whether an argument should be quoted.
93  */
94 static bool
95 needsQuote(const char *arg)
96 {
97     char c;
98     while (true) {
99         c = *arg++;
100         if (c == '\0') {
101             break;
102         }
103         if (c == ' ' || c == '\t' || c == '\"') {
104             return true;
105         }
106         if (c == '\\') {
107             c = *arg++;
108             if (c == '\0') {
109                 break;
110             }
111             if (c == '"') {
112                 return true;
113             }
114         }
115     }
116     return false;
117 }
118
119 static void
120 quoteArg(std::string &s, const char *arg)
121 {
122     char c;
123     unsigned backslashes = 0;
124     
125     s.push_back('"');
126     while (true) {
127         c = *arg++;
128         if (c == '\0') {
129             break;
130         } else if (c == '"') {
131             while (backslashes) {
132                 s.push_back('\\');
133                 --backslashes;
134             }
135             s.push_back('\\');
136         } else {
137             if (c == '\\') {
138                 ++backslashes;
139             } else {
140                 backslashes = 0;
141             }
142         }
143         s.push_back(c);
144     }
145     s.push_back('"');
146 }
147
148 int execute(char * const * args)
149 {
150     std::string commandLine;
151    
152     const char *arg0 = *args;
153     const char *arg;
154     char sep = 0;
155     while ((arg = *args++) != NULL) {
156         if (sep) {
157             commandLine.push_back(sep);
158         }
159
160         if (needsQuote(arg)) {
161             quoteArg(commandLine, arg);
162         } else {
163             commandLine.append(arg);
164         }
165
166         sep = ' ';
167     }
168
169     STARTUPINFO startupInfo;
170     memset(&startupInfo, 0, sizeof(startupInfo));
171     startupInfo.cb = sizeof(startupInfo);
172
173     PROCESS_INFORMATION processInformation;
174
175     if (!CreateProcessA(NULL,
176                         const_cast<char *>(commandLine.c_str()), // only modified by CreateProcessW
177                         0, // process attributes
178                         0, // thread attributes
179                         FALSE, // inherit handles
180                         0, // creation flags,
181                         NULL, // environment
182                         NULL, // current directory
183                         &startupInfo,
184                         &processInformation
185                         )) {
186         log("error: failed to execute %s\n", arg0);
187         return -1;
188     }
189
190     WaitForSingleObject(processInformation.hProcess, INFINITE);
191
192     DWORD exitCode = ~0UL;
193     GetExitCodeProcess(processInformation.hProcess, &exitCode);
194
195     CloseHandle(processInformation.hProcess);
196     CloseHandle(processInformation.hThread);
197
198     return (int)exitCode;
199 }
200
201 void
202 log(const char *format, ...)
203 {
204     char buf[4096];
205
206     va_list ap;
207     va_start(ap, format);
208     fflush(stdout);
209     vsnprintf(buf, sizeof buf, format, ap);
210     va_end(ap);
211
212     OutputDebugStringA(buf);
213
214     /*
215      * Also write the message to stderr, when a debugger is not present (to
216      * avoid duplicate messages in command line debuggers).
217      */
218 #if _WIN32_WINNT > 0x0400
219     if (!IsDebuggerPresent()) {
220         fflush(stdout);
221         fputs(buf, stderr);
222         fflush(stderr);
223     }
224 #endif
225 }
226
227 long long timeFrequency = 0LL;
228
229 void
230 abort(void)
231 {
232 #ifndef NDEBUG
233     DebugBreak();
234 #else
235     ExitProcess(0);
236 #endif
237 }
238
239
240 #ifndef DBG_PRINTEXCEPTION_C
241 #define DBG_PRINTEXCEPTION_C 0x40010006
242 #endif
243
244 static PVOID prevExceptionFilter = NULL;
245 static void (*gCallback)(void) = NULL;
246
247 static LONG CALLBACK
248 unhandledExceptionHandler(PEXCEPTION_POINTERS pExceptionInfo)
249 {
250     PEXCEPTION_RECORD pExceptionRecord = pExceptionInfo->ExceptionRecord;
251
252     /*
253      * Ignore OutputDebugStringA exception.
254      */
255     if (pExceptionRecord->ExceptionCode == DBG_PRINTEXCEPTION_C) {
256         return EXCEPTION_CONTINUE_SEARCH;
257     }
258
259     /*
260      * Ignore C++ exceptions
261      *
262      * http://support.microsoft.com/kb/185294
263      * http://blogs.msdn.com/b/oldnewthing/archive/2010/07/30/10044061.aspx
264      */
265     if (pExceptionRecord->ExceptionCode == 0xe06d7363) {
266         return EXCEPTION_CONTINUE_SEARCH;
267     }
268
269     /*
270      * Ignore thread naming exception.
271      *
272      * http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx
273      */
274     if (pExceptionRecord->ExceptionCode == 0x406d1388) {
275         return EXCEPTION_CONTINUE_SEARCH;
276     }
277
278     /*
279      * Ignore .NET exception.
280      *
281      * http://ig2600.blogspot.co.uk/2011/01/why-do-i-keep-getting-exception-code.html
282      */
283     if (pExceptionRecord->ExceptionCode == 0xe0434352) {
284         return EXCEPTION_CONTINUE_SEARCH;
285     }
286
287     // Clear direction flag
288 #ifdef _MSC_VER
289 #ifndef _WIN64
290     __asm {
291         cld
292     };
293 #endif
294 #else
295     asm("cld");
296 #endif
297
298     log("apitrace: warning: caught exception 0x%08lx\n", pExceptionRecord->ExceptionCode);
299
300     static int recursion_count = 0;
301     if (recursion_count) {
302         fprintf(stderr, "apitrace: warning: recursion handling exception\n");
303     } else {
304         if (gCallback) {
305             ++recursion_count;
306             gCallback();
307             --recursion_count;
308         }
309     }
310
311     return EXCEPTION_CONTINUE_SEARCH;
312 }
313
314 void
315 setExceptionCallback(void (*callback)(void))
316 {
317     assert(!gCallback);
318
319     if (!gCallback) {
320         gCallback = callback;
321
322         assert(!prevExceptionFilter);
323
324         prevExceptionFilter = AddVectoredExceptionHandler(0, unhandledExceptionHandler);
325     }
326 }
327
328 void
329 resetExceptionCallback(void)
330 {
331     if (gCallback) {
332         RemoveVectoredExceptionHandler(prevExceptionFilter);
333         gCallback = NULL;
334     }
335 }
336
337
338 } /* namespace os */