summaryrefslogtreecommitdiff
path: root/external/vpc/tier0/minidump.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /external/vpc/tier0/minidump.cpp
downloadarchived-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.cpp317
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