]> git.cworth.org Git - apitrace/blob - common/os_win32.cpp
Preserve both D3D9 shader byte code, and disassembly.
[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         switch (c)
129         if (c == '\0') {
130             break;
131         } else if (c == '"') {
132             while (backslashes) {
133                 s.push_back('\\');
134                 --backslashes;
135             }
136             s.push_back('\\');
137         } else {
138             if (c == '\\') {
139                 ++backslashes;
140             } else {
141                 backslashes = 0;
142             }
143         }
144         s.push_back(c);
145     }
146     s.push_back('"');
147 }
148
149 int execute(char * const * args)
150 {
151     std::string commandLine;
152    
153     const char *arg0 = *args;
154     const char *arg;
155     char sep = 0;
156     while ((arg = *args++) != NULL) {
157         if (sep) {
158             commandLine.push_back(sep);
159         }
160
161         if (needsQuote(arg)) {
162             quoteArg(commandLine, arg);
163         } else {
164             commandLine.append(arg);
165         }
166
167         sep = ' ';
168     }
169
170     STARTUPINFO startupInfo;
171     memset(&startupInfo, 0, sizeof(startupInfo));
172     startupInfo.cb = sizeof(startupInfo);
173
174     PROCESS_INFORMATION processInformation;
175
176     if (!CreateProcessA(NULL,
177                         const_cast<char *>(commandLine.c_str()), // only modified by CreateProcessW
178                         0, // process attributes
179                         0, // thread attributes
180                         FALSE, // inherit handles
181                         0, // creation flags,
182                         NULL, // environment
183                         NULL, // current directory
184                         &startupInfo,
185                         &processInformation
186                         )) {
187         log("error: failed to execute %s\n", arg0);
188         return -1;
189     }
190
191     WaitForSingleObject(processInformation.hProcess, INFINITE);
192
193     DWORD exitCode = ~0;
194     GetExitCodeProcess(processInformation.hProcess, &exitCode);
195
196     CloseHandle(processInformation.hProcess);
197     CloseHandle(processInformation.hThread);
198
199     return (int)exitCode;
200 }
201
202 void
203 log(const char *format, ...)
204 {
205     char buf[4096];
206
207     va_list ap;
208     va_start(ap, format);
209     fflush(stdout);
210     vsnprintf(buf, sizeof buf, format, ap);
211     va_end(ap);
212
213     OutputDebugStringA(buf);
214
215     /*
216      * Also write the message to stderr, when a debugger is not present (to
217      * avoid duplicate messages in command line debuggers).
218      */
219 #if _WIN32_WINNT > 0x0400
220     if (!IsDebuggerPresent()) {
221         fflush(stdout);
222         fputs(buf, stderr);
223         fflush(stderr);
224     }
225 #endif
226 }
227
228 long long timeFrequency = 0LL;
229
230 void
231 abort(void)
232 {
233 #ifndef NDEBUG
234     DebugBreak();
235 #else
236     ExitProcess(0);
237 #endif
238 }
239
240
241 #ifndef DBG_PRINTEXCEPTION_C
242 #define DBG_PRINTEXCEPTION_C 0x40010006
243 #endif
244
245 static PVOID prevExceptionFilter = NULL;
246 static void (*gCallback)(void) = NULL;
247
248 static LONG CALLBACK
249 unhandledExceptionHandler(PEXCEPTION_POINTERS pExceptionInfo)
250 {
251     PEXCEPTION_RECORD pExceptionRecord = pExceptionInfo->ExceptionRecord;
252
253     /*
254      * Ignore OutputDebugStringA exception.
255      */
256     if (pExceptionRecord->ExceptionCode == DBG_PRINTEXCEPTION_C) {
257         return EXCEPTION_CONTINUE_SEARCH;
258     }
259
260     /*
261      * Ignore C++ exceptions
262      *
263      * http://support.microsoft.com/kb/185294
264      * http://blogs.msdn.com/b/oldnewthing/archive/2010/07/30/10044061.aspx
265      */
266     if (pExceptionRecord->ExceptionCode == 0xe06d7363) {
267         return EXCEPTION_CONTINUE_SEARCH;
268     }
269
270     /*
271      * Ignore thread naming exception.
272      *
273      * http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx
274      */
275     if (pExceptionRecord->ExceptionCode == 0x406d1388) {
276         return EXCEPTION_CONTINUE_SEARCH;
277     }
278
279     // Clear direction flag
280 #ifdef _MSC_VER
281 #ifndef _WIN64
282     __asm {
283         cld
284     };
285 #endif
286 #else
287     asm("cld");
288 #endif
289
290     log("apitrace: warning: caught exception 0x%08lx\n", pExceptionRecord->ExceptionCode);
291
292     static int recursion_count = 0;
293     if (recursion_count) {
294         fprintf(stderr, "apitrace: warning: recursion handling exception\n");
295     } else {
296         if (gCallback) {
297             ++recursion_count;
298             gCallback();
299             --recursion_count;
300         }
301     }
302
303     return EXCEPTION_CONTINUE_SEARCH;
304 }
305
306 void
307 setExceptionCallback(void (*callback)(void))
308 {
309     assert(!gCallback);
310
311     if (!gCallback) {
312         gCallback = callback;
313
314         assert(!prevExceptionFilter);
315
316         prevExceptionFilter = AddVectoredExceptionHandler(0, unhandledExceptionHandler);
317     }
318 }
319
320 void
321 resetExceptionCallback(void)
322 {
323     if (gCallback) {
324         RemoveVectoredExceptionHandler(prevExceptionFilter);
325         gCallback = NULL;
326     }
327 }
328
329
330 } /* namespace os */