|
|
|
|
@@ -27,6 +27,14 @@
|
|
|
|
|
#include "linden_common.h"
|
|
|
|
|
#include "llapp.h"
|
|
|
|
|
|
|
|
|
|
#include <cstdlib>
|
|
|
|
|
|
|
|
|
|
#ifdef LL_DARWIN
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
#include <sys/sysctl.h>
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#include "llcommon.h"
|
|
|
|
|
#include "llapr.h"
|
|
|
|
|
#include "llerrorcontrol.h"
|
|
|
|
|
@@ -35,7 +43,9 @@
|
|
|
|
|
#include "lllivefile.h"
|
|
|
|
|
#include "llmemory.h"
|
|
|
|
|
#include "llstl.h" // for DeletePointer()
|
|
|
|
|
#include "llstring.h"
|
|
|
|
|
#include "lleventtimer.h"
|
|
|
|
|
#include "google_breakpad/exception_handler.h"
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Signal handling
|
|
|
|
|
@@ -43,13 +53,34 @@
|
|
|
|
|
// Windows uses structured exceptions, so it's handled a bit differently.
|
|
|
|
|
//
|
|
|
|
|
#if LL_WINDOWS
|
|
|
|
|
#include "windows.h"
|
|
|
|
|
|
|
|
|
|
LONG WINAPI default_windows_exception_handler(struct _EXCEPTION_POINTERS *exception_infop);
|
|
|
|
|
BOOL ConsoleCtrlHandler(DWORD fdwCtrlType);
|
|
|
|
|
bool windows_post_minidump_callback(const wchar_t* dump_path,
|
|
|
|
|
const wchar_t* minidump_id,
|
|
|
|
|
void* context,
|
|
|
|
|
EXCEPTION_POINTERS* exinfo,
|
|
|
|
|
MDRawAssertionInfo* assertion,
|
|
|
|
|
bool succeeded);
|
|
|
|
|
#else
|
|
|
|
|
# include <signal.h>
|
|
|
|
|
# include <unistd.h> // for fork()
|
|
|
|
|
void setup_signals();
|
|
|
|
|
void default_unix_signal_handler(int signum, siginfo_t *info, void *);
|
|
|
|
|
|
|
|
|
|
#if LL_LINUX
|
|
|
|
|
#include "google_breakpad/minidump_descriptor.h"
|
|
|
|
|
static bool unix_minidump_callback(const google_breakpad::MinidumpDescriptor& minidump_desc,
|
|
|
|
|
void* context,
|
|
|
|
|
bool succeeded);
|
|
|
|
|
#else
|
|
|
|
|
// Called by breakpad exception handler after the minidump has been generated.
|
|
|
|
|
bool unix_post_minidump_callback(const char *dump_dir,
|
|
|
|
|
const char *minidump_id,
|
|
|
|
|
void *context, bool succeeded);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
# if LL_DARWIN
|
|
|
|
|
/* OSX doesn't support SIGRT* */
|
|
|
|
|
S32 LL_SMACKDOWN_SIGNAL = SIGUSR1;
|
|
|
|
|
@@ -79,7 +110,6 @@ BOOL LLApp::sLogInSignal = FALSE;
|
|
|
|
|
// static
|
|
|
|
|
LLApp::EAppStatus LLApp::sStatus = LLApp::APP_STATUS_STOPPED; // Keeps track of application status
|
|
|
|
|
LLAppErrorHandler LLApp::sErrorHandler = NULL;
|
|
|
|
|
LLAppErrorHandler LLApp::sSyncErrorHandler = NULL;
|
|
|
|
|
BOOL LLApp::sErrorThreadRunning = FALSE;
|
|
|
|
|
#if !LL_WINDOWS
|
|
|
|
|
LLApp::child_map LLApp::sChildMap;
|
|
|
|
|
@@ -100,14 +130,6 @@ void LLApp::commonCtor()
|
|
|
|
|
|
|
|
|
|
LLCommon::initClass();
|
|
|
|
|
|
|
|
|
|
#if !LL_WINDOWS
|
|
|
|
|
// This must be initialized before the error handler.
|
|
|
|
|
sSigChildCount = new LLAtomicU32(0);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// Setup error handling
|
|
|
|
|
setupErrorHandling();
|
|
|
|
|
|
|
|
|
|
// initialize the options structure. We need to make this an array
|
|
|
|
|
// because the structured data will not auto-allocate if we
|
|
|
|
|
// reference an invalid location with the [] operator.
|
|
|
|
|
@@ -118,8 +140,19 @@ void LLApp::commonCtor()
|
|
|
|
|
mOptions.append(sd);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Make sure we clean up APR when we exit
|
|
|
|
|
// Don't need to do this if we're cleaning up APR in the destructor
|
|
|
|
|
//atexit(ll_cleanup_apr);
|
|
|
|
|
|
|
|
|
|
// Set the application to this instance.
|
|
|
|
|
sApplication = this;
|
|
|
|
|
|
|
|
|
|
mExceptionHandler = 0;
|
|
|
|
|
|
|
|
|
|
// initialize the buffer to write the minidump filename to
|
|
|
|
|
// (this is used to avoid allocating memory in the crash handler)
|
|
|
|
|
memset(mMinidumpPath, 0, MAX_MINDUMP_PATH_LENGTH);
|
|
|
|
|
mCrashReportPipeStr = L"\\\\.\\pipe\\LLCrashReporterPipe";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LLApp::LLApp(LLErrorThread *error_thread) :
|
|
|
|
|
@@ -131,10 +164,6 @@ LLApp::LLApp(LLErrorThread *error_thread) :
|
|
|
|
|
|
|
|
|
|
LLApp::~LLApp()
|
|
|
|
|
{
|
|
|
|
|
#if !LL_WINDOWS
|
|
|
|
|
delete sSigChildCount;
|
|
|
|
|
sSigChildCount = NULL;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// reclaim live file memory
|
|
|
|
|
std::for_each(mLiveFiles.begin(), mLiveFiles.end(), DeletePointer());
|
|
|
|
|
@@ -148,6 +177,8 @@ LLApp::~LLApp()
|
|
|
|
|
delete mThreadErrorp;
|
|
|
|
|
mThreadErrorp = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(mExceptionHandler != 0) delete mExceptionHandler;
|
|
|
|
|
|
|
|
|
|
LLCommon::cleanupClass();
|
|
|
|
|
}
|
|
|
|
|
@@ -207,6 +238,20 @@ bool LLApp::parseCommandOptions(int argc, char** argv)
|
|
|
|
|
}
|
|
|
|
|
++ii;
|
|
|
|
|
value.assign(argv[ii]);
|
|
|
|
|
|
|
|
|
|
#if LL_WINDOWS
|
|
|
|
|
//Windows changed command line parsing. Deal with it.
|
|
|
|
|
S32 slen = value.length() - 1;
|
|
|
|
|
S32 start = 0;
|
|
|
|
|
S32 end = slen;
|
|
|
|
|
if (argv[ii][start]=='"')start++;
|
|
|
|
|
if (argv[ii][end]=='"')end--;
|
|
|
|
|
if (start!=0 || end!=slen)
|
|
|
|
|
{
|
|
|
|
|
value = value.substr (start,end);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
commands[name] = value;
|
|
|
|
|
}
|
|
|
|
|
setOptionData(PRIORITY_COMMAND_LINE, commands);
|
|
|
|
|
@@ -254,14 +299,60 @@ void LLApp::setupErrorHandling()
|
|
|
|
|
// What we do is install an unhandled exception handler, which will try to do the right thing
|
|
|
|
|
// in the case of an error (generate a minidump)
|
|
|
|
|
|
|
|
|
|
// Disable this until the viewer gets ported so server crashes can be JIT debugged.
|
|
|
|
|
//LPTOP_LEVEL_EXCEPTION_FILTER prev_filter;
|
|
|
|
|
//prev_filter = SetUnhandledExceptionFilter(default_windows_exception_handler);
|
|
|
|
|
|
|
|
|
|
#if LL_SEND_CRASH_REPORTS
|
|
|
|
|
// This sets a callback to handle w32 signals to the console window.
|
|
|
|
|
// The viewer shouldn't be affected, sicne its a windowed app.
|
|
|
|
|
SetConsoleCtrlHandler( (PHANDLER_ROUTINE) ConsoleCtrlHandler, TRUE);
|
|
|
|
|
|
|
|
|
|
// Install the Google Breakpad crash handler for Windows
|
|
|
|
|
if(mExceptionHandler == 0)
|
|
|
|
|
{
|
|
|
|
|
llwarns << "adding breakpad exception handler" << llendl;
|
|
|
|
|
|
|
|
|
|
std::wostringstream ws;
|
|
|
|
|
ws << mCrashReportPipeStr << getPid();
|
|
|
|
|
std::wstring wpipe_name = ws.str();
|
|
|
|
|
std::string ptmp = std::string(wpipe_name.begin(), wpipe_name.end());
|
|
|
|
|
|
|
|
|
|
::Sleep(2000); //HACK hopefully a static wait won't blow up in my face before google fixes their implementation.
|
|
|
|
|
|
|
|
|
|
//HACK this for loop is ueless. Breakpad dumbly returns success when the OOP handler isn't initialized.
|
|
|
|
|
for (int retries=0;retries<5;++retries)
|
|
|
|
|
{
|
|
|
|
|
mExceptionHandler = new google_breakpad::ExceptionHandler(
|
|
|
|
|
L"",
|
|
|
|
|
NULL, //No filter
|
|
|
|
|
windows_post_minidump_callback,
|
|
|
|
|
0,
|
|
|
|
|
google_breakpad::ExceptionHandler::HANDLER_ALL,
|
|
|
|
|
MiniDumpNormal, //Generate a 'normal' minidump.
|
|
|
|
|
(WCHAR *)wpipe_name.c_str(),
|
|
|
|
|
NULL); //No custom client info.
|
|
|
|
|
if (mExceptionHandler)
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
::Sleep(100); //Wait a tick and try again.
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!mExceptionHandler)
|
|
|
|
|
{
|
|
|
|
|
llwarns << "Failed to initialize OOP exception handler. Defaulting to In Process handling" << llendl;
|
|
|
|
|
mExceptionHandler = new google_breakpad::ExceptionHandler(
|
|
|
|
|
std::wstring(mDumpPath.begin(),mDumpPath.end()), //Dump path
|
|
|
|
|
0, //dump filename
|
|
|
|
|
windows_post_minidump_callback,
|
|
|
|
|
0,
|
|
|
|
|
google_breakpad::ExceptionHandler::HANDLER_ALL);
|
|
|
|
|
}
|
|
|
|
|
if (mExceptionHandler)
|
|
|
|
|
{
|
|
|
|
|
mExceptionHandler->set_handle_debug_exceptions(true);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
#else
|
|
|
|
|
//
|
|
|
|
|
// Start up signal handling.
|
|
|
|
|
@@ -271,9 +362,61 @@ void LLApp::setupErrorHandling()
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
setup_signals();
|
|
|
|
|
|
|
|
|
|
// Add google breakpad exception handler configured for Darwin/Linux.
|
|
|
|
|
bool installHandler = true;
|
|
|
|
|
#if LL_DARWIN
|
|
|
|
|
// For the special case of Darwin, we do not want to install the handler if
|
|
|
|
|
// the process is being debugged as the app will exit with value ABRT (6) if
|
|
|
|
|
// we do. Unfortunately, the code below which performs that test relies on
|
|
|
|
|
// the structure kinfo_proc which has been tagged by apple as an unstable
|
|
|
|
|
// API. We disable this test for shipping versions to avoid conflicts with
|
|
|
|
|
// future releases of Darwin. This test is really only needed for developers
|
|
|
|
|
// starting the app from a debugger anyway.
|
|
|
|
|
#ifndef LL_RELEASE_FOR_DOWNLOAD
|
|
|
|
|
int mib[4];
|
|
|
|
|
mib[0] = CTL_KERN;
|
|
|
|
|
mib[1] = KERN_PROC;
|
|
|
|
|
mib[2] = KERN_PROC_PID;
|
|
|
|
|
mib[3] = getpid();
|
|
|
|
|
|
|
|
|
|
struct kinfo_proc info;
|
|
|
|
|
memset(&info, 0, sizeof(info));
|
|
|
|
|
|
|
|
|
|
size_t size = sizeof(info);
|
|
|
|
|
int result = sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0);
|
|
|
|
|
if((result == 0) || (errno == ENOMEM))
|
|
|
|
|
{
|
|
|
|
|
// P_TRACED flag is set, so this process is being debugged; do not install
|
|
|
|
|
// the handler
|
|
|
|
|
if(info.kp_proc.p_flag & P_TRACED) installHandler = false;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Failed to discover if the process is being debugged; default to
|
|
|
|
|
// installing the handler.
|
|
|
|
|
installHandler = true;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
if(installHandler && (mExceptionHandler == 0))
|
|
|
|
|
{
|
|
|
|
|
mExceptionHandler = new google_breakpad::ExceptionHandler(mDumpPath, 0, &unix_post_minidump_callback, 0, true, 0);
|
|
|
|
|
}
|
|
|
|
|
#elif LL_LINUX
|
|
|
|
|
if(installHandler && (mExceptionHandler == 0))
|
|
|
|
|
{
|
|
|
|
|
if (mDumpPath.empty())
|
|
|
|
|
{
|
|
|
|
|
mDumpPath = "/tmp";
|
|
|
|
|
}
|
|
|
|
|
google_breakpad::MinidumpDescriptor desc(mDumpPath);
|
|
|
|
|
//mExceptionHandler = new google_breakpad::ExceptionHandler(desc, 0, unix_minidump_callback, 0, true, 0);
|
|
|
|
|
mExceptionHandler = new google_breakpad::ExceptionHandler(desc, NULL, unix_minidump_callback, NULL, true, -1);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LLApp::startErrorThread()
|
|
|
|
|
@@ -311,20 +454,6 @@ void LLApp::setErrorHandler(LLAppErrorHandler handler)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void LLApp::setSyncErrorHandler(LLAppErrorHandler handler)
|
|
|
|
|
{
|
|
|
|
|
LLApp::sSyncErrorHandler = handler;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// static
|
|
|
|
|
void LLApp::runSyncErrorHandler()
|
|
|
|
|
{
|
|
|
|
|
if (LLApp::sSyncErrorHandler)
|
|
|
|
|
{
|
|
|
|
|
LLApp::sSyncErrorHandler();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// static
|
|
|
|
|
void LLApp::runErrorHandler()
|
|
|
|
|
{
|
|
|
|
|
@@ -348,15 +477,46 @@ void LLApp::setStatus(EAppStatus status)
|
|
|
|
|
// static
|
|
|
|
|
void LLApp::setError()
|
|
|
|
|
{
|
|
|
|
|
if (!isError())
|
|
|
|
|
{
|
|
|
|
|
// perform any needed synchronous error-handling
|
|
|
|
|
runSyncErrorHandler();
|
|
|
|
|
// set app status to ERROR so that the LLErrorThread notices
|
|
|
|
|
setStatus(APP_STATUS_ERROR);
|
|
|
|
|
}
|
|
|
|
|
// set app status to ERROR so that the LLErrorThread notices
|
|
|
|
|
setStatus(APP_STATUS_ERROR);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LLApp::setMiniDumpDir(const std::string &path)
|
|
|
|
|
{
|
|
|
|
|
if (path.empty())
|
|
|
|
|
{
|
|
|
|
|
mDumpPath = "/tmp";
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
mDumpPath = path;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(mExceptionHandler == 0) return;
|
|
|
|
|
#ifdef LL_WINDOWS
|
|
|
|
|
wchar_t buffer[MAX_MINDUMP_PATH_LENGTH];
|
|
|
|
|
mbstowcs(buffer, mDumpPath.c_str(), MAX_MINDUMP_PATH_LENGTH);
|
|
|
|
|
mExceptionHandler->set_dump_path(std::wstring(buffer));
|
|
|
|
|
#elif LL_LINUX
|
|
|
|
|
//google_breakpad::MinidumpDescriptor desc("/tmp"); //path works in debug fails in production inside breakpad lib so linux gets a little less stack reporting until it is patched.
|
|
|
|
|
google_breakpad::MinidumpDescriptor desc(mDumpPath); //path works in debug fails in production inside breakpad lib so linux gets a little less stack reporting until it is patched.
|
|
|
|
|
mExceptionHandler->set_minidump_descriptor(desc);
|
|
|
|
|
#else
|
|
|
|
|
mExceptionHandler->set_dump_path(mDumpPath);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LLApp::setDebugFileNames(const std::string &path)
|
|
|
|
|
{
|
|
|
|
|
mStaticDebugFileName = path + "static_debug_info.log";
|
|
|
|
|
mDynamicDebugFileName = path + "dynamic_debug_info.log";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LLApp::writeMiniDump()
|
|
|
|
|
{
|
|
|
|
|
if(mExceptionHandler == 0) return;
|
|
|
|
|
mExceptionHandler->WriteMinidump();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// static
|
|
|
|
|
void LLApp::setQuitting()
|
|
|
|
|
@@ -413,6 +573,12 @@ bool LLApp::isExiting()
|
|
|
|
|
void LLApp::disableCrashlogger()
|
|
|
|
|
{
|
|
|
|
|
// Disable Breakpad exception handler.
|
|
|
|
|
if (mExceptionHandler != 0)
|
|
|
|
|
{
|
|
|
|
|
delete mExceptionHandler;
|
|
|
|
|
mExceptionHandler = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sDisableCrashlogger = TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -787,4 +953,149 @@ void default_unix_signal_handler(int signum, siginfo_t *info, void *)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if LL_LINUX
|
|
|
|
|
bool unix_minidump_callback(const google_breakpad::MinidumpDescriptor& minidump_desc, void* context, bool succeeded)
|
|
|
|
|
{
|
|
|
|
|
// Copy minidump file path into fixed buffer in the app instance to avoid
|
|
|
|
|
// heap allocations in a crash handler.
|
|
|
|
|
|
|
|
|
|
// path format: <dump_dir>/<minidump_id>.dmp
|
|
|
|
|
|
|
|
|
|
//HACK: *path points to the buffer in getMiniDumpFilename which has already allocated space
|
|
|
|
|
//to avoid doing allocation during crash.
|
|
|
|
|
char * path = LLApp::instance()->getMiniDumpFilename();
|
|
|
|
|
int dir_path_len = strlen(path);
|
|
|
|
|
|
|
|
|
|
// The path must not be truncated.
|
|
|
|
|
S32 remaining = LLApp::MAX_MINDUMP_PATH_LENGTH - dir_path_len;
|
|
|
|
|
|
|
|
|
|
llassert( (remaining - strlen(minidump_desc.path())) > 5);
|
|
|
|
|
|
|
|
|
|
path += dir_path_len;
|
|
|
|
|
|
|
|
|
|
if (dir_path_len > 0 && path[-1] != '/')
|
|
|
|
|
{
|
|
|
|
|
*path++ = '/';
|
|
|
|
|
--remaining;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
strncpy(path, minidump_desc.path(), remaining);
|
|
|
|
|
|
|
|
|
|
llinfos << "generated minidump: " << LLApp::instance()->getMiniDumpFilename() << llendl;
|
|
|
|
|
LLApp::runErrorHandler();
|
|
|
|
|
|
|
|
|
|
#ifndef LL_RELEASE_FOR_DOWNLOAD
|
|
|
|
|
clear_signals();
|
|
|
|
|
return false;
|
|
|
|
|
#else
|
|
|
|
|
return true;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool unix_post_minidump_callback(const char *dump_dir,
|
|
|
|
|
const char *minidump_id,
|
|
|
|
|
void *context, bool succeeded)
|
|
|
|
|
{
|
|
|
|
|
// Copy minidump file path into fixed buffer in the app instance to avoid
|
|
|
|
|
// heap allocations in a crash handler.
|
|
|
|
|
|
|
|
|
|
// path format: <dump_dir>/<minidump_id>.dmp
|
|
|
|
|
int dirPathLength = strlen(dump_dir);
|
|
|
|
|
int idLength = strlen(minidump_id);
|
|
|
|
|
|
|
|
|
|
// The path must not be truncated.
|
|
|
|
|
llassert((dirPathLength + idLength + 5) <= LLApp::MAX_MINDUMP_PATH_LENGTH);
|
|
|
|
|
|
|
|
|
|
char * path = LLApp::instance()->getMiniDumpFilename();
|
|
|
|
|
S32 remaining = LLApp::MAX_MINDUMP_PATH_LENGTH;
|
|
|
|
|
strncpy(path, dump_dir, remaining);
|
|
|
|
|
remaining -= dirPathLength;
|
|
|
|
|
path += dirPathLength;
|
|
|
|
|
if (remaining > 0 && dirPathLength > 0 && path[-1] != '/')
|
|
|
|
|
{
|
|
|
|
|
*path++ = '/';
|
|
|
|
|
--remaining;
|
|
|
|
|
}
|
|
|
|
|
if (remaining > 0)
|
|
|
|
|
{
|
|
|
|
|
strncpy(path, minidump_id, remaining);
|
|
|
|
|
remaining -= idLength;
|
|
|
|
|
path += idLength;
|
|
|
|
|
strncpy(path, ".dmp", remaining);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
llinfos << "generated minidump: " << path << llendl;
|
|
|
|
|
LLApp::runErrorHandler();
|
|
|
|
|
|
|
|
|
|
#ifndef LL_RELEASE_FOR_DOWNLOAD
|
|
|
|
|
clear_signals();
|
|
|
|
|
return false;
|
|
|
|
|
#else
|
|
|
|
|
return true;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
#endif // !WINDOWS
|
|
|
|
|
|
|
|
|
|
#ifdef LL_WINDOWS
|
|
|
|
|
bool windows_post_minidump_callback(const wchar_t* dump_path,
|
|
|
|
|
const wchar_t* minidump_id,
|
|
|
|
|
void* context,
|
|
|
|
|
EXCEPTION_POINTERS* exinfo,
|
|
|
|
|
MDRawAssertionInfo* assertion,
|
|
|
|
|
bool succeeded)
|
|
|
|
|
{
|
|
|
|
|
char * path = LLApp::instance()->getMiniDumpFilename();
|
|
|
|
|
S32 remaining = LLApp::MAX_MINDUMP_PATH_LENGTH;
|
|
|
|
|
size_t bytesUsed;
|
|
|
|
|
|
|
|
|
|
bytesUsed = wcstombs(path, dump_path, static_cast<size_t>(remaining));
|
|
|
|
|
remaining -= bytesUsed;
|
|
|
|
|
path += bytesUsed;
|
|
|
|
|
if(remaining > 0 && bytesUsed > 0 && path[-1] != '\\')
|
|
|
|
|
{
|
|
|
|
|
*path++ = '\\';
|
|
|
|
|
--remaining;
|
|
|
|
|
}
|
|
|
|
|
if(remaining > 0)
|
|
|
|
|
{
|
|
|
|
|
bytesUsed = wcstombs(path, minidump_id, static_cast<size_t>(remaining));
|
|
|
|
|
remaining -= bytesUsed;
|
|
|
|
|
path += bytesUsed;
|
|
|
|
|
}
|
|
|
|
|
if(remaining > 0)
|
|
|
|
|
{
|
|
|
|
|
strncpy(path, ".dmp", remaining);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
llinfos << "generated minidump: " << LLApp::instance()->getMiniDumpFilename() << llendl;
|
|
|
|
|
// *NOTE:Mani - this code is stolen from LLApp, where its never actually used.
|
|
|
|
|
//OSMessageBox("Attach Debugger Now", "Error", OSMB_OK);
|
|
|
|
|
// *TODO: Translate the signals/exceptions into cross-platform stuff
|
|
|
|
|
// Windows implementation
|
|
|
|
|
llinfos << "Entering Windows Exception Handler..." << llendl;
|
|
|
|
|
|
|
|
|
|
if (LLApp::isError())
|
|
|
|
|
{
|
|
|
|
|
llwarns << "Got another fatal signal while in the error handler, die now!" << llendl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Flag status to error, so thread_error starts its work
|
|
|
|
|
LLApp::setError();
|
|
|
|
|
|
|
|
|
|
// Block in the exception handler until the app has stopped
|
|
|
|
|
// This is pretty sketchy, but appears to work just fine
|
|
|
|
|
while (!LLApp::isStopped())
|
|
|
|
|
{
|
|
|
|
|
ms_sleep(10);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifndef LL_RELEASE_FOR_DOWNLOAD
|
|
|
|
|
return false;
|
|
|
|
|
#else
|
|
|
|
|
return true;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|