llwindebug.cpp

Go to the documentation of this file.
00001 
00032 #include "llviewerprecompiledheaders.h"
00033 
00034 #ifdef LL_WINDOWS
00035 
00036 #include <tchar.h>
00037 #include <tlhelp32.h>
00038 #include "llwindebug.h"
00039 #include "llviewercontrol.h"
00040 #include "lldir.h"
00041 #include "llsd.h"
00042 #include "llsdserialize.h"
00043 
00044 #pragma warning(disable: 4200)  //nonstandard extension used : zero-sized array in struct/union
00045 #pragma warning(disable: 4100)  //unreferenced formal parameter
00046 
00047 /*
00048 LLSD Block for Windows Dump Information
00049 <llsd>
00050   <map>
00051     <key>Platform</key>
00052     <string></string>
00053     <key>Process</key>
00054     <string></string>
00055     <key>Module</key>
00056     <string></string>
00057     <key>DateModified</key>
00058     <string></string>
00059     <key>ExceptionCode</key>
00060     <string></string>
00061     <key>ExceptionRead/WriteAddress</key>
00062     <string></string>
00063     <key>Instruction</key>
00064     <string></string>
00065     <key>Registers</key>
00066     <map>
00067       <!-- Continued for all registers -->
00068       <key>EIP</key>
00069       <string>...</string>
00070       <!-- ... -->
00071     </map>
00072     <key>Call Stack</key>
00073     <array>
00074       <!-- One map per stack frame -->
00075       <map>
00076         <key>ModuleName</key>
00077         <string></string>
00078         <key>ModuleBaseAddress</key>
00079         <string></string>
00080         <key>ModuleOffsetAddress</key>
00081         <string></string>
00082         <key>Parameters</key>
00083         <array>
00084           <string></string>
00085         </array>
00086       </map>
00087       <!-- ... -->
00088     </array>
00089   </map>
00090 </llsd>
00091 
00092 */
00093 
00094 
00095 extern void (*gCrashCallback)(void);
00096 
00097 // based on dbghelp.h
00098 typedef BOOL (WINAPI *MINIDUMPWRITEDUMP)(HANDLE hProcess, DWORD dwPid, HANDLE hFile, MINIDUMP_TYPE DumpType,
00099                                                                         CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
00100                                                                         CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
00101                                                                         CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam
00102                                                                         );
00103 
00104 MINIDUMPWRITEDUMP f_mdwp = NULL;
00105 
00106 #undef UNICODE
00107 
00108 static LPTOP_LEVEL_EXCEPTION_FILTER gFilterFunc = NULL;
00109 
00110 HMODULE hDbgHelp;
00111 
00112 // Tool Help functions.
00113 typedef HANDLE (WINAPI * CREATE_TOOL_HELP32_SNAPSHOT)(DWORD dwFlags, DWORD th32ProcessID);
00114 typedef BOOL (WINAPI * MODULE32_FIRST)(HANDLE hSnapshot, LPMODULEENTRY32 lpme);
00115 typedef BOOL (WINAPI * MODULE32_NEST)(HANDLE hSnapshot, LPMODULEENTRY32 lpme);
00116 
00117 CREATE_TOOL_HELP32_SNAPSHOT     CreateToolhelp32Snapshot_;
00118 MODULE32_FIRST  Module32First_;
00119 MODULE32_NEST   Module32Next_;
00120 
00121 #define DUMP_SIZE_MAX   8000    //max size of our dump
00122 #define CALL_TRACE_MAX  ((DUMP_SIZE_MAX - 2000) / (MAX_PATH + 40))      //max number of traced calls
00123 #define NL                              L"\r\n" //new line
00124 
00125 BOOL WINAPI Get_Module_By_Ret_Addr(PBYTE Ret_Addr, LPWSTR Module_Name, PBYTE & Module_Addr);
00126 
00127 
00128 void printError( CHAR* msg )
00129 {
00130   DWORD eNum;
00131   TCHAR sysMsg[256];
00132   TCHAR* p;
00133 
00134   eNum = GetLastError( );
00135   FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
00136          NULL, eNum,
00137          MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
00138          sysMsg, 256, NULL );
00139 
00140   // Trim the end of the line and terminate it with a null
00141   p = sysMsg;
00142   while( ( *p > 31 ) || ( *p == 9 ) )
00143     ++p;
00144   do { *p-- = 0; } while( ( p >= sysMsg ) &&
00145                           ( ( *p == '.' ) || ( *p < 33 ) ) );
00146 
00147   // Display the message
00148   printf( "\n  WARNING: %s failed with error %d (%s)", msg, eNum, sysMsg );
00149 }
00150 
00151 BOOL GetProcessThreadIDs(DWORD process_id, std::vector<DWORD>& thread_ids) 
00152 { 
00153   HANDLE hThreadSnap = INVALID_HANDLE_VALUE; 
00154   THREADENTRY32 te32; 
00155  
00156   // Take a snapshot of all running threads  
00157   hThreadSnap = CreateToolhelp32Snapshot( TH32CS_SNAPTHREAD, 0 ); 
00158   if( hThreadSnap == INVALID_HANDLE_VALUE ) 
00159     return( FALSE ); 
00160  
00161   // Fill in the size of the structure before using it. 
00162   te32.dwSize = sizeof(THREADENTRY32 ); 
00163  
00164   // Retrieve information about the first thread,
00165   // and exit if unsuccessful
00166   if( !Thread32First( hThreadSnap, &te32 ) ) 
00167   {
00168     printError( "Thread32First" );  // Show cause of failure
00169     CloseHandle( hThreadSnap );     // Must clean up the snapshot object!
00170     return( FALSE );
00171   }
00172 
00173   // Now walk the thread list of the system,
00174   // and display information about each thread
00175   // associated with the specified process
00176   do 
00177   { 
00178     if( te32.th32OwnerProcessID == process_id )
00179     {
00180       thread_ids.push_back(te32.th32ThreadID); 
00181     }
00182   } while( Thread32Next(hThreadSnap, &te32 ) ); 
00183 
00184 //  Don't forget to clean up the snapshot object.
00185   CloseHandle( hThreadSnap );
00186   return( TRUE );
00187 }
00188 
00189 void WINAPI GetCallStackData(const CONTEXT* context_struct, LLSD& info)
00190 {       
00191     // Fill Str with call stack info.
00192     // pException can be either GetExceptionInformation() or NULL.
00193     // If pException = NULL - get current call stack.
00194 
00195     LPWSTR      Module_Name = new WCHAR[MAX_PATH];
00196         PBYTE   Module_Addr = 0;
00197         
00198         typedef struct STACK
00199         {
00200                 STACK * Ebp;
00201                 PBYTE   Ret_Addr;
00202                 DWORD   Param[0];
00203         } STACK, * PSTACK;
00204 
00205         PSTACK  Ebp;
00206 
00207     if(context_struct)
00208     {
00209         Ebp = (PSTACK)context_struct->Ebp;
00210     }
00211     else
00212     {
00213         // The context struct is NULL, 
00214         // so we will use the current stack.
00215         Ebp = (PSTACK)&context_struct - 1;
00216 
00217         // Skip frame of GetCallStackData().
00218                 if (!IsBadReadPtr(Ebp, sizeof(PSTACK)))
00219                         Ebp = Ebp->Ebp;         //caller ebp
00220     }
00221 
00222         // Trace CALL_TRACE_MAX calls maximum - not to exceed DUMP_SIZE_MAX.
00223         // Break trace on wrong stack frame.
00224         for (int Ret_Addr_I = 0, i = 0;
00225                 (Ret_Addr_I < CALL_TRACE_MAX) && !IsBadReadPtr(Ebp, sizeof(PSTACK)) && !IsBadCodePtr(FARPROC(Ebp->Ret_Addr));
00226                 Ret_Addr_I++, Ebp = Ebp->Ebp, ++i)
00227         {
00228                 // If module with Ebp->Ret_Addr found.
00229 
00230                 if (Get_Module_By_Ret_Addr(Ebp->Ret_Addr, Module_Name, Module_Addr))
00231                 {
00232                         // Save module's address and full path.
00233                         info["CallStack"][i]["ModuleName"] = ll_convert_wide_to_string(Module_Name);
00234                         info["CallStack"][i]["ModuleAddress"] = (int)Module_Addr;
00235                         info["CallStack"][i]["CallOffset"] = (int)(Ebp->Ret_Addr - Module_Addr);
00236 
00237                         LLSD params;
00238                         // Save 5 params of the call. We don't know the real number of params.
00239                         if (!IsBadReadPtr(Ebp, sizeof(PSTACK) + 5 * sizeof(DWORD)))
00240                         {
00241                                 for(int j = 0; j < 5; ++j)
00242                                 {
00243                                         params[j] = (int)Ebp->Param[j];
00244                                 }
00245                         }
00246                         info["CallStack"][i]["Parameters"] = params;
00247                 }
00248                 info["CallStack"][i]["ReturnAddress"] = (int)Ebp->Ret_Addr;                     
00249         }
00250 }
00251 
00252 BOOL GetThreadCallStack(DWORD thread_id, LLSD& info)
00253 {
00254     if(GetCurrentThreadId() == thread_id)
00255     {
00256         // Early exit for the current thread.
00257         // Suspending the current thread would be a bad idea.
00258         // Plus you can't retrieve a valid current thread context.
00259         return false;
00260     }
00261 
00262     HANDLE thread_handle = INVALID_HANDLE_VALUE; 
00263     thread_handle = OpenThread(THREAD_ALL_ACCESS, FALSE, thread_id);
00264     if(INVALID_HANDLE_VALUE == thread_handle)
00265     {
00266         return FALSE;
00267     }
00268 
00269     BOOL result = false;
00270     if(-1 != SuspendThread(thread_handle))
00271     {
00272         CONTEXT context_struct;
00273         context_struct.ContextFlags = CONTEXT_FULL;
00274         if(GetThreadContext(thread_handle, &context_struct))
00275         {
00276             GetCallStackData(&context_struct, info);
00277             result = true;
00278         }
00279         ResumeThread(thread_handle);
00280     }
00281     else
00282     {
00283         // Couldn't suspend thread.
00284     }
00285 
00286     CloseHandle(thread_handle);
00287     return result;
00288 }
00289 
00290 
00291 //Windows Call Stack Construction idea from 
00292 //http://www.codeproject.com/tools/minidump.asp
00293 
00294 //****************************************************************************************
00295 BOOL WINAPI Get_Module_By_Ret_Addr(PBYTE Ret_Addr, LPWSTR Module_Name, PBYTE & Module_Addr)
00296 //****************************************************************************************
00297 // Find module by Ret_Addr (address in the module).
00298 // Return Module_Name (full path) and Module_Addr (start address).
00299 // Return TRUE if found.
00300 {
00301         MODULEENTRY32   M = {sizeof(M)};
00302         HANDLE  hSnapshot;
00303 
00304         bool found = false;
00305         
00306         if (CreateToolhelp32Snapshot_)
00307         {
00308                 hSnapshot = CreateToolhelp32Snapshot_(TH32CS_SNAPMODULE, 0);
00309                 
00310                 if ((hSnapshot != INVALID_HANDLE_VALUE) &&
00311                         Module32First_(hSnapshot, &M))
00312                 {
00313                         do
00314                         {
00315                                 if (DWORD(Ret_Addr - M.modBaseAddr) < M.modBaseSize)
00316                                 {
00317                                         lstrcpyn(Module_Name, M.szExePath, MAX_PATH);
00318                                         Module_Addr = M.modBaseAddr;
00319                                         found = true;
00320                                         break;
00321                                 }
00322                         } while (Module32Next_(hSnapshot, &M));
00323                 }
00324 
00325                 CloseHandle(hSnapshot);
00326         }
00327 
00328         return found;
00329 } //Get_Module_By_Ret_Addr
00330 
00331 //******************************************************************
00332 void WINAPI Get_Call_Stack(PEXCEPTION_POINTERS pException, LLSD& info)
00333 //******************************************************************
00334 // Fill Str with call stack info.
00335 // pException can be either GetExceptionInformation() or NULL.
00336 // If pException = NULL - get current call stack.
00337 {       
00338         LPWSTR  Module_Name = new WCHAR[MAX_PATH];
00339         PBYTE   Module_Addr = 0;
00340         
00341         typedef struct STACK
00342         {
00343                 STACK * Ebp;
00344                 PBYTE   Ret_Addr;
00345                 DWORD   Param[0];
00346         } STACK, * PSTACK;
00347 
00348         STACK   Stack = {0, 0};
00349         PSTACK  Ebp;
00350 
00351         if (pException)         //fake frame for exception address
00352         {
00353                 Stack.Ebp = (PSTACK)pException->ContextRecord->Ebp;
00354                 Stack.Ret_Addr = (PBYTE)pException->ExceptionRecord->ExceptionAddress;
00355                 Ebp = &Stack;
00356         }
00357         else
00358         {
00359                 Ebp = (PSTACK)&pException - 1;  //frame addr of Get_Call_Stack()
00360 
00361                 // Skip frame of Get_Call_Stack().
00362                 if (!IsBadReadPtr(Ebp, sizeof(PSTACK)))
00363                         Ebp = Ebp->Ebp;         //caller ebp
00364         }
00365 
00366         // Trace CALL_TRACE_MAX calls maximum - not to exceed DUMP_SIZE_MAX.
00367         // Break trace on wrong stack frame.
00368         for (int Ret_Addr_I = 0, i = 0;
00369                 (Ret_Addr_I < CALL_TRACE_MAX) && !IsBadReadPtr(Ebp, sizeof(PSTACK)) && !IsBadCodePtr(FARPROC(Ebp->Ret_Addr));
00370                 Ret_Addr_I++, Ebp = Ebp->Ebp, ++i)
00371         {
00372                 // If module with Ebp->Ret_Addr found.
00373 
00374                 if (Get_Module_By_Ret_Addr(Ebp->Ret_Addr, Module_Name, Module_Addr))
00375                 {
00376                         // Save module's address and full path.
00377                         info["CallStack"][i]["ModuleName"] = ll_convert_wide_to_string(Module_Name);
00378                         info["CallStack"][i]["ModuleAddress"] = (int)Module_Addr;
00379                         info["CallStack"][i]["CallOffset"] = (int)(Ebp->Ret_Addr - Module_Addr);
00380 
00381                         LLSD params;
00382                         // Save 5 params of the call. We don't know the real number of params.
00383                         if (pException && !Ret_Addr_I)  //fake frame for exception address
00384                                 params[0] = "Exception Offset";
00385                         else if (!IsBadReadPtr(Ebp, sizeof(PSTACK) + 5 * sizeof(DWORD)))
00386                         {
00387                                 for(int j = 0; j < 5; ++j)
00388                                 {
00389                                         params[j] = (int)Ebp->Param[j];
00390                                 }
00391                         }
00392                         info["CallStack"][i]["Parameters"] = params;
00393                 }
00394                 info["CallStack"][i]["ReturnAddress"] = (int)Ebp->Ret_Addr;                     
00395         }
00396 } //Get_Call_Stack
00397 
00398 //***********************************
00399 void WINAPI Get_Version_Str(LLSD& info)
00400 //***********************************
00401 // Fill Str with Windows version.
00402 {
00403         OSVERSIONINFOEX V = {sizeof(OSVERSIONINFOEX)};  //EX for NT 5.0 and later
00404 
00405         if (!GetVersionEx((POSVERSIONINFO)&V))
00406         {
00407                 ZeroMemory(&V, sizeof(V));
00408                 V.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
00409                 GetVersionEx((POSVERSIONINFO)&V);
00410         }
00411 
00412         if (V.dwPlatformId != VER_PLATFORM_WIN32_NT)
00413                 V.dwBuildNumber = LOWORD(V.dwBuildNumber);      //for 9x HIWORD(dwBuildNumber) = 0x04xx
00414 
00415         info["Platform"] = llformat("Windows:  %d.%d.%d, SP %d.%d, Product Type %d",    //SP - service pack, Product Type - VER_NT_WORKSTATION,...
00416                 V.dwMajorVersion, V.dwMinorVersion, V.dwBuildNumber, V.wServicePackMajor, V.wServicePackMinor, V.wProductType);
00417 } //Get_Version_Str
00418 
00419 //*************************************************************
00420 LLSD WINAPI Get_Exception_Info(PEXCEPTION_POINTERS pException)
00421 //*************************************************************
00422 // Allocate Str[DUMP_SIZE_MAX] and return Str with dump, if !pException - just return call stack in Str.
00423 {
00424         LLSD info;
00425         LPWSTR          Str;
00426         int                     Str_Len;
00427 //      int                     i;
00428         LPWSTR          Module_Name = new WCHAR[MAX_PATH];
00429         PBYTE           Module_Addr;
00430         HANDLE          hFile;
00431         FILETIME        Last_Write_Time;
00432         FILETIME        Local_File_Time;
00433         SYSTEMTIME      T;
00434         
00435         Str = new WCHAR[DUMP_SIZE_MAX];
00436         Str_Len = 0;
00437         if (!Str)
00438                 return NULL;
00439         
00440         Get_Version_Str(info);
00441         
00442         GetModuleFileName(NULL, Str, MAX_PATH);
00443         info["Process"] = ll_convert_wide_to_string(Str);
00444 
00445         // If exception occurred.
00446         if (pException)
00447         {
00448                 EXCEPTION_RECORD &      E = *pException->ExceptionRecord;
00449                 CONTEXT &                       C = *pException->ContextRecord;
00450 
00451                 // If module with E.ExceptionAddress found - save its path and date.
00452                 if (Get_Module_By_Ret_Addr((PBYTE)E.ExceptionAddress, Module_Name, Module_Addr))
00453                 {
00454                         info["Module"] = ll_convert_wide_to_string(Module_Name);
00455 
00456                         if ((hFile = CreateFile(Module_Name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
00457                                 FILE_ATTRIBUTE_NORMAL, NULL)) != INVALID_HANDLE_VALUE)
00458                         {
00459                                 if (GetFileTime(hFile, NULL, NULL, &Last_Write_Time))
00460                                 {
00461                                         FileTimeToLocalFileTime(&Last_Write_Time, &Local_File_Time);
00462                                         FileTimeToSystemTime(&Local_File_Time, &T);
00463 
00464                                         info["DateModified"] = llformat("%02d/%02d/%d", T.wMonth, T.wDay, T.wYear);
00465                                 }
00466                                 CloseHandle(hFile);
00467                         }
00468                 }
00469                 else
00470                 {
00471                         info["ExceptionAddr"] = (int)E.ExceptionAddress;
00472                 }
00473                 
00474                 info["ExceptionCode"] = (int)E.ExceptionCode;
00475                 
00476                 /*
00477                 //TODO: Fix this
00478                 if (E.ExceptionCode == EXCEPTION_ACCESS_VIOLATION)
00479                 {
00480                         // Access violation type - Write/Read.
00481                         LLSD exception_info;
00482                         exception_info["Type"] = E.ExceptionInformation[0] ? "Write" : "Read";
00483                         exception_info["Address"] = llformat("%08x", E.ExceptionInformation[1]);
00484                         info["Exception Information"] = exception_info;
00485                 }
00486                 */
00487 
00488                 
00489                 // Save instruction that caused exception.
00490                 /*
00491                 LLString str;
00492                 for (i = 0; i < 16; i++)
00493                         str += llformat(" %02X", PBYTE(E.ExceptionAddress)[i]);
00494                 info["Instruction"] = str;
00495                 */
00496                 LLSD registers;
00497                 registers["EAX"] = (int)C.Eax;
00498                 registers["EBX"] = (int)C.Ebx;
00499                 registers["ECX"] = (int)C.Ecx;
00500                 registers["EDX"] = (int)C.Edx;
00501                 registers["ESI"] = (int)C.Esi;
00502                 registers["EDI"] = (int)C.Edi;
00503                 registers["ESP"] = (int)C.Esp;
00504                 registers["EBP"] = (int)C.Ebp;
00505                 registers["EIP"] = (int)C.Eip;
00506                 registers["EFlags"] = (int)C.EFlags;
00507                 info["Registers"] = registers;
00508         } //if (pException)
00509         
00510         // Save call stack info.
00511         Get_Call_Stack(pException, info);
00512 
00513         return info;
00514 } //Get_Exception_Info
00515 
00516 #define UNICODE
00517 
00518 
00519 class LLMemoryReserve {
00520 public:
00521         LLMemoryReserve();
00522         ~LLMemoryReserve();
00523         void reserve();
00524         void release();
00525 protected:
00526         unsigned char *mReserve;
00527         static const size_t MEMORY_RESERVATION_SIZE;
00528 };
00529 
00530 LLMemoryReserve::LLMemoryReserve() :
00531         mReserve(NULL)
00532 {
00533 };
00534 
00535 LLMemoryReserve::~LLMemoryReserve()
00536 {
00537         release();
00538 }
00539 
00540 // I dunno - this just seemed like a pretty good value.
00541 const size_t LLMemoryReserve::MEMORY_RESERVATION_SIZE = 5 * 1024 * 1024;
00542 
00543 void LLMemoryReserve::reserve()
00544 {
00545         if(NULL == mReserve)
00546                 mReserve = new unsigned char[MEMORY_RESERVATION_SIZE];
00547 };
00548 
00549 void LLMemoryReserve::release()
00550 {
00551         delete [] mReserve;
00552         mReserve = NULL;
00553 };
00554 
00555 static LLMemoryReserve gEmergencyMemoryReserve;
00556 
00557 // static
00558 void  LLWinDebug::initExceptionHandler(LPTOP_LEVEL_EXCEPTION_FILTER filter_func)
00559 {
00560 
00561         static bool s_first_run = true;
00562         // Load the dbghelp dll now, instead of waiting for the crash.
00563         // Less potential for stack mangling
00564 
00565         if (s_first_run)
00566         {
00567                 // First, try loading from the directory that the app resides in.
00568                 std::string local_dll_name = gDirUtilp->findFile("dbghelp.dll", gDirUtilp->getWorkingDir(), gDirUtilp->getExecutableDir());
00569 
00570                 HMODULE hDll = NULL;
00571                 hDll = LoadLibraryA(local_dll_name.c_str());
00572                 if (!hDll)
00573                 {
00574                         hDll = LoadLibrary(L"dbghelp.dll");
00575                 }
00576 
00577                 if (!hDll)
00578                 {
00579                         LL_WARNS("AppInit") << "Couldn't find dbghelp.dll!" << LL_ENDL;
00580                 }
00581                 else
00582                 {
00583                         f_mdwp = (MINIDUMPWRITEDUMP) GetProcAddress(hDll, "MiniDumpWriteDump");
00584 
00585                         if (!f_mdwp)
00586                         {
00587                                 FreeLibrary(hDll);
00588                                 hDll = NULL;
00589                         }
00590                 }
00591 
00592                 gEmergencyMemoryReserve.reserve();
00593 
00594                 s_first_run = false;
00595         }
00596 
00597         // Try to get Tool Help library functions.
00598         HMODULE hKernel32;
00599         hKernel32 = GetModuleHandle(_T("KERNEL32"));
00600         CreateToolhelp32Snapshot_ = (CREATE_TOOL_HELP32_SNAPSHOT)GetProcAddress(hKernel32, "CreateToolhelp32Snapshot");
00601         Module32First_ = (MODULE32_FIRST)GetProcAddress(hKernel32, "Module32FirstW");
00602         Module32Next_ = (MODULE32_NEST)GetProcAddress(hKernel32, "Module32NextW");
00603 
00604     LPTOP_LEVEL_EXCEPTION_FILTER prev_filter;
00605         prev_filter = SetUnhandledExceptionFilter(filter_func);
00606 
00607         if(prev_filter != gFilterFunc)
00608         {
00609                 LL_WARNS("AppInit") 
00610                         << "Replacing unknown exception (" << (void *)prev_filter << ") with (" << (void *)filter_func << ") !" << LL_ENDL;
00611         }
00612         
00613         gFilterFunc = filter_func;
00614 }
00615 
00616 bool LLWinDebug::checkExceptionHandler()
00617 {
00618         bool ok = true;
00619         LPTOP_LEVEL_EXCEPTION_FILTER prev_filter;
00620         prev_filter = SetUnhandledExceptionFilter(gFilterFunc);
00621 
00622         if (prev_filter != gFilterFunc)
00623         {
00624                 LL_WARNS("AppInit") << "Our exception handler (" << (void *)gFilterFunc << ") replaced with " << prev_filter << "!" << LL_ENDL;
00625                 ok = false;
00626         }
00627 
00628         if (prev_filter == NULL)
00629         {
00630                 ok = FALSE;
00631                 if (gFilterFunc == NULL)
00632                 {
00633                         LL_WARNS("AppInit") << "Exception handler uninitialized." << LL_ENDL;
00634                 }
00635                 else
00636                 {
00637                         LL_WARNS("AppInit") << "Our exception handler (" << (void *)gFilterFunc << ") replaced with NULL!" << LL_ENDL;
00638                 }
00639         }
00640 
00641         return ok;
00642 }
00643 
00644 void LLWinDebug::writeDumpToFile(MINIDUMP_TYPE type, MINIDUMP_EXCEPTION_INFORMATION *ExInfop, const char *filename)
00645 {
00646         if(f_mdwp == NULL || gDirUtilp == NULL) 
00647         {
00648                 return;
00649                 //write_debug("No way to generate a minidump, no MiniDumpWriteDump function!\n");
00650         }
00651         else
00652         {
00653                 std::string dump_path = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,
00654                                                                                                                                            filename);
00655 
00656                 HANDLE hFile = CreateFileA(dump_path.c_str(),
00657                                                                         GENERIC_WRITE,
00658                                                                         FILE_SHARE_WRITE,
00659                                                                         NULL,
00660                                                                         CREATE_ALWAYS,
00661                                                                         FILE_ATTRIBUTE_NORMAL,
00662                                                                         NULL);
00663 
00664                 if (hFile != INVALID_HANDLE_VALUE)
00665                 {
00666                         // Write the dump, ignoring the return value
00667                         f_mdwp(GetCurrentProcess(),
00668                                         GetCurrentProcessId(),
00669                                         hFile,
00670                                         type,
00671                                         ExInfop,
00672                                         NULL,
00673                                         NULL);
00674 
00675                         CloseHandle(hFile);
00676                 }
00677 
00678         }
00679 }
00680 
00681 // static
00682 void LLWinDebug::generateCrashStacks(struct _EXCEPTION_POINTERS *exception_infop)
00683 {
00684         // *NOTE:Mani - This method is no longer the exception handler.
00685         // Its called from viewer_windows_exception_handler() and other places.
00686 
00687         // 
00688         // Let go of a bunch of reserved memory to give library calls etc
00689         // a chance to execute normally in the case that we ran out of
00690         // memory.
00691         //
00692         LLSD info;
00693         std::string dump_path = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,
00694                                                                                                 "SecondLifeException");
00695         std::string log_path = dump_path + ".log";
00696 
00697         if (exception_infop)
00698         {
00699                 // Since there is exception info... Release the hounds.
00700                 gEmergencyMemoryReserve.release();
00701 
00702                 if(gSavedSettings.getControl("SaveMinidump") != NULL && gSavedSettings.getBOOL("SaveMinidump"))
00703                 {
00704                         _MINIDUMP_EXCEPTION_INFORMATION ExInfo;
00705 
00706                         ExInfo.ThreadId = ::GetCurrentThreadId();
00707                         ExInfo.ExceptionPointers = exception_infop;
00708                         ExInfo.ClientPointers = NULL;
00709 
00710                         writeDumpToFile(MiniDumpNormal, &ExInfo, "SecondLife.dmp");
00711                         writeDumpToFile((MINIDUMP_TYPE)(MiniDumpWithDataSegs | MiniDumpWithIndirectlyReferencedMemory), &ExInfo, "SecondLifePlus.dmp");
00712                 }
00713 
00714                 info = Get_Exception_Info(exception_infop);
00715         }
00716 
00717         LLSD threads;
00718     std::vector<DWORD> thread_ids;
00719     GetProcessThreadIDs(GetCurrentProcessId(), thread_ids);
00720 
00721     for(std::vector<DWORD>::iterator th_itr = thread_ids.begin(); 
00722                 th_itr != thread_ids.end();
00723                 ++th_itr)
00724     {
00725         LLSD thread_info;
00726         if(*th_itr != GetCurrentThreadId())
00727         {
00728             GetThreadCallStack(*th_itr, thread_info);
00729         }
00730 
00731         if(thread_info)
00732         {
00733             threads[llformat("ID %d", *th_itr)] = thread_info;
00734         }
00735     }
00736 
00737     info["Threads"] = threads;
00738 
00739         std::ofstream out_file(log_path.c_str());
00740         LLSDSerialize::toPrettyXML(info, out_file);
00741         out_file.close();
00742 }
00743 
00744 #endif

Generated on Fri May 16 08:34:25 2008 for SecondLife by  doxygen 1.5.5