Breakpad3: WIP, minidump files created
TODO: re-work sending crash logs get rid of standalone loggers
This commit is contained in:
@@ -558,6 +558,11 @@ LLAppViewer::LLAppViewer() :
|
||||
llerrs << "Oh no! An instance of LLAppViewer already exists! LLAppViewer is sort of like a singleton." << llendl;
|
||||
}
|
||||
|
||||
mDumpPath ="";
|
||||
|
||||
// Need to do this initialization before we do anything else, since anything
|
||||
// that touches files should really go through the lldir API
|
||||
gDirUtilp->initAppDirs("SecondLife");
|
||||
sInstance = this;
|
||||
}
|
||||
|
||||
@@ -580,7 +585,9 @@ public:
|
||||
};
|
||||
|
||||
bool LLAppViewer::init()
|
||||
{
|
||||
{
|
||||
setupErrorHandling();
|
||||
|
||||
//
|
||||
// Start of the application
|
||||
//
|
||||
@@ -605,9 +612,6 @@ bool LLAppViewer::init()
|
||||
//initialize particle index pool
|
||||
LLVOPartGroup::initClass();
|
||||
|
||||
// Need to do this initialization before we do anything else, since anything
|
||||
// that touches files should really go through the lldir API
|
||||
gDirUtilp->initAppDirs("SecondLife");
|
||||
// set skin search path to default, will be overridden later
|
||||
// this allows simple skinned file lookups to work
|
||||
gDirUtilp->setSkinFolder("default");
|
||||
@@ -636,6 +640,12 @@ bool LLAppViewer::init()
|
||||
initMaxHeapSize() ;
|
||||
|
||||
LLPrivateMemoryPoolManager::initClass((BOOL)gSavedSettings.getBOOL("MemoryPrivatePoolEnabled"), (U32)gSavedSettings.getU32("MemoryPrivatePoolSize")) ;
|
||||
// write Google Breakpad minidump files to a per-run dump directory to avoid multiple viewer issues.
|
||||
std::string logdir = gDirUtilp->getExpandedFilename(LL_PATH_DUMP, "");
|
||||
mDumpPath = logdir;
|
||||
setMiniDumpDir(logdir);
|
||||
logdir += gDirUtilp->getDirDelimiter();
|
||||
setDebugFileNames(logdir);
|
||||
|
||||
mAlloc.setProfilingEnabled(gSavedSettings.getBOOL("MemProfiling"));
|
||||
|
||||
@@ -1448,6 +1458,14 @@ bool LLAppViewer::cleanup()
|
||||
{
|
||||
//ditch LLVOAvatarSelf instance
|
||||
gAgentAvatarp = NULL;
|
||||
|
||||
// remove any old breakpad minidump files from the log directory
|
||||
if (! isError())
|
||||
{
|
||||
std::string logdir = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "");
|
||||
gDirUtilp->deleteFilesInDir(logdir, "*-*-*-*-*.dmp");
|
||||
}
|
||||
|
||||
cleanup_pose_stand();
|
||||
|
||||
//flag all elements as needing to be destroyed immediately
|
||||
@@ -1725,6 +1743,7 @@ bool LLAppViewer::cleanup()
|
||||
}
|
||||
// </edit>
|
||||
|
||||
removeDumpDir();
|
||||
writeDebugInfo();
|
||||
|
||||
if(!gDirUtilp->getLindenUserDir(true).empty())
|
||||
@@ -2449,7 +2468,6 @@ bool LLAppViewer::initConfiguration()
|
||||
|
||||
initMarkerFile();
|
||||
|
||||
checkForCrash();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2469,10 +2487,6 @@ bool LLAppViewer::initConfiguration()
|
||||
|
||||
initMarkerFile();
|
||||
|
||||
if(!mSecondInstance)
|
||||
{
|
||||
checkForCrash();
|
||||
}
|
||||
}
|
||||
|
||||
// need to do this here - need to have initialized global settings first
|
||||
@@ -2488,62 +2502,6 @@ bool LLAppViewer::initConfiguration()
|
||||
return true; // Config was successful.
|
||||
}
|
||||
|
||||
|
||||
void LLAppViewer::checkForCrash(void)
|
||||
{
|
||||
#if LL_SEND_CRASH_REPORTS
|
||||
// *NOTE:Mani The current state of the crash handler has the MacOSX
|
||||
// sending all crash reports as freezes, in order to let
|
||||
// the MacOSX CrashRepoter generate stacks before spawning the
|
||||
// SL crash logger.
|
||||
// The Linux and Windows clients generate their own stacks and
|
||||
// spawn the SL crash logger immediately. This may change in the future.
|
||||
#if LL_DARWIN
|
||||
if(gLastExecEvent != LAST_EXEC_NORMAL)
|
||||
#else
|
||||
if (gLastExecEvent == LAST_EXEC_FROZE)
|
||||
#endif
|
||||
{
|
||||
llinfos << "Last execution froze, requesting to send crash report." << llendl;
|
||||
//
|
||||
// Pop up a freeze or crash warning dialog
|
||||
//
|
||||
S32 choice;
|
||||
const S32 cb = gCrashSettings.getS32(CRASH_BEHAVIOR_SETTING);
|
||||
if(cb == CRASH_BEHAVIOR_ASK)
|
||||
{
|
||||
std::ostringstream msg;
|
||||
msg << LLTrans::getString("MBFrozenCrashed");
|
||||
std::string alert = LLTrans::getString("APP_NAME") + " " + LLTrans::getString("MBAlert");
|
||||
choice = OSMessageBox(msg.str(),
|
||||
alert,
|
||||
OSMB_YESNO);
|
||||
}
|
||||
else if(cb == CRASH_BEHAVIOR_NEVER_SEND)
|
||||
{
|
||||
choice = OSBTN_NO;
|
||||
}
|
||||
else
|
||||
{
|
||||
choice = OSBTN_YES;
|
||||
}
|
||||
|
||||
if (OSBTN_YES == choice)
|
||||
{
|
||||
llinfos << "Sending crash report." << llendl;
|
||||
|
||||
bool report_freeze = true;
|
||||
handleCrashReporting(report_freeze);
|
||||
}
|
||||
else
|
||||
{
|
||||
llinfos << "Not sending crash report." << llendl;
|
||||
}
|
||||
}
|
||||
#endif // LL_SEND_CRASH_REPORTS
|
||||
|
||||
}
|
||||
|
||||
bool LLAppViewer::initWindow()
|
||||
{
|
||||
LL_INFOS("AppInit") << "Initializing window..." << LL_ENDL;
|
||||
@@ -2613,12 +2571,21 @@ bool LLAppViewer::initWindow()
|
||||
return true;
|
||||
}
|
||||
|
||||
void LLAppViewer::writeDebugInfo()
|
||||
void LLAppViewer::writeDebugInfo(bool isStatic)
|
||||
{
|
||||
std::string debug_filename = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"debug_info.log");
|
||||
llinfos << "Opening debug file " << debug_filename << llendl;
|
||||
llofstream out_file(debug_filename);
|
||||
LLSDSerialize::toPrettyXML(gDebugInfo, out_file);
|
||||
//Try to do the minimum when writing data during a crash.
|
||||
std::string* debug_filename;
|
||||
debug_filename = ( isStatic
|
||||
? getStaticDebugFile()
|
||||
: getDynamicDebugFile() );
|
||||
|
||||
llinfos << "Opening debug file " << *debug_filename << llendl;
|
||||
llofstream out_file(*debug_filename);
|
||||
|
||||
isStatic ? LLSDSerialize::toPrettyXML(gDebugInfo, out_file)
|
||||
: LLSDSerialize::toPrettyXML(gDebugInfo["Dynamic"], out_file);
|
||||
|
||||
|
||||
out_file.close();
|
||||
}
|
||||
|
||||
@@ -2669,6 +2636,10 @@ void LLAppViewer::removeCacheFiles(const std::string& file_mask)
|
||||
|
||||
void LLAppViewer::writeSystemInfo()
|
||||
{
|
||||
|
||||
if (! gDebugInfo.has("Dynamic") )
|
||||
gDebugInfo["Dynamic"] = LLSD::emptyMap();
|
||||
|
||||
gDebugInfo["SLLog"] = LLError::logFileName();
|
||||
|
||||
gDebugInfo["ClientInfo"]["Name"] = gVersionChannel;
|
||||
@@ -2706,6 +2677,15 @@ void LLAppViewer::writeSystemInfo()
|
||||
// If the crash is handled by LLAppViewer::handleViewerCrash, ie not a freeze,
|
||||
// then the value of "CrashNotHandled" will be set to true.
|
||||
gDebugInfo["CrashNotHandled"] = (LLSD::Boolean)true;
|
||||
|
||||
// Insert crash host url (url to post crash log to) if configured. This insures
|
||||
// that the crash report will go to the proper location in the case of a
|
||||
// prior freeze.
|
||||
std::string crashHostUrl = gSavedSettings.get<std::string>("CrashHostUrl");
|
||||
if(crashHostUrl != "")
|
||||
{
|
||||
gDebugInfo["CrashHostUrl"] = crashHostUrl;
|
||||
}
|
||||
|
||||
// Dump some debugging info
|
||||
LL_INFOS("SystemInfo") << LLTrans::getString("APP_NAME")
|
||||
@@ -2730,13 +2710,6 @@ void LLAppViewer::writeSystemInfo()
|
||||
writeDebugInfo(); // Save out debug_info.log early, in case of crash.
|
||||
}
|
||||
|
||||
void LLAppViewer::handleSyncViewerCrash()
|
||||
{
|
||||
LLAppViewer* pApp = LLAppViewer::instance();
|
||||
// Call to pure virtual, handled by platform specific llappviewer instance.
|
||||
pApp->handleSyncCrashTrace();
|
||||
}
|
||||
|
||||
void LLAppViewer::handleViewerCrash()
|
||||
{
|
||||
llinfos << "Handle viewer crash entry." << llendl;
|
||||
@@ -2768,8 +2741,12 @@ void LLAppViewer::handleViewerCrash()
|
||||
}
|
||||
pApp->mReportedCrash = TRUE;
|
||||
|
||||
// Make sure the watchdog gets turned off...
|
||||
// pApp->destroyMainloopTimeout(); // SJB: Bah. This causes the crash handler to hang, not sure why.
|
||||
// Insert crash host url (url to post crash log to) if configured.
|
||||
std::string crashHostUrl = gSavedSettings.get<std::string>("CrashHostUrl");
|
||||
if(crashHostUrl != "")
|
||||
{
|
||||
gDebugInfo["Dynamic"]["CrashHostUrl"] = crashHostUrl;
|
||||
}
|
||||
|
||||
//We already do this in writeSystemInfo(), but we do it again here to make /sure/ we have a version
|
||||
//to check against no matter what
|
||||
@@ -2783,11 +2760,11 @@ void LLAppViewer::handleViewerCrash()
|
||||
LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
|
||||
if ( parcel && parcel->getMusicURL()[0])
|
||||
{
|
||||
gDebugInfo["ParcelMusicURL"] = parcel->getMusicURL();
|
||||
gDebugInfo["Dynamic"]["ParcelMusicURL"] = parcel->getMusicURL();
|
||||
}
|
||||
if ( parcel && parcel->getMediaURL()[0])
|
||||
{
|
||||
gDebugInfo["ParcelMediaURL"] = parcel->getMediaURL();
|
||||
gDebugInfo["Dynamic"]["ParcelMediaURL"] = parcel->getMediaURL();
|
||||
}
|
||||
|
||||
|
||||
@@ -2795,15 +2772,15 @@ void LLAppViewer::handleViewerCrash()
|
||||
gDebugInfo["CAFilename"] = gDirUtilp->getCAFile();
|
||||
gDebugInfo["ViewerExePath"] = gDirUtilp->getExecutablePathAndName();
|
||||
gDebugInfo["CurrentPath"] = gDirUtilp->getCurPath();
|
||||
gDebugInfo["SessionLength"] = F32(LLFrameTimer::getElapsedSeconds());
|
||||
gDebugInfo["Dynamic"]["SessionLength"] = F32(LLFrameTimer::getElapsedSeconds());
|
||||
gDebugInfo["StartupState"] = LLStartUp::getStartupStateString();
|
||||
gDebugInfo["RAMInfo"]["Allocated"] = (LLSD::Integer) LLMemory::getCurrentRSS() >> 10;
|
||||
gDebugInfo["Dynamic"]["RAMInfo"]["Allocated"] = (LLSD::Integer) LLMemory::getCurrentRSS() >> 10;
|
||||
gDebugInfo["FirstLogin"] = (LLSD::Boolean) gAgent.isFirstLogin();
|
||||
gDebugInfo["FirstRunThisInstall"] = gSavedSettings.getBOOL("FirstRunThisInstall");
|
||||
|
||||
if(gLogoutInProgress)
|
||||
{
|
||||
gDebugInfo["LastExecEvent"] = LAST_EXEC_LOGOUT_CRASH;
|
||||
gDebugInfo["Dynamic"]["LastExecEvent"] = LAST_EXEC_LOGOUT_CRASH;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2812,23 +2789,23 @@ void LLAppViewer::handleViewerCrash()
|
||||
|
||||
if(gAgent.getRegion())
|
||||
{
|
||||
gDebugInfo["CurrentSimHost"] = gAgent.getRegionHost().getHostName();
|
||||
gDebugInfo["CurrentRegion"] = gAgent.getRegion()->getName();
|
||||
gDebugInfo["Dynamic"]["CurrentSimHost"] = gAgent.getRegionHost().getHostName();
|
||||
gDebugInfo["Dynamic"]["CurrentRegion"] = gAgent.getRegion()->getName();
|
||||
|
||||
const LLVector3& loc = gAgent.getPositionAgent();
|
||||
gDebugInfo["CurrentLocationX"] = loc.mV[0];
|
||||
gDebugInfo["CurrentLocationY"] = loc.mV[1];
|
||||
gDebugInfo["CurrentLocationZ"] = loc.mV[2];
|
||||
gDebugInfo["Dynamic"]["CurrentLocationX"] = loc.mV[0];
|
||||
gDebugInfo["Dynamic"]["CurrentLocationY"] = loc.mV[1];
|
||||
gDebugInfo["Dynamic"]["CurrentLocationZ"] = loc.mV[2];
|
||||
}
|
||||
|
||||
if(LLAppViewer::instance()->mMainloopTimeout)
|
||||
{
|
||||
gDebugInfo["MainloopTimeoutState"] = LLAppViewer::instance()->mMainloopTimeout->getState();
|
||||
gDebugInfo["Dynamic"]["MainloopTimeoutState"] = LLAppViewer::instance()->mMainloopTimeout->getState();
|
||||
}
|
||||
|
||||
// The crash is being handled here so set this value to false.
|
||||
// Otherwise the crash logger will think this crash was a freeze.
|
||||
gDebugInfo["CrashNotHandled"] = (LLSD::Boolean)false;
|
||||
gDebugInfo["Dynamic"]["CrashNotHandled"] = (LLSD::Boolean)false;
|
||||
|
||||
//Write out the crash status file
|
||||
//Use marker file style setup, as that's the simplest, especially since
|
||||
@@ -2850,11 +2827,18 @@ void LLAppViewer::handleViewerCrash()
|
||||
LL_WARNS("MarkerFile") << "Cannot create error marker file " << crash_file_name << LL_ENDL;
|
||||
}
|
||||
}
|
||||
char *minidump_file = pApp->getMiniDumpFilename();
|
||||
if(minidump_file && minidump_file[0] != 0)
|
||||
{
|
||||
gDebugInfo["Dynamic"]["MinidumpPath"] = minidump_file;
|
||||
}
|
||||
|
||||
gDebugInfo["Dynamic"]["CrashType"]="crash";
|
||||
|
||||
if (gMessageSystem && gDirUtilp)
|
||||
{
|
||||
std::string filename;
|
||||
filename = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "stats.log");
|
||||
filename = gDirUtilp->getExpandedFilename(LL_PATH_DUMP, "stats.log");
|
||||
llofstream file(filename, llofstream::binary);
|
||||
if(file.good())
|
||||
{
|
||||
@@ -2870,19 +2854,15 @@ void LLAppViewer::handleViewerCrash()
|
||||
gMessageSystem->stopLogging();
|
||||
}
|
||||
|
||||
if (LLWorld::instanceExists()) LLWorld::getInstance()->getInfo(gDebugInfo);
|
||||
if (LLWorld::instanceExists()) LLWorld::getInstance()->getInfo(gDebugInfo["Dynamic"]);
|
||||
|
||||
// Close the debug file
|
||||
pApp->writeDebugInfo();
|
||||
pApp->writeDebugInfo(false); //false answers the isStatic question with the least overhead.
|
||||
|
||||
LLError::logToFile("");
|
||||
|
||||
// On Mac, we send the report on the next run, since we need macs crash report
|
||||
// for a stack trace, so we have to let it the app fail.
|
||||
#if !LL_DARWIN
|
||||
|
||||
// Remove the marker file, since otherwise we'll spawn a process that'll keep it locked
|
||||
if(gDebugInfo["LastExecEvent"].asInteger() == LAST_EXEC_LOGOUT_CRASH)
|
||||
if(gDebugInfo["Dynamic"]["LastExecEvent"].asInteger() == LAST_EXEC_LOGOUT_CRASH)
|
||||
{
|
||||
pApp->removeMarkerFile(true);
|
||||
}
|
||||
@@ -2891,11 +2871,6 @@ void LLAppViewer::handleViewerCrash()
|
||||
pApp->removeMarkerFile(false);
|
||||
}
|
||||
|
||||
// Call to pure virtual, handled by platform specific llappviewer instance.
|
||||
pApp->handleCrashReporting();
|
||||
|
||||
#endif //!LL_DARWIN
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -3020,6 +2995,18 @@ void LLAppViewer::removeMarkerFile(bool leave_logout_marker)
|
||||
LLAPRFile::remove( mLogoutMarkerFileName );
|
||||
mLogoutMarkerFile = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS("MarkerFile") << "leaving markers because this is a second instance" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
|
||||
void LLAppViewer::removeDumpDir()
|
||||
{
|
||||
//Call this routine only on clean exit. Crash reporter will clean up
|
||||
//its locking table for us.
|
||||
std::string dump_dir = gDirUtilp->getExpandedFilename(LL_PATH_DUMP, "");
|
||||
gDirUtilp->deleteDirAndContents(dump_dir);
|
||||
}
|
||||
|
||||
void LLAppViewer::forceQuit()
|
||||
@@ -3592,13 +3579,6 @@ void LLAppViewer::badNetworkHandler()
|
||||
|
||||
mPurgeOnExit = TRUE;
|
||||
|
||||
#if LL_WINDOWS
|
||||
// Generates the minidump.
|
||||
LLWinDebug::generateCrashStacks(NULL);
|
||||
#endif
|
||||
LLAppViewer::handleSyncViewerCrash();
|
||||
LLAppViewer::handleViewerCrash();
|
||||
|
||||
std::string grid_support_msg = "";
|
||||
if (!gHippoGridManager->getCurrentGrid()->getSupportUrl().empty())
|
||||
{
|
||||
@@ -3617,6 +3597,8 @@ void LLAppViewer::badNetworkHandler()
|
||||
"If the problem continues, please report the issue at: \n"
|
||||
"http://www.singularityviewer.org" << grid_support_msg;
|
||||
forceDisconnect(message.str());
|
||||
|
||||
LLApp::instance()->writeMiniDump();
|
||||
}
|
||||
|
||||
// This routine may get called more than once during the shutdown process.
|
||||
|
||||
Reference in New Issue
Block a user