diff options
Diffstat (limited to 'linden/indra/newview/llwindebug.cpp')
-rw-r--r-- | linden/indra/newview/llwindebug.cpp | 406 |
1 files changed, 325 insertions, 81 deletions
diff --git a/linden/indra/newview/llwindebug.cpp b/linden/indra/newview/llwindebug.cpp index b65262c..d0129c8 100644 --- a/linden/indra/newview/llwindebug.cpp +++ b/linden/indra/newview/llwindebug.cpp | |||
@@ -33,16 +33,69 @@ | |||
33 | 33 | ||
34 | #ifdef LL_WINDOWS | 34 | #ifdef LL_WINDOWS |
35 | 35 | ||
36 | #include <tchar.h> | ||
37 | #include <tlhelp32.h> | ||
38 | #include "llappviewer.h" | ||
36 | #include "llwindebug.h" | 39 | #include "llwindebug.h" |
37 | #include "llviewercontrol.h" | 40 | #include "llviewercontrol.h" |
38 | #include "lldir.h" | 41 | #include "lldir.h" |
42 | #include "llsd.h" | ||
43 | #include "llsdserialize.h" | ||
44 | |||
45 | #pragma warning(disable: 4200) //nonstandard extension used : zero-sized array in struct/union | ||
46 | #pragma warning(disable: 4100) //unreferenced formal parameter | ||
47 | |||
48 | /* | ||
49 | LLSD Block for Windows Dump Information | ||
50 | <llsd> | ||
51 | <map> | ||
52 | <key>Platform</key> | ||
53 | <string></string> | ||
54 | <key>Process</key> | ||
55 | <string></string> | ||
56 | <key>Module</key> | ||
57 | <string></string> | ||
58 | <key>DateModified</key> | ||
59 | <string></string> | ||
60 | <key>ExceptionCode</key> | ||
61 | <string></string> | ||
62 | <key>ExceptionRead/WriteAddress</key> | ||
63 | <string></string> | ||
64 | <key>Instruction</key> | ||
65 | <string></string> | ||
66 | <key>Registers</key> | ||
67 | <map> | ||
68 | <!-- Continued for all registers --> | ||
69 | <key>EIP</key> | ||
70 | <string>...</string> | ||
71 | <!-- ... --> | ||
72 | </map> | ||
73 | <key>Call Stack</key> | ||
74 | <array> | ||
75 | <!-- One map per stack frame --> | ||
76 | <map> | ||
77 | <key>ModuleName</key> | ||
78 | <string></string> | ||
79 | <key>ModuleBaseAddress</key> | ||
80 | <string></string> | ||
81 | <key>ModuleOffsetAddress</key> | ||
82 | <string></string> | ||
83 | <key>Parameters</key> | ||
84 | <array> | ||
85 | <string></string> | ||
86 | </array> | ||
87 | </map> | ||
88 | <!-- ... --> | ||
89 | </array> | ||
90 | </map> | ||
91 | </llsd> | ||
92 | |||
93 | */ | ||
39 | 94 | ||
40 | // From viewer.h | 95 | // From viewer.h |
41 | extern BOOL gInProductionGrid; | 96 | extern BOOL gInProductionGrid; |
42 | 97 | ||
43 | extern void (*gCrashCallback)(void); | 98 | extern void (*gCrashCallback)(void); |
44 | extern void write_debug(const char *str); | ||
45 | extern void write_debug(const std::string &str); | ||
46 | 99 | ||
47 | // based on dbghelp.h | 100 | // based on dbghelp.h |
48 | typedef BOOL (WINAPI *MINIDUMPWRITEDUMP)(HANDLE hProcess, DWORD dwPid, HANDLE hFile, MINIDUMP_TYPE DumpType, | 101 | typedef BOOL (WINAPI *MINIDUMPWRITEDUMP)(HANDLE hProcess, DWORD dwPid, HANDLE hFile, MINIDUMP_TYPE DumpType, |
@@ -53,6 +106,248 @@ typedef BOOL (WINAPI *MINIDUMPWRITEDUMP)(HANDLE hProcess, DWORD dwPid, HANDLE hF | |||
53 | 106 | ||
54 | MINIDUMPWRITEDUMP f_mdwp = NULL; | 107 | MINIDUMPWRITEDUMP f_mdwp = NULL; |
55 | 108 | ||
109 | #undef UNICODE | ||
110 | |||
111 | HMODULE hDbgHelp; | ||
112 | |||
113 | // Tool Help functions. | ||
114 | typedef HANDLE (WINAPI * CREATE_TOOL_HELP32_SNAPSHOT)(DWORD dwFlags, DWORD th32ProcessID); | ||
115 | typedef BOOL (WINAPI * MODULE32_FIRST)(HANDLE hSnapshot, LPMODULEENTRY32 lpme); | ||
116 | typedef BOOL (WINAPI * MODULE32_NEST)(HANDLE hSnapshot, LPMODULEENTRY32 lpme); | ||
117 | |||
118 | CREATE_TOOL_HELP32_SNAPSHOT CreateToolhelp32Snapshot_; | ||
119 | MODULE32_FIRST Module32First_; | ||
120 | MODULE32_NEST Module32Next_; | ||
121 | |||
122 | #define DUMP_SIZE_MAX 8000 //max size of our dump | ||
123 | #define CALL_TRACE_MAX ((DUMP_SIZE_MAX - 2000) / (MAX_PATH + 40)) //max number of traced calls | ||
124 | #define NL L"\r\n" //new line | ||
125 | |||
126 | //Windows Call Stack Construction idea from | ||
127 | //http://www.codeproject.com/tools/minidump.asp | ||
128 | |||
129 | //**************************************************************************************** | ||
130 | BOOL WINAPI Get_Module_By_Ret_Addr(PBYTE Ret_Addr, LPWSTR Module_Name, PBYTE & Module_Addr) | ||
131 | //**************************************************************************************** | ||
132 | // Find module by Ret_Addr (address in the module). | ||
133 | // Return Module_Name (full path) and Module_Addr (start address). | ||
134 | // Return TRUE if found. | ||
135 | { | ||
136 | MODULEENTRY32 M = {sizeof(M)}; | ||
137 | HANDLE hSnapshot; | ||
138 | |||
139 | bool found = false; | ||
140 | |||
141 | if (CreateToolhelp32Snapshot_) | ||
142 | { | ||
143 | hSnapshot = CreateToolhelp32Snapshot_(TH32CS_SNAPMODULE, 0); | ||
144 | |||
145 | if ((hSnapshot != INVALID_HANDLE_VALUE) && | ||
146 | Module32First_(hSnapshot, &M)) | ||
147 | { | ||
148 | do | ||
149 | { | ||
150 | if (DWORD(Ret_Addr - M.modBaseAddr) < M.modBaseSize) | ||
151 | { | ||
152 | lstrcpyn(Module_Name, M.szExePath, MAX_PATH); | ||
153 | Module_Addr = M.modBaseAddr; | ||
154 | found = true; | ||
155 | break; | ||
156 | } | ||
157 | } while (Module32Next_(hSnapshot, &M)); | ||
158 | } | ||
159 | |||
160 | CloseHandle(hSnapshot); | ||
161 | } | ||
162 | |||
163 | return found; | ||
164 | } //Get_Module_By_Ret_Addr | ||
165 | |||
166 | //****************************************************************** | ||
167 | void WINAPI Get_Call_Stack(PEXCEPTION_POINTERS pException, LLSD& info) | ||
168 | //****************************************************************** | ||
169 | // Fill Str with call stack info. | ||
170 | // pException can be either GetExceptionInformation() or NULL. | ||
171 | // If pException = NULL - get current call stack. | ||
172 | { | ||
173 | LPWSTR Module_Name = new WCHAR[MAX_PATH]; | ||
174 | PBYTE Module_Addr = 0; | ||
175 | |||
176 | typedef struct STACK | ||
177 | { | ||
178 | STACK * Ebp; | ||
179 | PBYTE Ret_Addr; | ||
180 | DWORD Param[0]; | ||
181 | } STACK, * PSTACK; | ||
182 | |||
183 | STACK Stack = {0, 0}; | ||
184 | PSTACK Ebp; | ||
185 | |||
186 | if (pException) //fake frame for exception address | ||
187 | { | ||
188 | Stack.Ebp = (PSTACK)pException->ContextRecord->Ebp; | ||
189 | Stack.Ret_Addr = (PBYTE)pException->ExceptionRecord->ExceptionAddress; | ||
190 | Ebp = &Stack; | ||
191 | } | ||
192 | else | ||
193 | { | ||
194 | Ebp = (PSTACK)&pException - 1; //frame addr of Get_Call_Stack() | ||
195 | |||
196 | // Skip frame of Get_Call_Stack(). | ||
197 | if (!IsBadReadPtr(Ebp, sizeof(PSTACK))) | ||
198 | Ebp = Ebp->Ebp; //caller ebp | ||
199 | } | ||
200 | |||
201 | // Trace CALL_TRACE_MAX calls maximum - not to exceed DUMP_SIZE_MAX. | ||
202 | // Break trace on wrong stack frame. | ||
203 | for (int Ret_Addr_I = 0, i = 0; | ||
204 | (Ret_Addr_I < CALL_TRACE_MAX) && !IsBadReadPtr(Ebp, sizeof(PSTACK)) && !IsBadCodePtr(FARPROC(Ebp->Ret_Addr)); | ||
205 | Ret_Addr_I++, Ebp = Ebp->Ebp, ++i) | ||
206 | { | ||
207 | // If module with Ebp->Ret_Addr found. | ||
208 | |||
209 | if (Get_Module_By_Ret_Addr(Ebp->Ret_Addr, Module_Name, Module_Addr)) | ||
210 | { | ||
211 | // Save module's address and full path. | ||
212 | info["CallStack"][i]["ModuleName"] = ll_convert_wide_to_string(Module_Name); | ||
213 | info["CallStack"][i]["ModuleAddress"] = (int)Module_Addr; | ||
214 | info["CallStack"][i]["CallOffset"] = (int)(Ebp->Ret_Addr - Module_Addr); | ||
215 | |||
216 | LLSD params; | ||
217 | // Save 5 params of the call. We don't know the real number of params. | ||
218 | if (pException && !Ret_Addr_I) //fake frame for exception address | ||
219 | params[0] = "Exception Offset"; | ||
220 | else if (!IsBadReadPtr(Ebp, sizeof(PSTACK) + 5 * sizeof(DWORD))) | ||
221 | { | ||
222 | for(int j = 0; j < 5; ++j) | ||
223 | { | ||
224 | params[j] = (int)Ebp->Param[j]; | ||
225 | } | ||
226 | } | ||
227 | info["CallStack"][i]["Parameters"] = params; | ||
228 | } | ||
229 | info["CallStack"][i]["ReturnAddress"] = (int)Ebp->Ret_Addr; | ||
230 | } | ||
231 | } //Get_Call_Stack | ||
232 | |||
233 | //*********************************** | ||
234 | void WINAPI Get_Version_Str(LLSD& info) | ||
235 | //*********************************** | ||
236 | // Fill Str with Windows version. | ||
237 | { | ||
238 | OSVERSIONINFOEX V = {sizeof(OSVERSIONINFOEX)}; //EX for NT 5.0 and later | ||
239 | |||
240 | if (!GetVersionEx((POSVERSIONINFO)&V)) | ||
241 | { | ||
242 | ZeroMemory(&V, sizeof(V)); | ||
243 | V.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); | ||
244 | GetVersionEx((POSVERSIONINFO)&V); | ||
245 | } | ||
246 | |||
247 | if (V.dwPlatformId != VER_PLATFORM_WIN32_NT) | ||
248 | V.dwBuildNumber = LOWORD(V.dwBuildNumber); //for 9x HIWORD(dwBuildNumber) = 0x04xx | ||
249 | |||
250 | info["Platform"] = llformat("Windows: %d.%d.%d, SP %d.%d, Product Type %d", //SP - service pack, Product Type - VER_NT_WORKSTATION,... | ||
251 | V.dwMajorVersion, V.dwMinorVersion, V.dwBuildNumber, V.wServicePackMajor, V.wServicePackMinor, V.wProductType); | ||
252 | } //Get_Version_Str | ||
253 | |||
254 | //************************************************************* | ||
255 | LLSD WINAPI Get_Exception_Info(PEXCEPTION_POINTERS pException) | ||
256 | //************************************************************* | ||
257 | // Allocate Str[DUMP_SIZE_MAX] and return Str with dump, if !pException - just return call stack in Str. | ||
258 | { | ||
259 | LLSD info; | ||
260 | LPWSTR Str; | ||
261 | int Str_Len; | ||
262 | int i; | ||
263 | LPWSTR Module_Name = new WCHAR[MAX_PATH]; | ||
264 | PBYTE Module_Addr; | ||
265 | HANDLE hFile; | ||
266 | FILETIME Last_Write_Time; | ||
267 | FILETIME Local_File_Time; | ||
268 | SYSTEMTIME T; | ||
269 | |||
270 | Str = new WCHAR[DUMP_SIZE_MAX]; | ||
271 | Str_Len = 0; | ||
272 | if (!Str) | ||
273 | return NULL; | ||
274 | |||
275 | Get_Version_Str(info); | ||
276 | |||
277 | GetModuleFileName(NULL, Str, MAX_PATH); | ||
278 | info["Process"] = ll_convert_wide_to_string(Str); | ||
279 | |||
280 | // If exception occurred. | ||
281 | if (pException) | ||
282 | { | ||
283 | EXCEPTION_RECORD & E = *pException->ExceptionRecord; | ||
284 | CONTEXT & C = *pException->ContextRecord; | ||
285 | |||
286 | // If module with E.ExceptionAddress found - save its path and date. | ||
287 | if (Get_Module_By_Ret_Addr((PBYTE)E.ExceptionAddress, Module_Name, Module_Addr)) | ||
288 | { | ||
289 | info["Module"] = ll_convert_wide_to_string(Module_Name); | ||
290 | |||
291 | if ((hFile = CreateFile(Module_Name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, | ||
292 | FILE_ATTRIBUTE_NORMAL, NULL)) != INVALID_HANDLE_VALUE) | ||
293 | { | ||
294 | if (GetFileTime(hFile, NULL, NULL, &Last_Write_Time)) | ||
295 | { | ||
296 | FileTimeToLocalFileTime(&Last_Write_Time, &Local_File_Time); | ||
297 | FileTimeToSystemTime(&Local_File_Time, &T); | ||
298 | |||
299 | info["DateModified"] = llformat("%02d/%02d/%d", T.wMonth, T.wDay, T.wYear); | ||
300 | } | ||
301 | CloseHandle(hFile); | ||
302 | } | ||
303 | } | ||
304 | else | ||
305 | { | ||
306 | info["ExceptionAddr"] = (int)E.ExceptionAddress; | ||
307 | } | ||
308 | |||
309 | info["ExceptionCode"] = (int)E.ExceptionCode; | ||
310 | |||
311 | /* | ||
312 | //TODO: Fix this | ||
313 | if (E.ExceptionCode == EXCEPTION_ACCESS_VIOLATION) | ||
314 | { | ||
315 | // Access violation type - Write/Read. | ||
316 | LLSD exception_info; | ||
317 | exception_info["Type"] = E.ExceptionInformation[0] ? "Write" : "Read"; | ||
318 | exception_info["Address"] = llformat("%08x", E.ExceptionInformation[1]); | ||
319 | info["Exception Information"] = exception_info; | ||
320 | } | ||
321 | */ | ||
322 | |||
323 | |||
324 | // Save instruction that caused exception. | ||
325 | LLString str; | ||
326 | for (i = 0; i < 16; i++) | ||
327 | str += llformat(" %02X", PBYTE(E.ExceptionAddress)[i]); | ||
328 | info["Instruction"] = str; | ||
329 | |||
330 | LLSD registers; | ||
331 | registers["EAX"] = (int)C.Eax; | ||
332 | registers["EBX"] = (int)C.Ebx; | ||
333 | registers["ECX"] = (int)C.Ecx; | ||
334 | registers["EDX"] = (int)C.Edx; | ||
335 | registers["ESI"] = (int)C.Esi; | ||
336 | registers["EDI"] = (int)C.Edi; | ||
337 | registers["ESP"] = (int)C.Esp; | ||
338 | registers["EBP"] = (int)C.Ebp; | ||
339 | registers["EIP"] = (int)C.Eip; | ||
340 | registers["EFlags"] = (int)C.EFlags; | ||
341 | info["Registers"] = registers; | ||
342 | } //if (pException) | ||
343 | |||
344 | // Save call stack info. | ||
345 | Get_Call_Stack(pException, info); | ||
346 | |||
347 | return info; | ||
348 | } //Get_Exception_Info | ||
349 | |||
350 | #define UNICODE | ||
56 | 351 | ||
57 | 352 | ||
58 | class LLMemoryReserve { | 353 | class LLMemoryReserve { |
@@ -96,7 +391,6 @@ static LLMemoryReserve gEmergencyMemoryReserve; | |||
96 | // static | 391 | // static |
97 | BOOL LLWinDebug::setupExceptionHandler() | 392 | BOOL LLWinDebug::setupExceptionHandler() |
98 | { | 393 | { |
99 | #ifdef LL_RELEASE_FOR_DOWNLOAD | ||
100 | 394 | ||
101 | static BOOL s_first_run = TRUE; | 395 | static BOOL s_first_run = TRUE; |
102 | // Load the dbghelp dll now, instead of waiting for the crash. | 396 | // Load the dbghelp dll now, instead of waiting for the crash. |
@@ -123,7 +417,7 @@ BOOL LLWinDebug::setupExceptionHandler() | |||
123 | msg += local_dll_name; | 417 | msg += local_dll_name; |
124 | msg += "!\n"; | 418 | msg += "!\n"; |
125 | 419 | ||
126 | write_debug(msg.c_str()); | 420 | //write_debug(msg.c_str()); |
127 | 421 | ||
128 | ok = FALSE; | 422 | ok = FALSE; |
129 | } | 423 | } |
@@ -133,7 +427,7 @@ BOOL LLWinDebug::setupExceptionHandler() | |||
133 | 427 | ||
134 | if (!f_mdwp) | 428 | if (!f_mdwp) |
135 | { | 429 | { |
136 | write_debug("No MiniDumpWriteDump!\n"); | 430 | //write_debug("No MiniDumpWriteDump!\n"); |
137 | FreeLibrary(hDll); | 431 | FreeLibrary(hDll); |
138 | hDll = NULL; | 432 | hDll = NULL; |
139 | ok = FALSE; | 433 | ok = FALSE; |
@@ -146,6 +440,13 @@ BOOL LLWinDebug::setupExceptionHandler() | |||
146 | LPTOP_LEVEL_EXCEPTION_FILTER prev_filter; | 440 | LPTOP_LEVEL_EXCEPTION_FILTER prev_filter; |
147 | prev_filter = SetUnhandledExceptionFilter(LLWinDebug::handleException); | 441 | prev_filter = SetUnhandledExceptionFilter(LLWinDebug::handleException); |
148 | 442 | ||
443 | // Try to get Tool Help library functions. | ||
444 | HMODULE hKernel32; | ||
445 | hKernel32 = GetModuleHandle(_T("KERNEL32")); | ||
446 | CreateToolhelp32Snapshot_ = (CREATE_TOOL_HELP32_SNAPSHOT)GetProcAddress(hKernel32, "CreateToolhelp32Snapshot"); | ||
447 | Module32First_ = (MODULE32_FIRST)GetProcAddress(hKernel32, "Module32FirstW"); | ||
448 | Module32Next_ = (MODULE32_NEST)GetProcAddress(hKernel32, "Module32NextW"); | ||
449 | |||
149 | if (s_first_run) | 450 | if (s_first_run) |
150 | { | 451 | { |
151 | // We're fine, this is the first run. | 452 | // We're fine, this is the first run. |
@@ -162,56 +463,16 @@ BOOL LLWinDebug::setupExceptionHandler() | |||
162 | llwarns << "Our exception handler (" << (void *)LLWinDebug::handleException << ") replaced with " << prev_filter << "!" << llendl; | 463 | llwarns << "Our exception handler (" << (void *)LLWinDebug::handleException << ") replaced with " << prev_filter << "!" << llendl; |
163 | ok = FALSE; | 464 | ok = FALSE; |
164 | } | 465 | } |
466 | |||
165 | return ok; | 467 | return ok; |
166 | #else | ||
167 | // Internal builds don't mess with exception handling. | 468 | // Internal builds don't mess with exception handling. |
168 | return TRUE; | 469 | //return TRUE; |
169 | #endif | ||
170 | } | ||
171 | |||
172 | void LLWinDebug::writeDumpToFile(MINIDUMP_TYPE type, MINIDUMP_EXCEPTION_INFORMATION *ExInfop, const char *filename) | ||
173 | { | ||
174 | if(f_mdwp == NULL) | ||
175 | { | ||
176 | write_debug("No way to generate a minidump, no MiniDumpWriteDump function!\n"); | ||
177 | } | ||
178 | else if(gDirUtilp == NULL) | ||
179 | { | ||
180 | write_debug("No way to generate a minidump, no gDirUtilp!\n"); | ||
181 | } | ||
182 | else | ||
183 | { | ||
184 | std::string dump_path = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, | ||
185 | filename); | ||
186 | |||
187 | HANDLE hFile = CreateFileA(dump_path.c_str(), | ||
188 | GENERIC_WRITE, | ||
189 | FILE_SHARE_WRITE, | ||
190 | NULL, | ||
191 | CREATE_ALWAYS, | ||
192 | FILE_ATTRIBUTE_NORMAL, | ||
193 | NULL); | ||
194 | |||
195 | if (hFile != INVALID_HANDLE_VALUE) | ||
196 | { | ||
197 | // Write the dump, ignoring the return value | ||
198 | f_mdwp(GetCurrentProcess(), | ||
199 | GetCurrentProcessId(), | ||
200 | hFile, | ||
201 | type, | ||
202 | ExInfop, | ||
203 | NULL, | ||
204 | NULL); | ||
205 | |||
206 | CloseHandle(hFile); | ||
207 | } | ||
208 | |||
209 | } | ||
210 | } | 470 | } |
211 | |||
212 | // static | 471 | // static |
213 | LONG LLWinDebug::handleException(struct _EXCEPTION_POINTERS *exception_infop) | 472 | LONG LLWinDebug::handleException(struct _EXCEPTION_POINTERS *exception_infop) |
214 | { | 473 | { |
474 | // *NOTE:Mani - This method is no longer the initial exception handler. | ||
475 | // It is called from viewer_windows_exception_handler() and other places. | ||
215 | 476 | ||
216 | // | 477 | // |
217 | // Let go of a bunch of reserved memory to give library calls etc | 478 | // Let go of a bunch of reserved memory to give library calls etc |
@@ -220,50 +481,34 @@ LONG LLWinDebug::handleException(struct _EXCEPTION_POINTERS *exception_infop) | |||
220 | // | 481 | // |
221 | gEmergencyMemoryReserve.release(); | 482 | gEmergencyMemoryReserve.release(); |
222 | 483 | ||
223 | BOOL userWantsMaxiDump = | ||
224 | (stricmp(gSavedSettings.getString("LastName").c_str(), "linden") == 0) | ||
225 | || (stricmp(gSavedSettings.getString("LastName").c_str(), "tester") == 0); | ||
226 | |||
227 | BOOL alsoSaveMaxiDump = userWantsMaxiDump && !gInProductionGrid; | ||
228 | |||
229 | /* Calculate alsoSaveMaxiDump here */ | ||
230 | |||
231 | if (exception_infop) | 484 | if (exception_infop) |
232 | { | 485 | { |
233 | _MINIDUMP_EXCEPTION_INFORMATION ExInfo; | ||
234 | 486 | ||
235 | ExInfo.ThreadId = ::GetCurrentThreadId(); | 487 | std::string dump_path = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, |
236 | ExInfo.ExceptionPointers = exception_infop; | 488 | "SecondLifeException"); |
237 | ExInfo.ClientPointers = NULL; | ||
238 | 489 | ||
239 | writeDumpToFile(MiniDumpNormal, &ExInfo, "SecondLife.dmp"); | 490 | std::string log_path = dump_path + ".log"; |
240 | 491 | ||
241 | if(alsoSaveMaxiDump) | 492 | LLSD info; |
242 | writeDumpToFile((MINIDUMP_TYPE)(MiniDumpWithDataSegs | MiniDumpWithIndirectlyReferencedMemory), &ExInfo, "SecondLifePlus.dmp"); | 493 | info = Get_Exception_Info(exception_infop); |
494 | if (info) | ||
495 | { | ||
496 | std::ofstream out_file(log_path.c_str()); | ||
497 | LLSDSerialize::toPrettyXML(info, out_file); | ||
498 | out_file.close(); | ||
499 | } | ||
243 | } | 500 | } |
244 | else | 501 | else |
245 | { | 502 | { |
246 | writeDumpToFile(MiniDumpNormal, NULL, "SecondLife.dmp"); | ||
247 | |||
248 | if(alsoSaveMaxiDump) | ||
249 | writeDumpToFile((MINIDUMP_TYPE)(MiniDumpWithDataSegs | MiniDumpWithIndirectlyReferencedMemory), NULL, "SecondLifePlus.dmp"); | ||
250 | } | ||
251 | |||
252 | if (!exception_infop) | ||
253 | { | ||
254 | // We're calling this due to a network error, not due to an actual exception. | 503 | // We're calling this due to a network error, not due to an actual exception. |
255 | // It doesn't realy matter what we return. | 504 | // It doesn't realy matter what we return. |
256 | return EXCEPTION_CONTINUE_SEARCH; | 505 | return EXCEPTION_CONTINUE_SEARCH; |
257 | } | 506 | } |
258 | 507 | ||
259 | // | 508 | //handle viewer crash must be called here since |
260 | // Call the newview crash callback, which will spawn the crash | 509 | //we don't return handling of the application |
261 | // reporter. It may or may not spawn a dialog. | 510 | //back to the process. |
262 | // | 511 | LLAppViewer::handleViewerCrash(); |
263 | if (gCrashCallback) | ||
264 | { | ||
265 | gCrashCallback(); | ||
266 | } | ||
267 | 512 | ||
268 | // | 513 | // |
269 | // At this point, we always want to exit the app. There's no graceful | 514 | // At this point, we always want to exit the app. There's no graceful |
@@ -276,4 +521,3 @@ LONG LLWinDebug::handleException(struct _EXCEPTION_POINTERS *exception_infop) | |||
276 | } | 521 | } |
277 | 522 | ||
278 | #endif | 523 | #endif |
279 | |||