diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /external/vpc/tier0/minidump.cpp | |
| download | archived-source-engine-2018-hl2-src-master.tar.xz archived-source-engine-2018-hl2-src-master.zip | |
Diffstat (limited to 'external/vpc/tier0/minidump.cpp')
| -rw-r--r-- | external/vpc/tier0/minidump.cpp | 317 |
1 files changed, 317 insertions, 0 deletions
diff --git a/external/vpc/tier0/minidump.cpp b/external/vpc/tier0/minidump.cpp new file mode 100644 index 0000000..7d2a85b --- /dev/null +++ b/external/vpc/tier0/minidump.cpp @@ -0,0 +1,317 @@ +//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "pch_tier0.h" +#include "tier0/minidump.h" +#include "tier0/platform.h" + + +#if defined( _WIN32 ) && !defined(_X360 ) && ( _MSC_VER >= 1300 ) + +#include "tier0/valve_off.h" +#define WIN_32_LEAN_AND_MEAN +#define _WIN32_WINNT 0x0403 +#include <windows.h> +#include <time.h> +#include <dbghelp.h> + +#endif + +// NOTE: This has to be the last file included! +#include "tier0/memdbgon.h" + + +#if defined( _WIN32 ) && !defined( _X360 ) + +#if _MSC_VER >= 1300 + +// MiniDumpWriteDump() function declaration (so we can just get the function directly from windows) +typedef BOOL (WINAPI *MINIDUMPWRITEDUMP) + ( + HANDLE hProcess, + DWORD dwPid, + HANDLE hFile, + MINIDUMP_TYPE DumpType, + CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, + CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, + CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam + ); + + +// true if we're currently writing a minidump caused by an assert +static bool g_bWritingNonfatalMinidump = false; +// counter used to make sure minidump names are unique +static int g_nMinidumpsWritten = 0; + +//----------------------------------------------------------------------------- +// Purpose: Creates a new file and dumps the exception info into it +// Input : uStructuredExceptionCode - windows exception code, unused. +// pExceptionInfo - call stack. +// minidumpType - type of minidump to write. +// ptchMinidumpFileNameBuffer - if not-NULL points to a writable tchar buffer +// of length at least _MAX_PATH to contain the name +// of the written minidump file on return. +//----------------------------------------------------------------------------- +bool WriteMiniDumpUsingExceptionInfo( + unsigned int uStructuredExceptionCode, + ExceptionInfo_t * pExceptionInfo, + uint32 minidumpType, + tchar *ptchMinidumpFileNameBuffer /* = NULL */ + ) +{ + if ( ptchMinidumpFileNameBuffer ) + { + *ptchMinidumpFileNameBuffer = tchar( 0 ); + } + + // get the function pointer directly so that we don't have to include the .lib, and that + // we can easily change it to using our own dll when this code is used on win98/ME/2K machines + HMODULE hDbgHelpDll = ::LoadLibrary( "DbgHelp.dll" ); + if ( !hDbgHelpDll ) + return false; + + bool bReturnValue = false; + MINIDUMPWRITEDUMP pfnMiniDumpWrite = (MINIDUMPWRITEDUMP) ::GetProcAddress( hDbgHelpDll, "MiniDumpWriteDump" ); + + if ( pfnMiniDumpWrite ) + { + // create a unique filename for the minidump based on the current time and module name + struct tm curtime; + Plat_GetLocalTime( &curtime ); + ++g_nMinidumpsWritten; + + // strip off the rest of the path from the .exe name + tchar rgchModuleName[MAX_PATH]; +#ifdef TCHAR_IS_WCHAR + ::GetModuleFileNameW( NULL, rgchModuleName, sizeof(rgchModuleName) / sizeof(tchar) ); +#else + ::GetModuleFileName( NULL, rgchModuleName, sizeof(rgchModuleName) / sizeof(tchar) ); +#endif + tchar *pch = _tcsrchr( rgchModuleName, '.' ); + if ( pch ) + { + *pch = 0; + } + pch = _tcsrchr( rgchModuleName, '\\' ); + if ( pch ) + { + // move past the last slash + pch++; + } + else + { + pch = _T("unknown"); + } + + + // can't use the normal string functions since we're in tier0 + tchar rgchFileName[MAX_PATH]; + _sntprintf( rgchFileName, sizeof(rgchFileName) / sizeof(tchar), + _T("%s_%s_%d%.2d%2d%.2d%.2d%.2d_%d.mdmp"), + pch, + g_bWritingNonfatalMinidump ? "assert" : "crash", + curtime.tm_year + 1900, /* Year less 2000 */ + curtime.tm_mon + 1, /* month (0 - 11 : 0 = January) */ + curtime.tm_mday, /* day of month (1 - 31) */ + curtime.tm_hour, /* hour (0 - 23) */ + curtime.tm_min, /* minutes (0 - 59) */ + curtime.tm_sec, /* seconds (0 - 59) */ + g_nMinidumpsWritten // ensures the filename is unique + ); + + BOOL bMinidumpResult = FALSE; +#ifdef TCHAR_IS_WCHAR + HANDLE hFile = ::CreateFileW( rgchFileName, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); +#else + HANDLE hFile = ::CreateFile( rgchFileName, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); +#endif + + if ( hFile ) + { + // dump the exception information into the file + _MINIDUMP_EXCEPTION_INFORMATION ExInfo; + ExInfo.ThreadId = ::GetCurrentThreadId(); + ExInfo.ExceptionPointers = (PEXCEPTION_POINTERS)pExceptionInfo; + ExInfo.ClientPointers = FALSE; + + bMinidumpResult = (*pfnMiniDumpWrite)( ::GetCurrentProcess(), ::GetCurrentProcessId(), hFile, (MINIDUMP_TYPE)minidumpType, &ExInfo, NULL, NULL ); + ::CloseHandle( hFile ); + + if ( bMinidumpResult ) + { + bReturnValue = true; + + if ( ptchMinidumpFileNameBuffer ) + { + // Copy the file name from "pSrc = rgchFileName" into "pTgt = ptchMinidumpFileNameBuffer" + tchar *pTgt = ptchMinidumpFileNameBuffer; + tchar const *pSrc = rgchFileName; + while ( ( *( pTgt ++ ) = *( pSrc ++ ) ) != tchar( 0 ) ) + continue; + } + } + + // fall through to trying again + } + + // mark any failed minidump writes by renaming them + if ( !bMinidumpResult ) + { + tchar rgchFailedFileName[MAX_PATH]; + _sntprintf( rgchFailedFileName, sizeof(rgchFailedFileName) / sizeof(tchar), "(failed)%s", rgchFileName ); + rename( rgchFileName, rgchFailedFileName ); + } + } + + ::FreeLibrary( hDbgHelpDll ); + + // call the log flush function if one is registered to try to flush any logs + //CallFlushLogFunc(); + + return bReturnValue; +} + + +void InternalWriteMiniDumpUsingExceptionInfo( unsigned int uStructuredExceptionCode, ExceptionInfo_t * pExceptionInfo ) +{ + // First try to write it with all the indirectly referenced memory (ie: a large file). + // If that doesn't work, then write a smaller one. + uint32 iType = MINIDUMP_WithDataSegs | MINIDUMP_WithIndirectlyReferencedMemory; + if ( !WriteMiniDumpUsingExceptionInfo( uStructuredExceptionCode, pExceptionInfo, iType ) ) + { + iType = MINIDUMP_WithDataSegs; + WriteMiniDumpUsingExceptionInfo( uStructuredExceptionCode, pExceptionInfo, iType ); + } +} + +// minidump function to use +static FnMiniDump g_pfnWriteMiniDump = InternalWriteMiniDumpUsingExceptionInfo; + +//----------------------------------------------------------------------------- +// Purpose: Set a function to call which will write our minidump, overriding +// the default function +// Input : pfn - Pointer to minidump function to set +// Output : Previously set function +//----------------------------------------------------------------------------- +FnMiniDump SetMiniDumpFunction( FnMiniDump pfn ) +{ + FnMiniDump pfnTemp = g_pfnWriteMiniDump; + g_pfnWriteMiniDump = pfn; + return pfnTemp; +} + + +//----------------------------------------------------------------------------- +// Unhandled exceptions +//----------------------------------------------------------------------------- +static FnMiniDump g_UnhandledExceptionFunction; +static LONG STDCALL ValveUnhandledExceptionFilter( _EXCEPTION_POINTERS* pExceptionInfo ) +{ + uint uStructuredExceptionCode = pExceptionInfo->ExceptionRecord->ExceptionCode; + g_UnhandledExceptionFunction( uStructuredExceptionCode, (ExceptionInfo_t*)pExceptionInfo ); + return EXCEPTION_CONTINUE_SEARCH; +} + +void MinidumpSetUnhandledExceptionFunction( FnMiniDump pfn ) +{ + g_UnhandledExceptionFunction = pfn; + SetUnhandledExceptionFilter( ValveUnhandledExceptionFilter ); +} + + +//----------------------------------------------------------------------------- +// Purpose: writes out a minidump from the current process +//----------------------------------------------------------------------------- +typedef void (*FnMiniDumpInternal_t)( unsigned int uStructuredExceptionCode, _EXCEPTION_POINTERS * pExceptionInfo ); + +void WriteMiniDump() +{ + // throw an exception so we can catch it and get the stack info + g_bWritingNonfatalMinidump = true; + __try + { + ::RaiseException + ( + 0, // dwExceptionCode + EXCEPTION_NONCONTINUABLE, // dwExceptionFlags + 0, // nNumberOfArguments, + NULL // const ULONG_PTR* lpArguments + ); + + // Never get here (non-continuable exception) + } + // Write the minidump from inside the filter (GetExceptionInformation() is only + // valid in the filter) + __except ( g_pfnWriteMiniDump( 0, (ExceptionInfo_t*)GetExceptionInformation() ), EXCEPTION_EXECUTE_HANDLER ) + { + } + g_bWritingNonfatalMinidump = false; +} + +PLATFORM_OVERLOAD bool g_bInException = false; +#include <eh.h> + +//----------------------------------------------------------------------------- +// Purpose: Catches and writes out any exception throw by the specified function +//----------------------------------------------------------------------------- +void CatchAndWriteMiniDump( FnWMain pfn, int argc, tchar *argv[] ) +{ + if ( Plat_IsInDebugSession() ) + { + // don't mask exceptions when running in the debugger + pfn( argc, argv ); + } + else + { + try + { +#pragma warning(push) +#pragma warning(disable : 4535) // warning C4535: calling _set_se_translator() requires /EHa + _set_se_translator( (FnMiniDumpInternal_t)g_pfnWriteMiniDump ); +#pragma warning(pop) + pfn( argc, argv ); + } + catch (...) + { + g_bInException = true; + Log_Msg( LOG_CONSOLE, _T("Fatal exception caught, minidump written\n") ); + // handle everything and just quit, we've already written out our minidump + } + } +} + +#else + +PLATFORM_INTERFACE void WriteMiniDump() +{ +} + +PLATFORM_INTERFACE void CatchAndWriteMiniDump( FnWMain pfn, int argc, tchar *argv[] ) +{ + pfn( argc, argv ); +} + +#endif +#elif defined(_X360 ) +PLATFORM_INTERFACE void WriteMiniDump() +{ +#if !defined( _CERT ) + DmCrashDump(false); +#endif +} + +#else // !_WIN32 + +PLATFORM_INTERFACE void WriteMiniDump() +{ +} + +PLATFORM_INTERFACE void CatchAndWriteMiniDump( FnWMain pfn, int argc, tchar *argv[] ) +{ + pfn( argc, argv ); +} + +#endif |