diff options
author | Kyle Machulis <qdot@lindenlab.com> | 2007-11-20 23:42:48 +0000 |
---|---|---|
committer | Kyle Machulis <qdot@lindenlab.com> | 2007-11-20 23:42:48 +0000 |
commit | 2e7c0d973ed28d732ea19762099ed3c55123780e (patch) | |
tree | 36b04301d325e07075880a8a64166c5284d1d61f /indra/newview | |
parent | 5356b917545d43df5537128245ee5b786b705b90 (diff) |
svn merge -r74104:74124 svn+ssh://svn/svn/linden/branches/crash-logger-cleanup-merge-6
Diffstat (limited to 'indra/newview')
-rw-r--r-- | indra/newview/llappviewer.cpp | 89 | ||||
-rw-r--r-- | indra/newview/llappviewer.h | 6 | ||||
-rw-r--r-- | indra/newview/llappviewerwin32.cpp | 13 | ||||
-rw-r--r-- | indra/newview/llstartup.cpp | 21 | ||||
-rw-r--r-- | indra/newview/llviewerregion.cpp | 22 | ||||
-rw-r--r-- | indra/newview/llviewerregion.h | 2 | ||||
-rw-r--r-- | indra/newview/llwindebug.cpp | 441 | ||||
-rw-r--r-- | indra/newview/llwindebug.h | 2 | ||||
-rw-r--r-- | indra/newview/llworld.cpp | 10 | ||||
-rw-r--r-- | indra/newview/llworld.h | 2 | ||||
-rw-r--r-- | indra/newview/macutil_Prefix.h | 3 |
11 files changed, 420 insertions, 191 deletions
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index c0e9833829..63d1986dec 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -106,6 +106,8 @@ #include "llcontainerview.h" #include "llhoverview.h" +#include "llsdserialize.h" + #if LL_WINDOWS && LL_LCD_COMPILE #include "lllcd.h" #endif @@ -267,6 +269,8 @@ BOOL gAcceptCriticalMessage = FALSE; LLUUID gViewerDigest; // MD5 digest of the viewer's executable file. BOOL gLastExecFroze = FALSE; +LLSD gDebugInfo; + U32 gFrameCount = 0; U32 gForegroundFrameCount = 0; // number of frames that app window was in foreground LLPumpIO* gServicePump = NULL; @@ -915,7 +919,6 @@ LLTextureFetch* LLAppViewer::sTextureFetch = NULL; LLAppViewer::LLAppViewer() : mMarkerFile(NULL), mLastExecFroze(false), - mDebugFile(NULL), mCrashBehavior(CRASH_BEHAVIOR_ASK), mReportedCrash(false), mNumSessions(0), @@ -1220,7 +1223,7 @@ bool LLAppViewer::init() CreateLCDDebugWindows(); #endif - writeDebug(gGLManager.getGLInfoString()); + gGLManager.getGLInfo(gDebugInfo); llinfos << gGLManager.getGLInfoString() << llendl; //load key settings @@ -2351,30 +2354,13 @@ bool LLAppViewer::initWindow() return true; } -void LLAppViewer::writeDebug(const char *str) -{ - if (!mDebugFile) - { - std::string debug_filename = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"debug_info.log"); - llinfos << "Opening debug file " << debug_filename << llendl; - mDebugFile = LLFile::fopen(debug_filename.c_str(), "w"); /* Flawfinder: ignore */ - if (!mDebugFile) - { - llinfos << "Opening debug file " << debug_filename << " failed. Using stderr." << llendl; - mDebugFile = stderr; - } - } - fputs(str, mDebugFile); - fflush(mDebugFile); -} - void LLAppViewer::closeDebug() { - if (mDebugFile) - { - fclose(mDebugFile); - } - mDebugFile = NULL; + std::string debug_filename = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"debug_info.log"); + llinfos << "Opening debug file " << debug_filename << llendl; + std::ofstream out_file(debug_filename.c_str()); + LLSDSerialize::toPrettyXML(gDebugInfo, out_file); + out_file.close(); } void LLAppViewer::cleanupSavedSettings() @@ -2443,23 +2429,22 @@ void LLAppViewer::removeCacheFiles(const char* file_mask) void LLAppViewer::writeSystemInfo() { - writeDebug("SL Log: "); - writeDebug(LLError::logFileName()); - writeDebug("\n"); - - std::string tmp_str = gSecondLife - + llformat(" version %d.%d.%d build %d", - LL_VERSION_MAJOR, LL_VERSION_MINOR, LL_VERSION_PATCH, LL_VERSION_BUILD); - writeDebug(tmp_str.c_str()); - writeDebug("\n"); - writeDebug(gSysCPU.getCPUString()); - writeDebug("\n"); + gDebugInfo["SLLog"] = LLError::logFileName(); + + gDebugInfo["ClientInfo"]["Name"] = gSecondLife; + gDebugInfo["ClientInfo"]["MajorVersion"] = LL_VERSION_MAJOR; + gDebugInfo["ClientInfo"]["MinorVersion"] = LL_VERSION_MINOR; + gDebugInfo["ClientInfo"]["PatchVersion"] = LL_VERSION_PATCH; + gDebugInfo["ClientInfo"]["BuildVersion"] = LL_VERSION_BUILD; + + gDebugInfo["CPUInfo"]["CPUFamily"] = gSysCPU.getFamily(); + gDebugInfo["CPUInfo"]["CPUMhz"] = gSysCPU.getMhz(); + gDebugInfo["CPUInfo"]["CPUAltivec"] = gSysCPU.hasAltivec(); + gDebugInfo["CPUInfo"]["CPUSSE"] = gSysCPU.hasSSE(); + gDebugInfo["CPUInfo"]["CPUSSE2"] = gSysCPU.hasSSE2(); - tmp_str = llformat("RAM: %u KB\n", gSysMemory.getPhysicalMemoryKB()); - writeDebug(tmp_str.c_str()); - writeDebug("OS: "); - writeDebug(getOSInfo().getOSString().c_str()); - writeDebug("\n"); + gDebugInfo["RAMInfo"] = llformat("%u", gSysMemory.getPhysicalMemoryKB()); + gDebugInfo["OSInfo"] = mSysOSInfo.getOSString().c_str(); // Dump some debugging info llinfos << gSecondLife << " version " @@ -2498,16 +2483,11 @@ void LLAppViewer::handleViewerCrash() } pApp->mReportedCrash = TRUE; - BOOL do_crash_report = FALSE; - - do_crash_report = TRUE; - - pApp->writeDebug("Viewer exe: "); - pApp->writeDebug(gDirUtilp->getExecutablePathAndName().c_str()); - pApp->writeDebug("\n"); - pApp->writeDebug("Cur path: "); - pApp->writeDebug(gDirUtilp->getCurPath().c_str()); - pApp->writeDebug("\n\n"); + gDebugInfo["SettingsFilename"] = gSettingsFileName; + gDebugInfo["CAFilename"] = gDirUtilp->getCAFile(); + gDebugInfo["ViewerExePath"] = gDirUtilp->getExecutablePathAndName().c_str(); + gDebugInfo["CurrentPath"] = gDirUtilp->getCurPath().c_str(); + gDebugInfo["CurrentSimHost"] = gAgent.getRegionHost().getHostName(); if (gMessageSystem && gDirUtilp) { @@ -2517,27 +2497,24 @@ void LLAppViewer::handleViewerCrash() if(file.good()) { gMessageSystem->summarizeLogs(file); + file.close(); } } if (gMessageSystem) { - pApp->writeDebug(gMessageSystem->getCircuitInfoString()); + gMessageSystem->getCircuitInfo(gDebugInfo["CircuitInfo"]); gMessageSystem->stopLogging(); } - pApp->writeDebug("\n"); if (gWorldp) { - pApp->writeDebug(gWorldp->getInfoString()); + gWorldp->getInfo(gDebugInfo); } // Close the debug file pApp->closeDebug(); LLError::logToFile(""); - // Close the SecondLife.log - //pApp->removeMarkerFile(); - // Call to pure virtual, handled by platform specifc llappviewer instance. pApp->handleCrashReporting(); diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h index 227a27a8ac..e97aead955 100644 --- a/indra/newview/llappviewer.h +++ b/indra/newview/llappviewer.h @@ -68,9 +68,6 @@ public: // This version stores the argc and argv for later usage, make sure the params passed in last as long as this class. bool tempStoreCommandOptions(int argc, char** argv); - // write string to "debug_info.log", used for crash reporting. - void writeDebug(const char *str); - void writeDebug(const std::string& str) { writeDebug(str.c_str()); }; void closeDebug(); const LLOSInfo& getOSInfo() const { return mSysOSInfo; } @@ -165,8 +162,6 @@ private: FILE *mMarkerFile; // A file created to indicate the app is running. bool mLastExecFroze; // Set on init if the marker file was found. - FILE* mDebugFile; // output stream written to via writeDebug() - LLOSInfo mSysOSInfo; S32 mCrashBehavior; bool mReportedCrash; @@ -202,6 +197,7 @@ extern BOOL gProbeHardware; extern LLString gDisabledMessage; // llstartup extern BOOL gHideLinks; // used by llpanellogin, lllfloaterbuycurrency, llstartup extern BOOL gInProductionGrid; +extern LLSD gDebugInfo; extern BOOL gAllowIdleAFK; extern F32 gAFKTimeout; diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp index 1d7a6690fc..814c209e67 100644 --- a/indra/newview/llappviewerwin32.cpp +++ b/indra/newview/llappviewerwin32.cpp @@ -322,9 +322,16 @@ bool LLAppViewerWin32::initWindow() return LLAppViewer::initWindow(); } -void write_debug_callback(const char* str) +void write_debug_dx(const char* str) { - LLAppViewer::instance()->writeDebug(str); + LLString value = gDebugInfo["DXInfo"].asString(); + value += str; + gDebugInfo["DXInfo"] = value; +} + +void write_debug_dx(const std::string& str) +{ + write_debug_dx(str.c_str()); } bool LLAppViewerWin32::initHardwareTest() @@ -340,7 +347,7 @@ bool LLAppViewerWin32::initHardwareTest() LLSplashScreen::update("Detecting hardware..."); llinfos << "Attempting to poll DirectX for hardware info" << llendl; - gDXHardware.setWriteDebugFunc(write_debug_callback); + gDXHardware.setWriteDebugFunc(write_debug_dx); BOOL probe_ok = gDXHardware.getInfo(vram_only); if (!probe_ok diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index c43c4e8685..dda155d0df 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -773,12 +773,11 @@ BOOL idle_startup() gSavedSettings.setString("FirstName", firstname); gSavedSettings.setString("LastName", lastname); + + + llinfos << "Attempting login as: " << firstname << " " << lastname << llendl; - LLAppViewer::instance()->writeDebug("Attempting login as: "); - LLAppViewer::instance()->writeDebug(firstname); - LLAppViewer::instance()->writeDebug(" "); - LLAppViewer::instance()->writeDebug(lastname); - LLAppViewer::instance()->writeDebug("\n"); + gDebugInfo["LoginName"] = firstname + " " + lastname; } // create necessary directories @@ -826,6 +825,7 @@ BOOL idle_startup() LLPanelLogin::close(); } + //For HTML parsing in text boxes. LLTextEditor::setLinkColor( gSavedSettings.getColor4("HTMLLinkColor") ); LLTextEditor::setURLCallbacks ( &LLWeb::loadURL, &LLURLDispatcher::dispatch, &LLURLDispatcher::dispatch ); @@ -895,6 +895,8 @@ BOOL idle_startup() if(STATE_LOGIN_AUTH_INIT == LLStartUp::getStartupState()) { //#define LL_MINIMIAL_REQUESTED_OPTIONS + gDebugInfo["GridUtilHost"] = gGridInfo[gGridChoice].mName; + lldebugs << "STATE_LOGIN_AUTH_INIT" << llendl; if (!gUserAuthp) { @@ -932,6 +934,7 @@ BOOL idle_startup() } LLAppViewer::instance()->getLoginURIs(); sAuthUris = LLAppViewer::instance()->getLoginURIs(); + sAuthUriNum = 0; auth_method = "login_to_simulator"; auth_desc = "Logging in. "; @@ -1226,15 +1229,11 @@ BOOL idle_startup() const char* text; text = gUserAuthp->getResponse("agent_id"); if(text) gAgentID.set(text); - LLAppViewer::instance()->writeDebug("AgentID: "); - LLAppViewer::instance()->writeDebug(text); - LLAppViewer::instance()->writeDebug("\n"); + gDebugInfo["AgentID"] = text; text = gUserAuthp->getResponse("session_id"); if(text) gAgentSessionID.set(text); - LLAppViewer::instance()->writeDebug("SessionID: "); - LLAppViewer::instance()->writeDebug(text); - LLAppViewer::instance()->writeDebug("\n"); + gDebugInfo["SessionID"] = text; text = gUserAuthp->getResponse("secure_session_id"); if(text) gAgent.mSecureSessionID.set(text); diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index 95a1db12df..5bfe023168 100644 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -964,28 +964,16 @@ void LLViewerRegion::updateCoarseLocations(LLMessageSystem* msg) } } -LLString LLViewerRegion::getInfoString() +void LLViewerRegion::getInfo(LLSD& info) { - char tmp_buf[256]; /* Flawfinder: ignore */ - LLString info; - - info = "Region: "; - getHost().getString(tmp_buf, 256); - info += tmp_buf; - info += ":"; - info += getName(); - info += "\n"; - + info["Region"]["Host"] = getHost().getIPandPort(); + info["Region"]["Name"] = getName(); U32 x, y; from_region_handle(getHandle(), &x, &y); - snprintf(tmp_buf, sizeof(tmp_buf), "%d:%d", x, y); /* Flawfinder: ignore */ - info += "Handle:"; - info += tmp_buf; - info += "\n"; - return info; + info["Region"]["Handle"]["x"] = (LLSD::Integer)x; + info["Region"]["Handle"]["y"] = (LLSD::Integer)y; } - void LLViewerRegion::cacheFullUpdate(LLViewerObject* objectp, LLDataPackerBinaryBuffer &dp) { U32 local_id = objectp->getLocalID(); diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h index 013a96f2d1..a0953e561e 100644 --- a/indra/newview/llviewerregion.h +++ b/indra/newview/llviewerregion.h @@ -223,7 +223,7 @@ public: F32 getLandHeightRegion(const LLVector3& region_pos); - LLString getInfoString(); + void getInfo(LLSD& info); // handle a full update message void cacheFullUpdate(LLViewerObject* objectp, LLDataPackerBinaryBuffer &dp); diff --git a/indra/newview/llwindebug.cpp b/indra/newview/llwindebug.cpp index 88ba5822eb..13c5ac3bbb 100644 --- a/indra/newview/llwindebug.cpp +++ b/indra/newview/llwindebug.cpp @@ -33,12 +33,70 @@ #ifdef LL_WINDOWS +#include <tchar.h> +#include <tlhelp32.h> +#include <atlbase.h> +#include "llappviewer.h" #include "llwindebug.h" #include "llviewercontrol.h" #include "lldir.h" - -#include "llappviewer.h" - +#include "llsd.h" +#include "llsdserialize.h" + +#pragma warning(disable: 4200) //nonstandard extension used : zero-sized array in struct/union +#pragma warning(disable: 4100) //unreferenced formal parameter + +/* +LLSD Block for Windows Dump Information +<llsd> + <map> + <key>Platform</key> + <string></string> + <key>Process</key> + <string></string> + <key>Module</key> + <string></string> + <key>Date Modified</key> + <string></string> + <key>Exception Code</key> + <string></string> + <key>Exception Read/Write Address</key> + <string></string> + <key>Instruction</key> + <string></string> + <key>Registers</key> + <map> + <!-- Continued for all registers --> + <key>EIP</key> + <string>...</string> + <!-- ... --> + </map> + <key>Call Stack</key> + <array> + <!-- One map per stack frame --> + <map> + <key>Module Name</key> + <string></string> + <key>Module Base Address</key> + <string></string> + <key>Module Offset Address</key> + <string></string> + <key>Parameters</key> + <array> + <string></string> + </array> + </map> + <!-- ... --> + </array> + </map> +</llsd> + +*/ + +// From viewer.h +extern BOOL gInProductionGrid; + +extern void (*gCrashCallback)(void); // based on dbghelp.h typedef BOOL (WINAPI *MINIDUMPWRITEDUMP)(HANDLE hProcess, DWORD dwPid, HANDLE hFile, MINIDUMP_TYPE DumpType, @@ -49,6 +107,255 @@ typedef BOOL (WINAPI *MINIDUMPWRITEDUMP)(HANDLE hProcess, DWORD dwPid, HANDLE hF MINIDUMPWRITEDUMP f_mdwp = NULL; +#undef UNICODE + +HMODULE hDbgHelp; + +// Tool Help functions. +typedef HANDLE (WINAPI * CREATE_TOOL_HELP32_SNAPSHOT)(DWORD dwFlags, DWORD th32ProcessID); +typedef BOOL (WINAPI * MODULE32_FIRST)(HANDLE hSnapshot, LPMODULEENTRY32 lpme); +typedef BOOL (WINAPI * MODULE32_NEST)(HANDLE hSnapshot, LPMODULEENTRY32 lpme); + +CREATE_TOOL_HELP32_SNAPSHOT CreateToolhelp32Snapshot_; +MODULE32_FIRST Module32First_; +MODULE32_NEST Module32Next_; + +#define DUMP_SIZE_MAX 8000 //max size of our dump +#define CALL_TRACE_MAX ((DUMP_SIZE_MAX - 2000) / (MAX_PATH + 40)) //max number of traced calls +#define NL L"\r\n" //new line + +//**************************************************************************************** +BOOL WINAPI Get_Module_By_Ret_Addr(PBYTE Ret_Addr, LPWSTR Module_Name, PBYTE & Module_Addr) +//**************************************************************************************** +// Find module by Ret_Addr (address in the module). +// Return Module_Name (full path) and Module_Addr (start address). +// Return TRUE if found. +{ + MODULEENTRY32 M = {sizeof(M)}; + HANDLE hSnapshot; + + bool found = false; + + if (CreateToolhelp32Snapshot_) + { + hSnapshot = CreateToolhelp32Snapshot_(TH32CS_SNAPMODULE, 0); + + if ((hSnapshot != INVALID_HANDLE_VALUE) && + Module32First_(hSnapshot, &M)) + { + do + { + if (DWORD(Ret_Addr - M.modBaseAddr) < M.modBaseSize) + { + lstrcpyn(Module_Name, M.szExePath, MAX_PATH); + Module_Addr = M.modBaseAddr; + found = true; + break; + } + } while (Module32Next_(hSnapshot, &M)); + } + + CloseHandle(hSnapshot); + } + + return found; +} //Get_Module_By_Ret_Addr + +//****************************************************************** +void WINAPI Get_Call_Stack(PEXCEPTION_POINTERS pException, LLSD& info) +//****************************************************************** +// Fill Str with call stack info. +// pException can be either GetExceptionInformation() or NULL. +// If pException = NULL - get current call stack. +{ + + USES_CONVERSION; + + LPWSTR Module_Name = new WCHAR[MAX_PATH]; + PBYTE Module_Addr = 0; + + typedef struct STACK + { + STACK * Ebp; + PBYTE Ret_Addr; + DWORD Param[0]; + } STACK, * PSTACK; + + STACK Stack = {0, 0}; + PSTACK Ebp; + + if (pException) //fake frame for exception address + { + Stack.Ebp = (PSTACK)pException->ContextRecord->Ebp; + Stack.Ret_Addr = (PBYTE)pException->ExceptionRecord->ExceptionAddress; + Ebp = &Stack; + } + else + { + Ebp = (PSTACK)&pException - 1; //frame addr of Get_Call_Stack() + + // Skip frame of Get_Call_Stack(). + if (!IsBadReadPtr(Ebp, sizeof(PSTACK))) + Ebp = Ebp->Ebp; //caller ebp + } + + // Trace CALL_TRACE_MAX calls maximum - not to exceed DUMP_SIZE_MAX. + // Break trace on wrong stack frame. + for (int Ret_Addr_I = 0, i = 0; + (Ret_Addr_I < CALL_TRACE_MAX) && !IsBadReadPtr(Ebp, sizeof(PSTACK)) && !IsBadCodePtr(FARPROC(Ebp->Ret_Addr)); + Ret_Addr_I++, Ebp = Ebp->Ebp, ++i) + { + // If module with Ebp->Ret_Addr found. + + if (Get_Module_By_Ret_Addr(Ebp->Ret_Addr, Module_Name, Module_Addr)) + { + // Save module's address and full path. + info["Call Stack"][i]["Module Name"] = W2A(Module_Name); + info["Call Stack"][i]["Module Address"] = (int)Module_Addr; + info["Call Stack"][i]["Call Offset"] = (int)(Ebp->Ret_Addr - Module_Addr); + + LLSD params; + // Save 5 params of the call. We don't know the real number of params. + if (pException && !Ret_Addr_I) //fake frame for exception address + params[0] = "Exception Offset"; + else if (!IsBadReadPtr(Ebp, sizeof(PSTACK) + 5 * sizeof(DWORD))) + { + for(int j = 0; j < 5; ++j) + { + params[j] = (int)Ebp->Param[j]; + } + } + info["Call Stack"][i]["Parameters"] = params; + } + info["Call Stack"][i]["Return Address"] = (int)Ebp->Ret_Addr; + } +} //Get_Call_Stack + +//*********************************** +void WINAPI Get_Version_Str(LLSD& info) +//*********************************** +// Fill Str with Windows version. +{ + OSVERSIONINFOEX V = {sizeof(OSVERSIONINFOEX)}; //EX for NT 5.0 and later + + if (!GetVersionEx((POSVERSIONINFO)&V)) + { + ZeroMemory(&V, sizeof(V)); + V.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx((POSVERSIONINFO)&V); + } + + if (V.dwPlatformId != VER_PLATFORM_WIN32_NT) + V.dwBuildNumber = LOWORD(V.dwBuildNumber); //for 9x HIWORD(dwBuildNumber) = 0x04xx + + info["Platform"] = llformat("Windows: %d.%d.%d, SP %d.%d, Product Type %d", //SP - service pack, Product Type - VER_NT_WORKSTATION,... + V.dwMajorVersion, V.dwMinorVersion, V.dwBuildNumber, V.wServicePackMajor, V.wServicePackMinor, V.wProductType); +} //Get_Version_Str + +//************************************************************* +LLSD WINAPI Get_Exception_Info(PEXCEPTION_POINTERS pException) +//************************************************************* +// Allocate Str[DUMP_SIZE_MAX] and return Str with dump, if !pException - just return call stack in Str. +{ + USES_CONVERSION; + + LLSD info; + LPWSTR Str; + int Str_Len; + int i; + LPWSTR Module_Name = new WCHAR[MAX_PATH]; + PBYTE Module_Addr; + HANDLE hFile; + FILETIME Last_Write_Time; + FILETIME Local_File_Time; + SYSTEMTIME T; + + Str = new WCHAR[DUMP_SIZE_MAX]; + Str_Len = 0; + if (!Str) + return NULL; + + Get_Version_Str(info); + + + GetModuleFileName(NULL, Str, MAX_PATH); + info["Process"] = W2A(Str); + + // If exception occurred. + if (pException) + { + EXCEPTION_RECORD & E = *pException->ExceptionRecord; + CONTEXT & C = *pException->ContextRecord; + + // If module with E.ExceptionAddress found - save its path and date. + if (Get_Module_By_Ret_Addr((PBYTE)E.ExceptionAddress, Module_Name, Module_Addr)) + { + info["Module"] = W2A(Module_Name); + + if ((hFile = CreateFile(Module_Name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, NULL)) != INVALID_HANDLE_VALUE) + { + if (GetFileTime(hFile, NULL, NULL, &Last_Write_Time)) + { + FileTimeToLocalFileTime(&Last_Write_Time, &Local_File_Time); + FileTimeToSystemTime(&Local_File_Time, &T); + + info["Date Modified"] = llformat("%02d/%02d/%d", T.wMonth, T.wDay, T.wYear); + } + CloseHandle(hFile); + } + } + else + { + info["Exception Addr"] = (int)E.ExceptionAddress; + } + + info["Exception Code"] = (int)E.ExceptionCode; + + /* + //TODO: Fix this + if (E.ExceptionCode == EXCEPTION_ACCESS_VIOLATION) + { + // Access violation type - Write/Read. + LLSD exception_info; + exception_info["Type"] = E.ExceptionInformation[0] ? "Write" : "Read"; + exception_info["Address"] = llformat("%08x", E.ExceptionInformation[1]); + info["Exception Information"] = exception_info; + } + */ + + + // Save instruction that caused exception. + Str_Len = 0; + for (i = 0; i < 16; i++) + Str_Len += wsprintf(Str + Str_Len, L" %02X", PBYTE(E.ExceptionAddress)[i]); + info["Instruction"] = W2A(Str); + + LLSD registers; + registers["EAX"] = (int)C.Eax; + registers["EBX"] = (int)C.Ebx; + registers["ECX"] = (int)C.Ecx; + registers["EDX"] = (int)C.Edx; + registers["ESI"] = (int)C.Esi; + registers["EDI"] = (int)C.Edi; + registers["ESP"] = (int)C.Esp; + registers["EBP"] = (int)C.Ebp; + registers["EIP"] = (int)C.Eip; + registers["EFlags"] = (int)C.EFlags; + info["Registers"] = registers; + } //if (pException) + + // Save call stack info. + Get_Call_Stack(pException, info); + + if (Str[0] == NL[0]) + lstrcpy(Str, Str + sizeof(NL) - 1); + + + return info; +} //Get_Exception_Info + +#define UNICODE class LLMemoryReserve { @@ -92,7 +399,6 @@ 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. @@ -119,7 +425,7 @@ BOOL LLWinDebug::setupExceptionHandler() msg += local_dll_name; msg += "!\n"; - LLAppViewer::instance()->writeDebug(msg.c_str()); + //write_debug(msg.c_str()); ok = FALSE; } @@ -129,7 +435,7 @@ BOOL LLWinDebug::setupExceptionHandler() if (!f_mdwp) { - LLAppViewer::instance()->writeDebug("No MiniDumpWriteDump!\n"); + //write_debug("No MiniDumpWriteDump!\n"); FreeLibrary(hDll); hDll = NULL; ok = FALSE; @@ -139,76 +445,37 @@ BOOL LLWinDebug::setupExceptionHandler() gEmergencyMemoryReserve.reserve(); } - // *REMOVE: LLApp now handles the exception handing. - // LLAppViewerWin32 calls SetUnhandledExceptionFilter() - - //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; - //} + LPTOP_LEVEL_EXCEPTION_FILTER prev_filter; + prev_filter = SetUnhandledExceptionFilter(LLWinDebug::handleException); - return ok; -#else - // Internal builds don't mess with exception handling. - return TRUE; -#endif -} + // Try to get Tool Help library functions. + HMODULE hKernel32; + hKernel32 = GetModuleHandle(_T("KERNEL32")); + CreateToolhelp32Snapshot_ = (CREATE_TOOL_HELP32_SNAPSHOT)GetProcAddress(hKernel32, "CreateToolhelp32Snapshot"); + Module32First_ = (MODULE32_FIRST)GetProcAddress(hKernel32, "Module32FirstW"); + Module32Next_ = (MODULE32_NEST)GetProcAddress(hKernel32, "Module32NextW"); -void LLWinDebug::writeDumpToFile(MINIDUMP_TYPE type, MINIDUMP_EXCEPTION_INFORMATION *ExInfop, const char *filename) -{ - if(f_mdwp == NULL) + if (s_first_run) { - LLAppViewer::instance()->writeDebug("No way to generate a minidump, no MiniDumpWriteDump function!\n"); + // We're fine, this is the first run. + s_first_run = FALSE; + return ok; } - else if(gDirUtilp == NULL) + if (!prev_filter) { - LLAppViewer::instance()->writeDebug("No way to generate a minidump, no gDirUtilp!\n"); + llwarns << "Our exception handler (" << (void *)LLWinDebug::handleException << ") replaced with NULL!" << llendl; + ok = FALSE; } - else + if (prev_filter != LLWinDebug::handleException) { - 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); - } - + llwarns << "Our exception handler (" << (void *)LLWinDebug::handleException << ") replaced with " << prev_filter << "!" << llendl; + ok = FALSE; } -} + return ok; + // Internal builds don't mess with exception handling. + //return TRUE; +} // static LONG LLWinDebug::handleException(struct _EXCEPTION_POINTERS *exception_infop) { @@ -222,42 +489,35 @@ LONG LLWinDebug::handleException(struct _EXCEPTION_POINTERS *exception_infop) // 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; + std::string dump_path = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, + "SecondLifeException"); - writeDumpToFile(MiniDumpNormal, &ExInfo, "SecondLife.dmp"); + std::string log_path = dump_path + ".log"; - if(alsoSaveMaxiDump) - writeDumpToFile((MINIDUMP_TYPE)(MiniDumpWithDataSegs | MiniDumpWithIndirectlyReferencedMemory), &ExInfo, "SecondLifePlus.dmp"); + LLSD info; + info = Get_Exception_Info(exception_infop); + if (info) + { + std::ofstream out_file(log_path.c_str()); + LLSDSerialize::toPrettyXML(info, out_file); + out_file.close(); + } } 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; } + //handle viewer crash must be called here since + //we don't return handling of the application + //back to the process. + LLAppViewer::handleViewerCrash(); + // // At this point, we always want to exit the app. There's no graceful // recovery for an unhandled exception. @@ -269,4 +529,3 @@ LONG LLWinDebug::handleException(struct _EXCEPTION_POINTERS *exception_infop) } #endif - diff --git a/indra/newview/llwindebug.h b/indra/newview/llwindebug.h index bb1f11df67..e420138216 100644 --- a/indra/newview/llwindebug.h +++ b/indra/newview/llwindebug.h @@ -41,7 +41,7 @@ public: static BOOL setupExceptionHandler(); static LONG WINAPI handleException(struct _EXCEPTION_POINTERS *pExceptionInfo); - static void writeDumpToFile(MINIDUMP_TYPE type, MINIDUMP_EXCEPTION_INFORMATION *ExInfop, const char *filename); + //static void writeDumpToFile(MINIDUMP_TYPE type, MINIDUMP_EXCEPTION_INFORMATION *ExInfop, const char *filename); }; #endif // LL_LLWINDEBUG_H diff --git a/indra/newview/llworld.cpp b/indra/newview/llworld.cpp index 36be05fe7f..e76123557c 100644 --- a/indra/newview/llworld.cpp +++ b/indra/newview/llworld.cpp @@ -972,16 +972,16 @@ void LLWorld::requestCacheMisses() } } -LLString LLWorld::getInfoString() +void LLWorld::getInfo(LLSD& info) { - LLString info_string("World Info:\n"); + LLSD region_info; for (region_list_t::iterator iter = mRegionList.begin(); iter != mRegionList.end(); ++iter) - { + { LLViewerRegion* regionp = *iter; - info_string += regionp->getInfoString(); + regionp->getInfo(region_info); + info["World"].append(region_info); } - return info_string; } void LLWorld::disconnectRegions() diff --git a/indra/newview/llworld.h b/indra/newview/llworld.h index 91685cd297..e634459acd 100644 --- a/indra/newview/llworld.h +++ b/indra/newview/llworld.h @@ -142,7 +142,7 @@ public: void setSpaceTimeUSec(const U64 space_time_usec); U64 getSpaceTimeUSec() const; - LLString getInfoString(); + void getInfo(LLSD& info); public: typedef std::list<LLViewerRegion*> region_list_t; diff --git a/indra/newview/macutil_Prefix.h b/indra/newview/macutil_Prefix.h index f8050c8d35..145a01c702 100644 --- a/indra/newview/macutil_Prefix.h +++ b/indra/newview/macutil_Prefix.h @@ -39,3 +39,6 @@ #include <Carbon/Carbon.h> +#undef check +#undef verify +#undef require |