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