From 38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 Mon Sep 17 00:00:00 2001 From: Jacek Antonelli Date: Fri, 15 Aug 2008 23:44:46 -0500 Subject: Second Life viewer sources 1.13.2.12 --- linden/indra/newview/llwindebug.cpp | 273 ++++++++++++++++++++++++++++++++++++ 1 file changed, 273 insertions(+) create mode 100644 linden/indra/newview/llwindebug.cpp (limited to 'linden/indra/newview/llwindebug.cpp') diff --git a/linden/indra/newview/llwindebug.cpp b/linden/indra/newview/llwindebug.cpp new file mode 100644 index 0000000..772ded4 --- /dev/null +++ b/linden/indra/newview/llwindebug.cpp @@ -0,0 +1,273 @@ +/** + * @file llwindebug.cpp + * @brief Windows debugging functions + * + * Copyright (c) 2004-2007, Linden Research, Inc. + * + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + */ + +#include "llviewerprecompiledheaders.h" + +#ifdef LL_WINDOWS + +#include "llwindebug.h" +#include "llviewercontrol.h" +#include "lldir.h" + +// From viewer.h +extern BOOL gInProductionGrid; + +extern void (*gCrashCallback)(void); +extern void write_debug(const char *str); +extern void write_debug(const std::string &str); + +// based on dbghelp.h +typedef BOOL (WINAPI *MINIDUMPWRITEDUMP)(HANDLE hProcess, DWORD dwPid, HANDLE hFile, MINIDUMP_TYPE DumpType, + CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, + CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, + CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam + ); + +MINIDUMPWRITEDUMP f_mdwp = NULL; + + + +class LLMemoryReserve { +public: + LLMemoryReserve(); + ~LLMemoryReserve(); + void reserve(); + void release(); +protected: + unsigned char *mReserve; + static const size_t MEMORY_RESERVATION_SIZE; +}; + +LLMemoryReserve::LLMemoryReserve() : + mReserve(NULL) +{ +}; + +LLMemoryReserve::~LLMemoryReserve() +{ + release(); +} + +// I dunno - this just seemed like a pretty good value. +const size_t LLMemoryReserve::MEMORY_RESERVATION_SIZE = 5 * 1024 * 1024; + +void LLMemoryReserve::reserve() +{ + if(NULL == mReserve) + mReserve = new unsigned char[MEMORY_RESERVATION_SIZE]; +}; + +void LLMemoryReserve::release() +{ + delete [] mReserve; + mReserve = NULL; +}; + +static LLMemoryReserve gEmergencyMemoryReserve; + +// static +BOOL LLWinDebug::setupExceptionHandler() +{ +#ifdef LL_RELEASE_FOR_DOWNLOAD + + static BOOL s_first_run = TRUE; + // Load the dbghelp dll now, instead of waiting for the crash. + // Less potential for stack mangling + + BOOL ok = TRUE; + if (s_first_run) + { + // First, try loading from the directory that the app resides in. + std::string local_dll_name = gDirUtilp->findFile("dbghelp.dll", gDirUtilp->getWorkingDir(), gDirUtilp->getExecutableDir()); + + HMODULE hDll = NULL; + hDll = LoadLibraryA(local_dll_name.c_str()); + if (!hDll) + { + hDll = LoadLibrary(L"dbghelp.dll"); + } + + if (!hDll) + { + llwarns << "Couldn't find dbghelp.dll!" << llendl; + + std::string msg = "Couldn't find dbghelp.dll at "; + msg += local_dll_name; + msg += "!\n"; + + write_debug(msg.c_str()); + + ok = FALSE; + } + else + { + f_mdwp = (MINIDUMPWRITEDUMP) GetProcAddress(hDll, "MiniDumpWriteDump"); + + if (!f_mdwp) + { + write_debug("No MiniDumpWriteDump!\n"); + ok = FALSE; + } + } + + gEmergencyMemoryReserve.reserve(); + } + + LPTOP_LEVEL_EXCEPTION_FILTER prev_filter; + prev_filter = SetUnhandledExceptionFilter(LLWinDebug::handleException); + + if (s_first_run) + { + // We're fine, this is the first run. + s_first_run = FALSE; + return ok; + } + if (!prev_filter) + { + llwarns << "Our exception handler (" << (void *)LLWinDebug::handleException << ") replaced with NULL!" << llendl; + ok = FALSE; + } + if (prev_filter != LLWinDebug::handleException) + { + llwarns << "Our exception handler (" << (void *)LLWinDebug::handleException << ") replaced with " << prev_filter << "!" << llendl; + ok = FALSE; + } + return ok; +#else + // Internal builds don't mess with exception handling. + return TRUE; +#endif +} + +void LLWinDebug::writeDumpToFile(MINIDUMP_TYPE type, MINIDUMP_EXCEPTION_INFORMATION *ExInfop, const char *filename) +{ + if(f_mdwp == NULL) + { + write_debug("No way to generate a minidump, no MiniDumpWriteDump function!\n"); + } + else if(gDirUtilp == NULL) + { + write_debug("No way to generate a minidump, no gDirUtilp!\n"); + } + else + { + std::string dump_path = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, + filename); + + HANDLE hFile = CreateFileA(dump_path.c_str(), + GENERIC_WRITE, + FILE_SHARE_WRITE, + NULL, + CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, + NULL); + + if (hFile != INVALID_HANDLE_VALUE) + { + // Write the dump, ignoring the return value + f_mdwp(GetCurrentProcess(), + GetCurrentProcessId(), + hFile, + type, + ExInfop, + NULL, + NULL); + + CloseHandle(hFile); + } + + } +} + +// static +LONG LLWinDebug::handleException(struct _EXCEPTION_POINTERS *exception_infop) +{ + + // + // Let go of a bunch of reserved memory to give library calls etc + // a chance to execute normally in the case that we ran out of + // memory. + // + gEmergencyMemoryReserve.release(); + + BOOL userWantsMaxiDump = + (stricmp(gSavedSettings.getString("LastName").c_str(), "linden") == 0) + || (stricmp(gSavedSettings.getString("LastName").c_str(), "tester") == 0); + + BOOL alsoSaveMaxiDump = userWantsMaxiDump && !gInProductionGrid; + + /* Calculate alsoSaveMaxiDump here */ + + if (exception_infop) + { + _MINIDUMP_EXCEPTION_INFORMATION ExInfo; + + ExInfo.ThreadId = ::GetCurrentThreadId(); + ExInfo.ExceptionPointers = exception_infop; + ExInfo.ClientPointers = NULL; + + writeDumpToFile(MiniDumpNormal, &ExInfo, "SecondLife.dmp"); + + if(alsoSaveMaxiDump) + writeDumpToFile((MINIDUMP_TYPE)(MiniDumpWithDataSegs | MiniDumpWithIndirectlyReferencedMemory), &ExInfo, "SecondLifePlus.dmp"); + } + else + { + writeDumpToFile(MiniDumpNormal, NULL, "SecondLife.dmp"); + + if(alsoSaveMaxiDump) + writeDumpToFile((MINIDUMP_TYPE)(MiniDumpWithDataSegs | MiniDumpWithIndirectlyReferencedMemory), NULL, "SecondLifePlus.dmp"); + } + + if (!exception_infop) + { + // We're calling this due to a network error, not due to an actual exception. + // It doesn't realy matter what we return. + return EXCEPTION_CONTINUE_SEARCH; + } + + // + // Call the newview crash callback, which will spawn the crash + // reporter. It may or may not spawn a dialog. + // + if (gCrashCallback) + { + gCrashCallback(); + } + + // + // At this point, we always want to exit the app. There's no graceful + // recovery for an unhandled exception. + // + // Just kill the process. + LONG retval = EXCEPTION_EXECUTE_HANDLER; + + return retval; +} + +#endif + -- cgit v1.1