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