mirror of
https://github.com/SDL-Hercules-390/hyperion.git
synced 2026-04-16 00:45:27 +02:00
422 lines
12 KiB
C
422 lines
12 KiB
C
/*********************************/
|
|
/* Hercules main executable code */
|
|
/*********************************/
|
|
|
|
#include "hstdinc.h"
|
|
#include "hercules.h"
|
|
#if defined(HDL_USE_LIBTOOL)
|
|
#include "ltdl.h"
|
|
#endif
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Non-Windows version...
|
|
|
|
#if !defined( _MSVC_ )
|
|
|
|
int main(int ac,char *av[])
|
|
{
|
|
SET_THREAD_NAME("bootstrap");
|
|
|
|
#if defined( OPTION_DYNAMIC_LOAD ) && defined( HDL_USE_LIBTOOL )
|
|
LTDL_SET_PRELOADED_SYMBOLS();
|
|
#endif
|
|
exit(impl(ac,av));
|
|
}
|
|
|
|
#else // defined( _MSVC_ )
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Windows version...
|
|
|
|
typedef BOOL (MINIDUMPWRITEDUMPFUNC)
|
|
(
|
|
HANDLE hProcess,
|
|
DWORD ProcessId,
|
|
HANDLE hDumpFile,
|
|
MINIDUMP_TYPE DumpType,
|
|
PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
|
|
PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
|
|
PMINIDUMP_CALLBACK_INFORMATION CallbackParam
|
|
);
|
|
|
|
static MINIDUMPWRITEDUMPFUNC* g_pfnMiniDumpWriteDumpFunc = NULL;
|
|
static HMODULE g_hDbgHelpDll = NULL;
|
|
static WCHAR g_wszHercDrive[_MAX_DRIVE] = L"";
|
|
static WCHAR g_wszHercDir[2*_MAX_DIR] = L"";
|
|
|
|
static void ProcessException( EXCEPTION_POINTERS* pExceptionPtrs );
|
|
|
|
#ifndef ARRAYSIZE
|
|
#define ARRAYSIZE(x) (sizeof(x)/sizeof(x[0]))
|
|
#endif
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
int main(int ac,char *av[])
|
|
{
|
|
int rc = 0;
|
|
|
|
SET_THREAD_NAME("bootstrap");
|
|
|
|
// If we're being debugged, then let the debugger
|
|
// catch the exception. Otherwise, let our exception
|
|
// handler catch it...
|
|
|
|
if ( IsDebuggerPresent() ) // (are we being debugged?)
|
|
{
|
|
rc = impl(ac,av); // (yes, let debugger catch the exception)
|
|
}
|
|
else // (not being debugged; use our exception handler)
|
|
{
|
|
if (1
|
|
&& (g_hDbgHelpDll = LoadLibrary(_T("DbgHelp.dll")))
|
|
&& (g_pfnMiniDumpWriteDumpFunc = (MINIDUMPWRITEDUMPFUNC*)
|
|
GetProcAddress( g_hDbgHelpDll, _T("MiniDumpWriteDump")))
|
|
)
|
|
{
|
|
WCHAR wszHercPath[_MAX_PATH] = L"";
|
|
GetModuleFileNameW( NULL, wszHercPath, ARRAYSIZE(wszHercPath) );
|
|
_wsplitpath( wszHercPath, g_wszHercDrive, g_wszHercDir, NULL, NULL );
|
|
}
|
|
|
|
SetErrorMode( SEM_NOGPFAULTERRORBOX );
|
|
|
|
__try
|
|
{
|
|
rc = impl(ac,av); // (Hercules, do your thing!)
|
|
}
|
|
__except
|
|
(
|
|
_tprintf( _T("\n\n") ),
|
|
_tprintf( _T(" ***************\n") ),
|
|
_tprintf( _T(" * OOPS! *\n") ),
|
|
_tprintf( _T(" ***************\n") ),
|
|
_tprintf( _T("\n") ),
|
|
_tprintf( _T(" Hercules has crashed!\n") ),
|
|
_tprintf( _T("\n") ),
|
|
_tprintf( _T("(you may need to press ENTER if no 'oops!' dialog-box appears)\n") ),
|
|
_tprintf( _T("\n") ),
|
|
ProcessException( GetExceptionInformation() ),
|
|
EXCEPTION_EXECUTE_HANDLER
|
|
)
|
|
{
|
|
rc = -1; // (indicate error)
|
|
}
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
static BOOL CreateMiniDump( EXCEPTION_POINTERS* pExceptionPtrs );
|
|
|
|
static void ProcessException( EXCEPTION_POINTERS* pExceptionPtrs )
|
|
{
|
|
if ( !g_pfnMiniDumpWriteDumpFunc )
|
|
{
|
|
MessageBox
|
|
(
|
|
NULL,
|
|
_T("The creation of a crash dump for analysis by the Hercules ")
|
|
_T("development team is NOT possible\nbecause the required 'DbgHelp.dll' ")
|
|
_T("is missing or is not installed or was otherwise not located.")
|
|
,_T("OOPS! Hercules has crashed!"),
|
|
MB_OK
|
|
);
|
|
|
|
return;
|
|
}
|
|
|
|
if ( IDYES == MessageBox
|
|
(
|
|
NULL,
|
|
_T("The creation of a crash dump for further analysis by ")
|
|
_T("the Hercules development team is strongly suggested.\n\n")
|
|
_T("Would you like to create a crash dump for ")
|
|
_T("the Hercules development team to analyze?")
|
|
,_T("OOPS! Hercules has crashed!"),
|
|
MB_YESNO
|
|
))
|
|
{
|
|
if ( CreateMiniDump( pExceptionPtrs ) )
|
|
{
|
|
// ZZ FIXME: Figure out why this MessageBox never appears.
|
|
// It *used* to but it's not anymore and I don't know why.
|
|
// The function *is* always returning TRUE... <grumble>
|
|
|
|
MessageBox
|
|
(
|
|
NULL,
|
|
_T("Please send the dump to the Hercules development team for analysis.")
|
|
,_T("Dump Complete"),
|
|
MB_OK
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// The following CreateMiniDump functions are based on
|
|
// Oleg Starodumov's sample at http://www.debuginfo.com
|
|
|
|
static void BuildUserStreams( MINIDUMP_USER_STREAM_INFORMATION* pMDUSI );
|
|
|
|
static BOOL CALLBACK MyMiniDumpCallback // (fwd ref)
|
|
(
|
|
PVOID pParam,
|
|
const PMINIDUMP_CALLBACK_INPUT pInput,
|
|
PMINIDUMP_CALLBACK_OUTPUT pOutput
|
|
);
|
|
|
|
static BOOL CreateMiniDump( EXCEPTION_POINTERS* pExceptionPtrs )
|
|
{
|
|
BOOL bSuccess = FALSE;
|
|
WCHAR wszDumpPath[4*_MAX_PATH];
|
|
HANDLE hDumpFile;
|
|
|
|
_wmakepath( wszDumpPath, g_wszHercDrive, g_wszHercDir, L"Hercules", L".dmp" );
|
|
|
|
_tprintf( _T("Creating crash dump \"%S\"...\n"), wszDumpPath );
|
|
_tprintf( _T("Please wait; this may take a few minutes...\n") );
|
|
_tprintf( _T("(another message will appear when the dump is complete)\n") );
|
|
|
|
hDumpFile = CreateFileW
|
|
(
|
|
wszDumpPath,
|
|
GENERIC_WRITE,
|
|
0, NULL, CREATE_ALWAYS,
|
|
FILE_ATTRIBUTE_NORMAL, NULL
|
|
);
|
|
|
|
if ( hDumpFile && INVALID_HANDLE_VALUE != hDumpFile )
|
|
{
|
|
// Create the minidump
|
|
|
|
MINIDUMP_EXCEPTION_INFORMATION mdei;
|
|
MINIDUMP_USER_STREAM_INFORMATION mdusi;
|
|
MINIDUMP_CALLBACK_INFORMATION mci;
|
|
MINIDUMP_TYPE mdt;
|
|
|
|
BuildUserStreams( &mdusi );
|
|
|
|
mdei.ThreadId = GetCurrentThreadId();
|
|
mdei.ExceptionPointers = pExceptionPtrs;
|
|
mdei.ClientPointers = FALSE;
|
|
|
|
mci.CallbackRoutine = (MINIDUMP_CALLBACK_ROUTINE) MyMiniDumpCallback;
|
|
mci.CallbackParam = 0;
|
|
|
|
mdt = (MINIDUMP_TYPE)
|
|
(0
|
|
| MiniDumpWithPrivateReadWriteMemory
|
|
| MiniDumpWithDataSegs
|
|
| MiniDumpWithHandleData
|
|
// | MiniDumpWithFullMemoryInfo
|
|
// | MiniDumpWithThreadInfo
|
|
| MiniDumpWithUnloadedModules
|
|
);
|
|
|
|
bSuccess = g_pfnMiniDumpWriteDumpFunc( GetCurrentProcess(), GetCurrentProcessId(),
|
|
hDumpFile, mdt, (pExceptionPtrs != 0) ? &mdei : 0, &mdusi, &mci );
|
|
|
|
CloseHandle( hDumpFile );
|
|
|
|
if ( bSuccess )
|
|
{
|
|
_tprintf( _T("Dump \"%S\" created.\n"), wszDumpPath );
|
|
}
|
|
else
|
|
_tprintf( _T("MiniDumpWriteDump failed! Error: %u\n"), GetLastError() );
|
|
}
|
|
else
|
|
{
|
|
_tprintf( _T("CreateFile failed! Error: %u\n"), GetLastError() );
|
|
}
|
|
|
|
return bSuccess;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Build User Stream Arrays...
|
|
|
|
#define MAX_MINIDUMP_USER_STREAMS (50)
|
|
|
|
static MINIDUMP_USER_STREAM UserStreamArray[MAX_MINIDUMP_USER_STREAMS];
|
|
|
|
static void BuildUserStreams( MINIDUMP_USER_STREAM_INFORMATION* pMDUSI )
|
|
{
|
|
static char host_info_str[256];
|
|
const char** ppszBldInfoStr;
|
|
int nNumBldInfoStrs;
|
|
ULONG UserStreamCount;
|
|
|
|
_ASSERTE( pMDUSI );
|
|
|
|
get_hostinfo_str( NULL, host_info_str, sizeof(host_info_str) );
|
|
nNumBldInfoStrs = get_buildinfo_strings( &ppszBldInfoStr );
|
|
|
|
UserStreamCount = min( (3+nNumBldInfoStrs), MAX_MINIDUMP_USER_STREAMS );
|
|
|
|
pMDUSI->UserStreamCount = UserStreamCount;
|
|
pMDUSI->UserStreamArray = UserStreamArray;
|
|
|
|
UserStreamCount = 0;
|
|
|
|
if ( UserStreamCount < pMDUSI->UserStreamCount )
|
|
{
|
|
UserStreamArray[UserStreamCount].Type = CommentStreamA;
|
|
UserStreamArray[UserStreamCount].Buffer = VERSION;
|
|
UserStreamArray[UserStreamCount].BufferSize = sizeof(VERSION);
|
|
UserStreamCount++;
|
|
}
|
|
|
|
if ( UserStreamCount < pMDUSI->UserStreamCount )
|
|
{
|
|
UserStreamArray[UserStreamCount].Type = CommentStreamA;
|
|
UserStreamArray[UserStreamCount].Buffer = HERCULES_COPYRIGHT;
|
|
UserStreamArray[UserStreamCount].BufferSize = sizeof(HERCULES_COPYRIGHT);
|
|
UserStreamCount++;
|
|
}
|
|
|
|
if ( UserStreamCount < pMDUSI->UserStreamCount )
|
|
{
|
|
UserStreamArray[UserStreamCount].Type = CommentStreamA;
|
|
UserStreamArray[UserStreamCount].Buffer = host_info_str;
|
|
UserStreamArray[UserStreamCount].BufferSize = strlen(host_info_str)+1;
|
|
UserStreamCount++;
|
|
}
|
|
|
|
for (; nNumBldInfoStrs && UserStreamCount < pMDUSI->UserStreamCount;
|
|
nNumBldInfoStrs--, UserStreamCount++, ppszBldInfoStr++ )
|
|
{
|
|
UserStreamArray[UserStreamCount].Type = CommentStreamA;
|
|
UserStreamArray[UserStreamCount].Buffer = (PVOID)*ppszBldInfoStr;
|
|
UserStreamArray[UserStreamCount].BufferSize = strlen(*ppszBldInfoStr)+1;
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Custom minidump callback
|
|
|
|
static BOOL IsDataSectionNeeded( const WCHAR* pwszModuleName ); // (fwd ref)
|
|
|
|
static BOOL CALLBACK MyMiniDumpCallback
|
|
(
|
|
PVOID pParam,
|
|
const PMINIDUMP_CALLBACK_INPUT pInput,
|
|
PMINIDUMP_CALLBACK_OUTPUT pOutput
|
|
)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
|
|
if ( !pInput || !pOutput )
|
|
return FALSE;
|
|
|
|
switch ( pInput->CallbackType )
|
|
{
|
|
case IncludeModuleCallback:
|
|
{
|
|
// Include the module into the dump
|
|
bRet = TRUE;
|
|
}
|
|
break;
|
|
|
|
case IncludeThreadCallback:
|
|
{
|
|
// Include the thread into the dump
|
|
bRet = TRUE;
|
|
}
|
|
break;
|
|
|
|
case ModuleCallback:
|
|
{
|
|
// Are data sections available for this module ?
|
|
|
|
if ( pOutput->ModuleWriteFlags & ModuleWriteDataSeg )
|
|
{
|
|
// Yes, but do we really need them?
|
|
|
|
if ( !IsDataSectionNeeded( pInput->Module.FullPath ) )
|
|
pOutput->ModuleWriteFlags &= (~ModuleWriteDataSeg);
|
|
}
|
|
|
|
bRet = TRUE;
|
|
}
|
|
break;
|
|
|
|
case ThreadCallback:
|
|
{
|
|
// Include all thread information into the minidump
|
|
bRet = TRUE;
|
|
}
|
|
break;
|
|
|
|
case ThreadExCallback:
|
|
{
|
|
// Include this information
|
|
bRet = TRUE;
|
|
}
|
|
break;
|
|
|
|
/* NOTE About MemoryCallback :
|
|
* This is defined for DbgHelp > 6.1..
|
|
* Since "false" is returned, it has been commented out.
|
|
*
|
|
* Additionally, false is now returned by default. This
|
|
* ensures that the callback function will operate correctly
|
|
* even with future versions of the DbhHelp DLL.
|
|
* -- Ivan
|
|
*/
|
|
// case MemoryCallback:
|
|
// {
|
|
// // We do not include any information here -> return FALSE
|
|
// bRet = FALSE;
|
|
// }
|
|
// break;
|
|
|
|
// Following default block added by ISW 2005/05/06
|
|
default:
|
|
{
|
|
// Do not return any information for unrecognized
|
|
// callback types.
|
|
bRet=FALSE;
|
|
}
|
|
break;
|
|
|
|
// case CancelCallback:
|
|
// break;
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// This function determines whether we need data sections of the given module
|
|
|
|
static BOOL IsDataSectionNeeded( const WCHAR* pwszModuleName )
|
|
{
|
|
BOOL bNeeded = FALSE;
|
|
WCHAR wszFileDir[_MAX_DIR] = L"";
|
|
WCHAR wszFileName[_MAX_FNAME] = L"";
|
|
|
|
_ASSERTE( pwszModuleName );
|
|
|
|
_wsplitpath( pwszModuleName, NULL, wszFileDir, wszFileName, NULL );
|
|
|
|
if ( _wcsicmp( wszFileName, L"ntdll" ) == 0 )
|
|
{
|
|
bNeeded = TRUE;
|
|
}
|
|
else if ( _wcsicmp( wszFileDir, g_wszHercDir ) == 0 )
|
|
{
|
|
bNeeded = TRUE;
|
|
}
|
|
|
|
return bNeeded;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
#endif // !defined( _MSVC_ )
|