X-Git-Url: https://git.cworth.org/git?a=blobdiff_plain;f=common%2Fos_win32.cpp;h=e9306cdc6dfa0168b3bca328d5511b66bb551932;hb=HEAD;hp=4e48da5089992c594615018eabd37bc9957d3e8f;hpb=b4a3d1495a5e92ba23bf463bcea34a6e75b55294;p=apitrace diff --git a/common/os_win32.cpp b/common/os_win32.cpp index 4e48da5..e9306cd 100644 --- a/common/os_win32.cpp +++ b/common/os_win32.cpp @@ -29,68 +29,177 @@ #include #include +#include + #include "os.hpp" +#include "os_string.hpp" namespace os { -/* - * Trick from http://locklessinc.com/articles/pthreads_on_windows/ - */ -static CRITICAL_SECTION -CriticalSection = { - (PCRITICAL_SECTION_DEBUG)-1, -1, 0, 0, 0, 0 -}; +String +getProcessName(void) +{ + String path; + size_t size = MAX_PATH; + char *buf = path.buf(size); + DWORD nWritten = GetModuleFileNameA(NULL, buf, size); + (void)nWritten; -void -AcquireMutex(void) -{ - EnterCriticalSection(&CriticalSection); + path.truncate(); + + return path; } +String +getCurrentDir(void) +{ + String path; + size_t size = MAX_PATH; + char *buf = path.buf(size); + + DWORD ret = GetCurrentDirectoryA(size, buf); + (void)ret; + + buf[size - 1] = 0; + path.truncate(); + + return path; +} -void -ReleaseMutex(void) +bool +String::exists(void) const { - LeaveCriticalSection(&CriticalSection); + DWORD attrs = GetFileAttributesA(str()); + return attrs != INVALID_FILE_ATTRIBUTES; } +bool +copyFile(const String &srcFileName, const String &dstFileName, bool override) +{ + return CopyFileA(srcFileName, dstFileName, !override); +} bool -GetProcessName(char *str, size_t size) +removeFile(const String &srcFilename) +{ + return DeleteFileA(srcFilename); +} + +/** + * Determine whether an argument should be quoted. + */ +static bool +needsQuote(const char *arg) { - char szProcessPath[PATH_MAX]; - char *lpProcessName; - char *lpProcessExt; + char c; + while (true) { + c = *arg++; + if (c == '\0') { + break; + } + if (c == ' ' || c == '\t' || c == '\"') { + return true; + } + if (c == '\\') { + c = *arg++; + if (c == '\0') { + break; + } + if (c == '"') { + return true; + } + } + } + return false; +} - GetModuleFileNameA(NULL, szProcessPath, sizeof(szProcessPath)/sizeof(szProcessPath[0])); +static void +quoteArg(std::string &s, const char *arg) +{ + char c; + unsigned backslashes = 0; + + s.push_back('"'); + while (true) { + c = *arg++; + if (c == '\0') { + break; + } else if (c == '"') { + while (backslashes) { + s.push_back('\\'); + --backslashes; + } + s.push_back('\\'); + } else { + if (c == '\\') { + ++backslashes; + } else { + backslashes = 0; + } + } + s.push_back(c); + } + s.push_back('"'); +} - lpProcessName = strrchr(szProcessPath, '\\'); - lpProcessName = lpProcessName ? lpProcessName + 1 : szProcessPath; +int execute(char * const * args) +{ + std::string commandLine; + + const char *arg0 = *args; + const char *arg; + char sep = 0; + while ((arg = *args++) != NULL) { + if (sep) { + commandLine.push_back(sep); + } + + if (needsQuote(arg)) { + quoteArg(commandLine, arg); + } else { + commandLine.append(arg); + } + + sep = ' '; + } - lpProcessExt = strrchr(lpProcessName, '.'); - if (lpProcessExt) { - *lpProcessExt = '\0'; + STARTUPINFO startupInfo; + memset(&startupInfo, 0, sizeof(startupInfo)); + startupInfo.cb = sizeof(startupInfo); + + PROCESS_INFORMATION processInformation; + + if (!CreateProcessA(NULL, + const_cast(commandLine.c_str()), // only modified by CreateProcessW + 0, // process attributes + 0, // thread attributes + FALSE, // inherit handles + 0, // creation flags, + NULL, // environment + NULL, // current directory + &startupInfo, + &processInformation + )) { + log("error: failed to execute %s\n", arg0); + return -1; } - strncpy(str, lpProcessName, size); + WaitForSingleObject(processInformation.hProcess, INFINITE); - return true; -} + DWORD exitCode = ~0UL; + GetExitCodeProcess(processInformation.hProcess, &exitCode); -bool -GetCurrentDir(char *str, size_t size) -{ - DWORD ret; - ret = GetCurrentDirectoryA(size, str); - str[size - 1] = 0; - return ret == 0 ? false : true; + CloseHandle(processInformation.hProcess); + CloseHandle(processInformation.hThread); + + return (int)exitCode; } void -DebugMessage(const char *format, ...) +log(const char *format, ...) { char buf[4096]; @@ -115,18 +224,10 @@ DebugMessage(const char *format, ...) #endif } -long long GetTime(void) -{ - static LARGE_INTEGER frequency; - LARGE_INTEGER counter; - if (!frequency.QuadPart) - QueryPerformanceFrequency(&frequency); - QueryPerformanceCounter(&counter); - return counter.QuadPart*1000000LL/frequency.QuadPart; -} +long long timeFrequency = 0LL; void -Abort(void) +abort(void) { #ifndef NDEBUG DebugBreak(); @@ -136,24 +237,82 @@ Abort(void) } -static LPTOP_LEVEL_EXCEPTION_FILTER prevExceptionFilter = NULL; +#ifndef DBG_PRINTEXCEPTION_C +#define DBG_PRINTEXCEPTION_C 0x40010006 +#endif + +static PVOID prevExceptionFilter = NULL; static void (*gCallback)(void) = NULL; -static LONG WINAPI UnhandledExceptionFilter(PEXCEPTION_POINTERS pExceptionInfo) +static LONG CALLBACK +unhandledExceptionHandler(PEXCEPTION_POINTERS pExceptionInfo) { - if (gCallback) { - gCallback(); + PEXCEPTION_RECORD pExceptionRecord = pExceptionInfo->ExceptionRecord; + + /* + * Ignore OutputDebugStringA exception. + */ + if (pExceptionRecord->ExceptionCode == DBG_PRINTEXCEPTION_C) { + return EXCEPTION_CONTINUE_SEARCH; + } + + /* + * Ignore C++ exceptions + * + * http://support.microsoft.com/kb/185294 + * http://blogs.msdn.com/b/oldnewthing/archive/2010/07/30/10044061.aspx + */ + if (pExceptionRecord->ExceptionCode == 0xe06d7363) { + return EXCEPTION_CONTINUE_SEARCH; + } + + /* + * Ignore thread naming exception. + * + * http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx + */ + if (pExceptionRecord->ExceptionCode == 0x406d1388) { + return EXCEPTION_CONTINUE_SEARCH; } - if (prevExceptionFilter) { - return prevExceptionFilter(pExceptionInfo); + /* + * Ignore .NET exception. + * + * http://ig2600.blogspot.co.uk/2011/01/why-do-i-keep-getting-exception-code.html + */ + if (pExceptionRecord->ExceptionCode == 0xe0434352) { + return EXCEPTION_CONTINUE_SEARCH; + } + + // Clear direction flag +#ifdef _MSC_VER +#ifndef _WIN64 + __asm { + cld + }; +#endif +#else + asm("cld"); +#endif + + log("apitrace: warning: caught exception 0x%08lx\n", pExceptionRecord->ExceptionCode); + + static int recursion_count = 0; + if (recursion_count) { + fprintf(stderr, "apitrace: warning: recursion handling exception\n"); } else { - return EXCEPTION_CONTINUE_SEARCH; + if (gCallback) { + ++recursion_count; + gCallback(); + --recursion_count; + } } + + return EXCEPTION_CONTINUE_SEARCH; } void -SetExceptionCallback(void (*callback)(void)) +setExceptionCallback(void (*callback)(void)) { assert(!gCallback); @@ -162,19 +321,17 @@ SetExceptionCallback(void (*callback)(void)) assert(!prevExceptionFilter); - /* - * TODO: Unfortunately it seems that the CRT will reset the exception - * handler in certain circumnstances. See - * http://www.codeproject.com/KB/winsdk/crash_hook.aspx - */ - prevExceptionFilter = SetUnhandledExceptionFilter(UnhandledExceptionFilter); + prevExceptionFilter = AddVectoredExceptionHandler(0, unhandledExceptionHandler); } } void -ResetExceptionCallback(void) +resetExceptionCallback(void) { - gCallback = NULL; + if (gCallback) { + RemoveVectoredExceptionHandler(prevExceptionFilter); + gCallback = NULL; + } }