/*++ Copyright (c) 1999-2002 Microsoft Corporation Module Name: impl.c Abstract: Author: Matthew D Hendel (math) 22-Sept-1999 Revision History: Comments: Any functions that will not be available on all platforms must be thunked so that the minidump dll will load on all platforms. For functions outside of NTDLL and KERNEL32, we use the delay-load import facility to achieve this. For functions that are in NTDLL and KERNEL32, we use bind the functions manually at DLL-load time. Functions: NTDLL NtOpenThread NT NtQuerySystemInformation NT NtQueryInformationProcess NT NtQueryInformationThread NT NtQueryObject NT RtlFreeHeap NT Kernel32: OpenThread NT5 Thread32First Not on NT4 Thread32Next Not on NT4 Module32First Not on NT4 Module32Next Not on NT4 CreateToolhelp32Snapshot Not on NT4 GetLongPathNameA/W Not on NT4/Win95. PSAPI: EnumProcessModules NT5 GetModuleFileNameExW NT5 --*/ #include "pch.h" #ifndef _WIN32_WCE #include #endif #if !defined (_WIN64_) #include "mprivate.h" #endif #include "nt4.h" #include "impl.h" // // Exported from Win.h // BOOL WinInitialize( ); VOID WinFree( ); // // Global Variables // HINSTANCE _DbgHelp; HINSTANCE _PsApi; BOOL FreeWin; // // APIs from DBGHELP // MINI_DUMP_READ_DUMP_STREAM xxxReadDumpStream; MINI_DUMP_WRITE_DUMP xxxWriteDump; // // APIs from NTDLL // NT_OPEN_THREAD xxxNtOpenThread; NT_QUERY_SYSTEM_INFORMATION xxxNtQuerySystemInformation; NT_QUERY_INFORMATION_PROCESS xxxNtQueryInformationProcess; NT_QUERY_INFORMATION_THREAD xxxNtQueryInformationThread; NT_QUERY_OBJECT xxxNtQueryObject; RTL_FREE_HEAP xxxRtlFreeHeap; #if defined (_X86_) // // APIs from Kernel32 // OPEN_THREAD xxxOpenThread; THREAD32_FIRST xxxThread32First; THREAD32_NEXT xxxThread32Next; MODULE32_FIRST xxxModule32First; MODULE32_NEXT xxxModule32Next; MODULE32_FIRST xxxModule32FirstW; MODULE32_NEXT xxxModule32NextW; CREATE_TOOLHELP32_SNAPSHOT xxxCreateToolhelp32Snapshot; GET_LONG_PATH_NAME_A xxxGetLongPathNameA; GET_LONG_PATH_NAME_W xxxGetLongPathNameW; #endif // // APIs from PSAPI // ENUM_PROCESS_MODULES xxxEnumProcessModules; GET_MODULE_FILE_NAME_EX_W xxxGetModuleFileNameExW; // // Function from dbghelp.dll // BOOL FailReadDumpStream( IN PVOID Base, ULONG StreamNumber, OUT PMINIDUMP_DIRECTORY * Dir, OPTIONAL OUT PVOID * Stream, OPTIONAL OUT ULONG * StreamSize OPTIONAL ) { SetLastError (ERROR_NOT_SUPPORTED); return FALSE; } BOOL FailWriteDump( IN HANDLE hProcess, IN DWORD ProcessId, IN HANDLE hFile, IN MINIDUMP_TYPE DumpType, IN CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, OPTIONAL IN CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, OPTIONAL IN CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam OPTIONAL ) { SetLastError (ERROR_NOT_SUPPORTED); return FALSE; } // // Functions imported from PSAPI.DLL. // BOOL WINAPI FailEnumProcessModules( HANDLE hProcess, HMODULE* lphModule, DWORD cb, LPDWORD lpcbNeeded ) { SetLastError (ERROR_NOT_SUPPORTED); return FALSE; } DWORD WINAPI FailGetModuleFileNameExW( HANDLE hProcess, HMODULE hModule, PWSTR lpFilename, DWORD nSize ) { SetLastError (ERROR_NOT_SUPPORTED); return 0; } // // Functions imported from NTDLL.DLL. NT Only. // NTSTATUS WINAPI FailNtOpenThread( PHANDLE ThreadHandle, ULONG Mask, PVOID Attributes, PVOID ClientId ) { SetLastError (ERROR_NOT_SUPPORTED); return STATUS_UNSUCCESSFUL; } NTSTATUS WINAPI FailNtQuerySystemInformation( IN INT SystemInformationClass, OUT PVOID SystemInformation, IN ULONG SystemInformationLength, OUT PULONG ReturnLength OPTIONAL ) { SetLastError (ERROR_NOT_SUPPORTED); return STATUS_UNSUCCESSFUL; } NTSTATUS WINAPI FailNtQueryInformationProcess( IN HANDLE ProcessHandle, IN INT ProcessInformationClass, OUT PVOID ProcessInformation, IN ULONG ProcessInformationLength, OUT PULONG ReturnLength OPTIONAL ) { SetLastError (ERROR_NOT_SUPPORTED); return STATUS_UNSUCCESSFUL; } NTSTATUS WINAPI FailNtQueryInformationThread( IN HANDLE ThreadHandle, IN INT ThreadInformationClass, OUT PVOID ThreadInformation, IN ULONG ThreadInformationLength, OUT PULONG ReturnLength OPTIONAL ) { SetLastError (ERROR_NOT_SUPPORTED); return STATUS_UNSUCCESSFUL; } NTSTATUS WINAPI FailNtQueryObject( IN HANDLE Handle, IN INT ObjectInformationClass, OUT PVOID ObjectInformation, IN ULONG Length, OUT PULONG ReturnLength OPTIONAL ) { SetLastError (ERROR_NOT_SUPPORTED); return STATUS_UNSUCCESSFUL; } BOOLEAN NTAPI FailRtlFreeHeap( IN PVOID HeapHandle, IN ULONG Flags, IN PVOID BaseAddress ) { return FALSE; } // // Functions imported from KERNEL32.DLL that may not be present. // HANDLE WINAPI FailOpenThread( DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwThreadId ) { SetLastError (ERROR_NOT_SUPPORTED); return NULL; } // // Toolhelp functions. Not present on NT4. // BOOL WINAPI FailThread32First( HANDLE hSnapshot, PVOID ThreadEntry ) { SetLastError (ERROR_NOT_SUPPORTED); return FALSE; } BOOL WINAPI FailThread32Next( HANDLE hSnapshot, PVOID ThreadEntry ) { SetLastError (ERROR_NOT_SUPPORTED); return FALSE; } BOOL WINAPI FailModule32First( HANDLE hSnapshot, PVOID Module ) { SetLastError (ERROR_NOT_SUPPORTED); return FALSE; } BOOL WINAPI FailModule32Next( HANDLE hSnapshot, PVOID Module ) { SetLastError (ERROR_NOT_SUPPORTED); return FALSE; } BOOL WINAPI FailModule32FirstW( HANDLE hSnapshot, PVOID Module ) { SetLastError (ERROR_NOT_SUPPORTED); return FALSE; } BOOL WINAPI FailModule32NextW( HANDLE hSnapshot, PVOID Module ) { SetLastError (ERROR_NOT_SUPPORTED); return FALSE; } HANDLE WINAPI FailCreateToolhelp32Snapshot( DWORD dwFlags, DWORD th32ProcessID ) { SetLastError (ERROR_NOT_SUPPORTED); return FALSE; } DWORD WINAPI FailGetLongPathNameA( LPCSTR lpszShortPath, LPSTR lpszLongPath, DWORD cchBuffer ) { SetLastError (ERROR_NOT_SUPPORTED); return 0; } DWORD WINAPI FailGetLongPathNameW( LPCWSTR lpszShortPath, LPWSTR lpszLongPath, DWORD cchBuffer ) { SetLastError (ERROR_NOT_SUPPORTED); return 0; } // // // Setup an import // #define SETUP_IMPORT(_dll, _import, _type) { \ if (_dll && xxx##_import == NULL ) { \ xxx##_import = (_type) GetProcAddress (_dll, #_import); \ } \ if ( xxx##_import == NULL) { \ xxx##_import = Fail##_import; \ } \ } VOID BindImports( ) { HINSTANCE Ntdll; #if !defined (_DBGHELP_SOURCE_) // // Bind to dbghelp imports. // // We can only use the dbghelp imports if the dbghelp on // the system is of recent vintage and therefore has a good // chance of including all the latest minidump code. Currently // Windows.NET Server (5.01 >= build 3620) has the latest minidump // code so its dbghelp can be used. If minidump.lib has major // feature additions this check will need to be revised. // { ULONG Type; ULONG Major; ULONG Minor; ULONG Build; GenGetSystemType (&Type, &Major, &Minor, NULL, &Build); if (Type != WinNt || Major < 5 || Minor < 1 || Build < 3620) { xxxReadDumpStream = FailReadDumpStream; xxxWriteDump = FailWriteDump; } else { if (_DbgHelp == NULL) { _DbgHelp = LoadLibrary ( "DBGHELP.DLL" ); } SETUP_IMPORT (_DbgHelp, ReadDumpStream, MINI_DUMP_READ_DUMP_STREAM); SETUP_IMPORT (_DbgHelp, WriteDump, MINI_DUMP_WRITE_DUMP); } } #endif // // Bind imports from NTDLL.DLL // Ntdll = GetModuleHandle ( "NTDLL.DLL" ); SETUP_IMPORT (Ntdll, NtOpenThread, NT_OPEN_THREAD); SETUP_IMPORT (Ntdll, NtQuerySystemInformation, NT_QUERY_SYSTEM_INFORMATION); SETUP_IMPORT (Ntdll, NtQueryInformationProcess, NT_QUERY_INFORMATION_PROCESS); SETUP_IMPORT (Ntdll, NtQueryInformationThread, NT_QUERY_INFORMATION_THREAD); SETUP_IMPORT (Ntdll, NtQueryObject, NT_QUERY_OBJECT); SETUP_IMPORT (Ntdll, RtlFreeHeap, RTL_FREE_HEAP); #if defined (_X86_) // // Bind imports from KERNEL32.DLL // { HINSTANCE Kernel32; Kernel32 = GetModuleHandle ( "KERNEL32.DLL" ); SETUP_IMPORT (Kernel32, OpenThread, OPEN_THREAD); SETUP_IMPORT (Kernel32, Thread32First, THREAD32_FIRST); SETUP_IMPORT (Kernel32, Thread32Next, THREAD32_NEXT); SETUP_IMPORT (Kernel32, Module32First, MODULE32_FIRST); SETUP_IMPORT (Kernel32, Module32Next, MODULE32_NEXT); SETUP_IMPORT (Kernel32, Module32FirstW, MODULE32_FIRST); SETUP_IMPORT (Kernel32, Module32NextW, MODULE32_NEXT); SETUP_IMPORT (Kernel32, CreateToolhelp32Snapshot, CREATE_TOOLHELP32_SNAPSHOT); SETUP_IMPORT (Kernel32, GetLongPathNameA, GET_LONG_PATH_NAME_A); SETUP_IMPORT (Kernel32, GetLongPathNameW, GET_LONG_PATH_NAME_W); } #endif if ( _PsApi == NULL ) { _PsApi = LoadLibrary ("PSAPI.DLL"); } #if defined (_X86_) if (_PsApi == NULL) { ULONG Type; ULONG Major; // // NT5 and later versions of NT come with PSAPI. If its not present // on the system and this is an NT4 system, use internal versions // of this function. // GenGetSystemType (&Type, &Major, NULL, NULL, NULL); if ( Type == WinNt && Major == 4) { xxxEnumProcessModules = Nt4EnumProcessModules; xxxGetModuleFileNameExW = Nt4GetModuleFileNameExW; } } #endif // // This will only change the thunks values when they are non-NULL. // SETUP_IMPORT (_PsApi, EnumProcessModules, ENUM_PROCESS_MODULES); SETUP_IMPORT (_PsApi, GetModuleFileNameExW, GET_MODULE_FILE_NAME_EX_W); } #if defined (_X86_) // // Win9x doesn't export these functions. // wchar_t * __cdecl xxx_wcscpy( wchar_t * dst, const wchar_t * src ) { wchar_t * cp = dst; while( *cp++ = *src++ ) ; /* Copy src over dst */ return( dst ); } LPWSTR WINAPI xxx_lstrcpynW( OUT LPWSTR lpString1, IN LPCWSTR lpString2, IN int iMaxLength ) { wchar_t * cp = lpString1; if (iMaxLength > 0) { while( iMaxLength > 1 && (*cp++ = *lpString2++) ) iMaxLength--; /* Copy src over dst */ if (cp > lpString1 && cp[-1]) { *cp = 0; } } return( lpString1 ); } size_t __cdecl xxx_wcslen ( const wchar_t * wcs ) { const wchar_t *eos = wcs; while( *eos++ ) ; return( (size_t)(eos - wcs - 1) ); } #endif VOID FreeImports( ) { xxxNtOpenThread = NULL; xxxNtQuerySystemInformation = NULL; xxxNtQueryInformationProcess = NULL; xxxNtQueryInformationThread = NULL; xxxNtQueryObject = NULL; xxxRtlFreeHeap = NULL; #if defined (_X86_) xxxOpenThread = NULL; xxxThread32First = NULL; xxxThread32Next = NULL; xxxModule32First = NULL; xxxModule32Next = NULL; xxxModule32FirstW = NULL; xxxModule32NextW = NULL; xxxCreateToolhelp32Snapshot = NULL; xxxGetLongPathNameA = NULL; xxxGetLongPathNameW = NULL; #endif xxxEnumProcessModules = NULL; xxxGetModuleFileNameExW = NULL; } BOOL MiniDumpSetup( ) { DWORD Type; GenGetSystemType ( &Type, NULL, NULL, NULL, NULL ); BindImports (); #if defined (_X86_) if ( xxxOpenThread == FailOpenThread && Type == Win9x ) { FreeWin = WinInitialize (); if (!FreeWin) { return FALSE; } } #endif return TRUE; } VOID MiniDumpFree( ) { if (_PsApi) { FreeLibrary ( _PsApi ); _PsApi = NULL; } #if defined (_X86_) if ( FreeWin ) { WinFree (); FreeWin = FALSE; } #endif }