llwindebug.cpp

Go to the documentation of this file.
00001 
00032 #include "llviewerprecompiledheaders.h"
00033 
00034 #ifdef LL_WINDOWS
00035 
00036 #include "llwindebug.h"
00037 #include "llviewercontrol.h"
00038 #include "lldir.h"
00039 
00040 // From viewer.h
00041 extern BOOL gInProductionGrid;
00042 
00043 extern void (*gCrashCallback)(void);
00044 extern void write_debug(const char *str);
00045 extern void write_debug(const std::string &str);
00046 
00047 // based on dbghelp.h
00048 typedef BOOL (WINAPI *MINIDUMPWRITEDUMP)(HANDLE hProcess, DWORD dwPid, HANDLE hFile, MINIDUMP_TYPE DumpType,
00049                                                                         CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
00050                                                                         CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
00051                                                                         CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam
00052                                                                         );
00053 
00054 MINIDUMPWRITEDUMP f_mdwp = NULL;
00055 
00056 
00057 
00058 class LLMemoryReserve {
00059 public:
00060         LLMemoryReserve();
00061         ~LLMemoryReserve();
00062         void reserve();
00063         void release();
00064 protected:
00065         unsigned char *mReserve;
00066         static const size_t MEMORY_RESERVATION_SIZE;
00067 };
00068 
00069 LLMemoryReserve::LLMemoryReserve() :
00070         mReserve(NULL)
00071 {
00072 };
00073 
00074 LLMemoryReserve::~LLMemoryReserve()
00075 {
00076         release();
00077 }
00078 
00079 // I dunno - this just seemed like a pretty good value.
00080 const size_t LLMemoryReserve::MEMORY_RESERVATION_SIZE = 5 * 1024 * 1024;
00081 
00082 void LLMemoryReserve::reserve()
00083 {
00084         if(NULL == mReserve)
00085                 mReserve = new unsigned char[MEMORY_RESERVATION_SIZE];
00086 };
00087 
00088 void LLMemoryReserve::release()
00089 {
00090         delete [] mReserve;
00091         mReserve = NULL;
00092 };
00093 
00094 static LLMemoryReserve gEmergencyMemoryReserve;
00095 
00096 // static
00097 BOOL LLWinDebug::setupExceptionHandler()
00098 {
00099 #ifdef LL_RELEASE_FOR_DOWNLOAD
00100 
00101         static BOOL s_first_run = TRUE;
00102         // Load the dbghelp dll now, instead of waiting for the crash.
00103         // Less potential for stack mangling
00104 
00105         BOOL ok = TRUE;
00106         if (s_first_run)
00107         {
00108                 // First, try loading from the directory that the app resides in.
00109                 std::string local_dll_name = gDirUtilp->findFile("dbghelp.dll", gDirUtilp->getWorkingDir(), gDirUtilp->getExecutableDir());
00110 
00111                 HMODULE hDll = NULL;
00112                 hDll = LoadLibraryA(local_dll_name.c_str());
00113                 if (!hDll)
00114                 {
00115                         hDll = LoadLibrary(L"dbghelp.dll");
00116                 }
00117 
00118                 if (!hDll)
00119                 {
00120                         llwarns << "Couldn't find dbghelp.dll!" << llendl;
00121 
00122                         std::string msg = "Couldn't find dbghelp.dll at ";
00123                         msg += local_dll_name;
00124                         msg += "!\n";
00125 
00126                         write_debug(msg.c_str());
00127 
00128                         ok = FALSE;
00129                 }
00130                 else
00131                 {
00132                         f_mdwp = (MINIDUMPWRITEDUMP) GetProcAddress(hDll, "MiniDumpWriteDump");
00133 
00134                         if (!f_mdwp)
00135                         {
00136                                 write_debug("No MiniDumpWriteDump!\n");
00137                                 FreeLibrary(hDll);
00138                                 hDll = NULL;
00139                                 ok = FALSE;
00140                         }
00141                 }
00142 
00143                 gEmergencyMemoryReserve.reserve();
00144         }
00145 
00146         LPTOP_LEVEL_EXCEPTION_FILTER prev_filter;
00147         prev_filter = SetUnhandledExceptionFilter(LLWinDebug::handleException);
00148 
00149         if (s_first_run)
00150         {
00151                 // We're fine, this is the first run.
00152                 s_first_run = FALSE;
00153                 return ok;
00154         }
00155         if (!prev_filter)
00156         {
00157                 llwarns << "Our exception handler (" << (void *)LLWinDebug::handleException << ") replaced with NULL!" << llendl;
00158                 ok = FALSE;
00159         }
00160         if (prev_filter != LLWinDebug::handleException)
00161         {
00162                 llwarns << "Our exception handler (" << (void *)LLWinDebug::handleException << ") replaced with " << prev_filter << "!" << llendl;
00163                 ok = FALSE;
00164         }
00165         return ok;
00166 #else
00167         // Internal builds don't mess with exception handling.
00168         return TRUE;
00169 #endif
00170 }
00171 
00172 void LLWinDebug::writeDumpToFile(MINIDUMP_TYPE type, MINIDUMP_EXCEPTION_INFORMATION *ExInfop, const char *filename)
00173 {
00174         if(f_mdwp == NULL) 
00175         {
00176                 write_debug("No way to generate a minidump, no MiniDumpWriteDump function!\n");
00177         }
00178         else if(gDirUtilp == NULL)
00179         {
00180                 write_debug("No way to generate a minidump, no gDirUtilp!\n");
00181         }
00182         else
00183         {
00184                 std::string dump_path = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,
00185                                                                                                                            filename);
00186 
00187                 HANDLE hFile = CreateFileA(dump_path.c_str(),
00188                                                                         GENERIC_WRITE,
00189                                                                         FILE_SHARE_WRITE,
00190                                                                         NULL,
00191                                                                         CREATE_ALWAYS,
00192                                                                         FILE_ATTRIBUTE_NORMAL,
00193                                                                         NULL);
00194 
00195                 if (hFile != INVALID_HANDLE_VALUE)
00196                 {
00197                         // Write the dump, ignoring the return value
00198                         f_mdwp(GetCurrentProcess(),
00199                                         GetCurrentProcessId(),
00200                                         hFile,
00201                                         type,
00202                                         ExInfop,
00203                                         NULL,
00204                                         NULL);
00205 
00206                         CloseHandle(hFile);
00207                 }
00208 
00209         }
00210 }
00211 
00212 // static
00213 LONG LLWinDebug::handleException(struct _EXCEPTION_POINTERS *exception_infop)
00214 {
00215 
00216         // 
00217         // Let go of a bunch of reserved memory to give library calls etc
00218         // a chance to execute normally in the case that we ran out of
00219         // memory.
00220         //
00221         gEmergencyMemoryReserve.release();
00222 
00223         BOOL userWantsMaxiDump =
00224                 (stricmp(gSavedSettings.getString("LastName").c_str(), "linden") == 0)
00225                 || (stricmp(gSavedSettings.getString("LastName").c_str(), "tester") == 0);
00226 
00227         BOOL alsoSaveMaxiDump = userWantsMaxiDump && !gInProductionGrid;
00228 
00229         /* Calculate alsoSaveMaxiDump here */
00230 
00231         if (exception_infop)
00232         {
00233                 _MINIDUMP_EXCEPTION_INFORMATION ExInfo;
00234 
00235                 ExInfo.ThreadId = ::GetCurrentThreadId();
00236                 ExInfo.ExceptionPointers = exception_infop;
00237                 ExInfo.ClientPointers = NULL;
00238 
00239                 writeDumpToFile(MiniDumpNormal, &ExInfo, "SecondLifeDale.dmp");
00240 
00241                 if(alsoSaveMaxiDump)
00242                         writeDumpToFile((MINIDUMP_TYPE)(MiniDumpWithDataSegs | MiniDumpWithIndirectlyReferencedMemory), &ExInfo, "SecondLifePlusDale.dmp");
00243         }
00244         else
00245         {
00246                 writeDumpToFile(MiniDumpNormal, NULL, "SecondLifeDale.dmp");
00247 
00248                 if(alsoSaveMaxiDump)
00249                         writeDumpToFile((MINIDUMP_TYPE)(MiniDumpWithDataSegs | MiniDumpWithIndirectlyReferencedMemory), NULL, "SecondLifePlusDale.dmp");
00250         }
00251 
00252         if (!exception_infop)
00253         {
00254                 // We're calling this due to a network error, not due to an actual exception.
00255                 // It doesn't realy matter what we return.
00256                 return EXCEPTION_CONTINUE_SEARCH;
00257         }
00258 
00259         //
00260         // Call the newview crash callback, which will spawn the crash
00261         // reporter.  It may or may not spawn a dialog.
00262         //
00263         if (gCrashCallback)
00264         {
00265                 gCrashCallback();
00266         }
00267 
00268         //
00269         // At this point, we always want to exit the app.  There's no graceful
00270         // recovery for an unhandled exception.
00271         // 
00272         // Just kill the process.
00273         LONG retval = EXCEPTION_EXECUTE_HANDLER;
00274         
00275         return retval;
00276 }
00277 
00278 #endif
00279 

Generated on Thu Jul 1 06:09:45 2010 for Second Life Viewer by  doxygen 1.4.7