mirror of
https://github.com/SDL-Hercules-390/hyperion.git
synced 2026-04-19 18:26:51 +02:00
- Added support for Posix 1003.1e capabilities git-svn-id: file:///home/jj/hercules.svn/trunk@4573 956126f8-22a0-4046-8f4a-272fa8102e63
489 lines
14 KiB
C
489 lines
14 KiB
C
/*********************************/
|
|
/* Hercules main executable code */
|
|
/*********************************/
|
|
|
|
// $Id$
|
|
//
|
|
// $Log$
|
|
// Revision 1.11 2006/12/28 03:04:34 fish
|
|
// Permanently disable in bootstrap.c Microsoft's completely INSANE Invalid CRT Parameter handling behavior
|
|
//
|
|
// Revision 1.10 2006/12/08 09:43:16 jj
|
|
// Add CVS message log
|
|
//
|
|
|
|
#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[])
|
|
{
|
|
DROP_PRIVILEGES(CAP_SYS_NICE);
|
|
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_ )
|
|
|
|
// (damn optimizer is getting in the way so disable it)
|
|
#pragma optimize( "", off )
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// 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;
|
|
|
|
// Global string buffers to prevent C4748 warning: "/GS can not protect
|
|
// parameters and local variables from local buffer overrun because
|
|
// optimizations are disabled in function"
|
|
|
|
static WCHAR g_wszHercDrive [ 4 * _MAX_DRIVE ] = {0};
|
|
static WCHAR g_wszHercDir [ 4 * _MAX_DIR ] = {0};
|
|
static WCHAR g_wszFileDir [ 4 * _MAX_DIR ] = {0};
|
|
static WCHAR g_wszHercPath [ 4 * _MAX_PATH ] = {0};
|
|
static WCHAR g_wszDumpPath [ 4 * _MAX_PATH ] = {0};
|
|
static WCHAR g_wszFileName [ 4 * _MAX_FNAME ] = {0};
|
|
|
|
static TCHAR g_szSaveTitle[ 512 ] = {0};
|
|
static LPCTSTR g_pszTempTitle = _T("{98C1C303-2A9E-11d4-9FF5-0060677l8D04}");
|
|
|
|
// (forward reference)
|
|
|
|
static void ProcessException( EXCEPTION_POINTERS* pExceptionPtrs );
|
|
|
|
// (helper macro)
|
|
|
|
#ifndef ARRAYSIZE
|
|
#define ARRAYSIZE(x) (sizeof(x)/sizeof(x[0]))
|
|
#endif
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
int main(int ac,char *av[])
|
|
{
|
|
int rc = 0;
|
|
|
|
SET_THREAD_NAME("bootstrap");
|
|
|
|
// Disable Microsoft's INSANE invalid crt parameter handling!
|
|
|
|
DISABLE_CRT_INVALID_PARAMETER_HANDLER();
|
|
|
|
// 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")))
|
|
)
|
|
{
|
|
GetModuleFileNameW( NULL, g_wszHercPath, ARRAYSIZE(g_wszHercPath) );
|
|
_wsplitpath( g_wszHercPath, g_wszHercDrive, g_wszHercDir, NULL, NULL );
|
|
}
|
|
|
|
SetErrorMode( SEM_NOGPFAULTERRORBOX );
|
|
|
|
__try
|
|
{
|
|
rc = impl(ac,av); // (Hercules, do your thing!)
|
|
}
|
|
__except
|
|
(
|
|
fflush(stdout),
|
|
fflush(stderr),
|
|
_ftprintf( stderr, _T("]!OOPS!\n") ),
|
|
fflush(stdout),
|
|
fflush(stderr),
|
|
Sleep(10),
|
|
_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 HWND FindConsoleHandle()
|
|
{
|
|
HWND hWnd;
|
|
if (!GetConsoleTitle(g_szSaveTitle,ARRAYSIZE(g_szSaveTitle)))
|
|
return NULL;
|
|
if (!SetConsoleTitle(g_pszTempTitle))
|
|
return NULL;
|
|
Sleep(20);
|
|
hWnd = FindWindow(NULL,g_pszTempTitle);
|
|
SetConsoleTitle(g_szSaveTitle);
|
|
return hWnd;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
static BOOL CreateMiniDump( EXCEPTION_POINTERS* pExceptionPtrs );
|
|
|
|
static void ProcessException( EXCEPTION_POINTERS* pExceptionPtrs )
|
|
{
|
|
UINT uiMBFlags =
|
|
0
|
|
| MB_SYSTEMMODAL
|
|
| MB_TOPMOST
|
|
| MB_SETFOREGROUND
|
|
;
|
|
|
|
HWND hwndMBOwner = FindConsoleHandle();
|
|
|
|
if (!hwndMBOwner || !IsWindowVisible(hwndMBOwner))
|
|
hwndMBOwner = GetDesktopWindow();
|
|
|
|
if ( !g_pfnMiniDumpWriteDumpFunc )
|
|
{
|
|
MessageBox
|
|
(
|
|
hwndMBOwner,
|
|
_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!"),
|
|
uiMBFlags
|
|
| MB_ICONERROR
|
|
| MB_OK
|
|
);
|
|
|
|
return;
|
|
}
|
|
|
|
if ( IDYES == MessageBox
|
|
(
|
|
hwndMBOwner,
|
|
_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!"),
|
|
uiMBFlags
|
|
| MB_ICONERROR
|
|
| MB_YESNO
|
|
))
|
|
{
|
|
if ( CreateMiniDump( pExceptionPtrs ) )
|
|
{
|
|
MessageBox
|
|
(
|
|
hwndMBOwner,
|
|
_T("Please send the dump to the Hercules development team for analysis.")
|
|
,_T("Dump Complete"),
|
|
uiMBFlags
|
|
| MB_ICONEXCLAMATION
|
|
| 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;
|
|
HANDLE hDumpFile;
|
|
|
|
_wmakepath( g_wszDumpPath, g_wszHercDrive, g_wszHercDir, L"Hercules", L".dmp" );
|
|
|
|
_tprintf( _T("Creating crash dump \"%ls\"...\n"), g_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
|
|
(
|
|
g_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 \"%ls\" created.\n"), g_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 (64)
|
|
|
|
static char g_host_info_str [ 1024 ];
|
|
static MINIDUMP_USER_STREAM UserStreamArray [ MAX_MINIDUMP_USER_STREAMS ];
|
|
|
|
static void BuildUserStreams( MINIDUMP_USER_STREAM_INFORMATION* pMDUSI )
|
|
{
|
|
const char** ppszBldInfoStr;
|
|
int nNumBldInfoStrs;
|
|
ULONG UserStreamCount;
|
|
|
|
_ASSERTE( pMDUSI );
|
|
|
|
get_hostinfo_str( NULL, g_host_info_str, sizeof(g_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 = g_host_info_str;
|
|
UserStreamArray[UserStreamCount].BufferSize = strlen(g_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;
|
|
|
|
_ASSERTE( pwszModuleName );
|
|
|
|
_wsplitpath( pwszModuleName, NULL, g_wszFileDir, g_wszFileName, NULL );
|
|
|
|
if ( _wcsicmp( g_wszFileName, L"ntdll" ) == 0 )
|
|
{
|
|
bNeeded = TRUE;
|
|
}
|
|
else if ( _wcsicmp( g_wszFileDir, g_wszHercDir ) == 0 )
|
|
{
|
|
bNeeded = TRUE;
|
|
}
|
|
|
|
return bNeeded;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
#pragma optimize( "", on )
|
|
|
|
#endif // !defined( _MSVC_ )
|