|
|
/******************************************************************************
Copyright (c) 2001 Microsoft Corporation
Module Name: faulth.c
Abstract: Implements fault reporting functions
Revision History: Much of this code taken from admin\pchealth\client\faultrep
******************************************************************************/
#include <windows.h>
#include <winver.h>
#include <ntverp.h>
#include <errorrep.h>
#include "util.h"
#include "faulth.h"
//#define TEST_WATSON 1
static LPWSTR plstrcpynW( LPWSTR lpString1, LPCWSTR lpString2, int iMaxLength ) { LPWSTR src,dst;
__try { src = (LPWSTR)lpString2; dst = lpString1;
if ( iMaxLength ) { while(iMaxLength && *src){ *dst++ = *src++; iMaxLength--; } if ( iMaxLength ) { *dst = '\0'; } else { dst--; *dst = '\0'; } } } __except (EXCEPTION_EXECUTE_HANDLER) { return NULL; }
return lpString1; }
#define sizeofSTRW(wsz) sizeof(wsz) / sizeof(wsz[0])
///////////////////////////////////////////////////////////////////////////////
// Global stuff
#ifdef TEST_WATSON
const CHAR c_szDWDefServerI[] = "officewatson"; #else
const CHAR c_szDWDefServerI[] = "watson.microsoft.com"; #endif
const CHAR c_szDWBrand[] = "WINDOWS"; const WCHAR c_wzDWDefAppName[] = L"Application"; const CHAR c_wszDWCmdLineU[] = "%s\\dwwin.exe -x -s %lu"; #define c_DWDefaultLCID 1033
_inline DWORD RolloverSubtract(DWORD dwA, DWORD dwB) { return (dwA >= dwB) ? (dwA - dwB) : (dwA + ((DWORD)-1 - dwB)); }
#ifdef TEST_WATSON
HANDLE hFaultLog = INVALID_HANDLE_VALUE; char *c_wszLogFileName = "faulth.log";
// Need to synchroize this?
static DebugLog(char *pszMessage, ...) { va_list arglist;
if( !pszMessage) return 0;
va_start(arglist,pszMessage); if (hFaultLog != INVALID_HANDLE_VALUE) { SYSTEMTIME st; DWORD cb, cbWritten; char szMsg[512];
GetSystemTime(&st); cb = wsprintf(szMsg, "%02d-%02d-%04d %02d:%02d:%02d ", st.wDay, st.wMonth, st.wYear, st.wHour, st.wMinute, st.wSecond ); WriteFile(hFaultLog, szMsg, cb, &cbWritten, NULL); /*cb = FormatMessageA(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING, pszMessage, 0,0, szMsg, 0, &arglist );*/ cb = wsprintf(szMsg, pszMessage, &arglist); WriteFile(hFaultLog, szMsg, cb, &cbWritten, NULL); } va_end(arglist); return 1; } #else
#define DebugLog(x)
#endif
HINSTANCE g_hInstance = NULL;
///////////////////////////////////////////////////////////////////////////////
// DllMain
// **************************************************************************
BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) { switch(dwReason) { case DLL_PROCESS_ATTACH: g_hInstance = hInstance; //DisableThreadLibraryCalls(hInstance);
break;
case DLL_PROCESS_DETACH: break; }
return TRUE; }
static EFaultRepRetVal StartDWException( IN PSETUP_FAULT_HANDLER This, IN LPEXCEPTION_POINTERS pep, IN DWORD dwOpt, IN DWORD dwFlags, IN DWORD dwTimeToWait) { SECURITY_ATTRIBUTES sa; PROCESS_INFORMATION pi; EFaultRepRetVal frrvRet = frrvErrNoDW; DWSharedMem15 *pdwsm = NULL; STARTUPINFOA si; HRESULT hr = NOERROR; HANDLE hevDone = NULL, hevAlive = NULL, hmut = NULL; HANDLE hfmShared = NULL, hProc = NULL; HANDLE rghWait[2]; DWORD dw, dwStart; BOOL fDWRunning = TRUE; char szCmdLine[MAX_PATH], szDir[MAX_PATH]; char szModuleFileName[DW_MAX_PATH]; char *pch;
VALIDATEPARM(hr, (pep == NULL)); if (FAILED(hr)) goto done;
// we need the following things to be inheritable, so create a SD that
// says it can be.
ZeroMemory(&sa, sizeof(sa)); sa.nLength = sizeof(sa); sa.bInheritHandle = TRUE;
// create the necessary events & mutexes
hevDone = CreateEvent(&sa, FALSE, FALSE, NULL); TESTBOOL(hr, (hevDone != NULL)); if (FAILED(hr)) goto done;
hevAlive = CreateEvent(&sa, FALSE, FALSE, NULL); TESTBOOL(hr, (hevAlive != NULL)); if (FAILED(hr)) goto done;
hmut = CreateMutex(&sa, FALSE, NULL); TESTBOOL(hr, (hmut != NULL)); if (FAILED(hr)) goto done;
TESTBOOL(hr, DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(), GetCurrentProcess(), &hProc, PROCESS_ALL_ACCESS, TRUE, 0)); if (FAILED(hr)) goto done;
// create the shared memory region & map it
hfmShared = CreateFileMapping(INVALID_HANDLE_VALUE, &sa, PAGE_READWRITE, 0, sizeof(DWSharedMem), NULL); TESTBOOL(hr, (hfmShared != NULL)); if (FAILED(hr)) goto done;
pdwsm = (DWSharedMem *)MapViewOfFile(hfmShared, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0); TESTBOOL(hr, (pdwsm != NULL)); if (FAILED(hr)) goto done;
// populate all the stuff that DW needs
ZeroMemory(pdwsm, sizeof(DWSharedMem15));
pdwsm->dwSize = sizeof(DWSharedMem15); pdwsm->pid = GetCurrentProcessId(); pdwsm->tid = GetCurrentThreadId(); pdwsm->eip = (DWORD_PTR)pep->ExceptionRecord->ExceptionAddress; pdwsm->pep = pep; pdwsm->hEventDone = hevDone; pdwsm->hEventNotifyDone = NULL; pdwsm->hEventAlive = hevAlive; pdwsm->hMutex = hmut; pdwsm->hProc = hProc; pdwsm->bfDWBehaviorFlags = dwFlags; pdwsm->msoctdsResult = msoctdsNull; pdwsm->fReportProblem = FALSE; pdwsm->bfmsoctdsOffer = msoctdsQuit; pdwsm->bfmsoctdsNotify = 0; if (dwOpt == 1) pdwsm->bfmsoctdsOffer |= msoctdsDebug; pdwsm->bfmsoctdsLetRun = pdwsm->bfmsoctdsOffer; pdwsm->iPingCurrent = 0; pdwsm->iPingEnd = 0; pdwsm->lcidUI = 1033;
lstrcpynA( pdwsm->szServer, This->szURL, DW_MAX_SERVERNAME); lstrcpynA( pdwsm->szBrand, c_szDWBrand, DW_APPNAME_LENGTH); GetModuleFileNameA( NULL, szModuleFileName, DW_MAX_PATH); MultiByteToWideChar( CP_ACP, 0, szModuleFileName, -1, pdwsm->wzModuleFileName, DW_MAX_PATH);
plstrcpynW( pdwsm->wzFormalAppName, This->wzAppName, DW_APPNAME_LENGTH); plstrcpynW( pdwsm->wzAdditionalFile, This->wzAdditionalFiles, DW_MAX_ADDFILES); plstrcpynW( pdwsm->wzErrorText, This->wzErrorText, DW_MAX_ERROR_CWC);
// create the process
if (!GetModuleFileNameA( g_hInstance, szDir, MAX_PATH) || !(pch = strrchr (szDir, '\\'))) { goto done; } *pch = '\0'; wsprintf( szCmdLine, c_wszDWCmdLineU, szDir, hfmShared); DebugLog( "CommandLine "); DebugLog( szCmdLine); DebugLog( "CurrentDir "); DebugLog( szDir); ZeroMemory(&si, sizeof(si)); ZeroMemory(&pi, sizeof(pi));
si.cb = sizeof(si); si.lpDesktop = "Winsta0\\Default";
TESTBOOL(hr, CreateProcessA(NULL, szCmdLine, NULL, NULL, TRUE, CREATE_DEFAULT_ERROR_MODE | NORMAL_PRIORITY_CLASS, NULL, szDir, &si, &pi)); if (FAILED(hr)) goto done;
// don't need the thread handle & we gotta close it, so close it now
CloseHandle(pi.hThread); // assume we succeed from here on...
frrvRet = frrvOk;
rghWait[0] = hevAlive; rghWait[1] = pi.hProcess;
dwStart = GetTickCount(); while(fDWRunning) { // gotta periodically get the Alive signal from DW.
switch(WaitForMultipleObjects(2, rghWait, FALSE, 120000)) { case WAIT_OBJECT_0: if (WaitForSingleObject(hevDone, 0) == WAIT_OBJECT_0) fDWRunning = FALSE;
if (dwTimeToWait != (DWORD)-1 && RolloverSubtract(GetTickCount(), dwStart) > dwTimeToWait) { frrvRet = frrvErrTimeout; fDWRunning = FALSE; }
continue;
case WAIT_OBJECT_0 + 1: fDWRunning = FALSE; continue; }
switch(WaitForSingleObject(hmut, DW_TIMEOUT_VALUE)) { // yay! we got the mutex. Try to detemine if DW finally responded
// while we were grabbing the mutex.
case WAIT_OBJECT_0: switch(WaitForMultipleObjects(2, rghWait, FALSE, 0)) { // If it hasn't responded, tell it to go away & fall thru
// into the 'it died' case.
case WAIT_TIMEOUT: SetEvent(hevDone);
// It died. Clean up.
case WAIT_OBJECT_0 + 1: fDWRunning = FALSE; frrvRet = frrvErrNoDW; continue; }
// ok, it responded. Is it done?
if (WaitForSingleObject(hevDone, 0) == WAIT_OBJECT_0) fDWRunning = FALSE;
ReleaseMutex(hmut); break;
// if the wait was abandoned, it means DW has gone to the great bit
// bucket in the sky without cleaning up. So release the mutex and
// fall into the default case
case WAIT_ABANDONED: ReleaseMutex(hmut); // if we timed out or otherwise failed, just die.
default: frrvRet = frrvErrNoDW; fDWRunning = FALSE; break; } } if (frrvRet != frrvOk) { CloseHandle(pi.hProcess); goto done; }
// if user told us to debug, return that back to the
if (pdwsm->msoctdsResult == msoctdsDebug) frrvRet = frrvLaunchDebugger;
// if we're going to launch Dr. Watson, wait for the DW process to die.
// Give it 5 minutes. If the user doesn't hit close by then, just return
// anyway...
if (dwOpt == (DWORD)-1) { if (WaitForSingleObject(pi.hProcess, 300000) == WAIT_TIMEOUT) frrvRet = frrvErrTimeout; }
CloseHandle(pi.hProcess);
done: // preserve the error code so that the following calls don't overwrite it
dw = GetLastError();
if (pdwsm != NULL) UnmapViewOfFile(pdwsm); if (hfmShared != NULL) CloseHandle(hfmShared); if (hevDone != NULL) CloseHandle(hevDone); if (hevAlive != NULL) CloseHandle(hevAlive); if (hmut != NULL) CloseHandle(hmut); if (hProc != NULL) CloseHandle(hProc);
SetLastError(dw);
return frrvRet; }
static EFaultRepRetVal FaultHandler( IN PSETUP_FAULT_HANDLER This, IN EXCEPTION_POINTERS *pep, IN DWORD dwOpt) { EFaultRepRetVal frrvRet = frrvErrNoDW; DWORD dwFlags = 0; char wszFile[MAX_PATH], *pwsz;
DebugLog("Inside FaultHandler\r\n"); GetModuleFileNameA(NULL, wszFile, sizeof(wszFile)/sizeof(wszFile[0]));
// Find last backslash
for(pwsz = wszFile + strlen(wszFile); pwsz >= wszFile && *pwsz != L'\\'; pwsz--);
// Should never happen
if (pwsz < wszFile) goto done;
if (*pwsz == L'\\') pwsz++;
// Don't want to debug dwwin.exe itself.
if (_stricmp(pwsz, "dwwin.exe") == 0 // || _stricmp(pwsz, "dumprep.exe") == 0
) goto done;
frrvRet = StartDWException(This, pep, dwOpt, dwFlags, -1);
done: return frrvRet; }
static BOOL FAULTHIsSupported( IN PSETUP_FAULT_HANDLER This ) { BOOL useExtendedInfo; DWORD dwServicePack; DWORD dwVersion,dwTemp,dwInfoSize; char *pInfo; VS_FIXEDFILEINFO *VsInfo; UINT DataLength; union { OSVERSIONINFO Normal; OSVERSIONINFOEX Ex; } Ovi;
DebugLog("Inside FAULTHIsSupported\r\n"); if ( !This) { return(FALSE); }
useExtendedInfo = TRUE; Ovi.Ex.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); if (!GetVersionEx((OSVERSIONINFO *)&Ovi.Ex) ) { //
// EX size not available; try the normal one
//
Ovi.Normal.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); if (!GetVersionEx((OSVERSIONINFO *)&Ovi.Normal) ) { DebugLog("Inside FAULTHIsSupported:Could not get os version!\r\n"); return(FALSE); } useExtendedInfo = FALSE; } if (useExtendedInfo) { dwServicePack = Ovi.Ex.wServicePackMajor * 100 + Ovi.Ex.wServicePackMinor; } else { dwServicePack = 0; } dwVersion = Ovi.Normal.dwMajorVersion * 100 + Ovi.Normal.dwMinorVersion; switch (Ovi.Normal.dwPlatformId) { case VER_PLATFORM_WIN32s: DebugLog("Inside FAULTHIsSupported:Unsupported win32s!\r\n"); return(FALSE); break; case VER_PLATFORM_WIN32_WINDOWS: if( dwVersion < 410) { DebugLog("Inside FAULTHIsSupported:Unsupported win9x!\r\n"); return(FALSE); } break; case VER_PLATFORM_WIN32_NT: if( dwVersion < 400) { DebugLog("Inside FAULTHIsSupported:Unsupported winNT!\r\n"); return(FALSE); }
if( dwVersion == 400 && dwServicePack < 500) { DebugLog("Inside FAULTHIsSupported:Unsupported ServicePack!\r\n"); return(FALSE); } break; default: return(FALSE); }
// Test for wininet.dll from ie 4.01.
dwInfoSize = GetFileVersionInfoSize( FAULTH_WININET_NAME, &dwTemp ); if( !dwInfoSize) { DebugLog("Inside FAULTHIsSupported:Could not find wininet.dll or determine version."); return( FALSE); }
pInfo = HeapAlloc( GetProcessHeap(), 0, dwInfoSize);
if( !pInfo || !GetFileVersionInfo( FAULTH_WININET_NAME, dwTemp, dwInfoSize, pInfo) || !VerQueryValue( pInfo, "\\", &VsInfo, &DataLength)) { DebugLog("Inside FAULTHIsSupported:Could not find wininet.dll or get version."); HeapFree( GetProcessHeap(), 0, pInfo); return( FALSE); } if( VsInfo->dwFileVersionMS < FAULTH_WININET_MIN_MS || ((VsInfo->dwFileVersionMS == FAULTH_WININET_MIN_MS) && (VsInfo->dwFileVersionLS < FAULTH_WININET_MIN_LS))) { DebugLog("Inside FAULTHIsSupported:Require a more recent wininet.dll."); HeapFree( GetProcessHeap(), 0, pInfo); return( FALSE); } HeapFree( GetProcessHeap(), 0, pInfo); return(TRUE); }
static void FAULTHSetURLA( IN PSETUP_FAULT_HANDLER This, IN PCSTR pszURL ) { DebugLog("Inside FAULTHSetURLA\r\n"); if (This && pszURL){ lstrcpynA( This->szURL, pszURL, DW_MAX_SERVERNAME); } }
static void FAULTHSetURLW( IN PSETUP_FAULT_HANDLER This, IN PCWSTR pwzURL ) { DebugLog("Inside FAULTHSetURLW\r\n"); if (This && pwzURL){ WideCharToMultiByte( CP_ACP, 0, pwzURL, -1, This->szURL, DW_MAX_SERVERNAME, NULL, NULL); } }
static void FAULTHSetErrorTextA( IN PSETUP_FAULT_HANDLER This, IN PCSTR pszErrorText ) { DebugLog("Inside FAULTHSetErrorTextA\r\n"); if (This && pszErrorText){ MultiByteToWideChar( CP_ACP, 0, pszErrorText, -1, This->wzErrorText, DW_MAX_ERROR_CWC); } }
static void FAULTHSetErrorTextW( IN PSETUP_FAULT_HANDLER This, IN PCWSTR pwzErrorText ) { DebugLog("Inside FAULTHSetErrorTextW\r\n"); if (This && pwzErrorText){ plstrcpynW( This->wzErrorText, pwzErrorText, DW_MAX_ERROR_CWC); } }
static void FAULTHSetAdditionalFilesA( IN PSETUP_FAULT_HANDLER This, IN PCSTR pszAdditionalFiles ) { DebugLog("Inside FAULTHSetAdditionalFilesA\r\n"); if (This && pszAdditionalFiles){ MultiByteToWideChar( CP_ACP, 0, pszAdditionalFiles, -1, This->wzAdditionalFiles, DW_MAX_ADDFILES); } }
static void FAULTHSetAdditionalFilesW( IN PSETUP_FAULT_HANDLER This, IN PCWSTR pwzAdditionalFiles ) { DebugLog("Inside FAULTHSetAdditionalFilesW\r\n"); if (This && pwzAdditionalFiles){ plstrcpynW( This->wzAdditionalFiles, pwzAdditionalFiles, DW_MAX_ADDFILES); } }
static void FAULTHSetAppNameA( IN PSETUP_FAULT_HANDLER This, IN PCSTR pszAppName ) { DebugLog("Inside FAULTHAppNameA\r\n"); if (This && pszAppName){ MultiByteToWideChar( CP_ACP, 0, pszAppName, -1, This->wzAppName, DW_APPNAME_LENGTH); } }
static void FAULTHSetAppNameW( IN PSETUP_FAULT_HANDLER This, IN PCWSTR pwzAppName ) { DebugLog("Inside FAULTHAppNameW\r\n"); if (This && pwzAppName){ plstrcpynW( This->wzAppName, pwzAppName, DW_APPNAME_LENGTH); } }
static void FAULTHSetLCID( IN PSETUP_FAULT_HANDLER This, IN LCID lcid ) { DebugLog("Inside FAULTHSetLCID\r\n"); if (This){ This->lcid = lcid; } }
static VOID FAULTHInit( IN PSETUP_FAULT_HANDLER This ) { DebugLog("Inside FAULTHInit\r\n"); if( This){ This->SetURLA = FAULTHSetURLA; This->SetURLW = FAULTHSetURLW; This->SetAppNameA = FAULTHSetAppNameA; This->SetAppNameW = FAULTHSetAppNameW; This->SetErrorTextA = FAULTHSetErrorTextA; This->SetErrorTextW = FAULTHSetErrorTextW; This->SetAdditionalFilesA = FAULTHSetAdditionalFilesA; This->SetAdditionalFilesW = FAULTHSetAdditionalFilesW; This->SetLCID = FAULTHSetLCID; This->IsSupported = FAULTHIsSupported; This->Report = FaultHandler; This->bDebug = FALSE; FAULTHSetURLA(This, c_szDWDefServerI); FAULTHSetAppNameW(This, c_wzDWDefAppName); FAULTHSetAdditionalFilesW(This, L""); FAULTHSetErrorTextW(This,L""); FAULTHSetLCID(This,c_DWDefaultLCID); } #ifdef TEST_WATSON
{ char szFile[MAX_PATH], *pwsz;
GetSystemDirectoryA(szFile, sizeof(szFile)/sizeof(szFile[0])); szFile[3] = '\0'; strcat(szFile, c_wszLogFileName); hFaultLog = CreateFileA(szFile, GENERIC_WRITE, FILE_SHARE_WRITE | FILE_SHARE_READ, NULL, OPEN_ALWAYS, 0, NULL); if (hFaultLog != INVALID_HANDLE_VALUE) { SYSTEMTIME st; DWORD cb, cbWritten; char szMsg[512]; GetSystemTime(&st); cb = wsprintf(szMsg, "%02d-%02d-%04d %02d:%02d:%02d Initalization\r\n", st.wDay, st.wMonth, st.wYear, st.wHour, st.wMinute, st.wSecond); SetFilePointer(hFaultLog, 0, NULL, FILE_END); WriteFile(hFaultLog, szMsg, cb, &cbWritten, NULL); } } DebugLog("exiting FAULTHInit\r\n"); #endif
}
PSETUP_FAULT_HANDLER APIENTRY FAULTHCreate( VOID) { PSETUP_FAULT_HANDLER This = NULL;
DebugLog("Inside FAULTHCreate\r\n"); This = HeapAlloc( GetProcessHeap(), 0, sizeof(SETUP_FAULT_HANDLER));
if( This) { FAULTHInit( This); }
DebugLog("exiting FAULTCreate\r\n"); return This; }
VOID APIENTRY FAULTHDelete( IN PSETUP_FAULT_HANDLER This ) { DebugLog("Inside FAULTHDelete\r\n"); if( This) { HeapFree( GetProcessHeap(), 0, This); } #ifdef TEST_WATSON
if (hFaultLog != INVALID_HANDLE_VALUE) { CloseHandle(hFaultLog); } #endif
}
|