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
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
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
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
00097 BOOL LLWinDebug::setupExceptionHandler()
00098 {
00099 #ifdef LL_RELEASE_FOR_DOWNLOAD
00100
00101 static BOOL s_first_run = TRUE;
00102
00103
00104
00105 BOOL ok = TRUE;
00106 if (s_first_run)
00107 {
00108
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
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
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
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
00213 LONG LLWinDebug::handleException(struct _EXCEPTION_POINTERS *exception_infop)
00214 {
00215
00216
00217
00218
00219
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
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
00255
00256 return EXCEPTION_CONTINUE_SEARCH;
00257 }
00258
00259
00260
00261
00262
00263 if (gCrashCallback)
00264 {
00265 gCrashCallback();
00266 }
00267
00268
00269
00270
00271
00272
00273 LONG retval = EXCEPTION_EXECUTE_HANDLER;
00274
00275 return retval;
00276 }
00277
00278 #endif
00279