Files
org-hyperion-cules/bootstrap.c
Ivan Warren eb1fb02cee - Move setting of CPU priority after spwaning timer thread
- Added support for Posix 1003.1e capabilities


git-svn-id: file:///home/jj/hercules.svn/trunk@4573 956126f8-22a0-4046-8f4a-272fa8102e63
2008-02-19 11:49:19 +00:00

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_ )