From 428a3bafb838949df9f046abe673ac1878dacdd6 Mon Sep 17 00:00:00 2001 From: Latif Khalifa Date: Tue, 1 Oct 2013 06:04:17 +0200 Subject: [PATCH 01/16] Breakpad3: cmake and prebuilds --- indra/cmake/CMakeLists.txt | 3 ++ indra/cmake/FindGoogleBreakpad.cmake | 40 +++++++++++++++ indra/cmake/GoogleBreakpad.cmake | 21 ++++++++ indra/cmake/LLAddBuildTest.cmake | 20 ++++++++ indra/cmake/LLSharedLibs.cmake | 73 ++++++++++++++++++++++++++++ install.xml | 29 +++++++++++ 6 files changed, 186 insertions(+) create mode 100644 indra/cmake/FindGoogleBreakpad.cmake create mode 100644 indra/cmake/GoogleBreakpad.cmake create mode 100644 indra/cmake/LLSharedLibs.cmake diff --git a/indra/cmake/CMakeLists.txt b/indra/cmake/CMakeLists.txt index 9eacfcada..4391a8985 100644 --- a/indra/cmake/CMakeLists.txt +++ b/indra/cmake/CMakeLists.txt @@ -37,6 +37,7 @@ set(cmake_SOURCE_FILES FindColladadom.cmake FindELFIO.cmake FindGLOD.cmake + FindGoogleBreakpad.cmake FindGooglePerfTools.cmake FindHunSpell.cmake FindJsonCpp.cmake @@ -50,6 +51,7 @@ set(cmake_SOURCE_FILES GStreamer010Plugin.cmake Glui.cmake Glut.cmake + GoogleBreakpad.cmake GooglePerfTools.cmake Hunspell.cmake JPEG.cmake @@ -69,6 +71,7 @@ set(cmake_SOURCE_FILES LLPlugin.cmake LLPrimitive.cmake LLPhysicsExtensions.cmake + LLSharedLibs.cmake LLQtWebkit.cmake LLRender.cmake LLUI.cmake diff --git a/indra/cmake/FindGoogleBreakpad.cmake b/indra/cmake/FindGoogleBreakpad.cmake new file mode 100644 index 000000000..1a0493be5 --- /dev/null +++ b/indra/cmake/FindGoogleBreakpad.cmake @@ -0,0 +1,40 @@ +# -*- cmake -*- + +# - Find Google BreakPad +# Find the Google BreakPad includes and library +# This module defines +# BREAKPAD_EXCEPTION_HANDLER_INCLUDE_DIR, where to find exception_handler.h, etc. +# BREAKPAD_EXCEPTION_HANDLER_LIBRARIES, the libraries needed to use Google BreakPad. +# BREAKPAD_EXCEPTION_HANDLER_FOUND, If false, do not try to use Google BreakPad. +# also defined, but not for general use are +# BREAKPAD_EXCEPTION_HANDLER_LIBRARY, where to find the Google BreakPad library. + +FIND_PATH(BREAKPAD_EXCEPTION_HANDLER_INCLUDE_DIR google_breakpad/exception_handler.h) + +SET(BREAKPAD_EXCEPTION_HANDLER_NAMES ${BREAKPAD_EXCEPTION_HANDLER_NAMES} breakpad_client) +FIND_LIBRARY(BREAKPAD_EXCEPTION_HANDLER_LIBRARY + NAMES ${BREAKPAD_EXCEPTION_HANDLER_NAMES} + ) + +IF (BREAKPAD_EXCEPTION_HANDLER_LIBRARY AND BREAKPAD_EXCEPTION_HANDLER_INCLUDE_DIR) + SET(BREAKPAD_EXCEPTION_HANDLER_LIBRARIES ${BREAKPAD_EXCEPTION_HANDLER_LIBRARY}) + SET(BREAKPAD_EXCEPTION_HANDLER_FOUND "YES") +ELSE (BREAKPAD_EXCEPTION_HANDLER_LIBRARY AND BREAKPAD_EXCEPTION_HANDLER_INCLUDE_DIR) + SET(BREAKPAD_EXCEPTION_HANDLER_FOUND "NO") +ENDIF (BREAKPAD_EXCEPTION_HANDLER_LIBRARY AND BREAKPAD_EXCEPTION_HANDLER_INCLUDE_DIR) + + +IF (BREAKPAD_EXCEPTION_HANDLER_FOUND) + IF (NOT BREAKPAD_EXCEPTION_HANDLER_FIND_QUIETLY) + MESSAGE(STATUS "Found Google BreakPad: ${BREAKPAD_EXCEPTION_HANDLER_LIBRARIES}") + ENDIF (NOT BREAKPAD_EXCEPTION_HANDLER_FIND_QUIETLY) +ELSE (BREAKPAD_EXCEPTION_HANDLER_FOUND) + IF (BREAKPAD_EXCEPTION_HANDLER_FIND_REQUIRED) + MESSAGE(FATAL_ERROR "Could not find Google BreakPad library") + ENDIF (BREAKPAD_EXCEPTION_HANDLER_FIND_REQUIRED) +ENDIF (BREAKPAD_EXCEPTION_HANDLER_FOUND) + +MARK_AS_ADVANCED( + BREAKPAD_EXCEPTION_HANDLER_LIBRARY + BREAKPAD_EXCEPTION_HANDLER_INCLUDE_DIR + ) diff --git a/indra/cmake/GoogleBreakpad.cmake b/indra/cmake/GoogleBreakpad.cmake new file mode 100644 index 000000000..20149c49f --- /dev/null +++ b/indra/cmake/GoogleBreakpad.cmake @@ -0,0 +1,21 @@ +# -*- cmake -*- +include(Prebuilt) + +if (STANDALONE) + set(BREAKPAD_EXCEPTION_HANDLER_FIND_REQUIRED ON) + include(FindGoogleBreakpad) +else (STANDALONE) + use_prebuilt_binary(google_breakpad) + if (DARWIN) + set(BREAKPAD_EXCEPTION_HANDLER_LIBRARIES exception_handler) + endif (DARWIN) + if (LINUX) + set(BREAKPAD_EXCEPTION_HANDLER_LIBRARIES breakpad_client) + endif (LINUX) + if (WINDOWS) + set(BREAKPAD_EXCEPTION_HANDLER_LIBRARIES exception_handler crash_generation_client crash_generation_server common) + endif (WINDOWS) + # yes, this does look dumb, no, it's not incorrect + # + set(BREAKPAD_INCLUDE_DIRECTORIES "${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include/google_breakpad" "${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include/google_breakpad/google_breakpad") +endif (STANDALONE) diff --git a/indra/cmake/LLAddBuildTest.cmake b/indra/cmake/LLAddBuildTest.cmake index 74f2e0cb1..3d42088bc 100644 --- a/indra/cmake/LLAddBuildTest.cmake +++ b/indra/cmake/LLAddBuildTest.cmake @@ -159,3 +159,23 @@ MACRO(ADD_VIEWER_COMM_BUILD_TEST name parent wrapper) ## MESSAGE(STATUS "ADD_VIEWER_COMM_BUILD_TEST ${name} wrapper = ${wrapper}") ADD_COMM_BUILD_TEST("${name}" "${parent}" "${wrapper}" llviewerprecompiledheaders.cpp) ENDMACRO(ADD_VIEWER_COMM_BUILD_TEST name parent wrapper) +MACRO(SET_TEST_PATH LISTVAR) + IF(WINDOWS) + # We typically build/package only Release variants of third-party + # libraries, so append the Release staging dir in case the library being + # sought doesn't have a debug variant. + set(${LISTVAR} ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR} ${SHARED_LIB_STAGING_DIR}/Release) + ELSEIF(DARWIN) + # We typically build/package only Release variants of third-party + # libraries, so append the Release staging dir in case the library being + # sought doesn't have a debug variant. + set(${LISTVAR} ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/Resources ${SHARED_LIB_STAGING_DIR}/Release/Resources /usr/lib) + ELSE(WINDOWS) + # Linux uses a single staging directory anyway. + IF (STANDALONE) + set(${LISTVAR} ${CMAKE_BINARY_DIR}/llcommon /usr/lib /usr/local/lib) + ELSE (STANDALONE) + set(${LISTVAR} ${SHARED_LIB_STAGING_DIR} /usr/lib) + ENDIF (STANDALONE) + ENDIF(WINDOWS) +ENDMACRO(SET_TEST_PATH) diff --git a/indra/cmake/LLSharedLibs.cmake b/indra/cmake/LLSharedLibs.cmake new file mode 100644 index 000000000..14dd67f32 --- /dev/null +++ b/indra/cmake/LLSharedLibs.cmake @@ -0,0 +1,73 @@ +# ll_deploy_sharedlibs_command +# target_exe: the cmake target of the executable for which the shared libs will be deployed. +macro(ll_deploy_sharedlibs_command target_exe) + get_target_property(TARGET_LOCATION ${target_exe} LOCATION) + get_filename_component(OUTPUT_PATH ${TARGET_LOCATION} PATH) + + if(DARWIN) + SET_TEST_PATH(SEARCH_DIRS) + get_target_property(IS_BUNDLE ${target_exe} MACOSX_BUNDLE) + if(IS_BUNDLE) + # If its a bundle the exe is not in the target location, this should find it. + get_filename_component(TARGET_FILE ${TARGET_LOCATION} NAME) + set(OUTPUT_PATH ${TARGET_LOCATION}.app/Contents/MacOS) + set(TARGET_LOCATION ${OUTPUT_PATH}/${TARGET_FILE}) + set(OUTPUT_PATH ${OUTPUT_PATH}/../Resources) + endif(IS_BUNDLE) + elseif(WINDOWS) + SET_TEST_PATH(SEARCH_DIRS) + LIST(APPEND SEARCH_DIRS "$ENV{SystemRoot}/system32") + elseif(LINUX) + SET_TEST_PATH(SEARCH_DIRS) + set(OUTPUT_PATH ${OUTPUT_PATH}/lib) + endif(DARWIN) + + add_custom_command( + TARGET ${target_exe} POST_BUILD + COMMAND ${CMAKE_COMMAND} + ARGS + "-DBIN_NAME=\"${TARGET_LOCATION}\"" + "-DSEARCH_DIRS=\"${SEARCH_DIRS}\"" + "-DDST_PATH=\"${OUTPUT_PATH}\"" + "-P" + "${CMAKE_SOURCE_DIR}/cmake/DeploySharedLibs.cmake" + ) + +endmacro(ll_deploy_sharedlibs_command) + +# ll_stage_sharedlib +# Performs config and adds a copy command for a sharedlib target. +macro(ll_stage_sharedlib DSO_TARGET) + # target gets written to the DLL staging directory. + # Also this directory is shared with RunBuildTest.cmake, y'know, for the tests. + set_target_properties(${DSO_TARGET} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${SHARED_LIB_STAGING_DIR}) + if(NOT WINDOWS) + get_target_property(DSO_PATH ${DSO_TARGET} LOCATION) + get_filename_component(DSO_FILE ${DSO_PATH} NAME) + if(DARWIN) + set(SHARED_LIB_STAGING_DIR_CONFIG ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/Resources) + else(DARWIN) + set(SHARED_LIB_STAGING_DIR_CONFIG ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}) + endif(DARWIN) + + # *TODO - maybe make this a symbolic link? -brad + add_custom_command( + TARGET ${DSO_TARGET} POST_BUILD + COMMAND ${CMAKE_COMMAND} + ARGS + -E + copy_if_different + ${DSO_PATH} + ${SHARED_LIB_STAGING_DIR_CONFIG}/${DSO_FILE} + COMMENT "Copying llcommon to the staging folder." + ) + endif(NOT WINDOWS) + + if (DARWIN) + set_target_properties(${DSO_TARGET} PROPERTIES + BUILD_WITH_INSTALL_RPATH 1 + INSTALL_NAME_DIR "@executable_path/../Resources" + ) + endif(DARWIN) + +endmacro(ll_stage_sharedlib) diff --git a/install.xml b/install.xml index 963182f91..6cedc87cb 100644 --- a/install.xml +++ b/install.xml @@ -562,6 +562,35 @@ + google_breakpad + + license + bsd + packages + + darwin + + md5sum + 723cd70d5090e448319b485b88aea379 + url + https://bitbucket.org/SingularityViewer/libraries/downloads/google_breakpad-0.0.0-rev1099-darwin-20130329.tar.bz2 + + linux + + md5sum + 849241f3b638ee90b553a2ef6346107c + url + https://bitbucket.org/SingularityViewer/libraries/downloads/google_breakpad-0.0.0-rev1099-linux-20130329.tar.bz2 + + windows + + md5sum + 7c33a10f132864f8492fd9ef9b6a4ccc + url + https://bitbucket.org/SingularityViewer/libraries/downloads/google_breakpad-0.0.0-rev1099-windows-20130813.tar.bz2 + + + gperftools copyright From 6c45bf0353bd1c9b1e0a27885e595d80723c791c Mon Sep 17 00:00:00 2001 From: Latif Khalifa Date: Tue, 1 Oct 2013 06:18:08 +0200 Subject: [PATCH 02/16] Breakpad3: Added linux64 prebuild thanks to Kokua --- install.xml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/install.xml b/install.xml index 6cedc87cb..43772ce31 100644 --- a/install.xml +++ b/install.xml @@ -582,6 +582,13 @@ url https://bitbucket.org/SingularityViewer/libraries/downloads/google_breakpad-0.0.0-rev1099-linux-20130329.tar.bz2 + linux64 + + md5sum + cf5300008895efcfcfcfacef05f32bff + url + https://bitbucket.org/SingularityViewer/libraries/downloads/google_breakpad-0.0.0-rev1099-linux64-20130506.tar.bz2 + windows md5sum From c87f7b0576c00fdd40471bcd99212f5202bf3494 Mon Sep 17 00:00:00 2001 From: Latif Khalifa Date: Tue, 1 Oct 2013 13:43:45 +0200 Subject: [PATCH 03/16] Breakpad3: WIP, minidump files created TODO: re-work sending crash logs get rid of standalone loggers --- indra/cmake/00-Common.cmake | 2 +- indra/llcommon/CMakeLists.txt | 3 + indra/llcommon/llapp.cpp | 387 +++++++- indra/llcommon/llapp.h | 68 +- indra/llcommon/llframetimer.h | 1 + indra/llcrashlogger/CMakeLists.txt | 2 + indra/llcrashlogger/llcrashlock.cpp | 211 +++++ indra/llcrashlogger/llcrashlock.h | 73 ++ indra/llcrashlogger/llcrashlogger.cpp | 468 +++++++--- indra/llcrashlogger/llcrashlogger.h | 66 +- indra/llmessage/aihttptimeoutpolicy.cpp | 3 +- indra/llvfs/lldir.cpp | 79 +- indra/llvfs/lldir.h | 7 +- indra/newview/app_settings/settings.xml | 11 + .../app_settings/settings_crash_behavior.xml | 2 +- indra/newview/llappviewer.cpp | 204 ++--- indra/newview/llappviewer.h | 8 +- indra/newview/llappviewerwin32.cpp | 140 ++- indra/newview/llappviewerwin32.h | 4 +- indra/newview/llwindebug.cpp | 848 ++---------------- indra/newview/llwindebug.h | 72 +- indra/win_crash_logger/CMakeLists.txt | 20 +- indra/win_crash_logger/StdAfx.cpp | 36 +- indra/win_crash_logger/StdAfx.h | 37 +- .../win_crash_logger/llcrashloggerwindows.cpp | 229 ++++- indra/win_crash_logger/llcrashloggerwindows.h | 71 +- indra/win_crash_logger/resource.h | 36 +- indra/win_crash_logger/win_crash_logger.cpp | 81 +- indra/win_crash_logger/win_crash_logger.h | 36 +- 29 files changed, 1745 insertions(+), 1460 deletions(-) create mode 100644 indra/llcrashlogger/llcrashlock.cpp create mode 100644 indra/llcrashlogger/llcrashlock.h diff --git a/indra/cmake/00-Common.cmake b/indra/cmake/00-Common.cmake index e8ce73f7d..92c75a2a6 100644 --- a/indra/cmake/00-Common.cmake +++ b/indra/cmake/00-Common.cmake @@ -16,7 +16,7 @@ set(CMAKE_CXX_FLAGS_RELEASE set(CMAKE_C_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}") set(CMAKE_CXX_FLAGS_RELWITHDEBINFO - "-DLL_RELEASE=1 -D_SECURE_SCL=0 -DLL_SEND_CRASH_REPORTS=0 -DNDEBUG -DLL_RELEASE_WITH_DEBUG_INFO=1") + "-DLL_RELEASE=1 -D_SECURE_SCL=0 -DLL_SEND_CRASH_REPORTS=1 -DNDEBUG -DLL_RELEASE_WITH_DEBUG_INFO=1") # Don't bother with a MinSizeRel build. diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index 6f93be79e..3d71566c7 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -7,11 +7,13 @@ include(00-Common) include(LLCommon) include(APR) include(Linking) +include(GoogleBreakpad) include_directories( ${EXPAT_INCLUDE_DIRS} ${LLCOMMON_INCLUDE_DIRS} ${ZLIB_INCLUDE_DIRS} + ${BREAKPAD_INCLUDE_DIRECTORIES} ) set(llcommon_SOURCE_FILES @@ -265,6 +267,7 @@ add_library (llcommon SHARED ${llcommon_SOURCE_FILES}) add_dependencies(llcommon prepare) target_link_libraries( llcommon + ${BREAKPAD_EXCEPTION_HANDLER_LIBRARIES} ${APRUTIL_LIBRARIES} ${APR_LIBRARIES} ${EXPAT_LIBRARIES} diff --git a/indra/llcommon/llapp.cpp b/indra/llcommon/llapp.cpp index a11effc15..0c494a56a 100644 --- a/indra/llcommon/llapp.cpp +++ b/indra/llcommon/llapp.cpp @@ -27,6 +27,14 @@ #include "linden_common.h" #include "llapp.h" +#include + +#ifdef LL_DARWIN +#include +#include +#include +#endif + #include "llcommon.h" #include "llapr.h" #include "llerrorcontrol.h" @@ -35,7 +43,9 @@ #include "lllivefile.h" #include "llmemory.h" #include "llstl.h" // for DeletePointer() +#include "llstring.h" #include "lleventtimer.h" +#include "google_breakpad/exception_handler.h" // // Signal handling @@ -43,13 +53,34 @@ // Windows uses structured exceptions, so it's handled a bit differently. // #if LL_WINDOWS +#include "windows.h" + LONG WINAPI default_windows_exception_handler(struct _EXCEPTION_POINTERS *exception_infop); BOOL ConsoleCtrlHandler(DWORD fdwCtrlType); +bool windows_post_minidump_callback(const wchar_t* dump_path, + const wchar_t* minidump_id, + void* context, + EXCEPTION_POINTERS* exinfo, + MDRawAssertionInfo* assertion, + bool succeeded); #else # include # include // for fork() void setup_signals(); void default_unix_signal_handler(int signum, siginfo_t *info, void *); + +#if LL_LINUX +#include "google_breakpad/minidump_descriptor.h" +static bool unix_minidump_callback(const google_breakpad::MinidumpDescriptor& minidump_desc, + void* context, + bool succeeded); +#else +// Called by breakpad exception handler after the minidump has been generated. +bool unix_post_minidump_callback(const char *dump_dir, + const char *minidump_id, + void *context, bool succeeded); +#endif + # if LL_DARWIN /* OSX doesn't support SIGRT* */ S32 LL_SMACKDOWN_SIGNAL = SIGUSR1; @@ -79,7 +110,6 @@ BOOL LLApp::sLogInSignal = FALSE; // static LLApp::EAppStatus LLApp::sStatus = LLApp::APP_STATUS_STOPPED; // Keeps track of application status LLAppErrorHandler LLApp::sErrorHandler = NULL; -LLAppErrorHandler LLApp::sSyncErrorHandler = NULL; BOOL LLApp::sErrorThreadRunning = FALSE; #if !LL_WINDOWS LLApp::child_map LLApp::sChildMap; @@ -100,14 +130,6 @@ void LLApp::commonCtor() LLCommon::initClass(); -#if !LL_WINDOWS - // This must be initialized before the error handler. - sSigChildCount = new LLAtomicU32(0); -#endif - - // Setup error handling - setupErrorHandling(); - // initialize the options structure. We need to make this an array // because the structured data will not auto-allocate if we // reference an invalid location with the [] operator. @@ -118,8 +140,19 @@ void LLApp::commonCtor() mOptions.append(sd); } + // Make sure we clean up APR when we exit + // Don't need to do this if we're cleaning up APR in the destructor + //atexit(ll_cleanup_apr); + // Set the application to this instance. sApplication = this; + + mExceptionHandler = 0; + + // initialize the buffer to write the minidump filename to + // (this is used to avoid allocating memory in the crash handler) + memset(mMinidumpPath, 0, MAX_MINDUMP_PATH_LENGTH); + mCrashReportPipeStr = L"\\\\.\\pipe\\LLCrashReporterPipe"; } LLApp::LLApp(LLErrorThread *error_thread) : @@ -131,10 +164,6 @@ LLApp::LLApp(LLErrorThread *error_thread) : LLApp::~LLApp() { -#if !LL_WINDOWS - delete sSigChildCount; - sSigChildCount = NULL; -#endif // reclaim live file memory std::for_each(mLiveFiles.begin(), mLiveFiles.end(), DeletePointer()); @@ -148,6 +177,8 @@ LLApp::~LLApp() delete mThreadErrorp; mThreadErrorp = NULL; } + + if(mExceptionHandler != 0) delete mExceptionHandler; LLCommon::cleanupClass(); } @@ -207,6 +238,20 @@ bool LLApp::parseCommandOptions(int argc, char** argv) } ++ii; value.assign(argv[ii]); + +#if LL_WINDOWS + //Windows changed command line parsing. Deal with it. + S32 slen = value.length() - 1; + S32 start = 0; + S32 end = slen; + if (argv[ii][start]=='"')start++; + if (argv[ii][end]=='"')end--; + if (start!=0 || end!=slen) + { + value = value.substr (start,end); + } +#endif + commands[name] = value; } setOptionData(PRIORITY_COMMAND_LINE, commands); @@ -254,14 +299,60 @@ void LLApp::setupErrorHandling() // What we do is install an unhandled exception handler, which will try to do the right thing // in the case of an error (generate a minidump) - // Disable this until the viewer gets ported so server crashes can be JIT debugged. - //LPTOP_LEVEL_EXCEPTION_FILTER prev_filter; - //prev_filter = SetUnhandledExceptionFilter(default_windows_exception_handler); - +#if LL_SEND_CRASH_REPORTS // This sets a callback to handle w32 signals to the console window. // The viewer shouldn't be affected, sicne its a windowed app. SetConsoleCtrlHandler( (PHANDLER_ROUTINE) ConsoleCtrlHandler, TRUE); + // Install the Google Breakpad crash handler for Windows + if(mExceptionHandler == 0) + { + llwarns << "adding breakpad exception handler" << llendl; + + std::wostringstream ws; + ws << mCrashReportPipeStr << getPid(); + std::wstring wpipe_name = ws.str(); + std::string ptmp = std::string(wpipe_name.begin(), wpipe_name.end()); + + ::Sleep(2000); //HACK hopefully a static wait won't blow up in my face before google fixes their implementation. + + //HACK this for loop is ueless. Breakpad dumbly returns success when the OOP handler isn't initialized. + for (int retries=0;retries<5;++retries) + { + mExceptionHandler = new google_breakpad::ExceptionHandler( + L"", + NULL, //No filter + windows_post_minidump_callback, + 0, + google_breakpad::ExceptionHandler::HANDLER_ALL, + MiniDumpNormal, //Generate a 'normal' minidump. + (WCHAR *)wpipe_name.c_str(), + NULL); //No custom client info. + if (mExceptionHandler) + { + break; + } + else + { + ::Sleep(100); //Wait a tick and try again. + } + } + if (!mExceptionHandler) + { + llwarns << "Failed to initialize OOP exception handler. Defaulting to In Process handling" << llendl; + mExceptionHandler = new google_breakpad::ExceptionHandler( + std::wstring(mDumpPath.begin(),mDumpPath.end()), //Dump path + 0, //dump filename + windows_post_minidump_callback, + 0, + google_breakpad::ExceptionHandler::HANDLER_ALL); + } + if (mExceptionHandler) + { + mExceptionHandler->set_handle_debug_exceptions(true); + } + } +#endif #else // // Start up signal handling. @@ -271,9 +362,61 @@ void LLApp::setupErrorHandling() // setup_signals(); + + // Add google breakpad exception handler configured for Darwin/Linux. + bool installHandler = true; +#if LL_DARWIN + // For the special case of Darwin, we do not want to install the handler if + // the process is being debugged as the app will exit with value ABRT (6) if + // we do. Unfortunately, the code below which performs that test relies on + // the structure kinfo_proc which has been tagged by apple as an unstable + // API. We disable this test for shipping versions to avoid conflicts with + // future releases of Darwin. This test is really only needed for developers + // starting the app from a debugger anyway. + #ifndef LL_RELEASE_FOR_DOWNLOAD + int mib[4]; + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PID; + mib[3] = getpid(); + + struct kinfo_proc info; + memset(&info, 0, sizeof(info)); + + size_t size = sizeof(info); + int result = sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0); + if((result == 0) || (errno == ENOMEM)) + { + // P_TRACED flag is set, so this process is being debugged; do not install + // the handler + if(info.kp_proc.p_flag & P_TRACED) installHandler = false; + } + else + { + // Failed to discover if the process is being debugged; default to + // installing the handler. + installHandler = true; + } + #endif + if(installHandler && (mExceptionHandler == 0)) + { + mExceptionHandler = new google_breakpad::ExceptionHandler(mDumpPath, 0, &unix_post_minidump_callback, 0, true, 0); + } +#elif LL_LINUX + if(installHandler && (mExceptionHandler == 0)) + { + if (mDumpPath.empty()) + { + mDumpPath = "/tmp"; + } + google_breakpad::MinidumpDescriptor desc(mDumpPath); + //mExceptionHandler = new google_breakpad::ExceptionHandler(desc, 0, unix_minidump_callback, 0, true, 0); + mExceptionHandler = new google_breakpad::ExceptionHandler(desc, NULL, unix_minidump_callback, NULL, true, -1); + } #endif +#endif } void LLApp::startErrorThread() @@ -311,20 +454,6 @@ void LLApp::setErrorHandler(LLAppErrorHandler handler) } -void LLApp::setSyncErrorHandler(LLAppErrorHandler handler) -{ - LLApp::sSyncErrorHandler = handler; -} - -// static -void LLApp::runSyncErrorHandler() -{ - if (LLApp::sSyncErrorHandler) - { - LLApp::sSyncErrorHandler(); - } -} - // static void LLApp::runErrorHandler() { @@ -348,15 +477,46 @@ void LLApp::setStatus(EAppStatus status) // static void LLApp::setError() { - if (!isError()) - { - // perform any needed synchronous error-handling - runSyncErrorHandler(); - // set app status to ERROR so that the LLErrorThread notices - setStatus(APP_STATUS_ERROR); - } + // set app status to ERROR so that the LLErrorThread notices + setStatus(APP_STATUS_ERROR); } +void LLApp::setMiniDumpDir(const std::string &path) +{ + if (path.empty()) + { + mDumpPath = "/tmp"; + } + else + { + mDumpPath = path; + } + + if(mExceptionHandler == 0) return; +#ifdef LL_WINDOWS + wchar_t buffer[MAX_MINDUMP_PATH_LENGTH]; + mbstowcs(buffer, mDumpPath.c_str(), MAX_MINDUMP_PATH_LENGTH); + mExceptionHandler->set_dump_path(std::wstring(buffer)); +#elif LL_LINUX + //google_breakpad::MinidumpDescriptor desc("/tmp"); //path works in debug fails in production inside breakpad lib so linux gets a little less stack reporting until it is patched. + google_breakpad::MinidumpDescriptor desc(mDumpPath); //path works in debug fails in production inside breakpad lib so linux gets a little less stack reporting until it is patched. + mExceptionHandler->set_minidump_descriptor(desc); +#else + mExceptionHandler->set_dump_path(mDumpPath); +#endif +} + +void LLApp::setDebugFileNames(const std::string &path) +{ + mStaticDebugFileName = path + "static_debug_info.log"; + mDynamicDebugFileName = path + "dynamic_debug_info.log"; +} + +void LLApp::writeMiniDump() +{ + if(mExceptionHandler == 0) return; + mExceptionHandler->WriteMinidump(); +} // static void LLApp::setQuitting() @@ -413,6 +573,12 @@ bool LLApp::isExiting() void LLApp::disableCrashlogger() { // Disable Breakpad exception handler. + if (mExceptionHandler != 0) + { + delete mExceptionHandler; + mExceptionHandler = 0; + } + sDisableCrashlogger = TRUE; } @@ -787,4 +953,149 @@ void default_unix_signal_handler(int signum, siginfo_t *info, void *) } } +#if LL_LINUX +bool unix_minidump_callback(const google_breakpad::MinidumpDescriptor& minidump_desc, void* context, bool succeeded) +{ + // Copy minidump file path into fixed buffer in the app instance to avoid + // heap allocations in a crash handler. + + // path format: /.dmp + + //HACK: *path points to the buffer in getMiniDumpFilename which has already allocated space + //to avoid doing allocation during crash. + char * path = LLApp::instance()->getMiniDumpFilename(); + int dir_path_len = strlen(path); + + // The path must not be truncated. + S32 remaining = LLApp::MAX_MINDUMP_PATH_LENGTH - dir_path_len; + + llassert( (remaining - strlen(minidump_desc.path())) > 5); + + path += dir_path_len; + + if (dir_path_len > 0 && path[-1] != '/') + { + *path++ = '/'; + --remaining; + } + + strncpy(path, minidump_desc.path(), remaining); + + llinfos << "generated minidump: " << LLApp::instance()->getMiniDumpFilename() << llendl; + LLApp::runErrorHandler(); + +#ifndef LL_RELEASE_FOR_DOWNLOAD + clear_signals(); + return false; +#else + return true; +#endif + +} +#endif + + +bool unix_post_minidump_callback(const char *dump_dir, + const char *minidump_id, + void *context, bool succeeded) +{ + // Copy minidump file path into fixed buffer in the app instance to avoid + // heap allocations in a crash handler. + + // path format: /.dmp + int dirPathLength = strlen(dump_dir); + int idLength = strlen(minidump_id); + + // The path must not be truncated. + llassert((dirPathLength + idLength + 5) <= LLApp::MAX_MINDUMP_PATH_LENGTH); + + char * path = LLApp::instance()->getMiniDumpFilename(); + S32 remaining = LLApp::MAX_MINDUMP_PATH_LENGTH; + strncpy(path, dump_dir, remaining); + remaining -= dirPathLength; + path += dirPathLength; + if (remaining > 0 && dirPathLength > 0 && path[-1] != '/') + { + *path++ = '/'; + --remaining; + } + if (remaining > 0) + { + strncpy(path, minidump_id, remaining); + remaining -= idLength; + path += idLength; + strncpy(path, ".dmp", remaining); + } + + llinfos << "generated minidump: " << path << llendl; + LLApp::runErrorHandler(); + +#ifndef LL_RELEASE_FOR_DOWNLOAD + clear_signals(); + return false; +#else + return true; +#endif +} #endif // !WINDOWS + +#ifdef LL_WINDOWS +bool windows_post_minidump_callback(const wchar_t* dump_path, + const wchar_t* minidump_id, + void* context, + EXCEPTION_POINTERS* exinfo, + MDRawAssertionInfo* assertion, + bool succeeded) +{ + char * path = LLApp::instance()->getMiniDumpFilename(); + S32 remaining = LLApp::MAX_MINDUMP_PATH_LENGTH; + size_t bytesUsed; + + bytesUsed = wcstombs(path, dump_path, static_cast(remaining)); + remaining -= bytesUsed; + path += bytesUsed; + if(remaining > 0 && bytesUsed > 0 && path[-1] != '\\') + { + *path++ = '\\'; + --remaining; + } + if(remaining > 0) + { + bytesUsed = wcstombs(path, minidump_id, static_cast(remaining)); + remaining -= bytesUsed; + path += bytesUsed; + } + if(remaining > 0) + { + strncpy(path, ".dmp", remaining); + } + + llinfos << "generated minidump: " << LLApp::instance()->getMiniDumpFilename() << llendl; + // *NOTE:Mani - this code is stolen from LLApp, where its never actually used. + //OSMessageBox("Attach Debugger Now", "Error", OSMB_OK); + // *TODO: Translate the signals/exceptions into cross-platform stuff + // Windows implementation + llinfos << "Entering Windows Exception Handler..." << llendl; + + if (LLApp::isError()) + { + llwarns << "Got another fatal signal while in the error handler, die now!" << llendl; + } + + // Flag status to error, so thread_error starts its work + LLApp::setError(); + + // Block in the exception handler until the app has stopped + // This is pretty sketchy, but appears to work just fine + while (!LLApp::isStopped()) + { + ms_sleep(10); + } + +#ifndef LL_RELEASE_FOR_DOWNLOAD + return false; +#else + return true; +#endif +} +#endif diff --git a/indra/llcommon/llapp.h b/indra/llcommon/llapp.h index d56e20800..aab871799 100644 --- a/indra/llcommon/llapp.h +++ b/indra/llcommon/llapp.h @@ -37,14 +37,10 @@ template class LLAtomic32; typedef LLAtomic32 LLAtomicU32; class LLErrorThread; class LLLiveFile; - - #if LL_LINUX - #include - //typedef struct siginfo siginfo_t; //Removed as per changes in glibc 2.16 - Drake Arconis +#include #endif - typedef void (*LLAppErrorHandler)(); typedef void (*LLAppChildCallback)(int pid, bool exited, int status); @@ -64,6 +60,10 @@ public: }; #endif +namespace google_breakpad { + class ExceptionHandler; // See exception_handler.h +} + class LL_COMMON_API LLApp : public LLOptionInterface { friend class LLErrorThread; @@ -212,11 +212,43 @@ public: #endif static int getPid(); - // - // Error handling methods - // + /** @name Error handling methods */ + //@{ + /** + * @brief Do our generic platform-specific error-handling setup -- + * signals on unix, structured exceptions on windows. + * + * DO call this method if your app will either spawn children or be + * spawned by a launcher. + * Call just after app object construction. + * (Otherwise your app will crash when getting signals, + * and will not core dump.) + * + * DO NOT call this method if your application has specialized + * error handling code. + */ + void setupErrorHandling(); + void setErrorHandler(LLAppErrorHandler handler); - void setSyncErrorHandler(LLAppErrorHandler handler); + static void runErrorHandler(); // run shortly after we detect an error, ran in the relatively robust context of the LLErrorThread - preferred. + //@} + + // the maximum length of the minidump filename returned by getMiniDumpFilename() + static const U32 MAX_MINDUMP_PATH_LENGTH = 256; + + // change the directory where Breakpad minidump files are written to + void setMiniDumpDir(const std::string &path); + void setDebugFileNames(const std::string &path); + + // Return the Google Breakpad minidump filename after a crash. + char *getMiniDumpFilename() { return mMinidumpPath; } + std::string* getStaticDebugFile() { return &mStaticDebugFileName; } + std::string* getDynamicDebugFile() { return &mDynamicDebugFileName; } + + // Write out a Google Breakpad minidump file. + void writeMiniDump(); + + #if !LL_WINDOWS // // Child process handling (Unix only for now) @@ -236,6 +268,7 @@ public: pid_t fork(); #endif + public: typedef std::map string_map; string_map mOptionMap; // Contains all command-line options and arguments in a map @@ -246,6 +279,9 @@ protected: static EAppStatus sStatus; // Reflects current application status static BOOL sErrorThreadRunning; // Set while the error thread is running static BOOL sDisableCrashlogger; // Let the OS handle crashes for us. + std::wstring mCrashReportPipeStr; //Name of pipe to use for crash reporting. + + std::string mDumpPath; //output path for google breakpad. Dependency workaround. #if !LL_WINDOWS static LLAtomicU32* sSigChildCount; // Number of SIGCHLDs received. @@ -254,26 +290,25 @@ protected: static LLAppChildCallback sDefaultChildCallback; #endif - /** - * @ brief This method is called once as soon as logging is initialized. - */ void startErrorThread(); + /** * @brief This method is called at the end, just prior to deinitializing curl. */ void stopErrorThread(); private: - void setupErrorHandling(); // Do platform-specific error-handling setup (signals, structured exceptions) - static void runErrorHandler(); // run shortly after we detect an error, ran in the relatively robust context of the LLErrorThread - preferred. - static void runSyncErrorHandler(); // run IMMEDIATELY when we get an error, ran in the context of the faulting thread. + // Contains the filename of the minidump file after a crash. + char mMinidumpPath[MAX_MINDUMP_PATH_LENGTH]; + + std::string mStaticDebugFileName; + std::string mDynamicDebugFileName; // *NOTE: On Windows, we need a routine to reset the structured // exception handler when some evil driver has taken it over for // their own purposes typedef int(*signal_handler_func)(int signum); static LLAppErrorHandler sErrorHandler; - static LLAppErrorHandler sSyncErrorHandler; // Default application threads LLErrorThread* mThreadErrorp; // Waits for app to go to status ERROR, then runs the error callback @@ -291,6 +326,7 @@ private: private: // the static application instance if it was created. static LLApp* sApplication; + google_breakpad::ExceptionHandler * mExceptionHandler; #if !LL_WINDOWS diff --git a/indra/llcommon/llframetimer.h b/indra/llcommon/llframetimer.h index b09937895..2813150c5 100644 --- a/indra/llcommon/llframetimer.h +++ b/indra/llcommon/llframetimer.h @@ -127,6 +127,7 @@ public: mRunning = false; } + void resetWithExpiry(F32 expiration) { reset(); setTimerExpirySec(expiration); } void pause(); // Mark elapsed time so far. void unpause(); // Move 'start' time in order to decrement time between pause and unpause from ElapsedTime. diff --git a/indra/llcrashlogger/CMakeLists.txt b/indra/llcrashlogger/CMakeLists.txt index a20e42a8d..61191b37c 100644 --- a/indra/llcrashlogger/CMakeLists.txt +++ b/indra/llcrashlogger/CMakeLists.txt @@ -19,12 +19,14 @@ include_directories( set(llcrashlogger_SOURCE_FILES llcrashlogger.cpp + llcrashlock.cpp ) set(llcrashlogger_HEADER_FILES CMakeLists.txt llcrashlogger.h + llcrashlock.h ) set_source_files_properties(${llcrashlogger_HEADER_FILES} diff --git a/indra/llcrashlogger/llcrashlock.cpp b/indra/llcrashlogger/llcrashlock.cpp new file mode 100644 index 000000000..82033f73e --- /dev/null +++ b/indra/llcrashlogger/llcrashlock.cpp @@ -0,0 +1,211 @@ +/** + * @file llformat.cpp + * @date January 2007 + * @brief string formatting utility + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "llcrashlock.h" +#include "lldir.h" +#include "llsd.h" +#include "llsdserialize.h" +#include "llnametable.h" +#include "llframetimer.h" +#include +#include +#include +#include + + +#if LL_WINDOWS //For windows platform. +#include +#include + +/* +namespace { + inline DWORD getpid() { + return GetCurrentProcessId(); + } +} +*/ + +bool LLCrashLock::isProcessAlive(U32 pid, const std::string& pname) +{ + std::wstring wpname; + wpname = std::wstring(pname.begin(), pname.end()); + + HANDLE snapshot; + PROCESSENTRY32 pe32; + + bool matched = false; + + snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + if (snapshot == INVALID_HANDLE_VALUE) + { + return false; + } + else + { + pe32.dwSize = sizeof(PROCESSENTRY32); + if (Process32First(snapshot, &pe32)) + { + do { + std::wstring wexecname = pe32.szExeFile; + std::string execname = std::string(wexecname.begin(), wexecname.end()); + if (!wpname.compare(pe32.szExeFile)) + { + if (pid == (U32)pe32.th32ProcessID) + { + matched = true; + break; + } + } + } while (Process32Next(snapshot, &pe32)); + } + } + + CloseHandle(snapshot); + return matched; +} + +#else //Everyone Else +bool LLCrashLock::isProcessAlive(U32 pid, const std::string& pname) +{ + //Will boost.process ever become a reality? + std::stringstream cmd; + + cmd << "pgrep '" << pname << "' | grep '^" << pid << "$'"; + return (!system(cmd.str().c_str())); +} +#endif //Everyone else. + + +LLCrashLock::LLCrashLock() : mCleanUp(true), mWaitingPID(0) +{ +} + +void LLCrashLock::setCleanUp(bool cleanup) +{ + mCleanUp = cleanup; //Allow cleanup to be disabled for debugging. +} + +LLSD LLCrashLock::getLockFile(std::string filename) +{ + LLSD lock_sd = LLSD::emptyMap(); + + llifstream ifile(filename); + + if (ifile.is_open()) + { + LLSDSerialize::fromXML(lock_sd, ifile); + ifile.close(); + } + + return lock_sd; +} + +bool LLCrashLock::putLockFile(std::string filename, const LLSD& data) +{ + bool result = true; + llofstream ofile(filename); + + if (!LLSDSerialize::toXML(data,ofile)) + { + result=false; + } + ofile.close(); + return result; +} + +bool LLCrashLock::requestMaster( F32 timeout ) +{ + if (mMaster.empty()) + { + mMaster = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, + "crash_master.lock"); + } + + LLSD lock_sd=getLockFile(mMaster); + + if (lock_sd.has("pid")) + { + mWaitingPID = lock_sd["pid"].asInteger(); + if ( isProcessAlive(mWaitingPID, gDirUtilp->getExecutableFilename()) ) + { + mTimer.resetWithExpiry(timeout); + return false; + } + } + + U32 pid = getpid(); + lock_sd["pid"] = (LLSD::Integer)pid; + return putLockFile(mMaster,lock_sd); +} + +bool LLCrashLock::checkMaster() +{ + if (mWaitingPID) + { + return (!isProcessAlive(mWaitingPID, gDirUtilp->getExecutableFilename())); + } + return false; +} + +bool LLCrashLock::isWaiting() +{ + return !mTimer.hasExpired(); +} + +void LLCrashLock::releaseMaster() +{ + //Yeeeeeeehaw + unlink(mMaster.c_str()); +} + +LLSD LLCrashLock::getProcessList() +{ + if (mDumpTable.empty()) + { + mDumpTable= gDirUtilp->getExpandedFilename(LL_PATH_LOGS, + "crash_table.lock"); + } + return getLockFile(mDumpTable); +} + +//static +bool LLCrashLock::fileExists(std::string filename) +{ + return boost::filesystem::exists(filename.c_str()); +} + +void LLCrashLock::cleanupProcess(std::string proc_dir) +{ + boost::filesystem::remove_all(proc_dir); +} + +bool LLCrashLock::putProcessList(const LLSD& proc_sd) +{ + return putLockFile(mDumpTable,proc_sd); +} diff --git a/indra/llcrashlogger/llcrashlock.h b/indra/llcrashlogger/llcrashlock.h new file mode 100644 index 000000000..cde183272 --- /dev/null +++ b/indra/llcrashlogger/llcrashlock.h @@ -0,0 +1,73 @@ +/** + * @file llpidlock.h + * @brief Maintainence of disk locking files for crash reporting + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_CRASHLOCK_H +#define LL_CRASHLOCK_H + +#include "llframetimer.h" + +class LLSD; + +#if !LL_WINDOWS //For non-windows platforms. +#include +#endif + +//Crash reporter will now be kicked off by the viewer but otherwise +//run independent of the viewer. + +class LLCrashLock +{ +public: + LLCrashLock(); + bool requestMaster( F32 timeout=300.0); //Wait until timeout for master lock. + bool checkMaster(); //True if available. False if not. + void releaseMaster( ); //Release master lockfile. + bool isLockPresent(std::string filename); //Check if lockfile exists. + bool isProcessAlive(U32 pid, const std::string& pname); //Check if pid is alive. + bool isWaiting(); //Waiting for master lock to be released. + LLSD getProcessList(); //Get next process pid/dir pairs + void cleanupProcess(std::string proc_dir); //Remove from list, clean up working dir. + bool putProcessList(const LLSD& processlist); //Write pid/dir pairs back to disk. + static bool fileExists(std::string filename); + + + //getters + S32 getPID(); + + //setters + void setCleanUp(bool cleanup=true); + void setSaveName(std::string savename); +private: + LLSD getLockFile(std::string filename); + bool putLockFile(std::string filename, const LLSD& data); + bool mCleanUp; + std::string mMaster; + std::string mDumpTable; + U32 mWaitingPID; //The process we're waiting on if any. + LLFrameTimer mTimer; +}; + +#endif // LL_CRASHLOCK_H diff --git a/indra/llcrashlogger/llcrashlogger.cpp b/indra/llcrashlogger/llcrashlogger.cpp index e072b5c79..97feae14c 100644 --- a/indra/llcrashlogger/llcrashlogger.cpp +++ b/indra/llcrashlogger/llcrashlogger.cpp @@ -2,62 +2,58 @@ * @file llcrashlogger.cpp * @brief Crash logger implementation * -* $LicenseInfo:firstyear=2003&license=viewergpl$ -* -* Copyright (c) 2003-2009, Linden Research, Inc. -* +* $LicenseInfo:firstyear=2003&license=viewerlgpl$ * Second Life Viewer Source Code -* The source code in this file ("Source Code") is provided by Linden Lab -* to you under the terms of the GNU General Public License, version 2.0 -* ("GPL"), unless you have obtained a separate licensing agreement -* ("Other License"), formally executed by you and Linden Lab. Terms of -* the GPL can be found in doc/GPL-license.txt in this distribution, or -* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 +* Copyright (C) 2010, Linden Research, Inc. * -* There are special exceptions to the terms and conditions of the GPL as -* it is applied to this Source Code. View the full text of the exception -* in the file doc/FLOSS-exception.txt in this software distribution, or -* online at -* http://secondlifegrid.net/programs/open_source/licensing/flossexception +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. * -* By copying, modifying or distributing this software, you acknowledge -* that you have read and understood your obligations described above, -* and agree to abide by those obligations. +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. * -* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO -* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, -* COMPLETENESS OR PERFORMANCE. +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ - -#include "linden_common.h" - #include #include #include #include #include "llcrashlogger.h" +#include "llcrashlock.h" +#include "linden_common.h" #include "llstring.h" -#include "indra_constants.h" // CRASH_BEHAVIOR_ASK, CRASH_SETTING_NAME +#include "indra_constants.h" // CRASH_BEHAVIOR_... #include "llerror.h" +#include "llerrorcontrol.h" #include "lltimer.h" #include "lldir.h" +#include "llfile.h" #include "llsdserialize.h" #include "lliopipe.h" #include "llpumpio.h" #include "llhttpclient.h" #include "llsdserialize.h" -#include "llcurl.h" +#include "llproxy.h" #include "aistatemachine.h" LLPumpIO* gServicePump; BOOL gBreak = false; BOOL gSent = false; +extern void startEngineThread(void); + class AIHTTPTimeoutPolicy; extern AIHTTPTimeoutPolicy crashLoggerResponder_timeout; -extern void startEngineThread(void); class LLCrashLoggerResponder : public LLHTTPClient::ResponderWithResult { @@ -66,42 +62,35 @@ public: { } - /*virtual*/ void error(U32 status, const std::string& reason) + virtual void error(U32 status, const std::string& reason) { - gBreak = true; + gBreak = true; } - /*virtual*/ void result(const LLSD& content) - { + virtual void result(const LLSD& content) + { gBreak = true; gSent = true; } - /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return crashLoggerResponder_timeout; } - /*virtual*/ char const* getName(void) const { return "LLCrashLoggerResponder"; } + virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const + { + return crashLoggerResponder_timeout; + } + + virtual char const* getName(void) const + { + return "LLCrashLoggerResponder"; + } }; -bool LLCrashLoggerText::mainLoop() -{ - std::cout << "Entering main loop" << std::endl; - sendCrashLogs(); - return true; -} - -void LLCrashLoggerText::updateApplication(const std::string& message) -{ - LLCrashLogger::updateApplication(message); - std::cout << message << std::endl; -} - LLCrashLogger::LLCrashLogger() : - mCrashBehavior(CRASH_BEHAVIOR_ASK), + mCrashBehavior(CRASH_BEHAVIOR_ALWAYS_SEND), mCrashInPreviousExec(false), + mCrashSettings("CrashSettings"), mSentCrashLogs(false), - mCrashHost(""), - mCrashSettings("CrashSettings") + mCrashHost("") { - } LLCrashLogger::~LLCrashLogger() @@ -163,38 +152,67 @@ std::string getStartupStateFromLog(std::string& sllog) return startup_state; } -void LLCrashLogger::gatherFiles() +bool LLCrashLogger::readDebugFromXML(LLSD& dest, const std::string& filename ) { - - /* - //TODO:This function needs to be reimplemented somewhere in here... - if(!previous_crash && is_crash_log) - { - // Make sure the file isn't too old. - double age = difftime(gLaunchTime, stat_data.st_mtimespec.tv_sec); - - // llinfos << "age is " << age << llendl; - - if(age > 60.0) - { - // The file was last modified more than 60 seconds before the crash reporter was launched. Assume it's stale. - llwarns << "File " << mFilename << " is too old!" << llendl; - return; - } - } - */ - - updateApplication("Gathering logs..."); - - // Figure out the filename of the debug log - std::string db_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"debug_info.log"); - std::ifstream debug_log_file(db_file_name.c_str()); - + std::string db_file_name = gDirUtilp->getExpandedFilename(LL_PATH_DUMP,filename); + std::ifstream debug_log_file(db_file_name.c_str()); + // Look for it in the debug_info.log file if (debug_log_file.is_open()) - { - LLSDSerialize::fromXML(mDebugLog, debug_log_file); + { + LLSDSerialize::fromXML(dest, debug_log_file); + debug_log_file.close(); + return true; + } + return false; +} +void LLCrashLogger::mergeLogs( LLSD src_sd ) +{ + LLSD::map_iterator iter = src_sd.beginMap(); + LLSD::map_iterator end = src_sd.endMap(); + for( ; iter != end; ++iter) + { + mDebugLog[iter->first] = iter->second; + } +} + +bool LLCrashLogger::readMinidump(std::string minidump_path) +{ + size_t length=0; + + std::ifstream minidump_stream(minidump_path.c_str(), std::ios_base::in | std::ios_base::binary); + if(minidump_stream.is_open()) + { + minidump_stream.seekg(0, std::ios::end); + length = (size_t)minidump_stream.tellg(); + minidump_stream.seekg(0, std::ios::beg); + + LLSD::Binary data; + data.resize(length); + + minidump_stream.read(reinterpret_cast(&(data[0])),length); + minidump_stream.close(); + + mCrashInfo["Minidump"] = data; + } + return (length>0?true:false); +} + +void LLCrashLogger::gatherFiles() +{ + updateApplication("Gathering logs..."); + + LLSD static_sd; + LLSD dynamic_sd; + + bool has_logs = readDebugFromXML( static_sd, "static_debug_info.log" ); + has_logs |= readDebugFromXML( dynamic_sd, "dynamic_debug_info.log" ); + + if ( has_logs ) + { + mDebugLog = static_sd; + mergeLogs(dynamic_sd); mCrashInPreviousExec = mDebugLog["CrashNotHandled"].asBoolean(); mFileMap["SecondLifeLog"] = mDebugLog["SLLog"].asString(); @@ -219,11 +237,9 @@ void LLCrashLogger::gatherFiles() mFileMap["SettingsXml"] = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS,"settings.xml"); } -#if !LL_DARWIN if(mCrashInPreviousExec) -#else -#endif { + // Restarting after freeze. // Replace the log file ext with .old, since the // instance that launched this process has overwritten // SecondLife.log @@ -235,7 +251,12 @@ void LLCrashLogger::gatherFiles() gatherPlatformSpecificFiles(); //Use the debug log to reconstruct the URL to send the crash report to - if(mDebugLog.has("CurrentSimHost")) + if(mDebugLog.has("CrashHostUrl")) + { + // Crash log receiver has been manually configured. + mCrashHost = mDebugLog["CrashHostUrl"].asString(); + } + else if(mDebugLog.has("CurrentSimHost")) { mCrashHost = "https://"; mCrashHost += mDebugLog["CurrentSimHost"].asString(); @@ -256,8 +277,7 @@ void LLCrashLogger::gatherFiles() mAltCrashHost = "https://login.agni.lindenlab.com:12043/crash/report"; mCrashInfo["DebugLog"] = mDebugLog; - mFileMap["StatsLog"] = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stats.log"); - mFileMap["StackTrace"] = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stack_trace.log"); + mFileMap["StatsLog"] = gDirUtilp->getExpandedFilename(LL_PATH_DUMP,"stats.log"); updateApplication("Encoding files..."); @@ -282,52 +302,115 @@ void LLCrashLogger::gatherFiles() trimSLLog(crash_info); } - mCrashInfo[(*itr).first] = rawstr_to_utf8(crash_info); + mCrashInfo[(*itr).first] = LLStringFn::strip_invalid_xml(rawstr_to_utf8(crash_info)); } + + std::string minidump_path; + + // Add minidump as binary. + bool has_minidump = mDebugLog.has("MinidumpPath"); + + if (has_minidump) + minidump_path = mDebugLog["MinidumpPath"].asString(); + + + if (has_minidump) + { + has_minidump = readMinidump(minidump_path); + } + + if (!has_minidump) //Viewer was probably so hosed it couldn't write remaining data. Try brute force. + { + //Look for a filename at least 30 characters long in the dump dir which contains the characters MDMP as the first 4 characters in the file. + typedef std::vector vec; + + std::string pathname = gDirUtilp->getExpandedFilename(LL_PATH_DUMP,""); + vec file_vec = gDirUtilp->getFilesInDir(pathname); + for(vec::const_iterator iter=file_vec.begin(); iter!=file_vec.end(); ++iter) + { + if ( ( iter->length() > 30 ) && (iter->rfind(".log") != (iter->length()-4) ) ) + { + std::string fullname = pathname + *iter; + std::ifstream fdat( fullname.c_str(), std::ifstream::binary); + if (fdat) + { + char buf[5]; + fdat.read(buf,4); + fdat.close(); + if (!strncmp(buf,"MDMP",4)) + { + minidump_path = *iter; + has_minidump = readMinidump(fullname); + mDebugLog["MinidumpPath"] = fullname; + } + } + } + } + } } LLSD LLCrashLogger::constructPostData() { - LLSD ret; return mCrashInfo; } +// Singu Note, defiend in indra_constants.h # const char* const CRASH_SETTINGS_FILE = "settings_crash_behavior.xml"; + S32 LLCrashLogger::loadCrashBehaviorSetting() { + // First check user_settings (in the user's home dir) std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, CRASH_SETTINGS_FILE); + if (! mCrashSettings.loadFromFile(filename)) + { + // Next check app_settings (in the SL program dir) + std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, CRASH_SETTINGS_FILE); + mCrashSettings.loadFromFile(filename); + } - mCrashSettings.loadFromFile(filename); - - S32 value = mCrashSettings.getS32(CRASH_BEHAVIOR_SETTING); - - if (value < CRASH_BEHAVIOR_ASK || CRASH_BEHAVIOR_NEVER_SEND < value) return CRASH_BEHAVIOR_ASK; + // If we didn't load any files above, this will return the default + S32 value = mCrashSettings.getS32("CrashSubmitBehavior"); - return value; + // Whatever value we got, make sure it's valid + switch (value) + { + case CRASH_BEHAVIOR_NEVER_SEND: + return CRASH_BEHAVIOR_NEVER_SEND; + case CRASH_BEHAVIOR_ALWAYS_SEND: + return CRASH_BEHAVIOR_ALWAYS_SEND; + } + + return CRASH_BEHAVIOR_ASK; } bool LLCrashLogger::saveCrashBehaviorSetting(S32 crash_behavior) { - if (crash_behavior != CRASH_BEHAVIOR_ASK && crash_behavior != CRASH_BEHAVIOR_ALWAYS_SEND) return false; + switch (crash_behavior) + { + case CRASH_BEHAVIOR_ASK: + case CRASH_BEHAVIOR_NEVER_SEND: + case CRASH_BEHAVIOR_ALWAYS_SEND: + break; + default: + return false; + } - mCrashSettings.setS32(CRASH_BEHAVIOR_SETTING, crash_behavior); + mCrashSettings.setS32("CrashSubmitBehavior", crash_behavior); std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, CRASH_SETTINGS_FILE); - mCrashSettings.saveToFile(filename, FALSE); return true; } -bool LLCrashLogger::runCrashLogPost(std::string host, LLSD data, std::string msg, int retries) +bool LLCrashLogger::runCrashLogPost(std::string host, LLSD data, std::string msg, int retries, int timeout) { gBreak = false; - std::string status_message; for(int i = 0; i < retries; ++i) { - status_message = llformat("%s, try %d...", msg.c_str(), i+1); - LLHTTPClient::post(host, data, new LLCrashLoggerResponder); + updateApplication(llformat("%s, try %d...", msg.c_str(), i+1)); + LLHTTPClient::post(host, data, new LLCrashLoggerResponder()); while(!gBreak) { - updateApplication(status_message); + updateApplication(); // No new message, just pump the IO } if(gSent) { @@ -337,89 +420,194 @@ bool LLCrashLogger::runCrashLogPost(std::string host, LLSD data, std::string msg return gSent; } -bool LLCrashLogger::sendCrashLogs() +bool LLCrashLogger::sendCrashLog(std::string dump_dir) { + gDirUtilp->setDumpDir( dump_dir ); + + std::string dump_path = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, + "SecondLifeCrashReport"); + std::string report_file = dump_path + ".log"; + gatherFiles(); - + LLSD post_data; post_data = constructPostData(); - + updateApplication("Sending reports..."); - std::string dump_path = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, - "SecondLifeCrashReport"); - std::string report_file = dump_path + ".log"; - std::ofstream out_file(report_file.c_str()); LLSDSerialize::toPrettyXML(post_data, out_file); out_file.close(); - + bool sent = false; - - // *TODO: Translate + + //*TODO: Translate if(mCrashHost != "") { - sent = runCrashLogPost(mCrashHost, post_data, std::string("Sending to server"), 3); + sent = runCrashLogPost(mCrashHost, post_data, std::string("Sending to server"), 3, 5); } - + if(!sent) { - sent = runCrashLogPost(mAltCrashHost, post_data, std::string("Sending to alternate server"), 3); + sent = runCrashLogPost(mAltCrashHost, post_data, std::string("Sending to alternate server"), 3, 5); } - + mSentCrashLogs = sent; + + return sent; +} - return true; +bool LLCrashLogger::sendCrashLogs() +{ + + //pertinent code from below moved into a subroutine. + LLSD locks = mKeyMaster.getProcessList(); + LLSD newlocks = LLSD::emptyArray(); + + LLSD opts = getOptionData(PRIORITY_COMMAND_LINE); + LLSD rec; + + if ( opts.has("pid") && opts.has("dumpdir") && opts.has("procname") ) + { + rec["pid"]=opts["pid"]; + rec["dumpdir"]=opts["dumpdir"]; + rec["procname"]=opts["procname"]; +#if LL_WINDOWS + locks.append(rec); +#endif + } + + if (locks.isArray()) + { + for (LLSD::array_iterator lock=locks.beginArray(); + lock !=locks.endArray(); + ++lock) + { + if ( (*lock).has("pid") && (*lock).has("dumpdir") && (*lock).has("procname") ) + { + if ( mKeyMaster.isProcessAlive( (*lock)["pid"].asInteger(), (*lock)["procname"].asString() ) ) + { + newlocks.append(*lock); + } + else + { + //TODO: This is a hack but I didn't want to include boost in another file or retest everything related to lldir + if (LLCrashLock::fileExists((*lock)["dumpdir"].asString())) + { + //the viewer cleans up the log directory on clean shutdown + //but is ignorant of the locking table. + if (!sendCrashLog((*lock)["dumpdir"].asString())) + { + newlocks.append(*lock); //Failed to send log so don't delete it. + } + else + { + mCrashInfo["DebugLog"].erase("MinidumpPath"); + + mKeyMaster.cleanupProcess((*lock)["dumpdir"].asString()); + } + } + } + } + else + { + llwarns << "Discarding corrupted entry from lock table." << llendl; + } + } + } +#if !LL_WINDOWS + if (rec) + { + newlocks.append(rec); + } +#endif + + mKeyMaster.putProcessList(newlocks); + return true; } void LLCrashLogger::updateApplication(const std::string& message) { + /* Sing TODO gServicePump->pump(); gServicePump->callback(); - gMainThreadEngine.mainloop(); + */ + if (!message.empty()) llinfos << message << llendl; } bool LLCrashLogger::init() { - // Initialize curl - AICurlInterface::initCurl(); - - // Initialize state machine engines. - AIEngine::setMaxCount(100); // StateMachineMaxTime - - // Start state machine thread. - startEngineThread(); + LLCurl::initCurl(); + AIEngine::setMaxCount(100); // We assume that all the logs we're looking for reside on the current drive gDirUtilp->initAppDirs("SecondLife"); + LLError::initForApplication(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "")); + // Default to the product name "Second Life" (this is overridden by the -name argument) mProductName = "Second Life"; - - mCrashSettings.declareS32(CRASH_BEHAVIOR_SETTING, CRASH_BEHAVIOR_ASK, "Controls behavior when viewer crashes " - "(0 = ask before sending crash report, 1 = always send crash report, 2 = never send crash report)"); + // Handle locking + bool locked = mKeyMaster.requestMaster(); //Request maser locking file. wait time is defaulted to 300S + + while (!locked && mKeyMaster.isWaiting()) + { +#if LL_WINDOWS + Sleep(1000); +#else + sleep(1); +#endif + locked = mKeyMaster.checkMaster(); + } + + if (!locked) + { + llwarns << "Unable to get master lock. Another crash reporter may be hung." << llendl; + return false; + } + + // Rename current log file to ".old" + std::string old_log_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "crashreport.log.old"); + std::string log_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "crashreport.log"); + +#if LL_WINDOWS + LLAPRFile::remove(old_log_file); +#endif + + LLFile::rename(log_file.c_str(), old_log_file.c_str()); + + // Set the log file to crashreport.log + LLError::logToFile(log_file); + + mCrashSettings.declareS32("CrashSubmitBehavior", CRASH_BEHAVIOR_ALWAYS_SEND, + "Controls behavior when viewer crashes " + "(0 = ask before sending crash report, " + "1 = always send crash report, " + "2 = never send crash report)"); + llinfos << "Loading crash behavior setting" << llendl; mCrashBehavior = loadCrashBehaviorSetting(); - + // If user doesn't want to send, bail out if (mCrashBehavior == CRASH_BEHAVIOR_NEVER_SEND) { llinfos << "Crash behavior is never_send, quitting" << llendl; return false; } - - // Start curl thread. + AICurlInterface::startCurlThread(&mCrashSettings); - - gServicePump = new LLPumpIO; - - //If we've opened the crash logger, assume we can delete the marker file if it exists - if( gDirUtilp ) - { - std::string marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"SecondLife.exec_marker"); - LLAPRFile::remove( marker_file ); - } - + startEngineThread(); + /* Singu Note: not needed for AICurl + gServicePump = new LLPumpIO(gAPRPoolp); + gServicePump->prime(gAPRPoolp); + LLHTTPClient::setPump(*gServicePump); + */ return true; } + +// For cleanup code common to all platforms. +void LLCrashLogger::commonCleanup() +{ + LLProxy::cleanupClass(); +} diff --git a/indra/llcrashlogger/llcrashlogger.h b/indra/llcrashlogger/llcrashlogger.h index 08e4a5f9f..78acc63b6 100644 --- a/indra/llcrashlogger/llcrashlogger.h +++ b/indra/llcrashlogger/llcrashlogger.h @@ -2,45 +2,38 @@ * @file llcrashlogger.h * @brief Crash Logger Definition * -* $LicenseInfo:firstyear=2003&license=viewergpl$ -* -* Copyright (c) 2003-2009, Linden Research, Inc. -* +* $LicenseInfo:firstyear=2003&license=viewerlgpl$ * Second Life Viewer Source Code -* The source code in this file ("Source Code") is provided by Linden Lab -* to you under the terms of the GNU General Public License, version 2.0 -* ("GPL"), unless you have obtained a separate licensing agreement -* ("Other License"), formally executed by you and Linden Lab. Terms of -* the GPL can be found in doc/GPL-license.txt in this distribution, or -* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 +* Copyright (C) 2010, Linden Research, Inc. * -* There are special exceptions to the terms and conditions of the GPL as -* it is applied to this Source Code. View the full text of the exception -* in the file doc/FLOSS-exception.txt in this software distribution, or -* online at -* http://secondlifegrid.net/programs/open_source/licensing/flossexception +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. * -* By copying, modifying or distributing this software, you acknowledge -* that you have read and understood your obligations described above, -* and agree to abide by those obligations. +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. * -* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO -* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, -* COMPLETENESS OR PERFORMANCE. +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ #ifndef LLCRASHLOGGER_H #define LLCRASHLOGGER_H -#include "linden_common.h" - #include +#include "linden_common.h" + #include "llapp.h" #include "llsd.h" #include "llcontrol.h" - -class AIHTTPTimeoutPolicy; +#include "llcrashlock.h" class LLCrashLogger : public LLApp { @@ -48,18 +41,25 @@ public: LLCrashLogger(); virtual ~LLCrashLogger(); S32 loadCrashBehaviorSetting(); + bool readDebugFromXML(LLSD& dest, const std::string& filename ); void gatherFiles(); + void mergeLogs( LLSD src_sd ); + virtual void gatherPlatformSpecificFiles() {} bool saveCrashBehaviorSetting(S32 crash_behavior); + bool sendCrashLog(std::string dump_dir); bool sendCrashLogs(); LLSD constructPostData(); virtual void updateApplication(const std::string& message = LLStringUtil::null); virtual bool init(); virtual bool mainLoop() = 0; - virtual bool cleanup() { return true; } + virtual bool cleanup() = 0; + void commonCleanup(); void setUserText(const std::string& text) { mCrashInfo["UserNotes"] = text; } S32 getCrashBehavior() { return mCrashBehavior; } - bool runCrashLogPost(std::string host, LLSD data, std::string msg, int retries); + bool runCrashLogPost(std::string host, LLSD data, std::string msg, int retries, int timeout); + bool readMinidump(std::string minidump_path); + protected: S32 mCrashBehavior; BOOL mCrashInPreviousExec; @@ -72,17 +72,7 @@ protected: std::string mAltCrashHost; LLSD mDebugLog; bool mSentCrashLogs; + LLCrashLock mKeyMaster; }; -class LLCrashLoggerText : public LLCrashLogger -{ -public: - LLCrashLoggerText(void) {} - ~LLCrashLoggerText(void) {} - - virtual bool mainLoop(); - virtual void updateApplication(const std::string& message = LLStringUtil::null); -}; - - #endif //LLCRASHLOGGER_H diff --git a/indra/llmessage/aihttptimeoutpolicy.cpp b/indra/llmessage/aihttptimeoutpolicy.cpp index aaf5bf8e1..019750efc 100644 --- a/indra/llmessage/aihttptimeoutpolicy.cpp +++ b/indra/llmessage/aihttptimeoutpolicy.cpp @@ -922,7 +922,6 @@ P(charactersResponder); P(checkAgentAppearanceServiceResponder); P(classifiedStatsResponder); P(consoleResponder); -P2(crashLoggerResponder, transfer_22s_connect_10s); P(createInventoryCategoryResponder); P(emeraldDicDownloader); P(environmentApplyResponder); @@ -993,4 +992,4 @@ P(webProfileResponders); P(wholeModelFeeResponder); P(wholeModelUploadResponder); P2(XMLRPCResponder, connect_40s); - +P2(crashLoggerResponder, transfer_300s); \ No newline at end of file diff --git a/indra/llvfs/lldir.cpp b/indra/llvfs/lldir.cpp index d2d5fa585..551338fa6 100644 --- a/indra/llvfs/lldir.cpp +++ b/indra/llvfs/lldir.cpp @@ -1,3 +1,4 @@ + /** * @file lldir.cpp * @brief implementation of directory utilities base class @@ -42,6 +43,7 @@ #include "lldiriterator.h" #include "stringize.h" +#include #include #include #include @@ -69,6 +71,8 @@ LLDir_Linux gDirUtil; LLDir *gDirUtilp = (LLDir *)&gDirUtil; +static const char* const empty = ""; +std::string LLDir::sDumpDir = ""; LLDir::LLDir() : mAppName(""), mExecutablePathAndName(""), @@ -89,7 +93,32 @@ LLDir::~LLDir() { } - +std::vector LLDir::getFilesInDir(const std::string &dirname) +{ + //Returns a vector of fullpath filenames. + + boost::filesystem::path p (dirname); + std::vector v; + + if (exists(p)) + { + if (is_directory(p)) + { + boost::filesystem::directory_iterator end_iter; + for (boost::filesystem::directory_iterator dir_itr(p); + dir_itr != end_iter; + ++dir_itr) + { + if (boost::filesystem::is_regular_file(dir_itr->status())) + { + v.push_back(dir_itr->path().filename().c_str()); + } + } + } + } + return v; +} + S32 LLDir::deleteFilesInDir(const std::string &dirname, const std::string &mask) { S32 count = 0; @@ -148,6 +177,12 @@ S32 LLDir::deleteFilesInDir(const std::string &dirname, const std::string &mask) return count; } +U32 LLDir::deleteDirAndContents(const std::string& dir_name) +{ + //Removes the directory and its contents. Returns number of files removed. + return boost::filesystem::remove_all(dir_name); +} + const std::string LLDir::findFile(const std::string &filename, const std::string& searchPath1, const std::string& searchPath2, @@ -235,6 +270,31 @@ const std::string &LLDir::getChatLogsDir() const return mChatLogsDir; } +void LLDir::setDumpDir( const std::string& path ) +{ + LLDir::sDumpDir = path; + if (! sDumpDir.empty() && sDumpDir.rbegin() == mDirDelimiter.rbegin() ) + { + sDumpDir.erase(sDumpDir.size() -1); + } +} + +const std::string &LLDir::getDumpDir() const +{ + if (sDumpDir.empty() ) + { + LLUUID uid; + uid.generate(); + + sDumpDir = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "") + + "dump-" + uid.asString(); + + dir_exists_or_crash(sDumpDir); + } + + return LLDir::sDumpDir; +} + const std::string &LLDir::getPerAccountChatLogsDir() const { return mPerAccountChatLogsDir; @@ -396,12 +456,29 @@ std::string LLDir::getExpandedFilename(ELLPath location, const std::string& subd prefix = getCacheDir(); break; + case LL_PATH_DUMP: + prefix=getDumpDir(); + break; + case LL_PATH_USER_SETTINGS: prefix = add(getOSUserAppDir(), "user_settings"); break; case LL_PATH_PER_SL_ACCOUNT: prefix = getLindenUserDir(); + if (prefix.empty()) + { + // if we're asking for the per-SL-account directory but we haven't + // logged in yet (or otherwise don't know the account name from + // which to build this string), then intentionally return a blank + // string to the caller and skip the below warning about a blank + // prefix. + LL_DEBUGS("LLDir") << "getLindenUserDir() not yet set: " + << ELLPathToString(location) + << ", '" << subdir1 << "', '" << subdir2 << "', '" << in_filename + << "' => ''" << LL_ENDL; + return std::string(); + } break; case LL_PATH_CHAT_LOGS: diff --git a/indra/llvfs/lldir.h b/indra/llvfs/lldir.h index 23f84bb41..5058b5479 100644 --- a/indra/llvfs/lldir.h +++ b/indra/llvfs/lldir.h @@ -53,6 +53,7 @@ typedef enum ELLPath LL_PATH_EXECUTABLE = 16, LL_PATH_DEFAULT_SKIN = 17, LL_PATH_FONTS = 18, + LL_PATH_DUMP = 19, LL_PATH_LAST } ELLPath; @@ -71,7 +72,8 @@ class LLDir const std::string& app_read_only_data_dir = "") = 0; virtual S32 deleteFilesInDir(const std::string &dirname, const std::string &mask); - + U32 deleteDirAndContents(const std::string& dir_name); + std::vector getFilesInDir(const std::string &dirname); // pure virtual functions virtual U32 countFilesInDir(const std::string &dirname, const std::string &mask) = 0; @@ -94,6 +96,7 @@ class LLDir const std::string &getOSUserAppDir() const; // Location of the os-specific user app dir const std::string &getLindenUserDir(bool empty_ok = false) const; // Location of the Linden user dir. const std::string &getChatLogsDir() const; // Location of the chat logs dir. + const std::string &getDumpDir() const; // Location of the per-run dump dir. const std::string &getPerAccountChatLogsDir() const; // Location of the per account chat logs dir. const std::string &getTempDir() const; // Common temporary directory const std::string getCacheDir(bool get_default = false) const; // Location of the cache. @@ -128,6 +131,7 @@ class LLDir // For producing safe download file names from potentially unsafe ones static std::string getScrubbedFileName(const std::string uncleanFileName); static std::string getForbiddenFileChars(); + void setDumpDir( const std::string& path ); virtual void setChatLogsDir(const std::string &path); // Set the chat logs dir to this user's dir virtual void setPerAccountChatLogsDir(const std::string &grid, const std::string &first, const std::string &last); // Set the per user chat log directory. @@ -173,6 +177,7 @@ protected: std::string mDefaultSkinDir; // Location for default skin info. std::string mUserSkinDir; // Location for user-modified skin info. std::string mLLPluginDir; // Location for plugins and plugin shell + static std::string sDumpDir; // Per-run crash report subdir of log directory. }; void dir_exists_or_crash(const std::string &dir_name); diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index cc9d96c27..ceed6ea95 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -2190,6 +2190,17 @@ This should be as low as possible, but too low may break functionality 1 + CrashHostUrl + + Comment + A URL pointing to a crash report handler; overrides cluster negotiation to locate crash handler. + Persist + 1 + Type + String + Value + + AFKTimeout Comment diff --git a/indra/newview/app_settings/settings_crash_behavior.xml b/indra/newview/app_settings/settings_crash_behavior.xml index 0665d86f2..d259b4381 100644 --- a/indra/newview/app_settings/settings_crash_behavior.xml +++ b/indra/newview/app_settings/settings_crash_behavior.xml @@ -9,7 +9,7 @@ Type S32 Value - 2 + 1 CurlMaxTotalConcurrentConnections diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 575be4210..d4b3aa736 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -558,6 +558,11 @@ LLAppViewer::LLAppViewer() : llerrs << "Oh no! An instance of LLAppViewer already exists! LLAppViewer is sort of like a singleton." << llendl; } + mDumpPath =""; + + // Need to do this initialization before we do anything else, since anything + // that touches files should really go through the lldir API + gDirUtilp->initAppDirs("SecondLife"); sInstance = this; } @@ -580,7 +585,9 @@ public: }; bool LLAppViewer::init() -{ +{ + setupErrorHandling(); + // // Start of the application // @@ -605,9 +612,6 @@ bool LLAppViewer::init() //initialize particle index pool LLVOPartGroup::initClass(); - // Need to do this initialization before we do anything else, since anything - // that touches files should really go through the lldir API - gDirUtilp->initAppDirs("SecondLife"); // set skin search path to default, will be overridden later // this allows simple skinned file lookups to work gDirUtilp->setSkinFolder("default"); @@ -636,6 +640,12 @@ bool LLAppViewer::init() initMaxHeapSize() ; LLPrivateMemoryPoolManager::initClass((BOOL)gSavedSettings.getBOOL("MemoryPrivatePoolEnabled"), (U32)gSavedSettings.getU32("MemoryPrivatePoolSize")) ; + // write Google Breakpad minidump files to a per-run dump directory to avoid multiple viewer issues. + std::string logdir = gDirUtilp->getExpandedFilename(LL_PATH_DUMP, ""); + mDumpPath = logdir; + setMiniDumpDir(logdir); + logdir += gDirUtilp->getDirDelimiter(); + setDebugFileNames(logdir); mAlloc.setProfilingEnabled(gSavedSettings.getBOOL("MemProfiling")); @@ -1448,6 +1458,14 @@ bool LLAppViewer::cleanup() { //ditch LLVOAvatarSelf instance gAgentAvatarp = NULL; + + // remove any old breakpad minidump files from the log directory + if (! isError()) + { + std::string logdir = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, ""); + gDirUtilp->deleteFilesInDir(logdir, "*-*-*-*-*.dmp"); + } + cleanup_pose_stand(); //flag all elements as needing to be destroyed immediately @@ -1725,6 +1743,7 @@ bool LLAppViewer::cleanup() } // + removeDumpDir(); writeDebugInfo(); if(!gDirUtilp->getLindenUserDir(true).empty()) @@ -2449,7 +2468,6 @@ bool LLAppViewer::initConfiguration() initMarkerFile(); - checkForCrash(); } else { @@ -2469,10 +2487,6 @@ bool LLAppViewer::initConfiguration() initMarkerFile(); - if(!mSecondInstance) - { - checkForCrash(); - } } // need to do this here - need to have initialized global settings first @@ -2488,62 +2502,6 @@ bool LLAppViewer::initConfiguration() return true; // Config was successful. } - -void LLAppViewer::checkForCrash(void) -{ -#if LL_SEND_CRASH_REPORTS - // *NOTE:Mani The current state of the crash handler has the MacOSX - // sending all crash reports as freezes, in order to let - // the MacOSX CrashRepoter generate stacks before spawning the - // SL crash logger. - // The Linux and Windows clients generate their own stacks and - // spawn the SL crash logger immediately. This may change in the future. -#if LL_DARWIN - if(gLastExecEvent != LAST_EXEC_NORMAL) -#else - if (gLastExecEvent == LAST_EXEC_FROZE) -#endif - { - llinfos << "Last execution froze, requesting to send crash report." << llendl; - // - // Pop up a freeze or crash warning dialog - // - S32 choice; - const S32 cb = gCrashSettings.getS32(CRASH_BEHAVIOR_SETTING); - if(cb == CRASH_BEHAVIOR_ASK) - { - std::ostringstream msg; - msg << LLTrans::getString("MBFrozenCrashed"); - std::string alert = LLTrans::getString("APP_NAME") + " " + LLTrans::getString("MBAlert"); - choice = OSMessageBox(msg.str(), - alert, - OSMB_YESNO); - } - else if(cb == CRASH_BEHAVIOR_NEVER_SEND) - { - choice = OSBTN_NO; - } - else - { - choice = OSBTN_YES; - } - - if (OSBTN_YES == choice) - { - llinfos << "Sending crash report." << llendl; - - bool report_freeze = true; - handleCrashReporting(report_freeze); - } - else - { - llinfos << "Not sending crash report." << llendl; - } - } -#endif // LL_SEND_CRASH_REPORTS - -} - bool LLAppViewer::initWindow() { LL_INFOS("AppInit") << "Initializing window..." << LL_ENDL; @@ -2613,12 +2571,21 @@ bool LLAppViewer::initWindow() return true; } -void LLAppViewer::writeDebugInfo() +void LLAppViewer::writeDebugInfo(bool isStatic) { - std::string debug_filename = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"debug_info.log"); - llinfos << "Opening debug file " << debug_filename << llendl; - llofstream out_file(debug_filename); - LLSDSerialize::toPrettyXML(gDebugInfo, out_file); + //Try to do the minimum when writing data during a crash. + std::string* debug_filename; + debug_filename = ( isStatic + ? getStaticDebugFile() + : getDynamicDebugFile() ); + + llinfos << "Opening debug file " << *debug_filename << llendl; + llofstream out_file(*debug_filename); + + isStatic ? LLSDSerialize::toPrettyXML(gDebugInfo, out_file) + : LLSDSerialize::toPrettyXML(gDebugInfo["Dynamic"], out_file); + + out_file.close(); } @@ -2669,6 +2636,10 @@ void LLAppViewer::removeCacheFiles(const std::string& file_mask) void LLAppViewer::writeSystemInfo() { + + if (! gDebugInfo.has("Dynamic") ) + gDebugInfo["Dynamic"] = LLSD::emptyMap(); + gDebugInfo["SLLog"] = LLError::logFileName(); gDebugInfo["ClientInfo"]["Name"] = gVersionChannel; @@ -2706,6 +2677,15 @@ void LLAppViewer::writeSystemInfo() // If the crash is handled by LLAppViewer::handleViewerCrash, ie not a freeze, // then the value of "CrashNotHandled" will be set to true. gDebugInfo["CrashNotHandled"] = (LLSD::Boolean)true; + + // Insert crash host url (url to post crash log to) if configured. This insures + // that the crash report will go to the proper location in the case of a + // prior freeze. + std::string crashHostUrl = gSavedSettings.get("CrashHostUrl"); + if(crashHostUrl != "") + { + gDebugInfo["CrashHostUrl"] = crashHostUrl; + } // Dump some debugging info LL_INFOS("SystemInfo") << LLTrans::getString("APP_NAME") @@ -2730,13 +2710,6 @@ void LLAppViewer::writeSystemInfo() writeDebugInfo(); // Save out debug_info.log early, in case of crash. } -void LLAppViewer::handleSyncViewerCrash() -{ - LLAppViewer* pApp = LLAppViewer::instance(); - // Call to pure virtual, handled by platform specific llappviewer instance. - pApp->handleSyncCrashTrace(); -} - void LLAppViewer::handleViewerCrash() { llinfos << "Handle viewer crash entry." << llendl; @@ -2768,8 +2741,12 @@ void LLAppViewer::handleViewerCrash() } pApp->mReportedCrash = TRUE; - // Make sure the watchdog gets turned off... -// pApp->destroyMainloopTimeout(); // SJB: Bah. This causes the crash handler to hang, not sure why. + // Insert crash host url (url to post crash log to) if configured. + std::string crashHostUrl = gSavedSettings.get("CrashHostUrl"); + if(crashHostUrl != "") + { + gDebugInfo["Dynamic"]["CrashHostUrl"] = crashHostUrl; + } //We already do this in writeSystemInfo(), but we do it again here to make /sure/ we have a version //to check against no matter what @@ -2783,11 +2760,11 @@ void LLAppViewer::handleViewerCrash() LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); if ( parcel && parcel->getMusicURL()[0]) { - gDebugInfo["ParcelMusicURL"] = parcel->getMusicURL(); + gDebugInfo["Dynamic"]["ParcelMusicURL"] = parcel->getMusicURL(); } if ( parcel && parcel->getMediaURL()[0]) { - gDebugInfo["ParcelMediaURL"] = parcel->getMediaURL(); + gDebugInfo["Dynamic"]["ParcelMediaURL"] = parcel->getMediaURL(); } @@ -2795,15 +2772,15 @@ void LLAppViewer::handleViewerCrash() gDebugInfo["CAFilename"] = gDirUtilp->getCAFile(); gDebugInfo["ViewerExePath"] = gDirUtilp->getExecutablePathAndName(); gDebugInfo["CurrentPath"] = gDirUtilp->getCurPath(); - gDebugInfo["SessionLength"] = F32(LLFrameTimer::getElapsedSeconds()); + gDebugInfo["Dynamic"]["SessionLength"] = F32(LLFrameTimer::getElapsedSeconds()); gDebugInfo["StartupState"] = LLStartUp::getStartupStateString(); - gDebugInfo["RAMInfo"]["Allocated"] = (LLSD::Integer) LLMemory::getCurrentRSS() >> 10; + gDebugInfo["Dynamic"]["RAMInfo"]["Allocated"] = (LLSD::Integer) LLMemory::getCurrentRSS() >> 10; gDebugInfo["FirstLogin"] = (LLSD::Boolean) gAgent.isFirstLogin(); gDebugInfo["FirstRunThisInstall"] = gSavedSettings.getBOOL("FirstRunThisInstall"); if(gLogoutInProgress) { - gDebugInfo["LastExecEvent"] = LAST_EXEC_LOGOUT_CRASH; + gDebugInfo["Dynamic"]["LastExecEvent"] = LAST_EXEC_LOGOUT_CRASH; } else { @@ -2812,23 +2789,23 @@ void LLAppViewer::handleViewerCrash() if(gAgent.getRegion()) { - gDebugInfo["CurrentSimHost"] = gAgent.getRegionHost().getHostName(); - gDebugInfo["CurrentRegion"] = gAgent.getRegion()->getName(); + gDebugInfo["Dynamic"]["CurrentSimHost"] = gAgent.getRegionHost().getHostName(); + gDebugInfo["Dynamic"]["CurrentRegion"] = gAgent.getRegion()->getName(); const LLVector3& loc = gAgent.getPositionAgent(); - gDebugInfo["CurrentLocationX"] = loc.mV[0]; - gDebugInfo["CurrentLocationY"] = loc.mV[1]; - gDebugInfo["CurrentLocationZ"] = loc.mV[2]; + gDebugInfo["Dynamic"]["CurrentLocationX"] = loc.mV[0]; + gDebugInfo["Dynamic"]["CurrentLocationY"] = loc.mV[1]; + gDebugInfo["Dynamic"]["CurrentLocationZ"] = loc.mV[2]; } if(LLAppViewer::instance()->mMainloopTimeout) { - gDebugInfo["MainloopTimeoutState"] = LLAppViewer::instance()->mMainloopTimeout->getState(); + gDebugInfo["Dynamic"]["MainloopTimeoutState"] = LLAppViewer::instance()->mMainloopTimeout->getState(); } // The crash is being handled here so set this value to false. // Otherwise the crash logger will think this crash was a freeze. - gDebugInfo["CrashNotHandled"] = (LLSD::Boolean)false; + gDebugInfo["Dynamic"]["CrashNotHandled"] = (LLSD::Boolean)false; //Write out the crash status file //Use marker file style setup, as that's the simplest, especially since @@ -2850,11 +2827,18 @@ void LLAppViewer::handleViewerCrash() LL_WARNS("MarkerFile") << "Cannot create error marker file " << crash_file_name << LL_ENDL; } } + char *minidump_file = pApp->getMiniDumpFilename(); + if(minidump_file && minidump_file[0] != 0) + { + gDebugInfo["Dynamic"]["MinidumpPath"] = minidump_file; + } + + gDebugInfo["Dynamic"]["CrashType"]="crash"; if (gMessageSystem && gDirUtilp) { std::string filename; - filename = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "stats.log"); + filename = gDirUtilp->getExpandedFilename(LL_PATH_DUMP, "stats.log"); llofstream file(filename, llofstream::binary); if(file.good()) { @@ -2870,19 +2854,15 @@ void LLAppViewer::handleViewerCrash() gMessageSystem->stopLogging(); } - if (LLWorld::instanceExists()) LLWorld::getInstance()->getInfo(gDebugInfo); + if (LLWorld::instanceExists()) LLWorld::getInstance()->getInfo(gDebugInfo["Dynamic"]); // Close the debug file - pApp->writeDebugInfo(); + pApp->writeDebugInfo(false); //false answers the isStatic question with the least overhead. LLError::logToFile(""); -// On Mac, we send the report on the next run, since we need macs crash report -// for a stack trace, so we have to let it the app fail. -#if !LL_DARWIN - // Remove the marker file, since otherwise we'll spawn a process that'll keep it locked - if(gDebugInfo["LastExecEvent"].asInteger() == LAST_EXEC_LOGOUT_CRASH) + if(gDebugInfo["Dynamic"]["LastExecEvent"].asInteger() == LAST_EXEC_LOGOUT_CRASH) { pApp->removeMarkerFile(true); } @@ -2891,11 +2871,6 @@ void LLAppViewer::handleViewerCrash() pApp->removeMarkerFile(false); } - // Call to pure virtual, handled by platform specific llappviewer instance. - pApp->handleCrashReporting(); - -#endif //!LL_DARWIN - return; } @@ -3020,6 +2995,18 @@ void LLAppViewer::removeMarkerFile(bool leave_logout_marker) LLAPRFile::remove( mLogoutMarkerFileName ); mLogoutMarkerFile = NULL; } + else + { + LL_WARNS("MarkerFile") << "leaving markers because this is a second instance" << LL_ENDL; + } +} + +void LLAppViewer::removeDumpDir() +{ + //Call this routine only on clean exit. Crash reporter will clean up + //its locking table for us. + std::string dump_dir = gDirUtilp->getExpandedFilename(LL_PATH_DUMP, ""); + gDirUtilp->deleteDirAndContents(dump_dir); } void LLAppViewer::forceQuit() @@ -3592,13 +3579,6 @@ void LLAppViewer::badNetworkHandler() mPurgeOnExit = TRUE; -#if LL_WINDOWS - // Generates the minidump. - LLWinDebug::generateCrashStacks(NULL); -#endif - LLAppViewer::handleSyncViewerCrash(); - LLAppViewer::handleViewerCrash(); - std::string grid_support_msg = ""; if (!gHippoGridManager->getCurrentGrid()->getSupportUrl().empty()) { @@ -3617,6 +3597,8 @@ void LLAppViewer::badNetworkHandler() "If the problem continues, please report the issue at: \n" "http://www.singularityviewer.org" << grid_support_msg; forceDisconnect(message.str()); + + LLApp::instance()->writeMiniDump(); } // This routine may get called more than once during the shutdown process. diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h index 1f9b5025c..251762040 100644 --- a/indra/newview/llappviewer.h +++ b/indra/newview/llappviewer.h @@ -77,7 +77,7 @@ public: bool quitRequested() { return mQuitRequested; } bool logoutRequestSent() { return mLogoutRequestSent; } - void writeDebugInfo(); + void writeDebugInfo(bool isStatic=true); const LLOSInfo& getOSInfo() const { return mSysOSInfo; } @@ -86,11 +86,8 @@ public: virtual bool restoreErrorTrap() = 0; // Require platform specific override to reset error handling mechanism. // return false if the error trap needed restoration. - virtual void handleCrashReporting(bool reportFreeze = false) = 0; // What to do with crash report? - virtual void handleSyncCrashTrace() = 0; // any low-level crash-prep that has to happen in the context of the crashing thread before the crash report is delivered. + virtual void initCrashReporting(bool reportFreeze = false) = 0; // What to do with crash report? static void handleViewerCrash(); // Hey! The viewer crashed. Do this, soon. - static void handleSyncViewerCrash(); // Hey! The viewer crashed. Do this right NOW in the context of the crashing thread. - void checkForCrash(); // Thread accessors static LLTextureCache* getTextureCache() { return sTextureCache; } @@ -118,6 +115,7 @@ public: void removeMarkerFile(bool leave_logout_marker = false); + void removeDumpDir(); // LLAppViewer testing helpers. // *NOTE: These will potentially crash the viewer. Only for debugging. virtual void forceErrorLLError(); diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp index 5ccb1f7e6..3be747d63 100644 --- a/indra/newview/llappviewerwin32.cpp +++ b/indra/newview/llappviewerwin32.cpp @@ -79,50 +79,6 @@ extern "C" { const std::string LLAppViewerWin32::sWindowClass = "Second Life"; -LONG WINAPI viewer_windows_exception_handler(struct _EXCEPTION_POINTERS *exception_infop) -{ - // *NOTE:Mani - this code is stolen from LLApp, where its never actually used. - //OSMessageBox("Attach Debugger Now", "Error", OSMB_OK); - // Translate the signals/exceptions into cross-platform stuff - // Windows implementation - _tprintf( _T("Entering Windows Exception Handler...\n") ); - llinfos << "Entering Windows Exception Handler..." << llendl; - - // Make sure the user sees something to indicate that the app crashed. - LONG retval; - - if (LLApp::isError()) - { - _tprintf( _T("Got another fatal signal while in the error handler, die now!\n") ); - llwarns << "Got another fatal signal while in the error handler, die now!" << llendl; - - retval = EXCEPTION_EXECUTE_HANDLER; - return retval; - } - - // Generate a minidump if we can. - // Before we wake the error thread... - // Which will start the crash reporting. - LLWinDebug::generateCrashStacks(exception_infop); - - // Flag status to error, so thread_error starts its work - LLApp::setError(); - - // Block in the exception handler until the app has stopped - // This is pretty sketchy, but appears to work just fine - while (!LLApp::isStopped()) - { - ms_sleep(10); - } - - // - // At this point, we always want to exit the app. There's no graceful - // recovery for an unhandled exception. - // - // Just kill the process. - retval = EXCEPTION_EXECUTE_HANDLER; - return retval; -} // Create app mutex creates a unique global windows object. // If the object can be created it returns true, otherwise @@ -187,8 +143,6 @@ int APIENTRY WINMAIN(HINSTANCE hInstance, gIconResource = MAKEINTRESOURCE(IDI_LL_ICON); LLAppViewerWin32* viewer_app_ptr = new LLAppViewerWin32(lpCmdLine); - - LLWinDebug::initExceptionHandler(viewer_windows_exception_handler); viewer_app_ptr->setErrorHandler(LLAppViewer::handleViewerCrash); @@ -407,10 +361,25 @@ bool LLAppViewerWin32::init() // (Don't send our data to Microsoft--at least until we are Logo approved and have a way // of getting the data back from them.) // - llinfos << "Turning off Windows error reporting." << llendl; + // llinfos << "Turning off Windows error reporting." << llendl; disableWinErrorReporting(); - return LLAppViewer::init(); +#ifndef LL_RELEASE_FOR_DOWNLOAD + LLWinDebug::instance().init(); +#endif + +#if LL_WINDOWS +#if LL_SEND_CRASH_REPORTS + + LLAppViewer* pApp = LLAppViewer::instance(); + pApp->initCrashReporting(); + +#endif +#endif + + bool success = LLAppViewer::init(); + + return success; } bool LLAppViewerWin32::cleanup() @@ -424,12 +393,6 @@ bool LLAppViewerWin32::cleanup() bool LLAppViewerWin32::initLogging() { - // Remove the crash stack log from previous executions. - // Since we've started logging a new instance of the app, we can assume - // *NOTE: This should happen before the we send a 'previous instance froze' - // crash report, but it must happen after we initialize the DirUtil. - LLWinDebug::clearCrashStacks(); - return LLAppViewer::initLogging(); } @@ -552,39 +515,66 @@ bool LLAppViewerWin32::initParseCommandLine(LLCommandLineParser& clp) } bool LLAppViewerWin32::restoreErrorTrap() -{ - return LLWinDebug::checkExceptionHandler(); +{ + return true; + //return LLWinDebug::checkExceptionHandler(); } -void LLAppViewerWin32::handleSyncCrashTrace() -{ - // do nothing -} - -void LLAppViewerWin32::handleCrashReporting(bool reportFreeze) +void LLAppViewerWin32::initCrashReporting(bool reportFreeze) { const char* logger_name = "win_crash_logger.exe"; std::string exe_path = gDirUtilp->getExecutableDir(); exe_path += gDirUtilp->getDirDelimiter(); exe_path += logger_name; - const char* arg_str = logger_name; + std::stringstream pid_str; + pid_str << LLApp::getPid(); + std::string logdir = gDirUtilp->getExpandedFilename(LL_PATH_DUMP, ""); + std::string appname = gDirUtilp->getExecutableFilename(); - // *NOTE:Mani - win_crash_logger.exe no longer parses command line options. - if(reportFreeze) + S32 slen = logdir.length() -1; + S32 end = slen; + while (logdir.at(end) == '/' || logdir.at(end) == '\\') end--; + + if (slen !=end) { - // Spawn crash logger. - // NEEDS to wait until completion, otherwise log files will get smashed. - _spawnl(_P_WAIT, exe_path.c_str(), arg_str, NULL); + logdir = logdir.substr(0,end+1); } - else + std::string arg_str = "\"" + exe_path + "\" -dumpdir \"" + logdir + "\" -procname \"" + appname + "\" -pid " + pid_str.str(); + llinfos << "spawning " << arg_str << llendl; + _spawnl(_P_NOWAIT, exe_path.c_str(), arg_str.c_str(), NULL); + +/* STARTUPINFO siStartupInfo; + + std::string arg_str = "-dumpdir \"" + logdir + "\" -procname \"" + appname + "\" -pid " + pid_str.str(); + + memset(&siStartupInfo, 0, sizeof(siStartupInfo)); + memset(&mCrashReporterProcessInfo, 0, sizeof(mCrashReporterProcessInfo)); + + siStartupInfo.cb = sizeof(siStartupInfo); + + std::wstring exe_wstr; + exe_wstr.assign(exe_path.begin(), exe_path.end()); + + std::wstring arg_wstr; + arg_wstr.assign(arg_str.begin(), arg_str.end()); + + if(CreateProcess(&exe_wstr[0], + &arg_wstr[0], // Application arguments + 0, + 0, + FALSE, + CREATE_DEFAULT_ERROR_MODE, + 0, + 0, // Working directory + &siStartupInfo, + &mCrashReporterProcessInfo) == FALSE) + // Could not start application -> call 'GetLastError()' { - S32 cb = gCrashSettings.getS32(CRASH_BEHAVIOR_SETTING); - if(cb != CRASH_BEHAVIOR_NEVER_SEND) - { - _spawnl(_P_NOWAIT, exe_path.c_str(), arg_str, NULL); - } - } + //llinfos << "CreateProcess failed " << GetLastError() << llendl; + return; + } + */ } //virtual diff --git a/indra/newview/llappviewerwin32.h b/indra/newview/llappviewerwin32.h index 13454edee..757f6ea0c 100644 --- a/indra/newview/llappviewerwin32.h +++ b/indra/newview/llappviewerwin32.h @@ -56,13 +56,13 @@ protected: virtual bool initParseCommandLine(LLCommandLineParser& clp); virtual bool restoreErrorTrap(); - virtual void handleCrashReporting(bool reportFreeze); - virtual void handleSyncCrashTrace(); + virtual void initCrashReporting(bool reportFreeze); virtual bool sendURLToOtherInstance(const std::string& url); std::string generateSerialNumber(); + static const std::string sWindowClass; private: diff --git a/indra/newview/llwindebug.cpp b/indra/newview/llwindebug.cpp index 5c7ee642d..446b9b96f 100644 --- a/indra/newview/llwindebug.cpp +++ b/indra/newview/llwindebug.cpp @@ -2,98 +2,35 @@ * @file llwindebug.cpp * @brief Windows debugging functions * - * $LicenseInfo:firstyear=2004&license=viewergpl$ - * - * Copyright (c) 2004-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2004&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ - #include "llviewerprecompiledheaders.h" -#include -#include #include "llwindebug.h" -#include "llviewercontrol.h" #include "lldir.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 - - - Platform - - Process - - Module - - DateModified - - ExceptionCode - - ExceptionRead/WriteAddress - - Instruction - - Registers - - - EIP - ... - - - Call Stack - - - - ModuleName - - ModuleBaseAddress - - ModuleOffsetAddress - - Parameters - - - - - - - - - -*/ - - -extern void (*gCrashCallback)(void); - // based on dbghelp.h typedef BOOL (WINAPI *MINIDUMPWRITEDUMP)(HANDLE hProcess, DWORD dwPid, HANDLE hFile, MINIDUMP_TYPE DumpType, CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, @@ -103,527 +40,6 @@ typedef BOOL (WINAPI *MINIDUMPWRITEDUMP)(HANDLE hProcess, DWORD dwPid, HANDLE hF MINIDUMPWRITEDUMP f_mdwp = NULL; -#undef UNICODE - -static LPTOP_LEVEL_EXCEPTION_FILTER gFilterFunc = NULL; - -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 - - -typedef struct STACK -{ - STACK * Ebp; - PBYTE Ret_Addr; - DWORD Param[0]; -} STACK, * PSTACK; - -BOOL WINAPI Get_Module_By_Ret_Addr(PBYTE Ret_Addr, LPWSTR Module_Name, PBYTE & Module_Addr); -void WINAPI Get_Call_Stack(const EXCEPTION_RECORD* exception_record, - const CONTEXT* context_record, - LLSD& info); - -void printError( CHAR* msg ) -{ - DWORD eNum; - TCHAR sysMsg[256]; - TCHAR* p; - - eNum = GetLastError( ); - FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, eNum, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language - sysMsg, 256, NULL ); - - // Trim the end of the line and terminate it with a null - p = sysMsg; - while( ( *p > 31 ) || ( *p == 9 ) ) - ++p; - do { *p-- = 0; } while( ( p >= sysMsg ) && - ( ( *p == '.' ) || ( *p < 33 ) ) ); - - // Display the message - printf( "\n WARNING: %s failed with error %d (%s)", msg, eNum, sysMsg ); -} - -BOOL GetProcessThreadIDs(DWORD process_id, std::vector& thread_ids) -{ - HANDLE hThreadSnap = INVALID_HANDLE_VALUE; - THREADENTRY32 te32; - - // Take a snapshot of all running threads - hThreadSnap = CreateToolhelp32Snapshot( TH32CS_SNAPTHREAD, 0 ); - if( hThreadSnap == INVALID_HANDLE_VALUE ) - return( FALSE ); - - // Fill in the size of the structure before using it. - te32.dwSize = sizeof(THREADENTRY32 ); - - // Retrieve information about the first thread, - // and exit if unsuccessful - if( !Thread32First( hThreadSnap, &te32 ) ) - { - printError( "Thread32First" ); // Show cause of failure - CloseHandle( hThreadSnap ); // Must clean up the snapshot object! - return( FALSE ); - } - - // Now walk the thread list of the system, - // and display information about each thread - // associated with the specified process - do - { - if( te32.th32OwnerProcessID == process_id ) - { - thread_ids.push_back(te32.th32ThreadID); - } - } while( Thread32Next(hThreadSnap, &te32 ) ); - -// Don't forget to clean up the snapshot object. - CloseHandle( hThreadSnap ); - return( TRUE ); -} - -BOOL GetThreadCallStack(DWORD thread_id, LLSD& info) -{ - if(GetCurrentThreadId() == thread_id) - { - // Early exit for the current thread. - // Suspending the current thread would be a bad idea. - // Plus you can't retrieve a valid current thread context. - return false; - } - - HANDLE thread_handle = INVALID_HANDLE_VALUE; - thread_handle = OpenThread(THREAD_ALL_ACCESS, FALSE, thread_id); - if(INVALID_HANDLE_VALUE == thread_handle) - { - return FALSE; - } - - BOOL result = false; - if(-1 != SuspendThread(thread_handle)) - { - CONTEXT context_struct; - context_struct.ContextFlags = CONTEXT_FULL; - if(GetThreadContext(thread_handle, &context_struct)) - { - Get_Call_Stack(NULL, &context_struct, info); - result = true; - } - ResumeThread(thread_handle); - } - else - { - // Couldn't suspend thread. - } - - CloseHandle(thread_handle); - return result; -} - - -//Windows Call Stack Construction idea from -//http://www.codeproject.com/tools/minidump.asp - -// **************************************************************************************** -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 - -bool has_valid_call_before(PDWORD cur_stack_loc) -{ - PBYTE p_first_byte = (PBYTE)(*cur_stack_loc - 1); - PBYTE p_second_byte = (PBYTE)(*cur_stack_loc -2); - PBYTE p_fifth_byte = (PBYTE)(*cur_stack_loc - 5); - PBYTE p_sixth_byte = (PBYTE)(*cur_stack_loc - 6); - - // make sure we can read it - if(IsBadReadPtr(p_sixth_byte, 6 * sizeof(BYTE))) - { - return false; - } - - // check for 9a + 4 bytes - if(*p_fifth_byte == 0x9A) - { - return true; - } - - // Check for E8 + 4 bytes and last byte is 00 or FF - if(*p_fifth_byte == 0xE8 && (*p_first_byte == 0x00 || *p_first_byte == 0xFF)) - { - return true; - } - - // the other is six bytes - if(*p_sixth_byte == 0xFF || *p_second_byte == 0xFF) - { - return true; - } - - return false; -} - -PBYTE get_valid_frame(PBYTE esp) -{ - PDWORD cur_stack_loc = NULL; - const int max_search = 400; - WCHAR module_name[MAX_PATH]; - PBYTE module_addr = 0; - - // round to highest multiple of four - esp = (esp + (4 - ((int)esp % 4)) % 4); - - // scroll through stack a few hundred places. - for (cur_stack_loc = (PDWORD) esp; cur_stack_loc < (PDWORD)esp + max_search; cur_stack_loc += 1) - { - // if you can read the pointer, - if (IsBadReadPtr(cur_stack_loc, sizeof(PDWORD))) - { - continue; - } - - // check if it's in a module - if (!Get_Module_By_Ret_Addr((PBYTE)*cur_stack_loc, module_name, module_addr)) - { - continue; - } - - // check if the code before the instruction ptr is a call - if(!has_valid_call_before(cur_stack_loc)) - { - continue; - } - - // if these all pass, return that ebp, otherwise continue till we're dead - return (PBYTE)(cur_stack_loc - 1); - } - - return NULL; -} - -bool shouldUseStackWalker(PSTACK Ebp, int max_depth) -{ - WCHAR Module_Name[MAX_PATH]; - PBYTE Module_Addr = 0; - int depth = 0; - - while (depth < max_depth) - { - if (IsBadReadPtr(Ebp, sizeof(PSTACK)) || - IsBadReadPtr(Ebp->Ebp, sizeof(PSTACK)) || - Ebp->Ebp < Ebp || - Ebp->Ebp - Ebp > 0xFFFFFF || - IsBadCodePtr(FARPROC(Ebp->Ebp->Ret_Addr)) || - !Get_Module_By_Ret_Addr(Ebp->Ebp->Ret_Addr, Module_Name, Module_Addr)) - { - return true; - } - depth++; - Ebp = Ebp->Ebp; - } - - return false; -} - -// ****************************************************************** -void WINAPI Get_Call_Stack(const EXCEPTION_RECORD* exception_record, - const CONTEXT* context_record, - LLSD& info) -// ****************************************************************** -// Fill Str with call stack info. -// pException can be either GetExceptionInformation() or NULL. -// If pException = NULL - get current call stack. -{ - LPWSTR Module_Name = new WCHAR[MAX_PATH]; - PBYTE Module_Addr = 0; - LLSD params; - PBYTE Esp = NULL; - LLSD tmp_info; - - bool fake_frame = false; - bool ebp_used = false; - const int HEURISTIC_MAX_WALK = 20; - int heuristic_walk_i = 0; - int Ret_Addr_I = 0; - - STACK Stack = {0, 0}; - PSTACK Ebp; - - if (exception_record && context_record) //fake frame for exception address - { - Stack.Ebp = (PSTACK)(context_record->Ebp); - Stack.Ret_Addr = (PBYTE)exception_record->ExceptionAddress; - Ebp = &Stack; - Esp = (PBYTE) context_record->Esp; - fake_frame = true; - } - else if(context_record) - { - Ebp = (PSTACK)(context_record->Ebp); - Esp = (PBYTE)(context_record->Esp); - } - else - { - Ebp = (PSTACK)&exception_record - 1; //frame addr of Get_Call_Stack() - Esp = (PBYTE)&exception_record; - - // 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 (Ret_Addr_I = 0; - heuristic_walk_i < HEURISTIC_MAX_WALK && - Ret_Addr_I < CALL_TRACE_MAX && !IsBadReadPtr(Ebp, sizeof(PSTACK)) && !IsBadCodePtr(FARPROC(Ebp->Ret_Addr)); - Ret_Addr_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. - tmp_info["CallStack"][Ret_Addr_I]["ModuleName"] = ll_convert_wide_to_string(Module_Name,CP_ACP); - tmp_info["CallStack"][Ret_Addr_I]["ModuleAddress"] = (int)Module_Addr; - tmp_info["CallStack"][Ret_Addr_I]["CallOffset"] = (int)(Ebp->Ret_Addr - Module_Addr); - - // Save 5 params of the call. We don't know the real number of params. - if (fake_frame && !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]; - } - } - tmp_info["CallStack"][Ret_Addr_I]["Parameters"] = params; - } - - tmp_info["CallStack"][Ret_Addr_I]["ReturnAddress"] = (int)Ebp->Ret_Addr; - - // get ready for next frame - // Set ESP to just after return address. Not the real esp, but just enough after the return address - if(!fake_frame) { - Esp = (PBYTE)Ebp + 8; - } - else - { - fake_frame = false; - } - - // is next ebp valid? - // only run if we've never found a good ebp - // and make sure the one after is valid as well - if( !ebp_used && - shouldUseStackWalker(Ebp, 2)) - { - heuristic_walk_i++; - PBYTE new_ebp = get_valid_frame(Esp); - if (new_ebp != NULL) - { - Ebp = (PSTACK)new_ebp; - } - } - else - { - ebp_used = true; - Ebp = Ebp->Ebp; - } - } -/* TODO remove or turn this code back on to edit the stack after i see a few raw ones. -Palmer - // Now go back through and edit out heuristic stacks that could very well be bogus. - // Leave the top and the last 3 stack chosen by the heuristic, however. - if(heuristic_walk_i > 2) - { - info["CallStack"][0] = tmp_info["CallStack"][0]; - std::string ttest = info["CallStack"][0]["ModuleName"]; - for(int cur_frame = 1; - (cur_frame + heuristic_walk_i - 2 < Ret_Addr_I); - ++cur_frame) - { - // edit out the middle heuristic found frames - info["CallStack"][cur_frame] = tmp_info["CallStack"][cur_frame + heuristic_walk_i - 2]; - } - } - else - { - info = tmp_info; - } -*/ - info = tmp_info; - info["HeuristicWalkI"] = heuristic_walk_i; - info["EbpUsed"] = ebp_used; - -} //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. -{ - 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"] = ll_convert_wide_to_string(Str,CP_ACP); - info["ThreadID"] = (S32)GetCurrentThreadId(); - - // 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"] = ll_convert_wide_to_string(Module_Name,CP_ACP); - - 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["DateModified"] = llformat("%02d/%02d/%d", T.wMonth, T.wDay, T.wYear); - } - CloseHandle(hFile); - } - } - else - { - info["ExceptionAddr"] = (int)E.ExceptionAddress; - } - - info["ExceptionCode"] = (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. - /* - std::string str; - for (i = 0; i < 16; i++) - str += llformat(" %02X", PBYTE(E.ExceptionAddress)[i]); - info["Instruction"] = 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->ExceptionRecord, pException->ContextRecord, info); - - return info; -} //Get_Exception_Info - -#define UNICODE - class LLMemoryReserve { public: @@ -663,66 +79,23 @@ void LLMemoryReserve::release() static LLMemoryReserve gEmergencyMemoryReserve; -#ifndef _M_IX86 - #error "The following code only works for x86!" -#endif -LPTOP_LEVEL_EXCEPTION_FILTER WINAPI MyDummySetUnhandledExceptionFilter( - LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter) + +LONG NTAPI vectoredHandler(PEXCEPTION_POINTERS exception_infop) { - if(lpTopLevelExceptionFilter == gFilterFunc) - return gFilterFunc; - - llinfos << "Someone tried to set the exception filter. Listing call stack modules" << llendl; - LLSD cs_info; - Get_Call_Stack(NULL, NULL, cs_info); - - if(cs_info.has("CallStack") && cs_info["CallStack"].isArray()) - { - LLSD cs = cs_info["CallStack"]; - for(LLSD::array_iterator i = cs.beginArray(); - i != cs.endArray(); - ++i) - { - llinfos << "Module: " << (*i)["ModuleName"] << llendl; - } - } - - return gFilterFunc; -} - -BOOL PreventSetUnhandledExceptionFilter() -{ - HMODULE hKernel32 = LoadLibrary(_T("kernel32.dll")); - if (hKernel32 == NULL) - return FALSE; - - void *pOrgEntry = GetProcAddress(hKernel32, "SetUnhandledExceptionFilter"); - if(pOrgEntry == NULL) - return FALSE; - - unsigned char newJump[ 100 ]; - DWORD dwOrgEntryAddr = (DWORD)pOrgEntry; - dwOrgEntryAddr += 5; // add 5 for 5 op-codes for jmp far - void *pNewFunc = &MyDummySetUnhandledExceptionFilter; - DWORD dwNewEntryAddr = (DWORD) pNewFunc; - DWORD dwRelativeAddr = dwNewEntryAddr - dwOrgEntryAddr; - - newJump[ 0 ] = 0xE9; // JMP absolute - memcpy(&newJump[ 1 ], &dwRelativeAddr, sizeof(pNewFunc)); - SIZE_T bytesWritten; - BOOL bRet = WriteProcessMemory(GetCurrentProcess(), - pOrgEntry, newJump, sizeof(pNewFunc) + 1, &bytesWritten); - return bRet; + LLWinDebug::instance().generateMinidump(exception_infop); + return EXCEPTION_CONTINUE_SEARCH; } // static -void LLWinDebug::initExceptionHandler(LPTOP_LEVEL_EXCEPTION_FILTER filter_func) +void LLWinDebug::init() { - static bool s_first_run = true; // Load the dbghelp dll now, instead of waiting for the crash. // Less potential for stack mangling + // Don't install vectored exception handler if being debugged. + if(IsDebuggerPresent()) return; + if (s_first_run) { // First, try loading from the directory that the app resides in. @@ -753,161 +126,68 @@ void LLWinDebug::initExceptionHandler(LPTOP_LEVEL_EXCEPTION_FILTER filter_func) gEmergencyMemoryReserve.reserve(); s_first_run = false; + + // Add this exeption hanlder to save windows style minidump. + AddVectoredExceptionHandler(0, &vectoredHandler); } - - // 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"); - - LPTOP_LEVEL_EXCEPTION_FILTER prev_filter; - prev_filter = SetUnhandledExceptionFilter(filter_func); - - // *REMOVE:Mani - //PreventSetUnhandledExceptionFilter(); - - if(prev_filter != gFilterFunc) - { - LL_WARNS("AppInit") - << "Replacing unknown exception (" << (void *)prev_filter << ") with (" << (void *)filter_func << ") !" << LL_ENDL; - } - - gFilterFunc = filter_func; -} - -bool LLWinDebug::checkExceptionHandler() -{ - bool ok = true; - LPTOP_LEVEL_EXCEPTION_FILTER prev_filter; - prev_filter = SetUnhandledExceptionFilter(gFilterFunc); - - if (prev_filter != gFilterFunc) - { - LL_WARNS("AppInit") << "Our exception handler (" << (void *)gFilterFunc << ") replaced with " << prev_filter << "!" << LL_ENDL; - ok = false; - } - - if (prev_filter == NULL) - { - ok = FALSE; - if (gFilterFunc == NULL) - { - LL_WARNS("AppInit") << "Exception handler uninitialized." << LL_ENDL; - } - else - { - LL_WARNS("AppInit") << "Our exception handler (" << (void *)gFilterFunc << ") replaced with NULL!" << LL_ENDL; - } - } - - return ok; } void LLWinDebug::writeDumpToFile(MINIDUMP_TYPE type, MINIDUMP_EXCEPTION_INFORMATION *ExInfop, const std::string& filename) { - if(f_mdwp == NULL || gDirUtilp == NULL) + // Temporary fix to switch out the code that writes the DMP file. + // Fix coming that doesn't write a mini dump file for regular C++ exceptions. + const bool enable_write_dump_file = false; + if ( enable_write_dump_file ) { - return; - //write_debug("No way to generate a minidump, no MiniDumpWriteDump function!\n"); - } - else - { - 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) + if(f_mdwp == NULL || gDirUtilp == NULL) { - // Write the dump, ignoring the return value - f_mdwp(GetCurrentProcess(), - GetCurrentProcessId(), - hFile, - type, - ExInfop, - NULL, - NULL); - - CloseHandle(hFile); + return; } + else + { + 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); + } + + } } } // static -void LLWinDebug::generateCrashStacks(struct _EXCEPTION_POINTERS *exception_infop) +void LLWinDebug::generateMinidump(struct _EXCEPTION_POINTERS *exception_infop) { - // *NOTE:Mani - This method is no longer the exception handler. - // Its called from viewer_windows_exception_handler() and other places. - - // - // Let go of a bunch of reserved memory to give library calls etc - // a chance to execute normally in the case that we ran out of - // memory. - // - LLSD info; std::string dump_path = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "SecondLifeException"); - std::string log_path = dump_path + ".log"; - if (exception_infop) { // Since there is exception info... Release the hounds. gEmergencyMemoryReserve.release(); - LLControlVariable* save_minimap = gSavedSettings.getControl("SaveMinidump"); - if(save_minimap && save_minimap->getValue().asBoolean()) - { - _MINIDUMP_EXCEPTION_INFORMATION ExInfo; + _MINIDUMP_EXCEPTION_INFORMATION ExInfo; - ExInfo.ThreadId = ::GetCurrentThreadId(); - ExInfo.ExceptionPointers = exception_infop; - ExInfo.ClientPointers = NULL; - - writeDumpToFile(MiniDumpNormal, &ExInfo, "SecondLife.dmp"); - writeDumpToFile((MINIDUMP_TYPE)(MiniDumpWithDataSegs | MiniDumpWithIndirectlyReferencedMemory), &ExInfo, "SecondLifePlus.dmp"); - } - - info = Get_Exception_Info(exception_infop); + ExInfo.ThreadId = ::GetCurrentThreadId(); + ExInfo.ExceptionPointers = exception_infop; + ExInfo.ClientPointers = NULL; + writeDumpToFile((MINIDUMP_TYPE)(MiniDumpWithDataSegs | MiniDumpWithIndirectlyReferencedMemory), &ExInfo, "SecondLife.dmp"); } - - LLSD threads; - std::vector thread_ids; - GetProcessThreadIDs(GetCurrentProcessId(), thread_ids); - - for(std::vector::iterator th_itr = thread_ids.begin(); - th_itr != thread_ids.end(); - ++th_itr) - { - LLSD thread_info; - if(*th_itr != GetCurrentThreadId()) - { - GetThreadCallStack(*th_itr, thread_info); - } - - if(thread_info) - { - threads[llformat("ID %d", *th_itr)] = thread_info; - } - } - - info["Threads"] = threads; - - llofstream out_file(log_path); - LLSDSerialize::toPrettyXML(info, out_file); - out_file.close(); -} - -void LLWinDebug::clearCrashStacks() -{ - LLSD info; - std::string dump_path = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "SecondLifeException.log"); - LLFile::remove(dump_path); } diff --git a/indra/newview/llwindebug.h b/indra/newview/llwindebug.h index f4a6a2d54..3837825d3 100644 --- a/indra/newview/llwindebug.h +++ b/indra/newview/llwindebug.h @@ -2,31 +2,25 @@ * @file llwindebug.h * @brief LLWinDebug class header file * - * $LicenseInfo:firstyear=2004&license=viewergpl$ - * - * Copyright (c) 2004-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2004&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -36,40 +30,14 @@ #include "stdtypes.h" #include -class LLWinDebug +class LLWinDebug: + public LLSingleton { public: - - /** - * @brief initialize the llwindebug exception filter callback - * - * Hand a windows unhandled exception filter to LLWinDebug - * This method should only be called to change the - * exception filter used by llwindebug. - * - * Setting filter_func to NULL will clear any custom filters. - **/ - static void initExceptionHandler(LPTOP_LEVEL_EXCEPTION_FILTER filter_func); - - /** - * @brief check the status of the exception filter. - * - * Resets unhandled exception filter to the filter specified - * w/ initExceptionFilter). - * Returns false if the exception filter was modified. - * - * *NOTE:Mani In the past mozlib has been accused of - * overriding the exception filter. If the mozlib filter - * is required, perhaps we can chain calls from our - * filter to mozlib's. - **/ - static bool checkExceptionHandler(); - - static void generateCrashStacks(struct _EXCEPTION_POINTERS *pExceptionInfo = NULL); - static void clearCrashStacks(); // Delete the crash stack file(s). - - static void writeDumpToFile(MINIDUMP_TYPE type, MINIDUMP_EXCEPTION_INFORMATION *ExInfop, const std::string& filename); + static void init(); + static void generateMinidump(struct _EXCEPTION_POINTERS *pExceptionInfo = NULL); private: + static void writeDumpToFile(MINIDUMP_TYPE type, MINIDUMP_EXCEPTION_INFORMATION *ExInfop, const std::string& filename); }; #endif // LL_LLWINDEBUG_H diff --git a/indra/win_crash_logger/CMakeLists.txt b/indra/win_crash_logger/CMakeLists.txt index eb2f45633..1f31db0b8 100644 --- a/indra/win_crash_logger/CMakeLists.txt +++ b/indra/win_crash_logger/CMakeLists.txt @@ -3,7 +3,6 @@ project(win_crash_logger) include(00-Common) -include(DirectX) include(LLCommon) include(LLCrashLogger) include(LLMath) @@ -12,6 +11,8 @@ include(LLVFS) include(LLWindow) include(LLXML) include(Linking) +include(LLSharedLibs) +include(GoogleBreakpad) include_directories( ${LLCOMMON_INCLUDE_DIRS} @@ -20,6 +21,11 @@ include_directories( ${LLWINDOW_INCLUDE_DIRS} ${LLXML_INCLUDE_DIRS} ${LLVFS_INCLUDE_DIRS} + ${BREAKPAD_INCLUDE_DIRECTORIES} + ) +include_directories(SYSTEM + ${LLCOMMON_SYSTEM_INCLUDE_DIRS} + ${LLXML_SYSTEM_INCLUDE_DIRS} ) set(win_crash_logger_SOURCE_FILES @@ -40,7 +46,7 @@ set_source_files_properties(${win_crash_logger_HEADER_FILES} PROPERTIES HEADER_FILE_ONLY TRUE) set(win_crash_logger_RESOURCE_FILES - snowglobe_icon.ico + ll_icon.ico ) set_source_files_properties(${win_crash_logger_RESOURCE_FILES} @@ -59,11 +65,12 @@ list(APPEND ${win_crash_logger_RESOURCE_FILES} ) -find_library(DXGUID_LIBRARY dxguid ${DIRECTX_LIBRARY_DIR}) +# find_library(DXGUID_LIBRARY dxguid ${DIRECTX_LIBRARY_DIR}) add_executable(windows-crash-logger WIN32 ${win_crash_logger_SOURCE_FILES}) target_link_libraries(windows-crash-logger + ${BREAKPAD_EXCEPTION_HANDLER_LIBRARIES} ${LLCRASHLOGGER_LIBRARIES} ${LLWINDOW_LIBRARIES} ${LLVFS_LIBRARIES} @@ -72,11 +79,13 @@ target_link_libraries(windows-crash-logger ${LLMATH_LIBRARIES} ${LLCOMMON_LIBRARIES} ${WINDOWS_LIBRARIES} - ${DXGUID_LIBRARY} +# ${DXGUID_LIBRARY} + ${GOOGLE_PERFTOOLS_LIBRARIES} user32 gdi32 ole32 oleaut32 + wininet Wldap32 ) @@ -87,3 +96,6 @@ if (WINDOWS) LINK_FLAGS_DEBUG "/NODEFAULTLIB:\"LIBCMT;LIBCMTD;MSVCRT\"" ) endif (WINDOWS) + +# Singu Note: not used by our build +# ll_deploy_sharedlibs_command(windows-crash-logger) diff --git a/indra/win_crash_logger/StdAfx.cpp b/indra/win_crash_logger/StdAfx.cpp index 02049766c..f56711af7 100644 --- a/indra/win_crash_logger/StdAfx.cpp +++ b/indra/win_crash_logger/StdAfx.cpp @@ -2,31 +2,25 @@ * @file StdAfx.cpp * @brief windows crash logger source file for includes * - * $LicenseInfo:firstyear=2003&license=viewergpl$ - * - * Copyright (c) 2003-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2003&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/win_crash_logger/StdAfx.h b/indra/win_crash_logger/StdAfx.h index 021a995f5..35976658a 100644 --- a/indra/win_crash_logger/StdAfx.h +++ b/indra/win_crash_logger/StdAfx.h @@ -2,31 +2,25 @@ * @file StdAfx.h * @brief standard system includes * - * $LicenseInfo:firstyear=2003&license=viewergpl$ - * - * Copyright (c) 2003-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2003&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -44,7 +38,6 @@ #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers - // Windows Header Files: #include diff --git a/indra/win_crash_logger/llcrashloggerwindows.cpp b/indra/win_crash_logger/llcrashloggerwindows.cpp index 1a233fe2f..e9102b725 100644 --- a/indra/win_crash_logger/llcrashloggerwindows.cpp +++ b/indra/win_crash_logger/llcrashloggerwindows.cpp @@ -2,31 +2,25 @@ * @file llcrashloggerwindows.cpp * @brief Windows crash logger implementation * -* $LicenseInfo:firstyear=2003&license=viewergpl$ -* -* Copyright (c) 2003-2009, Linden Research, Inc. -* +* $LicenseInfo:firstyear=2003&license=viewerlgpl$ * Second Life Viewer Source Code -* The source code in this file ("Source Code") is provided by Linden Lab -* to you under the terms of the GNU General Public License, version 2.0 -* ("GPL"), unless you have obtained a separate licensing agreement -* ("Other License"), formally executed by you and Linden Lab. Terms of -* the GPL can be found in doc/GPL-license.txt in this distribution, or -* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 +* Copyright (C) 2010, Linden Research, Inc. * -* There are special exceptions to the terms and conditions of the GPL as -* it is applied to this Source Code. View the full text of the exception -* in the file doc/FLOSS-exception.txt in this software distribution, or -* online at -* http://secondlifegrid.net/programs/open_source/licensing/flossexception +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. * -* By copying, modifying or distributing this software, you acknowledge -* that you have read and understood your obligations described above, -* and agree to abide by those obligations. +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. * -* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO -* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, -* COMPLETENESS OR PERFORMANCE. +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -40,7 +34,6 @@ #include "boost/tokenizer.hpp" -#include "dbghelp.h" #include "indra_constants.h" // CRASH_BEHAVIOR_ASK, CRASH_SETTING_NAME #include "llerror.h" #include "llfile.h" @@ -49,6 +42,10 @@ #include "lldxhardware.h" #include "lldir.h" #include "llsdserialize.h" +#include "llsdutil.h" + +#include +#include #define MAX_LOADSTRING 100 #define MAX_STRING 2048 @@ -71,6 +68,7 @@ BOOL gFirstDialog = TRUE; // Are we currently handling the Send/Don't Send dialo std::stringstream gDXInfo; bool gSendLogs = false; +LLCrashLoggerWindows* LLCrashLoggerWindows::sInstance = NULL; //Conversion from char* to wchar* //Replacement for ATL macros, doesn't allocate memory @@ -145,7 +143,7 @@ void LLCrashLoggerWindows::ProcessCaption(HWND hWnd) TCHAR header[MAX_STRING]; std::string final; GetWindowText(hWnd, templateText, sizeof(templateText)); - final = llformat(ll_convert_wide_to_string(templateText,CP_ACP).c_str(), gProductName.c_str()); + final = llformat(ll_convert_wide_to_string(templateText, CP_ACP).c_str(), gProductName.c_str()); ConvertLPCSTRToLPWSTR(final.c_str(), header); SetWindowText(hWnd, header); } @@ -158,7 +156,7 @@ void LLCrashLoggerWindows::ProcessDlgItemText(HWND hWnd, int nIDDlgItem) TCHAR header[MAX_STRING]; std::string final; GetDlgItemText(hWnd, nIDDlgItem, templateText, sizeof(templateText)); - final = llformat(ll_convert_wide_to_string(templateText,CP_ACP).c_str(), gProductName.c_str()); + final = llformat(ll_convert_wide_to_string(templateText, CP_ACP).c_str(), gProductName.c_str()); ConvertLPCSTRToLPWSTR(final.c_str(), header); SetDlgItemText(hWnd, nIDDlgItem, header); } @@ -201,7 +199,7 @@ bool handle_button_click(WORD button_id) wbuffer, // pointer to buffer for text 20000 // maximum size of string ); - std::string user_text(ll_convert_wide_to_string(wbuffer,CP_ACP)); + std::string user_text(ll_convert_wide_to_string(wbuffer, CP_ACP)); // Activate and show the window. ShowWindow(gHwndProgress, SW_SHOW); // Try doing this second to make the progress window go frontmost. @@ -247,14 +245,182 @@ LRESULT CALLBACK WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam LLCrashLoggerWindows::LLCrashLoggerWindows(void) { + if (LLCrashLoggerWindows::sInstance==NULL) + { + sInstance = this; + } } LLCrashLoggerWindows::~LLCrashLoggerWindows(void) { + sInstance = NULL; +} + +bool LLCrashLoggerWindows::getMessageWithTimeout(MSG *msg, UINT to) +{ + bool res; + const int timerID=37; + SetTimer(NULL, timerID, to, NULL); + res = GetMessage(msg, NULL, 0, 0); + KillTimer(NULL, timerID); + if (!res) + return false; + if (msg->message == WM_TIMER && msg->hwnd == NULL && msg->wParam == 1) + return false; //TIMEOUT! You could call SetLastError() or something... + return true; +} + +int LLCrashLoggerWindows::processingLoop() { + const int millisecs=1000; + static int first_connect = 1; + + LLSD options = getOptionData( LLApp::PRIORITY_COMMAND_LINE ); + + MSG msg; + + bool result; + + while (1) + { + result = getMessageWithTimeout(&msg, millisecs); + if ( result ) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + if (first_connect ) + { + if ( mClientsConnected > 0) + { + first_connect = 0; + } + } + else + { + if (mClientsConnected == 0) + { + break; + } + if (!mKeyMaster.isProcessAlive(mPID, mProcName) ) + { + break; + } + } + } + + llinfos << "session ending.." << llendl; + + llinfos << "clients connected :" << mClientsConnected << llendl; + + return 0; +} + + +void LLCrashLoggerWindows::OnClientConnected(void* context, + const google_breakpad::ClientInfo* client_info) +{ + llinfos << "client start. pid = " << client_info->pid() << llendl; + sInstance->mClientsConnected++; + +} + +void LLCrashLoggerWindows::OnClientExited(void* context, + const google_breakpad::ClientInfo* client_info) +{ + llinfos << "client end. pid = " << client_info->pid() << llendl; + sInstance->mClientsConnected--; +} + +/* +void LLCrashLoggerWindows::OnClientDumpRequest(void* context, + const google_breakpad::ClientInfo* client_info, + const std::wstring* file_path) +{ + ProcessingLock lock; + + if (!file_path) + { + llwarns << "dump with no file path" << llendl; + return; + } + if (!client_info) + { + llwarns << "dump with no client info" << llendl; + return; + } + + LLCrashLoggerWindows* self = static_cast(context); + if (!self) + { + llwarns << "dump with no context" << llendl; + return; + } + + DWORD pid = client_info->pid(); + + +// Send the crash dump using a worker thread. This operation has retry +// logic in case there is no internet connection at the time. +DumpJobInfo* dump_job = new DumpJobInfo(pid, self, map, +dump_location.value()); +if (!::QueueUserWorkItem(&CrashService::AsyncSendDump, +dump_job, WT_EXECUTELONGFUNCTION)) { +LOG(ERROR) << "could not queue job"; +} +} +*/ + +bool LLCrashLoggerWindows::initCrashServer() +{ + //For Breakpad on Windows we need a full Out of Process service to get good data. + //This routine starts up the service on a named pipe that the viewer will then + //communicate with. + using namespace google_breakpad; + + LLSD options = getOptionData( LLApp::PRIORITY_COMMAND_LINE ); + std::string dump_path = options["dumpdir"].asString(); + mClientsConnected = 0; + mPID = options["pid"].asInteger(); + mProcName = options["procname"].asString(); + + std::wostringstream ws; + //Generate a quasi-uniq name for the named pipe. For our purposes + //this is unique-enough with least hassle. Worst case for duplicate name + //is a second instance of the viewer will not do crash reporting. + ws << mCrashReportPipeStr << mPID; + std::wstring wpipe_name = ws.str(); + + std::wstring wdump_path; + wdump_path.assign(dump_path.begin(), dump_path.end()); + + //Pipe naming conventions: http://msdn.microsoft.com/en-us/library/aa365783%28v=vs.85%29.aspx + mCrashHandler = new CrashGenerationServer( (WCHAR *)wpipe_name.c_str(), + NULL, + &LLCrashLoggerWindows::OnClientConnected, this, + NULL, NULL, // &LLCrashLoggerWindows::OnClientDumpRequest, this, + &LLCrashLoggerWindows::OnClientExited, this, + NULL, NULL, + true, &wdump_path); + + if (!mCrashHandler) { + //Failed to start the crash server. + llwarns << "Failed to init crash server." << llendl; + return false; + } + + // Start servicing clients. + if (!mCrashHandler->Start()) { + llwarns << "Failed to start crash server." << llendl; + return false; + } + + return true; } bool LLCrashLoggerWindows::init(void) { + initCrashServer(); bool ok = LLCrashLogger::init(); if(!ok) return false; @@ -298,24 +464,23 @@ void LLCrashLoggerWindows::gatherPlatformSpecificFiles() SetCursor(gCursorWait); // At this point we're responsive enough the user could click the close button SetCursor(gCursorArrow); - mDebugLog["DisplayDeviceInfo"] = gDXHardware.getDisplayInfo(); - mFileMap["CrashLog"] = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"SecondLifeException.log"); + //mDebugLog["DisplayDeviceInfo"] = gDXHardware.getDisplayInfo(); //Not initialized. } bool LLCrashLoggerWindows::mainLoop() { - + llinfos << "CrashSubmitBehavior is " << mCrashBehavior << llendl; // Note: parent hwnd is 0 (the desktop). No dlg proc. See Petzold (5th ed) HexCalc example, Chapter 11, p529 // win_crash_logger.rc has been edited by hand. // Dialogs defined with CLASS "WIN_CRASH_LOGGER" (must be same as szWindowClass) gProductName = mProductName; - gHwndProgress = CreateDialog(hInst, MAKEINTRESOURCE(IDD_PROGRESS), 0, NULL); ProcessCaption(gHwndProgress); ShowWindow(gHwndProgress, SW_HIDE ); if (mCrashBehavior == CRASH_BEHAVIOR_ALWAYS_SEND) { + llinfos << "Showing crash report submit progress window." << llendl; ShowWindow(gHwndProgress, SW_SHOW ); sendCrashLogs(); } @@ -362,7 +527,7 @@ bool LLCrashLoggerWindows::mainLoop() void LLCrashLoggerWindows::updateApplication(const std::string& message) { - LLCrashLogger::updateApplication(); + LLCrashLogger::updateApplication(message); if(!message.empty()) show_progress(message); update_messages(); } @@ -376,8 +541,8 @@ bool LLCrashLoggerWindows::cleanup() sleep_and_pump_messages(3); } PostQuitMessage(0); + commonCleanup(); + mKeyMaster.releaseMaster(); return true; } - - diff --git a/indra/win_crash_logger/llcrashloggerwindows.h b/indra/win_crash_logger/llcrashloggerwindows.h index e6a9c77d5..85cafd54c 100644 --- a/indra/win_crash_logger/llcrashloggerwindows.h +++ b/indra/win_crash_logger/llcrashloggerwindows.h @@ -2,31 +2,25 @@ * @file llcrashloggerwindows.h * @brief Windows crash logger definition * -* $LicenseInfo:firstyear=2003&license=viewergpl$ -* -* Copyright (c) 2003-2009, Linden Research, Inc. -* +* $LicenseInfo:firstyear=2003&license=viewerlgpl$ * Second Life Viewer Source Code -* The source code in this file ("Source Code") is provided by Linden Lab -* to you under the terms of the GNU General Public License, version 2.0 -* ("GPL"), unless you have obtained a separate licensing agreement -* ("Other License"), formally executed by you and Linden Lab. Terms of -* the GPL can be found in doc/GPL-license.txt in this distribution, or -* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 +* Copyright (C) 2010, Linden Research, Inc. * -* There are special exceptions to the terms and conditions of the GPL as -* it is applied to this Source Code. View the full text of the exception -* in the file doc/FLOSS-exception.txt in this software distribution, or -* online at -* http://secondlifegrid.net/programs/open_source/licensing/flossexception +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. * -* By copying, modifying or distributing this software, you acknowledge -* that you have read and understood your obligations described above, -* and agree to abide by those obligations. +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. * -* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO -* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, -* COMPLETENESS OR PERFORMANCE. +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -37,21 +31,54 @@ #include "windows.h" #include "llstring.h" +class LLSD; + +namespace google_breakpad { + class CrashGenerationServer; + class ClientInfo; +} + class LLCrashLoggerWindows : public LLCrashLogger { public: LLCrashLoggerWindows(void); ~LLCrashLoggerWindows(void); + static LLCrashLoggerWindows* sInstance; + virtual bool init(); virtual bool mainLoop(); virtual void updateApplication(const std::string& message = LLStringUtil::null); virtual bool cleanup(); virtual void gatherPlatformSpecificFiles(); - //void annotateCallStack(); void setHandle(HINSTANCE hInst) { mhInst = hInst; } + int clients_connected() const { + return mClientsConnected; + } + bool getMessageWithTimeout(MSG *msg, UINT to); + + // Starts the processing loop. This function does not return unless the + // user is logging off or the user closes the crash service window. The + // return value is a good number to pass in ExitProcess(). + int processingLoop(); private: void ProcessDlgItemText(HWND hWnd, int nIDDlgItem); void ProcessCaption(HWND hWnd); + bool initCrashServer(); + google_breakpad::CrashGenerationServer* mCrashHandler; + static void OnClientConnected(void* context, + const google_breakpad::ClientInfo* client_info); + + /*static void OnClientDumpRequest( + void* context, + const google_breakpad::ClientInfo* client_info, + const std::wstring* file_path);*/ + + static void OnClientExited(void* context, + const google_breakpad::ClientInfo* client_info); + int mClientsConnected; + int mPID; + std::string mProcName; + HINSTANCE mhInst; }; diff --git a/indra/win_crash_logger/resource.h b/indra/win_crash_logger/resource.h index 54b9b4b82..37a387275 100644 --- a/indra/win_crash_logger/resource.h +++ b/indra/win_crash_logger/resource.h @@ -2,31 +2,25 @@ * @file resource.h * @brief Windows crash logger windows resources * -* $LicenseInfo:firstyear=2003&license=viewergpl$ -* -* Copyright (c) 2003-2009, Linden Research, Inc. -* +* $LicenseInfo:firstyear=2003&license=viewerlgpl$ * Second Life Viewer Source Code -* The source code in this file ("Source Code") is provided by Linden Lab -* to you under the terms of the GNU General Public License, version 2.0 -* ("GPL"), unless you have obtained a separate licensing agreement -* ("Other License"), formally executed by you and Linden Lab. Terms of -* the GPL can be found in doc/GPL-license.txt in this distribution, or -* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 +* Copyright (C) 2010, Linden Research, Inc. * -* There are special exceptions to the terms and conditions of the GPL as -* it is applied to this Source Code. View the full text of the exception -* in the file doc/FLOSS-exception.txt in this software distribution, or -* online at -* http://secondlifegrid.net/programs/open_source/licensing/flossexception +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. * -* By copying, modifying or distributing this software, you acknowledge -* that you have read and understood your obligations described above, -* and agree to abide by those obligations. +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. * -* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO -* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, -* COMPLETENESS OR PERFORMANCE. +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/win_crash_logger/win_crash_logger.cpp b/indra/win_crash_logger/win_crash_logger.cpp index 22837d269..e25e12834 100644 --- a/indra/win_crash_logger/win_crash_logger.cpp +++ b/indra/win_crash_logger/win_crash_logger.cpp @@ -2,79 +2,60 @@ * @file win_crash_logger.cpp * @brief Windows crash logger implementation * - * $LicenseInfo:firstyear=2003&license=viewergpl$ - * - * Copyright (c) 2003-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2003&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ -// win_crash_logger.cpp : Defines the entry point for the application. -// - -// Must be first include, precompiled headers. #include "linden_common.h" - #include "stdafx.h" - #include - #include "llcrashloggerwindows.h" +#include - -// -// Implementation -// - int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { - llinfos << "Starting crash reporter" << llendl; - + llinfos << "Starting crash reporter." << llendl; LLCrashLoggerWindows app; app.setHandle(hInstance); - bool ok = app.init(); - if(!ok) + app.parseCommandOptions(__argc, __argv); + + LLSD options = LLApp::instance()->getOptionData( + LLApp::PRIORITY_COMMAND_LINE); + if (!(options.has("pid") && options.has("dumpdir"))) + { + llwarns << "Insufficient parameters to crash report." << llendl; + } + if (! app.init()) { llwarns << "Unable to initialize application." << llendl; - return -1; + return 1; } - // Run the application main loop - if(!LLApp::isQuitting()) app.mainLoop(); - - if (!app.isError()) - { - // - // We don't want to do cleanup here if the error handler got called - - // the assumption is that the error handler is responsible for doing - // app cleanup if there was a problem. - // - app.cleanup(); - } + app.processingLoop(); + app.mainLoop(); + app.cleanup(); + llinfos << "Crash reporter finished normally." << llendl; return 0; } diff --git a/indra/win_crash_logger/win_crash_logger.h b/indra/win_crash_logger/win_crash_logger.h index 0bd42b1be..2cc2cf3dc 100644 --- a/indra/win_crash_logger/win_crash_logger.h +++ b/indra/win_crash_logger/win_crash_logger.h @@ -2,31 +2,25 @@ * @file win_crash_logger.h * @brief Windows crash logger project includes * - * $LicenseInfo:firstyear=2003&license=viewergpl$ - * - * Copyright (c) 2003-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2003&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ From 81fa147450ae84b4c6f1b5d42be28f35538dc89b Mon Sep 17 00:00:00 2001 From: Latif Khalifa Date: Tue, 1 Oct 2013 21:47:12 +0200 Subject: [PATCH 04/16] Breakpad: don't fork logger process on startup. Use singularity-debug as the dir for dumps --- indra/llvfs/lldir.cpp | 3 +++ indra/newview/llappviewerwin32.cpp | 2 ++ 2 files changed, 5 insertions(+) diff --git a/indra/llvfs/lldir.cpp b/indra/llvfs/lldir.cpp index 551338fa6..bb35c4fe4 100644 --- a/indra/llvfs/lldir.cpp +++ b/indra/llvfs/lldir.cpp @@ -283,12 +283,15 @@ const std::string &LLDir::getDumpDir() const { if (sDumpDir.empty() ) { + /* Singu Note: don't generate a different dump dir each time LLUUID uid; uid.generate(); sDumpDir = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "") + "dump-" + uid.asString(); + */ + sDumpDir = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "") + "singularity-debug"; dir_exists_or_crash(sDumpDir); } diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp index 3be747d63..5758fb5c4 100644 --- a/indra/newview/llappviewerwin32.cpp +++ b/indra/newview/llappviewerwin32.cpp @@ -522,6 +522,7 @@ bool LLAppViewerWin32::restoreErrorTrap() void LLAppViewerWin32::initCrashReporting(bool reportFreeze) { + /* Singu Note: don't fork the crash logger on start const char* logger_name = "win_crash_logger.exe"; std::string exe_path = gDirUtilp->getExecutableDir(); exe_path += gDirUtilp->getDirDelimiter(); @@ -543,6 +544,7 @@ void LLAppViewerWin32::initCrashReporting(bool reportFreeze) std::string arg_str = "\"" + exe_path + "\" -dumpdir \"" + logdir + "\" -procname \"" + appname + "\" -pid " + pid_str.str(); llinfos << "spawning " << arg_str << llendl; _spawnl(_P_NOWAIT, exe_path.c_str(), arg_str.c_str(), NULL); + */ /* STARTUPINFO siStartupInfo; From 98d7721ab285e3b3c0dfb4354accecc7598ab10c Mon Sep 17 00:00:00 2001 From: Latif Khalifa Date: Tue, 1 Oct 2013 23:41:38 +0200 Subject: [PATCH 05/16] Breakpad: Commence nuclear bombardment of the unused stuff Windows breakpad crash reports implemented and uploaded TODO: llappviewer linux and mac port of breakpad3 --- indra/CMakeLists.txt | 23 - indra/cmake/CMakeLists.txt | 1 - indra/cmake/LLCrashLogger.cmake | 7 - indra/linux_crash_logger/CMakeLists.txt | 72 - .../linux_crash_logger/linux_crash_logger.cpp | 45 - .../linux_crash_logger/llcrashloggerlinux.cpp | 148 -- indra/linux_crash_logger/llcrashloggerlinux.h | 50 - indra/llcrashlogger/CMakeLists.txt | 38 - indra/llcrashlogger/llcrashlock.cpp | 211 --- indra/llcrashlogger/llcrashlock.h | 73 - indra/mac_crash_logger/CMakeLists.txt | 76 -- .../CrashReporter.nib/classes.nib | 8 - .../CrashReporter.nib/info.nib | 18 - .../CrashReporter.nib/objects.xib | 68 - indra/mac_crash_logger/Info.plist | 26 - indra/mac_crash_logger/llcrashloggermac.cpp | 345 ----- indra/mac_crash_logger/llcrashloggermac.h | 52 - indra/mac_crash_logger/mac_crash_logger.cpp | 52 - indra/mac_updater/AutoUpdater.nib/classes.nib | 4 - indra/mac_updater/AutoUpdater.nib/info.nib | 14 - indra/mac_updater/AutoUpdater.nib/objects.xib | 56 - indra/mac_updater/CMakeLists.txt | 66 - indra/mac_updater/Info.plist | 26 - indra/mac_updater/mac_updater.cpp | 1204 ----------------- indra/newview/CMakeLists.txt | 4 +- indra/newview/app_settings/settings.xml | 2 +- indra/newview/llappviewer.cpp | 6 +- .../llcrashlogger.cpp | 299 +--- .../llcrashlogger.h | 13 +- indra/newview/viewer_manifest.py | 14 - indra/win_crash_logger/CMakeLists.txt | 101 -- indra/win_crash_logger/StdAfx.cpp | 34 - indra/win_crash_logger/StdAfx.h | 56 - indra/win_crash_logger/ll_icon.ico | Bin 2238 -> 0 bytes .../win_crash_logger/llcrashloggerwindows.cpp | 548 -------- indra/win_crash_logger/llcrashloggerwindows.h | 86 -- indra/win_crash_logger/resource.h | 63 - indra/win_crash_logger/snowglobe_icon.ico | Bin 4286 -> 0 bytes indra/win_crash_logger/win_crash_logger.cpp | 61 - indra/win_crash_logger/win_crash_logger.h | 38 - indra/win_crash_logger/win_crash_logger.ico | Bin 1078 -> 0 bytes indra/win_crash_logger/win_crash_logger.rc | 188 --- indra/win_updater/CMakeLists.txt | 35 - indra/win_updater/updater.cpp | 522 ------- 44 files changed, 35 insertions(+), 4718 deletions(-) delete mode 100644 indra/cmake/LLCrashLogger.cmake delete mode 100644 indra/linux_crash_logger/CMakeLists.txt delete mode 100644 indra/linux_crash_logger/linux_crash_logger.cpp delete mode 100644 indra/linux_crash_logger/llcrashloggerlinux.cpp delete mode 100644 indra/linux_crash_logger/llcrashloggerlinux.h delete mode 100644 indra/llcrashlogger/CMakeLists.txt delete mode 100644 indra/llcrashlogger/llcrashlock.cpp delete mode 100644 indra/llcrashlogger/llcrashlock.h delete mode 100644 indra/mac_crash_logger/CMakeLists.txt delete mode 100644 indra/mac_crash_logger/CrashReporter.nib/classes.nib delete mode 100644 indra/mac_crash_logger/CrashReporter.nib/info.nib delete mode 100644 indra/mac_crash_logger/CrashReporter.nib/objects.xib delete mode 100644 indra/mac_crash_logger/Info.plist delete mode 100644 indra/mac_crash_logger/llcrashloggermac.cpp delete mode 100644 indra/mac_crash_logger/llcrashloggermac.h delete mode 100644 indra/mac_crash_logger/mac_crash_logger.cpp delete mode 100644 indra/mac_updater/AutoUpdater.nib/classes.nib delete mode 100644 indra/mac_updater/AutoUpdater.nib/info.nib delete mode 100644 indra/mac_updater/AutoUpdater.nib/objects.xib delete mode 100644 indra/mac_updater/CMakeLists.txt delete mode 100644 indra/mac_updater/Info.plist delete mode 100644 indra/mac_updater/mac_updater.cpp rename indra/{llcrashlogger => newview}/llcrashlogger.cpp (55%) rename indra/{llcrashlogger => newview}/llcrashlogger.h (85%) delete mode 100644 indra/win_crash_logger/CMakeLists.txt delete mode 100644 indra/win_crash_logger/StdAfx.cpp delete mode 100644 indra/win_crash_logger/StdAfx.h delete mode 100644 indra/win_crash_logger/ll_icon.ico delete mode 100644 indra/win_crash_logger/llcrashloggerwindows.cpp delete mode 100644 indra/win_crash_logger/llcrashloggerwindows.h delete mode 100644 indra/win_crash_logger/resource.h delete mode 100644 indra/win_crash_logger/snowglobe_icon.ico delete mode 100644 indra/win_crash_logger/win_crash_logger.cpp delete mode 100644 indra/win_crash_logger/win_crash_logger.h delete mode 100644 indra/win_crash_logger/win_crash_logger.ico delete mode 100644 indra/win_crash_logger/win_crash_logger.rc delete mode 100644 indra/win_updater/CMakeLists.txt delete mode 100644 indra/win_updater/updater.cpp diff --git a/indra/CMakeLists.txt b/indra/CMakeLists.txt index fc7b0a878..8b71ccf51 100644 --- a/indra/CMakeLists.txt +++ b/indra/CMakeLists.txt @@ -75,7 +75,6 @@ if (WINDOWS AND EXISTS ${LIBS_CLOSED_DIR}copy_win_scripts) endif (WINDOWS AND EXISTS ${LIBS_CLOSED_DIR}copy_win_scripts) add_custom_target(viewer) -add_subdirectory(${LIBS_OPEN_PREFIX}llcrashlogger) add_subdirectory(${LIBS_OPEN_PREFIX}llplugin) add_subdirectory(${LIBS_OPEN_PREFIX}llui) @@ -87,28 +86,6 @@ add_subdirectory(${LIBS_OPEN_PREFIX}plugins) # add_subdirectory(${VIEWER_PREFIX}test_apps/llplugintest) #endif (NOT LINUX) -if (LINUX) - add_subdirectory(${VIEWER_PREFIX}linux_crash_logger) - add_dependencies(viewer linux-crash-logger-strip-target) -elseif (DARWIN) - #add_subdirectory(${VIEWER_PREFIX}mac_crash_logger) - #add_subdirectory(${VIEWER_PREFIX}mac_updater) - add_dependencies(viewer mac-crash-logger) - #add_dependencies(viewer mac-updater) -elseif (WINDOWS) - add_subdirectory(${VIEWER_PREFIX}win_crash_logger) - # cmake EXISTS requires an absolute path, see indra/cmake/Variables.cmake - if (EXISTS ${VIEWER_DIR}win_setup) - add_subdirectory(${VIEWER_DIR}win_setup) - endif (EXISTS ${VIEWER_DIR}win_setup) - add_subdirectory(${VIEWER_PREFIX}win_updater) - add_dependencies(viewer windows-updater) - add_dependencies(viewer windows-crash-logger) -elseif (SOLARIS) - add_subdirectory(solaris_crash_logger) - add_dependencies(viewer solaris-crash-logger) -endif (LINUX) - add_subdirectory(${VIEWER_PREFIX}newview/statemachine) add_subdirectory(${VIEWER_PREFIX}newview) add_dependencies(viewer secondlife-bin) diff --git a/indra/cmake/CMakeLists.txt b/indra/cmake/CMakeLists.txt index 4391a8985..5ff1b0399 100644 --- a/indra/cmake/CMakeLists.txt +++ b/indra/cmake/CMakeLists.txt @@ -61,7 +61,6 @@ set(cmake_SOURCE_FILES LLAudio.cmake LLCharacter.cmake LLCommon.cmake - LLCrashLogger.cmake LLImage.cmake LLImageJ2COJ.cmake LLInventory.cmake diff --git a/indra/cmake/LLCrashLogger.cmake b/indra/cmake/LLCrashLogger.cmake deleted file mode 100644 index f2cb83eb8..000000000 --- a/indra/cmake/LLCrashLogger.cmake +++ /dev/null @@ -1,7 +0,0 @@ -# -*- cmake -*- - -set(LLCRASHLOGGER_INCLUDE_DIRS - ${LIBS_OPEN_DIR}/llcrashlogger - ) - -set(LLCRASHLOGGER_LIBRARIES llcrashlogger) diff --git a/indra/linux_crash_logger/CMakeLists.txt b/indra/linux_crash_logger/CMakeLists.txt deleted file mode 100644 index d885e3704..000000000 --- a/indra/linux_crash_logger/CMakeLists.txt +++ /dev/null @@ -1,72 +0,0 @@ -# -*- cmake -*- - -project(linux_crash_logger) - -include(00-Common) -include(LLCommon) -include(LLCrashLogger) -include(LLMath) -include(LLMessage) -include(LLVFS) -include(LLXML) -include(Linking) -include(UI) - -include_directories( - ${LLCOMMON_INCLUDE_DIRS} - ${LLCRASHLOGGER_INCLUDE_DIRS} - ${LLMATH_INCLUDE_DIRS} - ${LLVFS_INCLUDE_DIRS} - ${LLXML_INCLUDE_DIRS} - ) - -set(linux_crash_logger_SOURCE_FILES - linux_crash_logger.cpp - llcrashloggerlinux.cpp - ) - -set(linux_crash_logger_HEADER_FILES - CMakeLists.txt - - llcrashloggerlinux.h - ) - -set_source_files_properties(${linux_crash_logger_HEADER_FILES} - PROPERTIES HEADER_FILE_ONLY TRUE) - -list(APPEND linux_crash_logger_SOURCE_FILES - ${linux_crash_logger_HEADER_FILES} - ) - -set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--as-needed") - -add_executable(linux-crash-logger ${linux_crash_logger_SOURCE_FILES}) - -target_link_libraries(linux-crash-logger - ${LLCRASHLOGGER_LIBRARIES} - ${LLVFS_LIBRARIES} - ${LLXML_LIBRARIES} - ${LLMESSAGE_LIBRARIES} - ${LLUI_LIBRARIES} - ${LLVFS_LIBRARIES} - ${LLMATH_LIBRARIES} - ${LLCOMMON_LIBRARIES} - ${UI_LIBRARIES} - ${DB_LIBRARIES} - ${XMLRPCEPI_LIBRARIES} - ${CURL_LIBRARIES} - ${APR_LIBRARIES} - ${APRUTIL_LIBRARIES} - ${CRYPTO_LIBRARIES} - rt - ) - -add_custom_command( - OUTPUT linux-crash-logger-stripped - COMMAND strip - ARGS --strip-debug -o linux-crash-logger-stripped linux-crash-logger - DEPENDS linux-crash-logger - ) - -add_custom_target(linux-crash-logger-strip-target ALL - DEPENDS linux-crash-logger-stripped) diff --git a/indra/linux_crash_logger/linux_crash_logger.cpp b/indra/linux_crash_logger/linux_crash_logger.cpp deleted file mode 100644 index 97eec851b..000000000 --- a/indra/linux_crash_logger/linux_crash_logger.cpp +++ /dev/null @@ -1,45 +0,0 @@ -/** - * @file linux_crash_logger.cpp - * @brief Linux crash logger implementation - * - * $LicenseInfo:firstyear=2003&license=viewergpl$ - * - * Copyright (c) 2003-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#include "llcrashloggerlinux.h" - -int main(int argc, char **argv) -{ - LLCrashLoggerLinux app; - app.parseCommandOptions(argc, argv); - app.init(); - app.mainLoop(); - app.cleanup(); - return 0; -} - - diff --git a/indra/linux_crash_logger/llcrashloggerlinux.cpp b/indra/linux_crash_logger/llcrashloggerlinux.cpp deleted file mode 100644 index 039b70ec4..000000000 --- a/indra/linux_crash_logger/llcrashloggerlinux.cpp +++ /dev/null @@ -1,148 +0,0 @@ -/** - * @file llcrashloggerlinux.cpp - * @brief Linux crash logger implementation - * - * $LicenseInfo:firstyear=2003&license=viewergpl$ - * - * Copyright (c) 2003-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#include "llcrashloggerlinux.h" - -#include - -#include "linden_common.h" - -#include "boost/tokenizer.hpp" - -#include "indra_constants.h" // CRASH_BEHAVIOR_ASK, CRASH_SETTING_NAME -#include "llerror.h" -#include "llfile.h" -#include "lltimer.h" -#include "llstring.h" -#include "lldir.h" -#include "llsdserialize.h" - -#if LL_GTK -# include "gtk/gtk.h" -#endif // LL_GTK - -#define MAX_LOADSTRING 100 - -// These need to be localized. -static const char dialog_text[] = -"Second Life appears to have crashed or frozen last time it ran.\n" -"This crash reporter collects information about your computer's hardware, operating system, and some Second Life logs, all of which are used for debugging purposes only.\n" -"\n" -"Send crash report?"; - -static const char dialog_title[] = -"Second Life Crash Logger"; - -#if LL_GTK -static void response_callback (GtkDialog *dialog, - gint arg1, - gpointer user_data) -{ - gint *response = (gint*)user_data; - *response = arg1; - gtk_widget_destroy(GTK_WIDGET(dialog)); - gtk_main_quit(); -} -#endif // LL_GTK - -static BOOL do_ask_dialog(void) -{ -#if LL_GTK - gtk_disable_setlocale(); - if (!gtk_init_check(NULL, NULL)) { - llinfos << "Could not initialize GTK for 'ask to send crash report' dialog; not sending report." << llendl; - return FALSE; - } - - GtkWidget *win = NULL; - GtkDialogFlags flags = GTK_DIALOG_MODAL; - GtkMessageType messagetype = GTK_MESSAGE_QUESTION; - GtkButtonsType buttons = GTK_BUTTONS_YES_NO; - gint response = GTK_RESPONSE_NONE; - - win = gtk_message_dialog_new(NULL, - flags, messagetype, buttons, - "%s", dialog_text); - gtk_window_set_type_hint(GTK_WINDOW(win), - GDK_WINDOW_TYPE_HINT_DIALOG); - gtk_window_set_title(GTK_WINDOW(win), dialog_title); - g_signal_connect (win, - "response", - G_CALLBACK (response_callback), - &response); - gtk_widget_show_all (win); - gtk_main(); - - return (GTK_RESPONSE_OK == response || - GTK_RESPONSE_YES == response || - GTK_RESPONSE_APPLY == response); -#else - return FALSE; -#endif // LL_GTK -} - -LLCrashLoggerLinux::LLCrashLoggerLinux(void) -{ -} - -LLCrashLoggerLinux::~LLCrashLoggerLinux(void) -{ -} - -void LLCrashLoggerLinux::gatherPlatformSpecificFiles() -{ - mFileMap["CrashLog"] = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stack_trace.log").c_str(); -} - -bool LLCrashLoggerLinux::mainLoop() -{ - bool send_logs = true; - if(CRASH_BEHAVIOR_ASK == getCrashBehavior()) - { - send_logs = do_ask_dialog(); - } - else if(CRASH_BEHAVIOR_NEVER_SEND == getCrashBehavior()) - { - send_logs = false; - } - - if(send_logs) - { - sendCrashLogs(); - } - return true; -} - -void LLCrashLoggerLinux::updateApplication(const std::string& message) -{ - LLCrashLogger::updateApplication(message); -} diff --git a/indra/linux_crash_logger/llcrashloggerlinux.h b/indra/linux_crash_logger/llcrashloggerlinux.h deleted file mode 100644 index 937d547f8..000000000 --- a/indra/linux_crash_logger/llcrashloggerlinux.h +++ /dev/null @@ -1,50 +0,0 @@ -/** - * @file llcrashloggerlinux.h - * @brief Linux crash logger definition - * - * $LicenseInfo:firstyear=2003&license=viewergpl$ - * - * Copyright (c) 2003-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#ifndef LLCRASHLOGGERLINUX_H -#define LLCRASHLOGGERLINUX_H - -#include "linden_common.h" -#include "llcrashlogger.h" -#include "llstring.h" - -class LLCrashLoggerLinux : public LLCrashLogger -{ -public: - LLCrashLoggerLinux(void); - ~LLCrashLoggerLinux(void); - virtual bool mainLoop(); - virtual void updateApplication(const std::string& = LLStringUtil::null); - virtual void gatherPlatformSpecificFiles(); -}; - -#endif diff --git a/indra/llcrashlogger/CMakeLists.txt b/indra/llcrashlogger/CMakeLists.txt deleted file mode 100644 index 61191b37c..000000000 --- a/indra/llcrashlogger/CMakeLists.txt +++ /dev/null @@ -1,38 +0,0 @@ -# -*- cmake -*- - -project(llcrashlogger) - -include(00-Common) -include(LLCommon) -include(LLMath) -include(LLMessage) -include(LLVFS) -include(LLXML) - -include_directories( - ${LLCOMMON_INCLUDE_DIRS} - ${LLMATH_INCLUDE_DIRS} - ${LLMESSAGE_INCLUDE_DIRS} - ${LLVFS_INCLUDE_DIRS} - ${LLXML_INCLUDE_DIRS} - ) - -set(llcrashlogger_SOURCE_FILES - llcrashlogger.cpp - llcrashlock.cpp - ) - -set(llcrashlogger_HEADER_FILES - CMakeLists.txt - - llcrashlogger.h - llcrashlock.h - ) - -set_source_files_properties(${llcrashlogger_HEADER_FILES} - PROPERTIES HEADER_FILE_ONLY TRUE) - -list(APPEND llcrashlogger_SOURCE_FILES ${llcrashlogger_HEADER_FILES}) - -add_library(llcrashlogger ${llcrashlogger_SOURCE_FILES}) -add_dependencies(llcrashlogger prepare) diff --git a/indra/llcrashlogger/llcrashlock.cpp b/indra/llcrashlogger/llcrashlock.cpp deleted file mode 100644 index 82033f73e..000000000 --- a/indra/llcrashlogger/llcrashlock.cpp +++ /dev/null @@ -1,211 +0,0 @@ -/** - * @file llformat.cpp - * @date January 2007 - * @brief string formatting utility - * - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" - -#include "llcrashlock.h" -#include "lldir.h" -#include "llsd.h" -#include "llsdserialize.h" -#include "llnametable.h" -#include "llframetimer.h" -#include -#include -#include -#include - - -#if LL_WINDOWS //For windows platform. -#include -#include - -/* -namespace { - inline DWORD getpid() { - return GetCurrentProcessId(); - } -} -*/ - -bool LLCrashLock::isProcessAlive(U32 pid, const std::string& pname) -{ - std::wstring wpname; - wpname = std::wstring(pname.begin(), pname.end()); - - HANDLE snapshot; - PROCESSENTRY32 pe32; - - bool matched = false; - - snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); - if (snapshot == INVALID_HANDLE_VALUE) - { - return false; - } - else - { - pe32.dwSize = sizeof(PROCESSENTRY32); - if (Process32First(snapshot, &pe32)) - { - do { - std::wstring wexecname = pe32.szExeFile; - std::string execname = std::string(wexecname.begin(), wexecname.end()); - if (!wpname.compare(pe32.szExeFile)) - { - if (pid == (U32)pe32.th32ProcessID) - { - matched = true; - break; - } - } - } while (Process32Next(snapshot, &pe32)); - } - } - - CloseHandle(snapshot); - return matched; -} - -#else //Everyone Else -bool LLCrashLock::isProcessAlive(U32 pid, const std::string& pname) -{ - //Will boost.process ever become a reality? - std::stringstream cmd; - - cmd << "pgrep '" << pname << "' | grep '^" << pid << "$'"; - return (!system(cmd.str().c_str())); -} -#endif //Everyone else. - - -LLCrashLock::LLCrashLock() : mCleanUp(true), mWaitingPID(0) -{ -} - -void LLCrashLock::setCleanUp(bool cleanup) -{ - mCleanUp = cleanup; //Allow cleanup to be disabled for debugging. -} - -LLSD LLCrashLock::getLockFile(std::string filename) -{ - LLSD lock_sd = LLSD::emptyMap(); - - llifstream ifile(filename); - - if (ifile.is_open()) - { - LLSDSerialize::fromXML(lock_sd, ifile); - ifile.close(); - } - - return lock_sd; -} - -bool LLCrashLock::putLockFile(std::string filename, const LLSD& data) -{ - bool result = true; - llofstream ofile(filename); - - if (!LLSDSerialize::toXML(data,ofile)) - { - result=false; - } - ofile.close(); - return result; -} - -bool LLCrashLock::requestMaster( F32 timeout ) -{ - if (mMaster.empty()) - { - mMaster = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, - "crash_master.lock"); - } - - LLSD lock_sd=getLockFile(mMaster); - - if (lock_sd.has("pid")) - { - mWaitingPID = lock_sd["pid"].asInteger(); - if ( isProcessAlive(mWaitingPID, gDirUtilp->getExecutableFilename()) ) - { - mTimer.resetWithExpiry(timeout); - return false; - } - } - - U32 pid = getpid(); - lock_sd["pid"] = (LLSD::Integer)pid; - return putLockFile(mMaster,lock_sd); -} - -bool LLCrashLock::checkMaster() -{ - if (mWaitingPID) - { - return (!isProcessAlive(mWaitingPID, gDirUtilp->getExecutableFilename())); - } - return false; -} - -bool LLCrashLock::isWaiting() -{ - return !mTimer.hasExpired(); -} - -void LLCrashLock::releaseMaster() -{ - //Yeeeeeeehaw - unlink(mMaster.c_str()); -} - -LLSD LLCrashLock::getProcessList() -{ - if (mDumpTable.empty()) - { - mDumpTable= gDirUtilp->getExpandedFilename(LL_PATH_LOGS, - "crash_table.lock"); - } - return getLockFile(mDumpTable); -} - -//static -bool LLCrashLock::fileExists(std::string filename) -{ - return boost::filesystem::exists(filename.c_str()); -} - -void LLCrashLock::cleanupProcess(std::string proc_dir) -{ - boost::filesystem::remove_all(proc_dir); -} - -bool LLCrashLock::putProcessList(const LLSD& proc_sd) -{ - return putLockFile(mDumpTable,proc_sd); -} diff --git a/indra/llcrashlogger/llcrashlock.h b/indra/llcrashlogger/llcrashlock.h deleted file mode 100644 index cde183272..000000000 --- a/indra/llcrashlogger/llcrashlock.h +++ /dev/null @@ -1,73 +0,0 @@ -/** - * @file llpidlock.h - * @brief Maintainence of disk locking files for crash reporting - * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_CRASHLOCK_H -#define LL_CRASHLOCK_H - -#include "llframetimer.h" - -class LLSD; - -#if !LL_WINDOWS //For non-windows platforms. -#include -#endif - -//Crash reporter will now be kicked off by the viewer but otherwise -//run independent of the viewer. - -class LLCrashLock -{ -public: - LLCrashLock(); - bool requestMaster( F32 timeout=300.0); //Wait until timeout for master lock. - bool checkMaster(); //True if available. False if not. - void releaseMaster( ); //Release master lockfile. - bool isLockPresent(std::string filename); //Check if lockfile exists. - bool isProcessAlive(U32 pid, const std::string& pname); //Check if pid is alive. - bool isWaiting(); //Waiting for master lock to be released. - LLSD getProcessList(); //Get next process pid/dir pairs - void cleanupProcess(std::string proc_dir); //Remove from list, clean up working dir. - bool putProcessList(const LLSD& processlist); //Write pid/dir pairs back to disk. - static bool fileExists(std::string filename); - - - //getters - S32 getPID(); - - //setters - void setCleanUp(bool cleanup=true); - void setSaveName(std::string savename); -private: - LLSD getLockFile(std::string filename); - bool putLockFile(std::string filename, const LLSD& data); - bool mCleanUp; - std::string mMaster; - std::string mDumpTable; - U32 mWaitingPID; //The process we're waiting on if any. - LLFrameTimer mTimer; -}; - -#endif // LL_CRASHLOCK_H diff --git a/indra/mac_crash_logger/CMakeLists.txt b/indra/mac_crash_logger/CMakeLists.txt deleted file mode 100644 index daf3e1085..000000000 --- a/indra/mac_crash_logger/CMakeLists.txt +++ /dev/null @@ -1,76 +0,0 @@ -# -*- cmake -*- - -project(mac_crash_logger) - -include(00-Common) -include(LLCommon) -include(LLCrashLogger) -include(LLMath) -include(LLMessage) -include(LLVFS) -include(LLXML) -include(Linking) - -include_directories( - ${LLCOMMON_INCLUDE_DIRS} - ${LLCRASHLOGGER_INCLUDE_DIRS} - ${LLMATH_INCLUDE_DIRS} - ${LLVFS_INCLUDE_DIRS} - ${LLXML_INCLUDE_DIRS} - ) - -set(mac_crash_logger_SOURCE_FILES - mac_crash_logger.cpp - llcrashloggermac.cpp - ) - -set(mac_crash_logger_HEADER_FILES - CMakeLists.txt - - llcrashloggermac.h - ) - -set_source_files_properties(${mac_crash_logger_HEADER_FILES} - PROPERTIES HEADER_FILE_ONLY TRUE) -list(APPEND mac_crash_logger_SOURCE_FILES ${mac_crash_logger_HEADER_FILES}) - -set(mac_crash_logger_RESOURCE_FILES - CrashReporter.nib/ - ) -set_source_files_properties( - ${mac_crash_logger_RESOURCE_FILES} - PROPERTIES - HEADER_FILE_ONLY TRUE - ) -SOURCE_GROUP("Resources" FILES ${mac_crash_logger_RESOURCE_FILES}) -list(APPEND mac_crash_logger_SOURCE_FILES ${mac_crash_logger_RESOURCE_FILES}) - -add_executable(mac-crash-logger - MACOSX_BUNDLE - ${mac_crash_logger_SOURCE_FILES}) - -set_target_properties(mac-crash-logger - PROPERTIES - MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist - ) - -target_link_libraries(mac-crash-logger - ${LLCRASHLOGGER_LIBRARIES} - ${LLVFS_LIBRARIES} - ${LLXML_LIBRARIES} - ${LLMESSAGE_LIBRARIES} - ${LLVFS_LIBRARIES} - ${LLMATH_LIBRARIES} - ${LLCOMMON_LIBRARIES} - ) - -add_custom_command( - TARGET mac-crash-logger POST_BUILD - COMMAND ${CMAKE_COMMAND} - ARGS - -E - copy_directory - ${CMAKE_CURRENT_SOURCE_DIR}/CrashReporter.nib - ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/mac-crash-logger.app/Contents/Resources/CrashReporter.nib - ) - diff --git a/indra/mac_crash_logger/CrashReporter.nib/classes.nib b/indra/mac_crash_logger/CrashReporter.nib/classes.nib deleted file mode 100644 index c4b887e72..000000000 --- a/indra/mac_crash_logger/CrashReporter.nib/classes.nib +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IBVersion - 1 - - diff --git a/indra/mac_crash_logger/CrashReporter.nib/info.nib b/indra/mac_crash_logger/CrashReporter.nib/info.nib deleted file mode 100644 index 06805c0e4..000000000 --- a/indra/mac_crash_logger/CrashReporter.nib/info.nib +++ /dev/null @@ -1,18 +0,0 @@ - - - - - IBFramework Version - 629 - IBLastKnownRelativeProjectPath - ../../build-darwin-i386/SecondLife.xcodeproj - IBOldestOS - 5 - IBOpenObjects - - IBSystem Version - 9E17 - targetFramework - IBCarbonFramework - - diff --git a/indra/mac_crash_logger/CrashReporter.nib/objects.xib b/indra/mac_crash_logger/CrashReporter.nib/objects.xib deleted file mode 100644 index 634d1c532..000000000 --- a/indra/mac_crash_logger/CrashReporter.nib/objects.xib +++ /dev/null @@ -1,68 +0,0 @@ - - - - - - - ok - Send Report - 414 273 434 378 - - - not! - 2 - Don't Send - 414 390 434 487 - - - Second Life appears to have crashed or frozen the last time it ran. This crash reporter collects information about your computer's hardware configuration, operating system, and some Second Life logs, all of which are used for debugging purposes only. In the space below, please briefly describe what you were doing or trying to do just prior to the crash. Thank you for your help! This report is NOT read by Customer Support. If you have billing or other questions, please go to: http://www.secondlife.com/support/ If you don't wish to send Linden Lab a crash report, press Cancel. - 20 20 231 487 - - - 2 - 3 - 7 - Second Life Crash Logger - - - - - - - text - TRUE - 242 23 391 484 - - - remb - Remember This Choice - 415 20 433 186 - - - 0 0 454 507 - - 257 653 711 1160 - 0 0 768 1024 - - - - - - - - - - - - - - - - CrashReporter - - File's Owner - - - IBCarbonFramework - 194 - diff --git a/indra/mac_crash_logger/Info.plist b/indra/mac_crash_logger/Info.plist deleted file mode 100644 index f48293e82..000000000 --- a/indra/mac_crash_logger/Info.plist +++ /dev/null @@ -1,26 +0,0 @@ - - - - - CFBundleDevelopmentRegion - English - CFBundleExecutable - mac-crash-logger - CFBundleGetInfoString - - CFBundleIconFile - - CFBundleIdentifier - com.secondlife.indra.crashreporter - CFBundleInfoDictionaryVersion - 6.0 - CFBundlePackageType - APPL - CFBundleShortVersionString - - CFBundleSignature - ???? - CFBundleVersion - 1.0.0 - - diff --git a/indra/mac_crash_logger/llcrashloggermac.cpp b/indra/mac_crash_logger/llcrashloggermac.cpp deleted file mode 100644 index 16efa4fe2..000000000 --- a/indra/mac_crash_logger/llcrashloggermac.cpp +++ /dev/null @@ -1,345 +0,0 @@ -/** - * @file llcrashloggermac.cpp - * @brief Mac OSX crash logger implementation - * - * $LicenseInfo:firstyear=2003&license=viewergpl$ - * - * Copyright (c) 2003-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - - -#include "llcrashloggermac.h" - -#include -#include -#include - -#include "boost/tokenizer.hpp" - -#include "indra_constants.h" // CRASH_BEHAVIOR_ASK, CRASH_SETTING_NAME -#include "llerror.h" -#include "llfile.h" -#include "lltimer.h" -#include "llstring.h" -#include "lldir.h" -#include "llsdserialize.h" - -#define MAX_LOADSTRING 100 -const char* const SETTINGS_FILE_HEADER = "version"; -const S32 SETTINGS_FILE_VERSION = 101; - -// Windows Message Handlers - -BOOL gFirstDialog = TRUE; // Are we currently handling the Send/Don't Send dialog? -LLFILE *gDebugFile = NULL; - -WindowRef gWindow = NULL; -EventHandlerRef gEventHandler = NULL; -std::string gUserNotes = ""; -bool gSendReport = false; -bool gRememberChoice = false; -IBNibRef nib = NULL; - -OSStatus dialogHandler(EventHandlerCallRef handler, EventRef event, void *userdata) -{ - OSStatus result = eventNotHandledErr; - OSStatus err; - UInt32 evtClass = GetEventClass(event); - UInt32 evtKind = GetEventKind(event); - if((evtClass == kEventClassCommand) && (evtKind == kEventCommandProcess)) - { - HICommand cmd; - err = GetEventParameter(event, kEventParamDirectObject, typeHICommand, NULL, sizeof(cmd), NULL, &cmd); - - - - if(err == noErr) - { - //Get the value of the checkbox - ControlID id; - ControlRef checkBox = NULL; - id.signature = 'remb'; - id.id = 0; - err = GetControlByID(gWindow, &id, &checkBox); - - if(err == noErr) - { - if(GetControl32BitValue(checkBox) == kControlCheckBoxCheckedValue) - { - gRememberChoice = true; - } - else - { - gRememberChoice = false; - } - } - switch(cmd.commandID) - { - case kHICommandOK: - { - char buffer[65535]; /* Flawfinder: ignore */ - Size size = sizeof(buffer) - 1; - ControlRef textField = NULL; - - id.signature = 'text'; - id.id = 0; - - err = GetControlByID(gWindow, &id, &textField); - if(err == noErr) - { - // Get the user response text - err = GetControlData(textField, kControlNoPart, kControlEditTextTextTag, size, (Ptr)buffer, &size); - } - if(err == noErr) - { - // Make sure the string is terminated. - buffer[size] = 0; - gUserNotes = buffer; - - llinfos << buffer << llendl; - } - - // Send the report. - - QuitAppModalLoopForWindow(gWindow); - gSendReport = true; - result = noErr; - } - break; - - case kHICommandCancel: - QuitAppModalLoopForWindow(gWindow); - result = noErr; - break; - default: - result = eventNotHandledErr; - } - } - } - - return(result); -} - - -LLCrashLoggerMac::LLCrashLoggerMac(void) -{ -} - -LLCrashLoggerMac::~LLCrashLoggerMac(void) -{ -} - -bool LLCrashLoggerMac::init(void) -{ - bool ok = LLCrashLogger::init(); - if(!ok) return false; - if(mCrashBehavior != CRASH_BEHAVIOR_ASK) return true; - - // Real UI... - OSStatus err; - - err = CreateNibReference(CFSTR("CrashReporter"), &nib); - - if(err == noErr) - { - err = CreateWindowFromNib(nib, CFSTR("CrashReporter"), &gWindow); - } - - if(err == noErr) - { - // Set focus to the edit text area - ControlRef textField = NULL; - ControlID id; - - id.signature = 'text'; - id.id = 0; - - // Don't set err if any of this fails, since it's non-critical. - if(GetControlByID(gWindow, &id, &textField) == noErr) - { - SetKeyboardFocus(gWindow, textField, kControlFocusNextPart); - } - } - - if(err == noErr) - { - ShowWindow(gWindow); - } - - if(err == noErr) - { - // Set up an event handler for the window. - EventTypeSpec handlerEvents[] = - { - { kEventClassCommand, kEventCommandProcess } - }; - - InstallWindowEventHandler( - gWindow, - NewEventHandlerUPP(dialogHandler), - GetEventTypeCount (handlerEvents), - handlerEvents, - 0, - &gEventHandler); - } - return true; -} - -void LLCrashLoggerMac::gatherPlatformSpecificFiles() -{ - updateApplication("Gathering hardware information..."); - char path[MAX_PATH]; - FSRef folder; - - if(FSFindFolder(kUserDomain, kLogsFolderType, false, &folder) == noErr) - { - // folder is an FSRef to ~/Library/Logs/ - if(FSRefMakePath(&folder, (UInt8*)&path, sizeof(path)) == noErr) - { - struct stat dw_stat; - std::string mBuf; - bool isLeopard = false; - // Try the 10.3 path first... - std::string dw_file_name = std::string(path) + std::string("/CrashReporter/Second Life.crash.log"); - int res = stat(dw_file_name.c_str(), &dw_stat); - - if (res) - { - // Try the 10.2 one next... - dw_file_name = std::string(path) + std::string("/Second Life.crash.log"); - res = stat(dw_file_name.c_str(), &dw_stat); - } - - if(res) - { - //10.5: Like 10.3+, except it puts the crash time in the file instead of dividing it up - //using asterisks. Get a directory listing, search for files starting with second life, - //use the last one found. - std::string old_file_name, current_file_name, pathname, mask; - pathname = std::string(path) + std::string("/CrashReporter/"); - mask = "Second Life*"; - while(gDirUtilp->getNextFileInDir(pathname, mask, current_file_name, false)) - { - old_file_name = current_file_name; - } - if(old_file_name != "") - { - dw_file_name = pathname + old_file_name; - res=stat(dw_file_name.c_str(), &dw_stat); - isLeopard = true; - } - } - - if (!res) - { - std::ifstream fp(dw_file_name.c_str()); - std::stringstream str; - if(!fp.is_open()) return; - str << fp.rdbuf(); - mBuf = str.str(); - - if(!isLeopard) - { - // Crash logs consist of a number of entries, one per crash. - // Each entry is preceeded by "**********" on a line by itself. - // We want only the most recent (i.e. last) one. - const char *sep = "**********"; - const char *start = mBuf.c_str(); - const char *cur = start; - const char *temp = strstr(cur, sep); - - while(temp != NULL) - { - // Skip past the marker we just found - cur = temp + strlen(sep); /* Flawfinder: ignore */ - - // and try to find another - temp = strstr(cur, sep); - } - - // If there's more than one entry in the log file, strip all but the last one. - if(cur != start) - { - mBuf.erase(0, cur - start); - } - } - mCrashInfo["CrashLog"] = mBuf; - } - else - { - llwarns << "Couldn't find any CrashReporter files..." << llendl; - } - } - } -} - -bool LLCrashLoggerMac::mainLoop() -{ - OSStatus err = noErr; - - if(err == noErr && mCrashBehavior == CRASH_BEHAVIOR_ASK) - { - RunAppModalLoopForWindow(gWindow); - } - else if (mCrashBehavior == CRASH_BEHAVIOR_ALWAYS_SEND) - { - gSendReport = true; - } - - if(gRememberChoice) - { - if(gSendReport) saveCrashBehaviorSetting(CRASH_BEHAVIOR_ALWAYS_SEND); - else saveCrashBehaviorSetting(CRASH_BEHAVIOR_NEVER_SEND); - } - - if(gSendReport) - { - setUserText(gUserNotes); - sendCrashLogs(); - } - - if(gWindow != NULL) - { - DisposeWindow(gWindow); - } - - if(nib != NULL) - { - DisposeNibReference(nib); - } - - return true; -} - -void LLCrashLoggerMac::updateApplication(const std::string& message) -{ - LLCrashLogger::updateApplication(); -} - -bool LLCrashLoggerMac::cleanup() -{ - return true; -} diff --git a/indra/mac_crash_logger/llcrashloggermac.h b/indra/mac_crash_logger/llcrashloggermac.h deleted file mode 100644 index a76535afe..000000000 --- a/indra/mac_crash_logger/llcrashloggermac.h +++ /dev/null @@ -1,52 +0,0 @@ -/** - * @file llcrashloggermac.h - * @brief Mac OSX crash logger definition - * - * $LicenseInfo:firstyear=2003&license=viewergpl$ - * - * Copyright (c) 2003-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#ifndef LLCRASHLOGGERMAC_H -#define LLCRASHLOGGERMAC_H - -#include "linden_common.h" -#include "llcrashlogger.h" -#include "llstring.h" - -class LLCrashLoggerMac : public LLCrashLogger -{ -public: - LLCrashLoggerMac(void); - ~LLCrashLoggerMac(void); - virtual bool init(); - virtual bool mainLoop(); - virtual void updateApplication(const std::string& message = LLStringUtil::null); - virtual bool cleanup(); - virtual void gatherPlatformSpecificFiles(); -}; - -#endif diff --git a/indra/mac_crash_logger/mac_crash_logger.cpp b/indra/mac_crash_logger/mac_crash_logger.cpp deleted file mode 100644 index 1f5663d8a..000000000 --- a/indra/mac_crash_logger/mac_crash_logger.cpp +++ /dev/null @@ -1,52 +0,0 @@ -/** - * @file mac_crash_logger.cpp - * @brief Mac OSX crash logger implementation - * - * $LicenseInfo:firstyear=2003&license=viewergpl$ - * - * Copyright (c) 2003-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#include "linden_common.h" - -#include "llcrashloggermac.h" - -int main(int argc, char **argv) -{ - //time(&gLaunchTime); - - llinfos << "Starting Second Life Viewer Crash Reporter" << llendl; - - LLCrashLoggerMac app; - app.parseCommandOptions(argc, argv); - if(!app.init()) - { - return 0; - } - app.mainLoop(); - - return 0; -} diff --git a/indra/mac_updater/AutoUpdater.nib/classes.nib b/indra/mac_updater/AutoUpdater.nib/classes.nib deleted file mode 100644 index ea58db118..000000000 --- a/indra/mac_updater/AutoUpdater.nib/classes.nib +++ /dev/null @@ -1,4 +0,0 @@ -{ -IBClasses = (); -IBVersion = 1; -} diff --git a/indra/mac_updater/AutoUpdater.nib/info.nib b/indra/mac_updater/AutoUpdater.nib/info.nib deleted file mode 100644 index a49a92385..000000000 --- a/indra/mac_updater/AutoUpdater.nib/info.nib +++ /dev/null @@ -1,14 +0,0 @@ - - - - - IBDocumentLocation - 103 138 356 240 0 0 1280 1002 - IBFramework Version - 362.0 - IBSystem Version - 7D24 - targetFramework - IBCarbonFramework - - diff --git a/indra/mac_updater/AutoUpdater.nib/objects.xib b/indra/mac_updater/AutoUpdater.nib/objects.xib deleted file mode 100644 index 310411b71..000000000 --- a/indra/mac_updater/AutoUpdater.nib/objects.xib +++ /dev/null @@ -1,56 +0,0 @@ - - - IBCarbonFramework - - NSApplication - - - - 405 222 533 663 - Second Life Updater - - 0 0 128 441 - - - 20 20 44 421 - what - Initializing… - - - 88 351 108 421 - Cancel - not! - 2 - - - 51 19 70 422 - prog - 50 - - - - FALSE - 2 - 3 - 7 - - - - - - - - - - - - - - - File's Owner - - Updater - - - 194 - diff --git a/indra/mac_updater/CMakeLists.txt b/indra/mac_updater/CMakeLists.txt deleted file mode 100644 index b769a2e17..000000000 --- a/indra/mac_updater/CMakeLists.txt +++ /dev/null @@ -1,66 +0,0 @@ -# -*- cmake -*- - -project(mac_updater) - -include(00-Common) -include(CURL) -include(LLCommon) -include(LLVFS) -include(Linking) - -include_directories( - ${LLCOMMON_INCLUDE_DIRS} - ${LLVFS_INCLUDE_DIRS} - ) - -set(mac_updater_SOURCE_FILES - mac_updater.cpp - ) - -set(mac_updater_HEADER_FILES - CMakeLists.txt - ) - -set_source_files_properties(${mac_updater_HEADER_FILES} - PROPERTIES HEADER_FILE_ONLY TRUE) - -list(APPEND mac_updater_SOURCE_FILES ${mac_updater_HEADER_FILES}) - - -set(mac_updater_RESOURCE_FILES - AutoUpdater.nib/ - ) -set_source_files_properties( - ${mac_updater_RESOURCE_FILES} - PROPERTIES - HEADER_FILE_ONLY TRUE - ) -SOURCE_GROUP("Resources" FILES ${mac_updater_RESOURCE_FILES}) -list(APPEND mac_updater_SOURCE_FILES ${mac_updater_RESOURCE_FILES}) - -add_executable(mac-updater - MACOSX_BUNDLE - ${mac_updater_SOURCE_FILES}) - -set_target_properties(mac-updater - PROPERTIES - MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist - ) - -target_link_libraries(mac-updater - ${LLVFS_LIBRARIES} - ${CURL_LIBRARIES} - ${OPENSSL_LIBRARIES} - ${LLCOMMON_LIBRARIES} - ) - -add_custom_command( - TARGET mac-updater POST_BUILD - COMMAND ${CMAKE_COMMAND} - ARGS - -E - copy_directory - ${CMAKE_CURRENT_SOURCE_DIR}/AutoUpdater.nib - ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/mac-updater.app/Contents/Resources/AutoUpdater.nib - ) - diff --git a/indra/mac_updater/Info.plist b/indra/mac_updater/Info.plist deleted file mode 100644 index bb27fddb0..000000000 --- a/indra/mac_updater/Info.plist +++ /dev/null @@ -1,26 +0,0 @@ - - - - - CFBundleDevelopmentRegion - English - CFBundleExecutable - mac-updater - CFBundleGetInfoString - - CFBundleIconFile - - CFBundleIdentifier - com.secondlife.indra.autoupdater - CFBundleInfoDictionaryVersion - 6.0 - CFBundlePackageType - APPL - CFBundleShortVersionString - - CFBundleSignature - ???? - CFBundleVersion - 1.0.0 - - diff --git a/indra/mac_updater/mac_updater.cpp b/indra/mac_updater/mac_updater.cpp deleted file mode 100644 index 0fd4615b4..000000000 --- a/indra/mac_updater/mac_updater.cpp +++ /dev/null @@ -1,1204 +0,0 @@ -/** - * @file mac_updater.cpp - * @brief - * - * $LicenseInfo:firstyear=2006&license=viewergpl$ - * - * Copyright (c) 2006-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#include "linden_common.h" - -#include -#include -#include - -#include -#include - -#include "llerror.h" -#include "lltimer.h" -#include "lldir.h" -#include "llfile.h" - -#include "llstring.h" - -#include - -#include "llerrorcontrol.h" - -enum -{ - kEventClassCustom = 'Cust', - kEventCustomProgress = 'Prog', - kEventParamCustomCurValue = 'Cur ', - kEventParamCustomMaxValue = 'Max ', - kEventParamCustomText = 'Text', - kEventCustomDone = 'Done', -}; - -WindowRef gWindow = NULL; -EventHandlerRef gEventHandler = NULL; -OSStatus gFailure = noErr; -Boolean gCancelled = false; - -const char *gUpdateURL; -const char *gProductName; -const char *gBundleID; - -void *updatethreadproc(void*); - -pthread_t updatethread; - -OSStatus setProgress(int cur, int max) -{ - OSStatus err; - ControlRef progressBar = NULL; - ControlID id; - - id.signature = 'prog'; - id.id = 0; - - err = GetControlByID(gWindow, &id, &progressBar); - if(err == noErr) - { - Boolean indeterminate; - - if(max == 0) - { - indeterminate = true; - err = SetControlData(progressBar, kControlEntireControl, kControlProgressBarIndeterminateTag, sizeof(Boolean), (Ptr)&indeterminate); - } - else - { - double percentage = (double)cur / (double)max; - SetControlMinimum(progressBar, 0); - SetControlMaximum(progressBar, 100); - SetControlValue(progressBar, (SInt16)(percentage * 100)); - - indeterminate = false; - err = SetControlData(progressBar, kControlEntireControl, kControlProgressBarIndeterminateTag, sizeof(Boolean), (Ptr)&indeterminate); - - Draw1Control(progressBar); - } - } - - return(err); -} - -OSStatus setProgressText(CFStringRef text) -{ - OSStatus err; - ControlRef progressText = NULL; - ControlID id; - - id.signature = 'what'; - id.id = 0; - - err = GetControlByID(gWindow, &id, &progressText); - if(err == noErr) - { - err = SetControlData(progressText, kControlEntireControl, kControlStaticTextCFStringTag, sizeof(CFStringRef), (Ptr)&text); - Draw1Control(progressText); - } - - return(err); -} - -OSStatus sendProgress(long cur, long max, CFStringRef text = NULL) -{ - OSStatus result; - EventRef evt; - - result = CreateEvent( - NULL, - kEventClassCustom, - kEventCustomProgress, - 0, - kEventAttributeNone, - &evt); - - // This event needs to be targeted at the window so it goes to the window's handler. - if(result == noErr) - { - EventTargetRef target = GetWindowEventTarget(gWindow); - result = SetEventParameter ( - evt, - kEventParamPostTarget, - typeEventTargetRef, - sizeof(target), - &target); - } - - if(result == noErr) - { - result = SetEventParameter ( - evt, - kEventParamCustomCurValue, - typeLongInteger, - sizeof(cur), - &cur); - } - - if(result == noErr) - { - result = SetEventParameter ( - evt, - kEventParamCustomMaxValue, - typeLongInteger, - sizeof(max), - &max); - } - - if(result == noErr) - { - if(text != NULL) - { - result = SetEventParameter ( - evt, - kEventParamCustomText, - typeCFStringRef, - sizeof(text), - &text); - } - } - - if(result == noErr) - { - // Send the event - PostEventToQueue( - GetMainEventQueue(), - evt, - kEventPriorityStandard); - - } - - return(result); -} - -OSStatus sendDone(void) -{ - OSStatus result; - EventRef evt; - - result = CreateEvent( - NULL, - kEventClassCustom, - kEventCustomDone, - 0, - kEventAttributeNone, - &evt); - - // This event needs to be targeted at the window so it goes to the window's handler. - if(result == noErr) - { - EventTargetRef target = GetWindowEventTarget(gWindow); - result = SetEventParameter ( - evt, - kEventParamPostTarget, - typeEventTargetRef, - sizeof(target), - &target); - } - - if(result == noErr) - { - // Send the event - PostEventToQueue( - GetMainEventQueue(), - evt, - kEventPriorityStandard); - - } - - return(result); -} - -OSStatus dialogHandler(EventHandlerCallRef handler, EventRef event, void *userdata) -{ - OSStatus result = eventNotHandledErr; - OSStatus err; - UInt32 evtClass = GetEventClass(event); - UInt32 evtKind = GetEventKind(event); - - if((evtClass == kEventClassCommand) && (evtKind == kEventCommandProcess)) - { - HICommand cmd; - err = GetEventParameter(event, kEventParamDirectObject, typeHICommand, NULL, sizeof(cmd), NULL, &cmd); - - if(err == noErr) - { - switch(cmd.commandID) - { - case kHICommandCancel: - gCancelled = true; -// QuitAppModalLoopForWindow(gWindow); - result = noErr; - break; - } - } - } - else if((evtClass == kEventClassCustom) && (evtKind == kEventCustomProgress)) - { - // Request to update the progress dialog - long cur = 0; - long max = 0; - CFStringRef text = NULL; - (void) GetEventParameter(event, kEventParamCustomCurValue, typeLongInteger, NULL, sizeof(cur), NULL, &cur); - (void) GetEventParameter(event, kEventParamCustomMaxValue, typeLongInteger, NULL, sizeof(max), NULL, &max); - (void) GetEventParameter(event, kEventParamCustomText, typeCFStringRef, NULL, sizeof(text), NULL, &text); - - err = setProgress(cur, max); - if(err == noErr) - { - if(text != NULL) - { - setProgressText(text); - } - } - - result = noErr; - } - else if((evtClass == kEventClassCustom) && (evtKind == kEventCustomDone)) - { - // We're done. Exit the modal loop. - QuitAppModalLoopForWindow(gWindow); - result = noErr; - } - - return(result); -} - -#if 0 -size_t curl_download_callback(void *data, size_t size, size_t nmemb, - void *user_data) -{ - S32 bytes = size * nmemb; - char *cdata = (char *) data; - for (int i =0; i < bytes; i += 1) - { - gServerResponse.append(cdata[i]); - } - return bytes; -} -#endif - -int curl_progress_callback_func(void *clientp, - double dltotal, - double dlnow, - double ultotal, - double ulnow) -{ - int max = (int)(dltotal / 1024.0); - int cur = (int)(dlnow / 1024.0); - sendProgress(cur, max); - - if(gCancelled) - return(1); - - return(0); -} - -int parse_args(int argc, char **argv) -{ - int j; - - for (j = 1; j < argc; j++) - { - if ((!strcmp(argv[j], "-url")) && (++j < argc)) - { - gUpdateURL = argv[j]; - } - else if ((!strcmp(argv[j], "-name")) && (++j < argc)) - { - gProductName = argv[j]; - } - else if ((!strcmp(argv[j], "-bundleid")) && (++j < argc)) - { - gBundleID = argv[j]; - } - } - - return 0; -} - -int main(int argc, char **argv) -{ - // We assume that all the logs we're looking for reside on the current drive - gDirUtilp->initAppDirs("SecondLife"); - - LLError::initForApplication( gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "")); - - // Rename current log file to ".old" - std::string old_log_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "updater.log.old"); - std::string log_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "updater.log"); - LLFile::rename(log_file.c_str(), old_log_file.c_str()); - - // Set the log file to updater.log - LLError::logToFile(log_file); - - ///////////////////////////////////////// - // - // Process command line arguments - // - gUpdateURL = NULL; - gProductName = NULL; - gBundleID = NULL; - parse_args(argc, argv); - if (!gUpdateURL) - { - llinfos << "Usage: mac_updater -url [-name ] [-program ]" << llendl; - exit(1); - } - else - { - llinfos << "Update url is: " << gUpdateURL << llendl; - if (gProductName) - { - llinfos << "Product name is: " << gProductName << llendl; - } - else - { - gProductName = "Second Life"; - } - if (gBundleID) - { - llinfos << "Bundle ID is: " << gBundleID << llendl; - } - else - { - gBundleID = "com.secondlife.indra.viewer"; - } - } - - llinfos << "Starting " << gProductName << " Updater" << llendl; - - // Real UI... - OSStatus err; - IBNibRef nib = NULL; - - err = CreateNibReference(CFSTR("AutoUpdater"), &nib); - - char windowTitle[MAX_PATH]; /* Flawfinder: ignore */ - snprintf(windowTitle, sizeof(windowTitle), "%s Updater", gProductName); - CFStringRef windowTitleRef = NULL; - windowTitleRef = CFStringCreateWithCString(NULL, windowTitle, kCFStringEncodingUTF8); - - if(err == noErr) - { - err = CreateWindowFromNib(nib, CFSTR("Updater"), &gWindow); - } - - if (err == noErr) - { - err = SetWindowTitleWithCFString(gWindow, windowTitleRef); - } - CFRelease(windowTitleRef); - - if(err == noErr) - { - // Set up an event handler for the window. - EventTypeSpec handlerEvents[] = - { - { kEventClassCommand, kEventCommandProcess }, - { kEventClassCustom, kEventCustomProgress }, - { kEventClassCustom, kEventCustomDone } - }; - InstallStandardEventHandler(GetWindowEventTarget(gWindow)); - InstallWindowEventHandler( - gWindow, - NewEventHandlerUPP(dialogHandler), - GetEventTypeCount (handlerEvents), - handlerEvents, - 0, - &gEventHandler); - } - - if(err == noErr) - { - ShowWindow(gWindow); - SelectWindow(gWindow); - } - - if(err == noErr) - { - pthread_create(&updatethread, - NULL, - &updatethreadproc, - NULL); - - } - - if(err == noErr) - { - RunAppModalLoopForWindow(gWindow); - } - - void *threadresult; - - pthread_join(updatethread, &threadresult); - - if(!gCancelled && (gFailure != noErr)) - { - // Something went wrong. Since we always just tell the user to download a new version, we don't really care what. - AlertStdCFStringAlertParamRec params; - SInt16 retval_mac = 1; - DialogRef alert = NULL; - OSStatus err; - - params.version = kStdCFStringAlertVersionOne; - params.movable = false; - params.helpButton = false; - params.defaultText = (CFStringRef)kAlertDefaultOKText; - params.cancelText = 0; - params.otherText = 0; - params.defaultButton = 1; - params.cancelButton = 0; - params.position = kWindowDefaultPosition; - params.flags = 0; - - err = CreateStandardAlert( - kAlertStopAlert, - CFSTR("Error"), - CFSTR("An error occurred while updating Second Life. Please download the latest version from www.secondlife.com."), - ¶ms, - &alert); - - if(err == noErr) - { - err = RunStandardAlert( - alert, - NULL, - &retval_mac); - } - - } - - // Don't dispose of things, just exit. This keeps the update thread from potentially getting hosed. - exit(0); - - if(gWindow != NULL) - { - DisposeWindow(gWindow); - } - - if(nib != NULL) - { - DisposeNibReference(nib); - } - - return 0; -} - -bool isDirWritable(FSRef &dir) -{ - bool result = false; - - // Test for a writable directory by creating a directory, then deleting it again. - // This is kinda lame, but will pretty much always give the right answer. - - OSStatus err = noErr; - char temp[PATH_MAX] = ""; /* Flawfinder: ignore */ - - err = FSRefMakePath(&dir, (UInt8*)temp, sizeof(temp)); - - if(err == noErr) - { - strncat(temp, "/.test_XXXXXX", (sizeof(temp) - strlen(temp)) - 1); - - if(mkdtemp(temp) != NULL) - { - // We were able to make the directory. This means the directory is writable. - result = true; - - // Clean up. - rmdir(temp); - } - } - -#if 0 - // This seemed like a good idea, but won't tell us if we're on a volume mounted read-only. - UInt8 perm; - err = FSGetUserPrivilegesPermissions(&targetParentRef, &perm, NULL); - if(err == noErr) - { - if(perm & kioACUserNoMakeChangesMask) - { - // Parent directory isn't writable. - llinfos << "Target parent directory not writable." << llendl; - err = -1; - replacingTarget = false; - } - } -#endif - - return result; -} - -static std::string HFSUniStr255_to_utf8str(const HFSUniStr255* src) -{ - llutf16string string16((U16*)&(src->unicode), src->length); - std::string result = utf16str_to_utf8str(string16); - return result; -} - -int restoreObject(const char* aside, const char* target, const char* path, const char* object) -{ - char source[PATH_MAX] = ""; /* Flawfinder: ignore */ - char dest[PATH_MAX] = ""; /* Flawfinder: ignore */ - snprintf(source, sizeof(source), "%s/%s/%s", aside, path, object); - snprintf(dest, sizeof(dest), "%s/%s", target, path); - FSRef sourceRef; - FSRef destRef; - OSStatus err; - err = FSPathMakeRef((UInt8 *)source, &sourceRef, NULL); - if(err != noErr) return false; - err = FSPathMakeRef((UInt8 *)dest, &destRef, NULL); - if(err != noErr) return false; - - llinfos << "Copying " << source << " to " << dest << llendl; - - err = FSCopyObjectSync( - &sourceRef, - &destRef, - NULL, - NULL, - kFSFileOperationOverwrite); - - if(err != noErr) return false; - return true; -} - -// Replace any mention of "Second Life" with the product name. -void filterFile(const char* filename) -{ - char temp[PATH_MAX] = ""; /* Flawfinder: ignore */ - // First copy the target's version, so we can run it through sed. - snprintf(temp, sizeof(temp), "cp '%s' '%s.tmp'", filename, filename); - system(temp); /* Flawfinder: ignore */ - - // Now run it through sed. - snprintf(temp, sizeof(temp), - "sed 's/Second Life/%s/g' '%s.tmp' > '%s'", gProductName, filename, filename); - system(temp); /* Flawfinder: ignore */ -} - -static bool isFSRefViewerBundle(FSRef *targetRef) -{ - bool result = false; - CFURLRef targetURL = NULL; - CFBundleRef targetBundle = NULL; - CFStringRef targetBundleID = NULL; - CFStringRef sourceBundleID = NULL; - - targetURL = CFURLCreateFromFSRef(NULL, targetRef); - - if(targetURL == NULL) - { - llinfos << "Error creating target URL." << llendl; - } - else - { - targetBundle = CFBundleCreate(NULL, targetURL); - } - - if(targetBundle == NULL) - { - llinfos << "Failed to create target bundle." << llendl; - } - else - { - targetBundleID = CFBundleGetIdentifier(targetBundle); - } - - if(targetBundleID == NULL) - { - llinfos << "Couldn't retrieve target bundle ID." << llendl; - } - else - { - sourceBundleID = CFStringCreateWithCString(NULL, gBundleID, kCFStringEncodingUTF8); - if(CFStringCompare(sourceBundleID, targetBundleID, 0) == kCFCompareEqualTo) - { - // This is the bundle we're looking for. - result = true; - } - else - { - llinfos << "Target bundle ID mismatch." << llendl; - } - } - - // Don't release targetBundleID -- since we don't retain it, it's released when targetBundle is released. - if(targetURL != NULL) - CFRelease(targetURL); - if(targetBundle != NULL) - CFRelease(targetBundle); - - return result; -} - -// Search through the directory specified by 'parent' for an item that appears to be a Second Life viewer. -static OSErr findAppBundleOnDiskImage(FSRef *parent, FSRef *app) -{ - FSIterator iterator; - bool found = false; - - OSErr err = FSOpenIterator( parent, kFSIterateFlat, &iterator ); - if(!err) - { - do - { - ItemCount actualObjects = 0; - Boolean containerChanged = false; - FSCatalogInfo info; - FSRef ref; - HFSUniStr255 unicodeName; - err = FSGetCatalogInfoBulk( - iterator, - 1, - &actualObjects, - &containerChanged, - kFSCatInfoNodeFlags, - &info, - &ref, - NULL, - &unicodeName ); - - if(actualObjects == 0) - break; - - if(!err) - { - // Call succeeded and not done with the iteration. - std::string name = HFSUniStr255_to_utf8str(&unicodeName); - - llinfos << "Considering \"" << name << "\"" << llendl; - - if(info.nodeFlags & kFSNodeIsDirectoryMask) - { - // This is a directory. See if it's a .app - if(name.find(".app") != std::string::npos) - { - // Looks promising. Check to see if it has the right bundle identifier. - if(isFSRefViewerBundle(&ref)) - { - // This is the one. Return it. - *app = ref; - found = true; - } - } - } - } - } - while(!err && !found); - - FSCloseIterator(iterator); - } - - if(!err && !found) - err = fnfErr; - - return err; -} - -void *updatethreadproc(void*) -{ - char tempDir[PATH_MAX] = ""; /* Flawfinder: ignore */ - FSRef tempDirRef; - char temp[PATH_MAX] = ""; /* Flawfinder: ignore */ - // *NOTE: This buffer length is used in a scanf() below. - char deviceNode[1024] = ""; /* Flawfinder: ignore */ - LLFILE *downloadFile = NULL; - OSStatus err; - ProcessSerialNumber psn; - char target[PATH_MAX] = ""; /* Flawfinder: ignore */ - FSRef targetRef; - FSRef targetParentRef; - FSVolumeRefNum targetVol; - FSRef trashFolderRef; - Boolean replacingTarget = false; - - memset(&tempDirRef, 0, sizeof(tempDirRef)); - memset(&targetRef, 0, sizeof(targetRef)); - memset(&targetParentRef, 0, sizeof(targetParentRef)); - - try - { - // Attempt to get a reference to the Second Life application bundle containing this updater. - // Any failures during this process will cause us to default to updating /Applications/Second Life.app - { - FSRef myBundle; - - err = GetCurrentProcess(&psn); - if(err == noErr) - { - err = GetProcessBundleLocation(&psn, &myBundle); - } - - if(err == noErr) - { - // Sanity check: Make sure the name of the item referenced by targetRef is "Second Life.app". - FSRefMakePath(&myBundle, (UInt8*)target, sizeof(target)); - - llinfos << "Updater bundle location: " << target << llendl; - } - - // Our bundle should be in Second Life.app/Contents/Resources/AutoUpdater.app - // so we need to go up 3 levels to get the path to the main application bundle. - if(err == noErr) - { - err = FSGetCatalogInfo(&myBundle, kFSCatInfoNone, NULL, NULL, NULL, &targetRef); - } - if(err == noErr) - { - err = FSGetCatalogInfo(&targetRef, kFSCatInfoNone, NULL, NULL, NULL, &targetRef); - } - if(err == noErr) - { - err = FSGetCatalogInfo(&targetRef, kFSCatInfoNone, NULL, NULL, NULL, &targetRef); - } - - // And once more to get the parent of the target - if(err == noErr) - { - err = FSGetCatalogInfo(&targetRef, kFSCatInfoNone, NULL, NULL, NULL, &targetParentRef); - } - - if(err == noErr) - { - FSRefMakePath(&targetRef, (UInt8*)target, sizeof(target)); - llinfos << "Path to target: " << target << llendl; - } - - // Sanity check: make sure the target is a bundle with the right identifier - if(err == noErr) - { - // Assume the worst... - err = -1; - - if(isFSRefViewerBundle(&targetRef)) - { - // This is the bundle we're looking for. - err = noErr; - replacingTarget = true; - } - } - - // Make sure the target's parent directory is writable. - if(err == noErr) - { - if(!isDirWritable(targetParentRef)) - { - // Parent directory isn't writable. - llinfos << "Target parent directory not writable." << llendl; - err = -1; - replacingTarget = false; - } - } - - if(err != noErr) - { - Boolean isDirectory; - llinfos << "Target search failed, defaulting to /Applications/" << gProductName << ".app." << llendl; - - // Set up the parent directory - err = FSPathMakeRef((UInt8*)"/Applications", &targetParentRef, &isDirectory); - if((err != noErr) || (!isDirectory)) - { - // We're so hosed. - llinfos << "Applications directory not found, giving up." << llendl; - throw 0; - } - - snprintf(target, sizeof(target), "/Applications/%s.app", gProductName); - - memset(&targetRef, 0, sizeof(targetRef)); - err = FSPathMakeRef((UInt8*)target, &targetRef, NULL); - if(err == fnfErr) - { - // This is fine, just means we're not replacing anything. - err = noErr; - replacingTarget = false; - } - else - { - replacingTarget = true; - } - - // Make sure the target's parent directory is writable. - if(err == noErr) - { - if(!isDirWritable(targetParentRef)) - { - // Parent directory isn't writable. - llinfos << "Target parent directory not writable." << llendl; - err = -1; - replacingTarget = false; - } - } - - } - - // If we haven't fixed all problems by this point, just bail. - if(err != noErr) - { - llinfos << "Unable to pick a target, giving up." << llendl; - throw 0; - } - } - - // Find the volID of the volume the target resides on - { - FSCatalogInfo info; - err = FSGetCatalogInfo( - &targetParentRef, - kFSCatInfoVolume, - &info, - NULL, - NULL, - NULL); - - if(err != noErr) - throw 0; - - targetVol = info.volume; - } - - // Find the temporary items and trash folders on that volume. - err = FSFindFolder( - targetVol, - kTrashFolderType, - true, - &trashFolderRef); - - if(err != noErr) - throw 0; - -#if 0 // *HACK for DEV-11935 see below for details. - - FSRef tempFolderRef; - - err = FSFindFolder( - targetVol, - kTemporaryFolderType, - true, - &tempFolderRef); - - if(err != noErr) - throw 0; - - err = FSRefMakePath(&tempFolderRef, (UInt8*)temp, sizeof(temp)); - - if(err != noErr) - throw 0; - -#else - - // *HACK for DEV-11935 the above kTemporaryFolderType query was giving - // back results with path names that seem to be too long to be used as - // mount points. I suspect this incompatibility was introduced in the - // Leopard 10.5.2 update, but I have not verified this. - char const HARDCODED_TMP[] = "/tmp"; - strncpy(temp, HARDCODED_TMP, sizeof(HARDCODED_TMP)); - -#endif // 0 *HACK for DEV-11935 - - strncat(temp, "/SecondLifeUpdate_XXXXXX", (sizeof(temp) - strlen(temp)) - 1); - if(mkdtemp(temp) == NULL) - { - throw 0; - } - - strncpy(tempDir, temp, sizeof(tempDir)); - temp[sizeof(tempDir) - 1] = '\0'; - - llinfos << "tempDir is " << tempDir << llendl; - - err = FSPathMakeRef((UInt8*)tempDir, &tempDirRef, NULL); - - if(err != noErr) - throw 0; - - chdir(tempDir); - - snprintf(temp, sizeof(temp), "SecondLife.dmg"); - - downloadFile = LLFile::fopen(temp, "wb"); /* Flawfinder: ignore */ - if(downloadFile == NULL) - { - throw 0; - } - - { - CURL *curl = curl_easy_init(); - - curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); - // curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &curl_download_callback); - curl_easy_setopt(curl, CURLOPT_FILE, downloadFile); - curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0); - curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, &curl_progress_callback_func); - curl_easy_setopt(curl, CURLOPT_URL, gUpdateURL); - curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1); - - sendProgress(0, 1, CFSTR("Downloading...")); - - CURLcode result = curl_easy_perform(curl); - - curl_easy_cleanup(curl); - - if(gCancelled) - { - llinfos << "User cancel, bailing out."<< llendl; - throw 0; - } - - if(result != CURLE_OK) - { - llinfos << "Error " << result << " while downloading disk image."<< llendl; - throw 0; - } - - fclose(downloadFile); - downloadFile = NULL; - } - - sendProgress(0, 0, CFSTR("Mounting image...")); - LLFile::mkdir("mnt", 0700); - - // NOTE: we could add -private at the end of this command line to keep the image from showing up in the Finder, - // but if our cleanup fails, this makes it much harder for the user to unmount the image. - std::string mountOutput; - FILE* mounter = popen("hdiutil attach SecondLife.dmg -mountpoint mnt", "r"); /* Flawfinder: ignore */ - - if(mounter == NULL) - { - llinfos << "Failed to mount disk image, exiting."<< llendl; - throw 0; - } - - // We need to scan the output from hdiutil to find the device node it uses to attach the disk image. - // If we don't have this information, we can't detach it later. - while(mounter != NULL) - { - size_t len = fread(temp, 1, sizeof(temp)-1, mounter); - temp[len] = 0; - mountOutput.append(temp); - if(len < sizeof(temp)-1) - { - // End of file or error. - int result = pclose(mounter); - if(result != 0) - { - // NOTE: We used to abort here, but pclose() started returning - // -1, possibly when the size of the DMG passed a certain point - llinfos << "Unexpected result closing pipe: " << result << llendl; - } - mounter = NULL; - } - } - - if(!mountOutput.empty()) - { - const char *s = mountOutput.c_str(); - const char *prefix = "/dev/"; - char *sub = strstr(s, prefix); - - if(sub != NULL) - { - sub += strlen(prefix); /* Flawfinder: ignore */ - sscanf(sub, "%1023s", deviceNode); /* Flawfinder: ignore */ - } - } - - if(deviceNode[0] != 0) - { - llinfos << "Disk image attached on /dev/" << deviceNode << llendl; - } - else - { - llinfos << "Disk image device node not found!" << llendl; - throw 0; - } - - // Get an FSRef to the new application on the disk image - FSRef sourceRef; - FSRef mountRef; - snprintf(temp, sizeof(temp), "%s/mnt", tempDir); - - llinfos << "Disk image mount point is: " << temp << llendl; - - err = FSPathMakeRef((UInt8 *)temp, &mountRef, NULL); - if(err != noErr) - { - llinfos << "Couldn't make FSRef to disk image mount point." << llendl; - throw 0; - } - - err = findAppBundleOnDiskImage(&mountRef, &sourceRef); - if(err != noErr) - { - llinfos << "Couldn't find application bundle on mounted disk image." << llendl; - throw 0; - } - - FSRef asideRef; - char aside[MAX_PATH]; /* Flawfinder: ignore */ - - // this will hold the name of the destination target - CFStringRef appNameRef; - - if(replacingTarget) - { - // Get the name of the target we're replacing - HFSUniStr255 appNameUniStr; - err = FSGetCatalogInfo(&targetRef, 0, NULL, &appNameUniStr, NULL, NULL); - if(err != noErr) - throw 0; - appNameRef = FSCreateStringFromHFSUniStr(NULL, &appNameUniStr); - - // Move aside old version (into work directory) - err = FSMoveObject(&targetRef, &tempDirRef, &asideRef); - if(err != noErr) - throw 0; - - // Grab the path for later use. - err = FSRefMakePath(&asideRef, (UInt8*)aside, sizeof(aside)); - } - else - { - // Construct the name of the target based on the product name - char appName[MAX_PATH]; /* Flawfinder: ignore */ - snprintf(appName, sizeof(appName), "%s.app", gProductName); - appNameRef = CFStringCreateWithCString(NULL, appName, kCFStringEncodingUTF8); - } - - sendProgress(0, 0, CFSTR("Copying files...")); - - llinfos << "Starting copy..." << llendl; - - // Copy the new version from the disk image to the target location. - err = FSCopyObjectSync( - &sourceRef, - &targetParentRef, - appNameRef, - &targetRef, - kFSFileOperationDefaultOptions); - - // Grab the path for later use. - err = FSRefMakePath(&targetRef, (UInt8*)target, sizeof(target)); - if(err != noErr) - throw 0; - - llinfos << "Copy complete. Target = " << target << llendl; - - if(err != noErr) - { - // Something went wrong during the copy. Attempt to put the old version back and bail. - (void)FSDeleteObject(&targetRef); - if(replacingTarget) - { - (void)FSMoveObject(&asideRef, &targetParentRef, NULL); - } - throw 0; - } - else - { - // The update has succeeded. Clear the cache directory. - - sendProgress(0, 0, CFSTR("Clearing cache...")); - - llinfos << "Clearing cache..." << llendl; - - gDirUtilp->deleteFilesInDir(gDirUtilp->getExpandedFilename(LL_PATH_CACHE,""),"*.*"); - - llinfos << "Clear complete." << llendl; - - } - } - catch(...) - { - if(!gCancelled) - if(gFailure == noErr) - gFailure = -1; - } - - // Failures from here on out are all non-fatal and not reported. - sendProgress(0, 3, CFSTR("Cleaning up...")); - - // Close disk image file if necessary - if(downloadFile != NULL) - { - llinfos << "Closing download file." << llendl; - - fclose(downloadFile); - downloadFile = NULL; - } - - sendProgress(1, 3); - // Unmount image - if(deviceNode[0] != 0) - { - llinfos << "Detaching disk image." << llendl; - - snprintf(temp, sizeof(temp), "hdiutil detach '%s'", deviceNode); - system(temp); /* Flawfinder: ignore */ - } - - sendProgress(2, 3); - - // Move work directory to the trash - if(tempDir[0] != 0) - { -// chdir("/"); -// FSDeleteObjects(tempDirRef); - - llinfos << "Moving work directory to the trash." << llendl; - - err = FSMoveObject(&tempDirRef, &trashFolderRef, NULL); - -// snprintf(temp, sizeof(temp), "rm -rf '%s'", tempDir); -// printf("%s\n", temp); -// system(temp); - } - - if(!gCancelled && !gFailure && (target[0] != 0)) - { - llinfos << "Touching application bundle." << llendl; - - snprintf(temp, sizeof(temp), "touch '%s'", target); - system(temp); /* Flawfinder: ignore */ - - llinfos << "Launching updated application." << llendl; - - snprintf(temp, sizeof(temp), "open '%s'", target); - system(temp); /* Flawfinder: ignore */ - } - - sendDone(); - - return(NULL); -} diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 74cbf25a0..6d16d66a1 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -140,6 +140,7 @@ set(viewer_SOURCE_FILES llcompilequeue.cpp llconfirmationmanager.cpp llconsole.cpp + llcrashlogger.cpp llcurrencyuimanager.cpp llcylinder.cpp lldaycyclemanager.cpp @@ -656,6 +657,7 @@ set(viewer_HEADER_FILES llcompilequeue.h llconfirmationmanager.h llconsole.h + llcrashlogger.h llcurrencyuimanager.h llcylinder.h lldaycyclemanager.h @@ -1532,7 +1534,6 @@ if (WINDOWS) if (PACKAGE) add_custom_target(package ALL DEPENDS ${CMAKE_CFG_INTDIR}/touched.bat) - add_dependencies(package windows-updater windows-crash-logger) endif (PACKAGE) endif (WINDOWS) @@ -1684,7 +1685,6 @@ if (DARWIN) if (PACKAGE) add_custom_target(package ALL DEPENDS ${VIEWER_BINARY_NAME}) - add_dependencies(package mac-updater mac-crash-logger) add_custom_command( TARGET package POST_BUILD diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index ceed6ea95..9748e07a8 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -2199,7 +2199,7 @@ This should be as low as possible, but too low may break functionality Type String Value - + http://crash.singularityviewer.org/submit.php> AFKTimeout diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index d4b3aa736..df48dc69a 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -86,7 +86,7 @@ #include "llvocache.h" #include "llvopartgroup.h" #include "llfloaterteleporthistory.h" - +#include "llcrashlogger.h" #include "llweb.h" #include "llsecondlifeurls.h" @@ -640,6 +640,10 @@ bool LLAppViewer::init() initMaxHeapSize() ; LLPrivateMemoryPoolManager::initClass((BOOL)gSavedSettings.getBOOL("MemoryPrivatePoolEnabled"), (U32)gSavedSettings.getU32("MemoryPrivatePoolSize")) ; + // Check if we have a crash report to send + LLCrashLogger crashLogger; + crashLogger.checkCrashDump(); + // write Google Breakpad minidump files to a per-run dump directory to avoid multiple viewer issues. std::string logdir = gDirUtilp->getExpandedFilename(LL_PATH_DUMP, ""); mDumpPath = logdir; diff --git a/indra/llcrashlogger/llcrashlogger.cpp b/indra/newview/llcrashlogger.cpp similarity index 55% rename from indra/llcrashlogger/llcrashlogger.cpp rename to indra/newview/llcrashlogger.cpp index 97feae14c..862f69588 100644 --- a/indra/llcrashlogger/llcrashlogger.cpp +++ b/indra/newview/llcrashlogger.cpp @@ -23,13 +23,9 @@ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ -#include -#include -#include -#include +#include "llviewerprecompiledheaders.h" #include "llcrashlogger.h" -#include "llcrashlock.h" #include "linden_common.h" #include "llstring.h" #include "indra_constants.h" // CRASH_BEHAVIOR_... @@ -46,12 +42,6 @@ #include "llproxy.h" #include "aistatemachine.h" -LLPumpIO* gServicePump; -BOOL gBreak = false; -BOOL gSent = false; - -extern void startEngineThread(void); - class AIHTTPTimeoutPolicy; extern AIHTTPTimeoutPolicy crashLoggerResponder_timeout; @@ -64,13 +54,12 @@ public: virtual void error(U32 status, const std::string& reason) { - gBreak = true; + llwarns << "Crash report sending failed: " << reason << llendl; } virtual void result(const LLSD& content) { - gBreak = true; - gSent = true; + llinfos << "Crash report successfully sent" << llendl; } virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const @@ -88,7 +77,6 @@ LLCrashLogger::LLCrashLogger() : mCrashBehavior(CRASH_BEHAVIOR_ALWAYS_SEND), mCrashInPreviousExec(false), mCrashSettings("CrashSettings"), - mSentCrashLogs(false), mCrashHost("") { } @@ -250,32 +238,6 @@ void LLCrashLogger::gatherFiles() gatherPlatformSpecificFiles(); - //Use the debug log to reconstruct the URL to send the crash report to - if(mDebugLog.has("CrashHostUrl")) - { - // Crash log receiver has been manually configured. - mCrashHost = mDebugLog["CrashHostUrl"].asString(); - } - else if(mDebugLog.has("CurrentSimHost")) - { - mCrashHost = "https://"; - mCrashHost += mDebugLog["CurrentSimHost"].asString(); - mCrashHost += ":12043/crash/report"; - } - else if(mDebugLog.has("GridName")) - { - // This is a 'little' hacky, but its the best simple solution. - std::string grid_host = mDebugLog["GridName"].asString(); - LLStringUtil::toLower(grid_host); - - mCrashHost = "https://login."; - mCrashHost += grid_host; - mCrashHost += ".lindenlab.com:12043/crash/report"; - } - - // Use login servers as the alternate, since they are already load balanced and have a known name - mAltCrashHost = "https://login.agni.lindenlab.com:12043/crash/report"; - mCrashInfo["DebugLog"] = mDebugLog; mFileMap["StatsLog"] = gDirUtilp->getExpandedFilename(LL_PATH_DUMP,"stats.log"); @@ -354,80 +316,15 @@ LLSD LLCrashLogger::constructPostData() return mCrashInfo; } -// Singu Note, defiend in indra_constants.h # const char* const CRASH_SETTINGS_FILE = "settings_crash_behavior.xml"; - -S32 LLCrashLogger::loadCrashBehaviorSetting() -{ - // First check user_settings (in the user's home dir) - std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, CRASH_SETTINGS_FILE); - if (! mCrashSettings.loadFromFile(filename)) - { - // Next check app_settings (in the SL program dir) - std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, CRASH_SETTINGS_FILE); - mCrashSettings.loadFromFile(filename); - } - - // If we didn't load any files above, this will return the default - S32 value = mCrashSettings.getS32("CrashSubmitBehavior"); - - // Whatever value we got, make sure it's valid - switch (value) - { - case CRASH_BEHAVIOR_NEVER_SEND: - return CRASH_BEHAVIOR_NEVER_SEND; - case CRASH_BEHAVIOR_ALWAYS_SEND: - return CRASH_BEHAVIOR_ALWAYS_SEND; - } - - return CRASH_BEHAVIOR_ASK; -} - -bool LLCrashLogger::saveCrashBehaviorSetting(S32 crash_behavior) -{ - switch (crash_behavior) - { - case CRASH_BEHAVIOR_ASK: - case CRASH_BEHAVIOR_NEVER_SEND: - case CRASH_BEHAVIOR_ALWAYS_SEND: - break; - default: - return false; - } - - mCrashSettings.setS32("CrashSubmitBehavior", crash_behavior); - std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, CRASH_SETTINGS_FILE); - mCrashSettings.saveToFile(filename, FALSE); - - return true; -} - -bool LLCrashLogger::runCrashLogPost(std::string host, LLSD data, std::string msg, int retries, int timeout) -{ - gBreak = false; - for(int i = 0; i < retries; ++i) - { - updateApplication(llformat("%s, try %d...", msg.c_str(), i+1)); - LLHTTPClient::post(host, data, new LLCrashLoggerResponder()); - while(!gBreak) - { - updateApplication(); // No new message, just pump the IO - } - if(gSent) - { - return gSent; - } - } - return gSent; -} bool LLCrashLogger::sendCrashLog(std::string dump_dir) { gDirUtilp->setDumpDir( dump_dir ); std::string dump_path = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, - "SecondLifeCrashReport"); + "SingularityCrashReport"); std::string report_file = dump_path + ".log"; - + gatherFiles(); LLSD post_data; @@ -438,176 +335,30 @@ bool LLCrashLogger::sendCrashLog(std::string dump_dir) std::ofstream out_file(report_file.c_str()); LLSDSerialize::toPrettyXML(post_data, out_file); out_file.close(); - - bool sent = false; - - //*TODO: Translate - if(mCrashHost != "") - { - sent = runCrashLogPost(mCrashHost, post_data, std::string("Sending to server"), 3, 5); - } - - if(!sent) - { - sent = runCrashLogPost(mAltCrashHost, post_data, std::string("Sending to alternate server"), 3, 5); - } - - mSentCrashLogs = sent; - - return sent; -} -bool LLCrashLogger::sendCrashLogs() -{ + LLHTTPClient::post(mCrashHost, post_data, new LLCrashLoggerResponder()); - //pertinent code from below moved into a subroutine. - LLSD locks = mKeyMaster.getProcessList(); - LLSD newlocks = LLSD::emptyArray(); - - LLSD opts = getOptionData(PRIORITY_COMMAND_LINE); - LLSD rec; - - if ( opts.has("pid") && opts.has("dumpdir") && opts.has("procname") ) - { - rec["pid"]=opts["pid"]; - rec["dumpdir"]=opts["dumpdir"]; - rec["procname"]=opts["procname"]; -#if LL_WINDOWS - locks.append(rec); -#endif - } - - if (locks.isArray()) - { - for (LLSD::array_iterator lock=locks.beginArray(); - lock !=locks.endArray(); - ++lock) - { - if ( (*lock).has("pid") && (*lock).has("dumpdir") && (*lock).has("procname") ) - { - if ( mKeyMaster.isProcessAlive( (*lock)["pid"].asInteger(), (*lock)["procname"].asString() ) ) - { - newlocks.append(*lock); - } - else - { - //TODO: This is a hack but I didn't want to include boost in another file or retest everything related to lldir - if (LLCrashLock::fileExists((*lock)["dumpdir"].asString())) - { - //the viewer cleans up the log directory on clean shutdown - //but is ignorant of the locking table. - if (!sendCrashLog((*lock)["dumpdir"].asString())) - { - newlocks.append(*lock); //Failed to send log so don't delete it. - } - else - { - mCrashInfo["DebugLog"].erase("MinidumpPath"); - - mKeyMaster.cleanupProcess((*lock)["dumpdir"].asString()); - } - } - } - } - else - { - llwarns << "Discarding corrupted entry from lock table." << llendl; - } - } - } -#if !LL_WINDOWS - if (rec) - { - newlocks.append(rec); - } -#endif - - mKeyMaster.putProcessList(newlocks); - return true; -} - -void LLCrashLogger::updateApplication(const std::string& message) -{ - /* Sing TODO - gServicePump->pump(); - gServicePump->callback(); - */ - if (!message.empty()) llinfos << message << llendl; -} - -bool LLCrashLogger::init() -{ - LLCurl::initCurl(); - AIEngine::setMaxCount(100); - - // We assume that all the logs we're looking for reside on the current drive - gDirUtilp->initAppDirs("SecondLife"); - - LLError::initForApplication(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "")); - - // Default to the product name "Second Life" (this is overridden by the -name argument) - mProductName = "Second Life"; - - // Handle locking - bool locked = mKeyMaster.requestMaster(); //Request maser locking file. wait time is defaulted to 300S - - while (!locked && mKeyMaster.isWaiting()) - { -#if LL_WINDOWS - Sleep(1000); -#else - sleep(1); -#endif - locked = mKeyMaster.checkMaster(); - } - - if (!locked) - { - llwarns << "Unable to get master lock. Another crash reporter may be hung." << llendl; - return false; - } - - // Rename current log file to ".old" - std::string old_log_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "crashreport.log.old"); - std::string log_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "crashreport.log"); - -#if LL_WINDOWS - LLAPRFile::remove(old_log_file); -#endif - - LLFile::rename(log_file.c_str(), old_log_file.c_str()); - - // Set the log file to crashreport.log - LLError::logToFile(log_file); - - mCrashSettings.declareS32("CrashSubmitBehavior", CRASH_BEHAVIOR_ALWAYS_SEND, - "Controls behavior when viewer crashes " - "(0 = ask before sending crash report, " - "1 = always send crash report, " - "2 = never send crash report)"); - - llinfos << "Loading crash behavior setting" << llendl; - mCrashBehavior = loadCrashBehaviorSetting(); - - // If user doesn't want to send, bail out - if (mCrashBehavior == CRASH_BEHAVIOR_NEVER_SEND) - { - llinfos << "Crash behavior is never_send, quitting" << llendl; - return false; - } - - AICurlInterface::startCurlThread(&mCrashSettings); - startEngineThread(); - /* Singu Note: not needed for AICurl - gServicePump = new LLPumpIO(gAPRPoolp); - gServicePump->prime(gAPRPoolp); - LLHTTPClient::setPump(*gServicePump); - */ return true; } -// For cleanup code common to all platforms. -void LLCrashLogger::commonCleanup() + +void LLCrashLogger::updateApplication(const std::string& message) { - LLProxy::cleanupClass(); + if (!message.empty()) llinfos << message << llendl; +} + + +void LLCrashLogger::checkCrashDump() +{ + mCrashHost = gSavedSettings.getString("CrashHostUrl"); + std::string dumpDir = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "") + "singularity-debug"; + if (gDirUtilp->fileExists(dumpDir)) + { + sendCrashLog(dumpDir); + gDirUtilp->deleteDirAndContents(dumpDir); + } + else + { + llinfos << "No crash dump found frome previous run, not sending report" << LL_ENDL; + } } diff --git a/indra/llcrashlogger/llcrashlogger.h b/indra/newview/llcrashlogger.h similarity index 85% rename from indra/llcrashlogger/llcrashlogger.h rename to indra/newview/llcrashlogger.h index 78acc63b6..e23d5330c 100644 --- a/indra/llcrashlogger/llcrashlogger.h +++ b/indra/newview/llcrashlogger.h @@ -33,9 +33,8 @@ #include "llapp.h" #include "llsd.h" #include "llcontrol.h" -#include "llcrashlock.h" -class LLCrashLogger : public LLApp +class LLCrashLogger { public: LLCrashLogger(); @@ -48,17 +47,12 @@ public: virtual void gatherPlatformSpecificFiles() {} bool saveCrashBehaviorSetting(S32 crash_behavior); bool sendCrashLog(std::string dump_dir); - bool sendCrashLogs(); LLSD constructPostData(); virtual void updateApplication(const std::string& message = LLStringUtil::null); - virtual bool init(); - virtual bool mainLoop() = 0; - virtual bool cleanup() = 0; - void commonCleanup(); void setUserText(const std::string& text) { mCrashInfo["UserNotes"] = text; } S32 getCrashBehavior() { return mCrashBehavior; } - bool runCrashLogPost(std::string host, LLSD data, std::string msg, int retries, int timeout); bool readMinidump(std::string minidump_path); + void checkCrashDump(); protected: S32 mCrashBehavior; @@ -69,10 +63,7 @@ protected: std::string mProductName; LLSD mCrashInfo; std::string mCrashHost; - std::string mAltCrashHost; LLSD mDebugLog; - bool mSentCrashLogs; - LLCrashLock mKeyMaster; }; #endif //LLCRASHLOGGER_H diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 437916c94..44f7dddca 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -339,10 +339,6 @@ class WindowsManifest(ViewerManifest): self.path(path_pair[1]) self.end_prefix() - # pull in the crash logger and updater from other projects - self.path(src='../win_crash_logger/%s/windows-crash-logger.exe' % self.args['configuration'], dst="win_crash_logger.exe") - self.path(src='../win_updater/%s/windows-updater.exe' % self.args['configuration'], dst="updater.exe") - def nsi_file_commands(self, install=True): def wpath(path): @@ -545,18 +541,10 @@ class DarwinManifest(ViewerManifest): print "Skipping libfmodex.dylib - not found" pass - # our apps - try: - self.path("../mac_crash_logger/" + self.args['configuration'] + "/mac-crash-logger.app", "mac-crash-logger.app") - self.path("../mac_updater/" + self.args['configuration'] + "/mac-updater.app", "mac-updater.app") - except: - pass - # plugin launcher self.path("../llplugin/slplugin/" + self.args['configuration'] + "/SLPlugin.app", "SLPlugin.app") # dependencies on shared libs - mac_crash_logger_res_path = self.dst_path_of("mac-crash-logger.app/Contents/Resources") slplugin_res_path = self.dst_path_of("SLPlugin.app/Contents/Resources") for libfile in ("libllcommon.dylib", "libapr-1.0.dylib", @@ -717,10 +705,8 @@ class LinuxManifest(ViewerManifest): if self.buildtype().lower()=='release': self.path("secondlife-stripped","bin/"+self.binary_name()) - self.path("../linux_crash_logger/linux-crash-logger-stripped","linux-crash-logger.bin") else: self.path("secondlife-bin","bin/"+self.binary_name()) - self.path("../linux_crash_logger/linux-crash-logger","linux-crash-logger.bin") self.path("../llplugin/slplugin/SLPlugin", "bin/SLPlugin") if self.prefix("res-sdl"): diff --git a/indra/win_crash_logger/CMakeLists.txt b/indra/win_crash_logger/CMakeLists.txt deleted file mode 100644 index 1f31db0b8..000000000 --- a/indra/win_crash_logger/CMakeLists.txt +++ /dev/null @@ -1,101 +0,0 @@ -# -*- cmake -*- - -project(win_crash_logger) - -include(00-Common) -include(LLCommon) -include(LLCrashLogger) -include(LLMath) -include(LLMessage) -include(LLVFS) -include(LLWindow) -include(LLXML) -include(Linking) -include(LLSharedLibs) -include(GoogleBreakpad) - -include_directories( - ${LLCOMMON_INCLUDE_DIRS} - ${LLCRASHLOGGER_INCLUDE_DIRS} - ${LLMATH_INCLUDE_DIRS} - ${LLWINDOW_INCLUDE_DIRS} - ${LLXML_INCLUDE_DIRS} - ${LLVFS_INCLUDE_DIRS} - ${BREAKPAD_INCLUDE_DIRECTORIES} - ) -include_directories(SYSTEM - ${LLCOMMON_SYSTEM_INCLUDE_DIRS} - ${LLXML_SYSTEM_INCLUDE_DIRS} - ) - -set(win_crash_logger_SOURCE_FILES - win_crash_logger.cpp - llcrashloggerwindows.cpp - ) - -set(win_crash_logger_HEADER_FILES - CMakeLists.txt - - llcrashloggerwindows.h - resource.h - StdAfx.h - win_crash_logger.h - ) - -set_source_files_properties(${win_crash_logger_HEADER_FILES} - PROPERTIES HEADER_FILE_ONLY TRUE) - -set(win_crash_logger_RESOURCE_FILES - ll_icon.ico - ) - -set_source_files_properties(${win_crash_logger_RESOURCE_FILES} - PROPERTIES HEADER_FILE_ONLY TRUE) - -set(win_crash_logger_RESOURCE_FILES - win_crash_logger.rc - ${win_crash_logger_RESOURCE_FILES} - ) - -SOURCE_GROUP("Resource Files" FILES ${win_crash_logger_RESOURCE_FILES}) - -list(APPEND - win_crash_logger_SOURCE_FILES - ${win_crash_logger_HEADER_FILES} - ${win_crash_logger_RESOURCE_FILES} - ) - -# find_library(DXGUID_LIBRARY dxguid ${DIRECTX_LIBRARY_DIR}) - -add_executable(windows-crash-logger WIN32 ${win_crash_logger_SOURCE_FILES}) - -target_link_libraries(windows-crash-logger - ${BREAKPAD_EXCEPTION_HANDLER_LIBRARIES} - ${LLCRASHLOGGER_LIBRARIES} - ${LLWINDOW_LIBRARIES} - ${LLVFS_LIBRARIES} - ${LLXML_LIBRARIES} - ${LLMESSAGE_LIBRARIES} - ${LLMATH_LIBRARIES} - ${LLCOMMON_LIBRARIES} - ${WINDOWS_LIBRARIES} -# ${DXGUID_LIBRARY} - ${GOOGLE_PERFTOOLS_LIBRARIES} - user32 - gdi32 - ole32 - oleaut32 - wininet - Wldap32 - ) - -if (WINDOWS) - set_target_properties(windows-crash-logger - PROPERTIES - LINK_FLAGS "/NODEFAULTLIB:LIBCMT" - LINK_FLAGS_DEBUG "/NODEFAULTLIB:\"LIBCMT;LIBCMTD;MSVCRT\"" - ) -endif (WINDOWS) - -# Singu Note: not used by our build -# ll_deploy_sharedlibs_command(windows-crash-logger) diff --git a/indra/win_crash_logger/StdAfx.cpp b/indra/win_crash_logger/StdAfx.cpp deleted file mode 100644 index f56711af7..000000000 --- a/indra/win_crash_logger/StdAfx.cpp +++ /dev/null @@ -1,34 +0,0 @@ -/** - * @file StdAfx.cpp - * @brief windows crash logger source file for includes - * - * $LicenseInfo:firstyear=2003&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -// stdafx.cpp : source file that includes just the standard includes -// win_crash_logger.pch will be the pre-compiled header -// stdafx.obj will contain the pre-compiled type information - -#include "stdafx.h" - -// TODO: reference any additional headers you need in STDAFX.H -// and not in this file diff --git a/indra/win_crash_logger/StdAfx.h b/indra/win_crash_logger/StdAfx.h deleted file mode 100644 index 35976658a..000000000 --- a/indra/win_crash_logger/StdAfx.h +++ /dev/null @@ -1,56 +0,0 @@ -/** - * @file StdAfx.h - * @brief standard system includes - * - * $LicenseInfo:firstyear=2003&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -// stdafx.h : include file for standard system include files, -// or project specific include files that are used frequently, but -// are changed infrequently -// - -#if !defined(AFX_STDAFX_H__A9DB83DB_A9FD_11D0_BFD1_444553540000__INCLUDED_) -#define AFX_STDAFX_H__A9DB83DB_A9FD_11D0_BFD1_444553540000__INCLUDED_ - -#if _MSC_VER > 1000 -#pragma once -#endif // _MSC_VER > 1000 - -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers - -// Windows Header Files: -#include - -// C RunTime Header Files -#include -#include -#include - -// Local Header Files - -// TODO: reference additional headers your program requires here - -//{{AFX_INSERT_LOCATION}} -// Microsoft Visual C++ will insert additional declarations immediately before the previous line. - -#endif // !defined(AFX_STDAFX_H__A9DB83DB_A9FD_11D0_BFD1_444553540000__INCLUDED_) diff --git a/indra/win_crash_logger/ll_icon.ico b/indra/win_crash_logger/ll_icon.ico deleted file mode 100644 index 566346dfe301eec04d1fb819ecec2f2dd8d2483c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2238 zcmc&!-ES0C96fhtciXi#L~4tniK1>MzL=O0o*E+oAB;3H(P{_^u|O#W+q>H@XlbRT z*&?M~`aMv(?G|WlM{S7%J|Hy_1D4^VxNZ~s*gt}VH#~QCci2Ys)jPR!cYYuDob&tL zyMW-cWeeOfn-7%m*IS%hIJa{O(8$r@bC-3m!mV3T_`yzyfuDhyByiy#MD!Zacmdkp zR*2s3vADR17s}p;s67u+AA>maBM`rZyd59WHVz~lh}aGITE@8k0`dCW!1x`A#%XNa z{06j^d1zlTZ}3;3;Uao_d!a>t050B#=($CVpWy$Z4x;TU%FD~4M=iwTaR?s?M-mX5 zLlEH+yu7gpIR85^_7J`kL;kYtI)-Q;%u&}TIj4pBBC+8{XHSBTKIK+wT@HNJe z|8Wg@@!X9)BKL>DrDdKWp6R9pG)`Z&3E!c9VD>Ngk4^&3Q|#3wxlAJ(jY4CuMC=+i z6>owT9>wFwj~P!p&(f18PayhkV{L7Xb!FbUy9n%yL96XTOG^uUhr4)Iy5Rq`587Ft z)6Y)xE?h$KYi}}slIO1tsGZ|IypG`ZT4*P2V1T`AU=Q}6M(|)0{8b(BH}H-%lk@3C zVCXjVL#;exH=zyABk*Azg5_TVFO?urUWwp)N0Gm)9s0?68o - -#include "boost/tokenizer.hpp" - -#include "indra_constants.h" // CRASH_BEHAVIOR_ASK, CRASH_SETTING_NAME -#include "llerror.h" -#include "llfile.h" -#include "lltimer.h" -#include "llstring.h" -#include "lldxhardware.h" -#include "lldir.h" -#include "llsdserialize.h" -#include "llsdutil.h" - -#include -#include - -#define MAX_LOADSTRING 100 -#define MAX_STRING 2048 -const char* const SETTINGS_FILE_HEADER = "version"; -const S32 SETTINGS_FILE_VERSION = 101; - -// Windows Message Handlers - -// Global Variables: -HINSTANCE hInst= NULL; // current instance -TCHAR szTitle[MAX_LOADSTRING]; /* Flawfinder: ignore */ // The title bar text -TCHAR szWindowClass[MAX_LOADSTRING]; /* Flawfinder: ignore */ // The title bar text - -std::string gProductName; -HWND gHwndReport = NULL; // Send/Don't Send dialog -HWND gHwndProgress = NULL; // Progress window -HCURSOR gCursorArrow = NULL; -HCURSOR gCursorWait = NULL; -BOOL gFirstDialog = TRUE; // Are we currently handling the Send/Don't Send dialog? -std::stringstream gDXInfo; -bool gSendLogs = false; - -LLCrashLoggerWindows* LLCrashLoggerWindows::sInstance = NULL; - -//Conversion from char* to wchar* -//Replacement for ATL macros, doesn't allocate memory -//For more info see: http://www.codeguru.com/forum/showthread.php?t=337247 -void ConvertLPCSTRToLPWSTR (const char* pCstring, WCHAR* outStr) -{ - if (pCstring != NULL) - { - int nInputStrLen = strlen (pCstring); - // Double NULL Termination - int nOutputStrLen = MultiByteToWideChar(CP_ACP, 0, pCstring, nInputStrLen, NULL, 0) + 2; - if (outStr) - { - memset (outStr, 0x00, sizeof (WCHAR)*nOutputStrLen); - MultiByteToWideChar (CP_ACP, 0, pCstring, nInputStrLen, outStr, nInputStrLen); - } - } -} - -void write_debug(const char *str) -{ - gDXInfo << str; /* Flawfinder: ignore */ -} - -void write_debug(std::string& str) -{ - write_debug(str.c_str()); -} - -void show_progress(const std::string& message) -{ - std::wstring msg = wstring_to_utf16str(utf8str_to_wstring(message)); - if (gHwndProgress) - { - SendDlgItemMessage(gHwndProgress, // handle to destination window - IDC_LOG, - WM_SETTEXT, // message to send - FALSE, // undo option - (LPARAM)msg.c_str()); - } -} - -void update_messages() -{ - MSG msg; - while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) - { - if (msg.message == WM_QUIT) - { - exit(0); - } - TranslateMessage(&msg); - DispatchMessage(&msg); - } -} - -void sleep_and_pump_messages( U32 seconds ) -{ - const U32 CYCLES_PER_SECOND = 10; - U32 cycles = seconds * CYCLES_PER_SECOND; - while( cycles-- ) - { - update_messages(); - ms_sleep(1000 / CYCLES_PER_SECOND); - } -} - -// Include product name in the window caption. -void LLCrashLoggerWindows::ProcessCaption(HWND hWnd) -{ - TCHAR templateText[MAX_STRING]; /* Flawfinder: ignore */ - TCHAR header[MAX_STRING]; - std::string final; - GetWindowText(hWnd, templateText, sizeof(templateText)); - final = llformat(ll_convert_wide_to_string(templateText, CP_ACP).c_str(), gProductName.c_str()); - ConvertLPCSTRToLPWSTR(final.c_str(), header); - SetWindowText(hWnd, header); -} - - -// Include product name in the diaog item text. -void LLCrashLoggerWindows::ProcessDlgItemText(HWND hWnd, int nIDDlgItem) -{ - TCHAR templateText[MAX_STRING]; /* Flawfinder: ignore */ - TCHAR header[MAX_STRING]; - std::string final; - GetDlgItemText(hWnd, nIDDlgItem, templateText, sizeof(templateText)); - final = llformat(ll_convert_wide_to_string(templateText, CP_ACP).c_str(), gProductName.c_str()); - ConvertLPCSTRToLPWSTR(final.c_str(), header); - SetDlgItemText(hWnd, nIDDlgItem, header); -} - -bool handle_button_click(WORD button_id) -{ - // Is this something other than Send or Don't Send? - if (button_id != IDOK - && button_id != IDCANCEL) - { - return false; - } - - // See if "do this next time" is checked and save state - S32 crash_behavior = CRASH_BEHAVIOR_ASK; - LRESULT result = SendDlgItemMessage(gHwndReport, IDC_CHECK_AUTO, BM_GETCHECK, 0, 0); - if (result == BST_CHECKED) - { - if (button_id == IDOK) - { - crash_behavior = CRASH_BEHAVIOR_ALWAYS_SEND; - } - else if (button_id == IDCANCEL) - { - crash_behavior = CRASH_BEHAVIOR_NEVER_SEND; - } - ((LLCrashLoggerWindows*)LLCrashLogger::instance())->saveCrashBehaviorSetting(crash_behavior); - } - - // We're done with this dialog. - gFirstDialog = FALSE; - - // Send the crash report if requested - if (button_id == IDOK) - { - gSendLogs = TRUE; - WCHAR wbuffer[20000]; - GetDlgItemText(gHwndReport, // handle to dialog box - IDC_EDIT1, // control identifier - wbuffer, // pointer to buffer for text - 20000 // maximum size of string - ); - std::string user_text(ll_convert_wide_to_string(wbuffer, CP_ACP)); - // Activate and show the window. - ShowWindow(gHwndProgress, SW_SHOW); - // Try doing this second to make the progress window go frontmost. - ShowWindow(gHwndReport, SW_HIDE); - ((LLCrashLoggerWindows*)LLCrashLogger::instance())->setUserText(user_text); - ((LLCrashLoggerWindows*)LLCrashLogger::instance())->sendCrashLogs(); - } - // Quit the app - LLApp::setQuitting(); - return true; -} - - -LRESULT CALLBACK WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam ) -{ - switch( message ) - { - case WM_CREATE: - return 0; - - case WM_COMMAND: - if( gFirstDialog ) - { - WORD button_id = LOWORD(wParam); - bool handled = handle_button_click(button_id); - if (handled) - { - return 0; - } - } - break; - - case WM_DESTROY: - // Closing the window cancels - LLApp::setQuitting(); - PostQuitMessage(0); - return 0; - } - - return DefWindowProc(hwnd, message, wParam, lParam); -} - - -LLCrashLoggerWindows::LLCrashLoggerWindows(void) -{ - if (LLCrashLoggerWindows::sInstance==NULL) - { - sInstance = this; - } -} - -LLCrashLoggerWindows::~LLCrashLoggerWindows(void) -{ - sInstance = NULL; -} - -bool LLCrashLoggerWindows::getMessageWithTimeout(MSG *msg, UINT to) -{ - bool res; - const int timerID=37; - SetTimer(NULL, timerID, to, NULL); - res = GetMessage(msg, NULL, 0, 0); - KillTimer(NULL, timerID); - if (!res) - return false; - if (msg->message == WM_TIMER && msg->hwnd == NULL && msg->wParam == 1) - return false; //TIMEOUT! You could call SetLastError() or something... - return true; -} - -int LLCrashLoggerWindows::processingLoop() { - const int millisecs=1000; - static int first_connect = 1; - - LLSD options = getOptionData( LLApp::PRIORITY_COMMAND_LINE ); - - MSG msg; - - bool result; - - while (1) - { - result = getMessageWithTimeout(&msg, millisecs); - if ( result ) - { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - - if (first_connect ) - { - if ( mClientsConnected > 0) - { - first_connect = 0; - } - } - else - { - if (mClientsConnected == 0) - { - break; - } - if (!mKeyMaster.isProcessAlive(mPID, mProcName) ) - { - break; - } - } - } - - llinfos << "session ending.." << llendl; - - llinfos << "clients connected :" << mClientsConnected << llendl; - - return 0; -} - - -void LLCrashLoggerWindows::OnClientConnected(void* context, - const google_breakpad::ClientInfo* client_info) -{ - llinfos << "client start. pid = " << client_info->pid() << llendl; - sInstance->mClientsConnected++; - -} - -void LLCrashLoggerWindows::OnClientExited(void* context, - const google_breakpad::ClientInfo* client_info) -{ - llinfos << "client end. pid = " << client_info->pid() << llendl; - sInstance->mClientsConnected--; -} - -/* -void LLCrashLoggerWindows::OnClientDumpRequest(void* context, - const google_breakpad::ClientInfo* client_info, - const std::wstring* file_path) -{ - ProcessingLock lock; - - if (!file_path) - { - llwarns << "dump with no file path" << llendl; - return; - } - if (!client_info) - { - llwarns << "dump with no client info" << llendl; - return; - } - - LLCrashLoggerWindows* self = static_cast(context); - if (!self) - { - llwarns << "dump with no context" << llendl; - return; - } - - DWORD pid = client_info->pid(); - - -// Send the crash dump using a worker thread. This operation has retry -// logic in case there is no internet connection at the time. -DumpJobInfo* dump_job = new DumpJobInfo(pid, self, map, -dump_location.value()); -if (!::QueueUserWorkItem(&CrashService::AsyncSendDump, -dump_job, WT_EXECUTELONGFUNCTION)) { -LOG(ERROR) << "could not queue job"; -} -} -*/ - -bool LLCrashLoggerWindows::initCrashServer() -{ - //For Breakpad on Windows we need a full Out of Process service to get good data. - //This routine starts up the service on a named pipe that the viewer will then - //communicate with. - using namespace google_breakpad; - - LLSD options = getOptionData( LLApp::PRIORITY_COMMAND_LINE ); - std::string dump_path = options["dumpdir"].asString(); - mClientsConnected = 0; - mPID = options["pid"].asInteger(); - mProcName = options["procname"].asString(); - - std::wostringstream ws; - //Generate a quasi-uniq name for the named pipe. For our purposes - //this is unique-enough with least hassle. Worst case for duplicate name - //is a second instance of the viewer will not do crash reporting. - ws << mCrashReportPipeStr << mPID; - std::wstring wpipe_name = ws.str(); - - std::wstring wdump_path; - wdump_path.assign(dump_path.begin(), dump_path.end()); - - //Pipe naming conventions: http://msdn.microsoft.com/en-us/library/aa365783%28v=vs.85%29.aspx - mCrashHandler = new CrashGenerationServer( (WCHAR *)wpipe_name.c_str(), - NULL, - &LLCrashLoggerWindows::OnClientConnected, this, - NULL, NULL, // &LLCrashLoggerWindows::OnClientDumpRequest, this, - &LLCrashLoggerWindows::OnClientExited, this, - NULL, NULL, - true, &wdump_path); - - if (!mCrashHandler) { - //Failed to start the crash server. - llwarns << "Failed to init crash server." << llendl; - return false; - } - - // Start servicing clients. - if (!mCrashHandler->Start()) { - llwarns << "Failed to start crash server." << llendl; - return false; - } - - return true; -} - -bool LLCrashLoggerWindows::init(void) -{ - initCrashServer(); - bool ok = LLCrashLogger::init(); - if(!ok) return false; - - /* - mbstowcs( gProductName, mProductName.c_str(), LL_ARRAY_SIZE(gProductName) ); - gProductName[ LL_ARRY_SIZE(gProductName) - 1 ] = 0; - swprintf(gProductName, L"Second Life"); - */ - - llinfos << "Loading dialogs" << llendl; - - // Initialize global strings - LoadString(mhInst, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); - LoadString(mhInst, IDC_WIN_CRASH_LOGGER, szWindowClass, MAX_LOADSTRING); - - gCursorArrow = LoadCursor(NULL, IDC_ARROW); - gCursorWait = LoadCursor(NULL, IDC_WAIT); - - // Register a window class that will be used by our dialogs - WNDCLASS wndclass; - wndclass.style = CS_HREDRAW | CS_VREDRAW; - wndclass.lpfnWndProc = WndProc; - wndclass.cbClsExtra = 0; - wndclass.cbWndExtra = DLGWINDOWEXTRA; // Required, since this is used for dialogs! - wndclass.hInstance = mhInst; - wndclass.hIcon = LoadIcon(hInst, MAKEINTRESOURCE( IDI_WIN_CRASH_LOGGER ) ); - wndclass.hCursor = gCursorArrow; - wndclass.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1); - wndclass.lpszMenuName = NULL; - wndclass.lpszClassName = szWindowClass; - RegisterClass( &wndclass ); - - return true; -} - -void LLCrashLoggerWindows::gatherPlatformSpecificFiles() -{ - updateApplication("Gathering hardware information. App may appear frozen."); - // DX hardware probe blocks, so we can't cancel during it - //Generate our dx_info.log file - SetCursor(gCursorWait); - // At this point we're responsive enough the user could click the close button - SetCursor(gCursorArrow); - //mDebugLog["DisplayDeviceInfo"] = gDXHardware.getDisplayInfo(); //Not initialized. -} - -bool LLCrashLoggerWindows::mainLoop() -{ - llinfos << "CrashSubmitBehavior is " << mCrashBehavior << llendl; - // Note: parent hwnd is 0 (the desktop). No dlg proc. See Petzold (5th ed) HexCalc example, Chapter 11, p529 - // win_crash_logger.rc has been edited by hand. - // Dialogs defined with CLASS "WIN_CRASH_LOGGER" (must be same as szWindowClass) - gProductName = mProductName; - gHwndProgress = CreateDialog(hInst, MAKEINTRESOURCE(IDD_PROGRESS), 0, NULL); - ProcessCaption(gHwndProgress); - ShowWindow(gHwndProgress, SW_HIDE ); - - if (mCrashBehavior == CRASH_BEHAVIOR_ALWAYS_SEND) - { - llinfos << "Showing crash report submit progress window." << llendl; - ShowWindow(gHwndProgress, SW_SHOW ); - sendCrashLogs(); - } - else if (mCrashBehavior == CRASH_BEHAVIOR_ASK) - { - gHwndReport = CreateDialog(hInst, MAKEINTRESOURCE(IDD_PREVREPORTBOX), 0, NULL); - // Ignore result - (void) SendDlgItemMessage(gHwndReport, IDC_CHECK_AUTO, BM_SETCHECK, 0, 0); - // Include the product name in the caption and various dialog items. - ProcessCaption(gHwndReport); - ProcessDlgItemText(gHwndReport, IDC_STATIC_MSG); - - // Update the header to include whether or not we crashed on the last run. - std::string headerStr; - TCHAR header[MAX_STRING]; - if (mCrashInPreviousExec) - { - headerStr = llformat("%s appears to have crashed or frozen the last time it ran.", mProductName.c_str()); - } - else - { - headerStr = llformat("%s appears to have crashed.", mProductName.c_str()); - } - ConvertLPCSTRToLPWSTR(headerStr.c_str(), header); - SetDlgItemText(gHwndReport, IDC_STATIC_HEADER, header); - ShowWindow(gHwndReport, SW_SHOW ); - - MSG msg; - memset(&msg, 0, sizeof(msg)); - while (!LLApp::isQuitting() && GetMessage(&msg, NULL, 0, 0)) - { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - return msg.wParam; - } - else - { - llwarns << "Unknown crash behavior " << mCrashBehavior << llendl; - return 1; - } - return 0; -} - -void LLCrashLoggerWindows::updateApplication(const std::string& message) -{ - LLCrashLogger::updateApplication(message); - if(!message.empty()) show_progress(message); - update_messages(); -} - -bool LLCrashLoggerWindows::cleanup() -{ - if(gSendLogs) - { - if(mSentCrashLogs) show_progress("Done"); - else show_progress("Could not connect to servers, logs not sent"); - sleep_and_pump_messages(3); - } - PostQuitMessage(0); - commonCleanup(); - mKeyMaster.releaseMaster(); - return true; -} - diff --git a/indra/win_crash_logger/llcrashloggerwindows.h b/indra/win_crash_logger/llcrashloggerwindows.h deleted file mode 100644 index 85cafd54c..000000000 --- a/indra/win_crash_logger/llcrashloggerwindows.h +++ /dev/null @@ -1,86 +0,0 @@ -/** -* @file llcrashloggerwindows.h -* @brief Windows crash logger definition -* -* $LicenseInfo:firstyear=2003&license=viewerlgpl$ -* Second Life Viewer Source Code -* Copyright (C) 2010, Linden Research, Inc. -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; -* version 2.1 of the License only. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -* -* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA -* $/LicenseInfo$ -*/ - -#ifndef LLCRASHLOGGERWINDOWS_H -#define LLCRASHLOGGERWINDOWS_H - -#include "llcrashlogger.h" -#include "windows.h" -#include "llstring.h" - -class LLSD; - -namespace google_breakpad { - class CrashGenerationServer; - class ClientInfo; -} - -class LLCrashLoggerWindows : public LLCrashLogger -{ -public: - LLCrashLoggerWindows(void); - ~LLCrashLoggerWindows(void); - static LLCrashLoggerWindows* sInstance; - - virtual bool init(); - virtual bool mainLoop(); - virtual void updateApplication(const std::string& message = LLStringUtil::null); - virtual bool cleanup(); - virtual void gatherPlatformSpecificFiles(); - void setHandle(HINSTANCE hInst) { mhInst = hInst; } - int clients_connected() const { - return mClientsConnected; - } - bool getMessageWithTimeout(MSG *msg, UINT to); - - // Starts the processing loop. This function does not return unless the - // user is logging off or the user closes the crash service window. The - // return value is a good number to pass in ExitProcess(). - int processingLoop(); -private: - void ProcessDlgItemText(HWND hWnd, int nIDDlgItem); - void ProcessCaption(HWND hWnd); - bool initCrashServer(); - google_breakpad::CrashGenerationServer* mCrashHandler; - static void OnClientConnected(void* context, - const google_breakpad::ClientInfo* client_info); - - /*static void OnClientDumpRequest( - void* context, - const google_breakpad::ClientInfo* client_info, - const std::wstring* file_path);*/ - - static void OnClientExited(void* context, - const google_breakpad::ClientInfo* client_info); - int mClientsConnected; - int mPID; - std::string mProcName; - - HINSTANCE mhInst; - -}; - -#endif diff --git a/indra/win_crash_logger/resource.h b/indra/win_crash_logger/resource.h deleted file mode 100644 index 37a387275..000000000 --- a/indra/win_crash_logger/resource.h +++ /dev/null @@ -1,63 +0,0 @@ -/** -* @file resource.h -* @brief Windows crash logger windows resources -* -* $LicenseInfo:firstyear=2003&license=viewerlgpl$ -* Second Life Viewer Source Code -* Copyright (C) 2010, Linden Research, Inc. -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; -* version 2.1 of the License only. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -* -* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA -* $/LicenseInfo$ -*/ - -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by win_crash_logger.rc -// -#define IDC_MYICON 2 -#define IDD_REPORT 9 -#define IDD_WIN_CRASH_LOGGER_DIALOG 102 -#define IDD_ABOUTBOX 103 -#define IDS_APP_TITLE 103 -#define IDM_ABOUT 104 -#define IDM_EXIT 105 -#define IDS_HELLO 106 -#define IDI_WIN_CRASH_LOGGER 107 -#define IDI_SMALL 108 -#define IDC_WIN_CRASH_LOGGER 109 -#define IDR_MAINFRAME 128 -#define IDD_PROGRESS 129 -#define IDD_PREVREPORTBOX 130 -#define IDC_EDIT1 1000 -#define IDC_LOG 1004 -#define IDC_CHECK_AUTO 1006 -#define IDC_STATIC_HEADER 1007 -#define IDC_STATIC_WHATINFO 1008 -#define IDC_STATIC_MOTIVATION 1009 -#define IDC_STATIC_MSG 1010 -#define IDC_STATIC -1 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 131 -#define _APS_NEXT_COMMAND_VALUE 32771 -#define _APS_NEXT_CONTROL_VALUE 1011 -#define _APS_NEXT_SYMED_VALUE 110 -#endif -#endif diff --git a/indra/win_crash_logger/snowglobe_icon.ico b/indra/win_crash_logger/snowglobe_icon.ico deleted file mode 100644 index 8ed0fede1f748ed78ea07782f89ffc71276fa53f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4286 zcmb7I33OD|8GcAvEdmwt6!hS+?cv}lWm5_TIm#l7P{9=f$QB?F z!j^>)mOx0tB!-Yol1VZl>r5t@$*gbI_hw1R1_eEhy z_b4j%JqF!=lJK5fidEmCJYjC@=lwKBa~1n~p!B;(!Pc;~%to87hl&O1jv;Zfb?5)x z5hc5NK!2bY^ameD<-y;f@=zZbBAE1rUaNxP${PM&Nn@3VXrA=+2YM5yUVJUH!ECkJ z9P=Qb**NJizd3g5nl8{CAWVjLxG$=X^g~r-e;7}VhVjfaR39AxTcsN2%uT4KaZ}=K z7^8-eUVqYmqLmZz(S`R$>e?>tIovl6gv;{HW6rP*hx>EP>c|0v^?MkPJqgqCr(i2M z0FToO>xCKcTC@<=TVYT85I(O5w#@Y~9eav+4CHGVU&f{S_z2?ARpG!eepU}O#_9wY zR&*l$XSjbHGim^8jt_+S)DW1Xhr$v&5^mjD$X*e$#}1z*AF||wt8gzY(Zfh@C~8g) zM$IvbNmM`1#dMs;&rIgF83w~@p9lKP;@%iNze9`u2(67CNxnW!c80>36Anx20$Afl zz;=2hZ1JPuNEid3;XDFM{^kg@5vN*)fj)g0?<^)U-Nv{(`* zq4M%F6lijx&xwNh>|}^ps~~wCgfSkj#0hX+d=akmW8pYI2?37m@2iAsH0ityckX7M7s;W6 z*Db=99}ZjMRCu$Nz;R&;l2>5SjLe65;hJui)lHmM)5&U8~$M;Jfh*wv@7Bh(Kj)J6K zMi_rb{`Myne0E;2a|7mtX>eYe!t-cM`Ufn!EWW2CR}Eyt8OUTa7ziL>z5*%ZZ_r2d zN8VQgv^%@Qer`MhWnl?@%U~%@ftbA>&daYsO8Emk>J_c{X@7<0>qlTZJrRv%s}WHD z6ZzXZ!x%FT679vH+W=oO`I|I>_R~9XYPQ2=DS<0@18T3YCH#*lXA_k88ws1&pGbSp zf0g`9p9XjKhp-nPhuf~_^&{C!;dfOLzMuMDBE*ZYLr1-={Lmm=-_r-yvwx($v8r`% zuo`t&!S6Qlee1KAz*8Q9+OjVZ(tH3p<89c^yrAG`5kA`kD2sRwp}d8>c38~i)R$qq zG9Nydh1>C4GErwahXC!rfb4^(Fbv|Q*WgT>3%{*^*G9;pLA~iP{8n}Ao^=`_rZ0jo zbuwx-^H8f@j$qC_lpY+e;D-}7>j6mntS@Tw7eh*&gzAJD(B&nd##jxvDVxWjR=*F; z#$9N(Mxs{CrXC<6C^>mff}UzL+ApHnv=2?y+Y!|7Z}q+A8l2R_EV^rOX}&}q#ovE* zCSmna@ZTV8-hX2kb!?HZ&W1z13YuIsD)LSvSh5w4oXzmMY-lp>!%fR!+_XpImNNm( z?lkzR|H?Hg+;S)4mUtRBZO74UK0vy=A<_Bh&ifD9*a%B`B8=4r_)ETpH)RT97j|T4 z5bMAE9Hu8fe>6LXqONce+?v&>FItR-vQJ8=kurJ`YFCB8hM!I_x^1QIK-(yHYU3nOBNToQO!ALcBjhqiz%Ba|gx! z2-%G%zf&P=)+8BTo)LZ#a%7ngXBSPYsBUlZ;+dVWRqHy6ok zA6I<;qCIvS{=NH`I&5SsZ~f;~bKj9aQ54(r@M|E%rO;y{_RJoP=qTcq5f}Kac{_OtM#^K)mGiT>GH0U-{P4D4##bYmJ z;&!kYH)~D!@pcdug(_II(fG01gQh?weh3gRstpz^RxfNX)R%35I&8Fp?fT!i-zN_D z?%%1O4My<#7V`fX<(~YPuHsJUI_@?Q{!JeWvo4@2HxhT7oVasCPxyH}M{F-NnP+xr*g@p@S_|H=2SxDUFuWbXJgOjoFn*U%meXo-i8 zbNPYZZ&(shLvz=5OhWA9t_m)z^DmgK2jTqMIO9!n-|wICOCLl0(w-FG4oZxbC+jV& zxBg!~{}LCnrQ8*jJ5&4b-|QS?X9>e(J@w)Jt?LPF=|CMoz+FL@dP@)n)d@mRyC8I7 mk|hWox6r>36cK*qN6}-?ELv-Cl`hOCv&}FF>vN7t*#8AV8$}fW diff --git a/indra/win_crash_logger/win_crash_logger.cpp b/indra/win_crash_logger/win_crash_logger.cpp deleted file mode 100644 index e25e12834..000000000 --- a/indra/win_crash_logger/win_crash_logger.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/** - * @file win_crash_logger.cpp - * @brief Windows crash logger implementation - * - * $LicenseInfo:firstyear=2003&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" -#include "stdafx.h" -#include -#include "llcrashloggerwindows.h" -#include - - -int APIENTRY WinMain(HINSTANCE hInstance, - HINSTANCE hPrevInstance, - LPSTR lpCmdLine, - int nCmdShow) -{ - llinfos << "Starting crash reporter." << llendl; - LLCrashLoggerWindows app; - app.setHandle(hInstance); - app.parseCommandOptions(__argc, __argv); - - LLSD options = LLApp::instance()->getOptionData( - LLApp::PRIORITY_COMMAND_LINE); - if (!(options.has("pid") && options.has("dumpdir"))) - { - llwarns << "Insufficient parameters to crash report." << llendl; - } - if (! app.init()) - { - llwarns << "Unable to initialize application." << llendl; - return 1; - } - - app.processingLoop(); - app.mainLoop(); - app.cleanup(); - llinfos << "Crash reporter finished normally." << llendl; - return 0; -} diff --git a/indra/win_crash_logger/win_crash_logger.h b/indra/win_crash_logger/win_crash_logger.h deleted file mode 100644 index 2cc2cf3dc..000000000 --- a/indra/win_crash_logger/win_crash_logger.h +++ /dev/null @@ -1,38 +0,0 @@ -/** - * @file win_crash_logger.h - * @brief Windows crash logger project includes - * - * $LicenseInfo:firstyear=2003&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - - -#if !defined(AFX_WIN_CRASH_LOGGER_H__79802F4B_7C37_4F63_A2BB_0768788C3A27__INCLUDED_) -#define AFX_WIN_CRASH_LOGGER_H__79802F4B_7C37_4F63_A2BB_0768788C3A27__INCLUDED_ - -#if _MSC_VER > 1000 -#pragma once -#endif // _MSC_VER > 1000 - -#include "resource.h" - - -#endif // !defined(AFX_WIN_CRASH_LOGGER_H__79802F4B_7C37_4F63_A2BB_0768788C3A27__INCLUDED_) diff --git a/indra/win_crash_logger/win_crash_logger.ico b/indra/win_crash_logger/win_crash_logger.ico deleted file mode 100644 index 386883523bcc032db77b69b047cbc5c15ae3b7fe..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1078 zcmeH_K@!3s3`IZHwe$$AoF2oYaWszOk{jR)NR>_(PRDWOZgV)&%Zp6VccBVa2?uQ&sh9LW;!?J w2dwKn!S@jnH5GJS10MR3&V{nkc?%F^XS#jrb=7ItXV>BJ*yg?&H~)SR4}%AClK=n! diff --git a/indra/win_crash_logger/win_crash_logger.rc b/indra/win_crash_logger/win_crash_logger.rc deleted file mode 100644 index 2819722f6..000000000 --- a/indra/win_crash_logger/win_crash_logger.rc +++ /dev/null @@ -1,188 +0,0 @@ -// Microsoft Visual C++ generated resource script. -// -#include "resource.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#define APSTUDIO_HIDDEN_SYMBOLS -#include "windows.h" -#undef APSTUDIO_HIDDEN_SYMBOLS -#include "resource.h" - -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (U.S.) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -#ifdef _WIN32 -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US -#pragma code_page(1252) -#endif //_WIN32 - -///////////////////////////////////////////////////////////////////////////// -// -// Icon -// - -// Icon with lowest ID value placed first to ensure application icon -// remains consistent on all systems. -IDI_WIN_CRASH_LOGGER ICON "ll_icon.ico" - -///////////////////////////////////////////////////////////////////////////// -// -// Menu -// - -IDC_WIN_CRASH_LOGGER MENU -BEGIN - POPUP "&File" - BEGIN - MENUITEM "E&xit", IDM_EXIT - END - POPUP "&Help" - BEGIN - MENUITEM "&About ...", IDM_ABOUT - END -END - - -///////////////////////////////////////////////////////////////////////////// -// -// Dialog -// - -IDD_PROGRESS DIALOGEX 100, 100, 234, 33 -STYLE DS_SETFONT | DS_SETFOREGROUND | WS_CAPTION | WS_SYSMENU -CAPTION "%s Crash Logger" -CLASS "WIN_CRASH_LOGGER" -FONT 8, "MS Sans Serif", 0, 0, 0x0 -BEGIN - LTEXT "Static",IDC_LOG,7,7,220,8 -END - -IDD_REPORT DIALOGEX 100, 100, 297, 125 -STYLE DS_SETFONT | DS_SETFOREGROUND | WS_CAPTION | WS_SYSMENU -CAPTION "%s Crash Logger" -CLASS "WIN_CRASH_LOGGER" -FONT 8, "MS Sans Serif", 0, 0, 0x0 -BEGIN - DEFPUSHBUTTON "Send",IDOK,198,104,45,15,WS_GROUP - PUSHBUTTON "Don't Send",IDCANCEL,247,104,45,15,WS_GROUP - LTEXT "%s appears to have crashed.",IDC_STATIC_HEADER,4,4,288,14 - LTEXT "This crash reporter collects information about your computer's hardware, operating system, and some %s logs, which are used for debugging purposes only.",IDC_STATIC_WHATINFO,4,23,288,19,NOT WS_GROUP - CONTROL "Remember this choice",IDC_CHECK_AUTO,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,4,106,89,13 - LTEXT "Sending crash reports is the best way to help us improve the quality of %s.",IDC_STATIC_MOTIVATION,4,43,288,8 - LTEXT "If you continue to experience this problem, please try:",IDC_STATIC,4,57,251,8 - LTEXT "- Contacting support by visiting http://www.secondlife.com/support",IDC_STATIC,4,67,231,8 -END - -IDD_PREVREPORTBOX DIALOGEX 100, 100, 232, 213 -STYLE DS_SETFONT | DS_SETFOREGROUND | WS_CAPTION | WS_SYSMENU -CAPTION "%s Crash Logger" -CLASS "WIN_CRASH_LOGGER" -FONT 8, "MS Sans Serif", 0, 0, 0x0 -BEGIN - DEFPUSHBUTTON "Send Report",IDOK,131,193,45,15,WS_GROUP - EDITTEXT IDC_EDIT1,3,100,223,89,ES_MULTILINE | ES_WANTRETURN | WS_VSCROLL - PUSHBUTTON "Don't Send",IDCANCEL,181,193,45,15,WS_GROUP - LTEXT "%s appears to have crashed or frozen the last time it ran.",IDC_STATIC_HEADER,4,4,214,8 - LTEXT "This crash reporter collects information about your computer's",IDC_STATIC,4,17,201,8 - LTEXT "hardware configuration, operating system, and some %s",IDC_STATIC_MSG,4,25,212,8 - LTEXT "logs, all of which are used for debugging purposes only.",IDC_STATIC,4,33,210,8 - LTEXT "In the space below, please briefly describe what you were doing",IDC_STATIC,3,48,208,8 - LTEXT "or trying to do just prior to the crash.",IDC_STATIC,3,56,204,8 - LTEXT "If you don't wish to send Linden Lab a crash report, press Don't Send.",IDC_STATIC,3,90,223,8 - LTEXT "This report is NOT read by customer support. If you have billing or",IDC_STATIC,3,68,208,8 - LTEXT "other questions, please go to: www.secondlife.com/support",IDC_STATIC,3,76,206,8 - CONTROL "Remember this choice",IDC_CHECK_AUTO,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,3,193,89,13 -END - - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -2 TEXTINCLUDE -BEGIN - "#define APSTUDIO_HIDDEN_SYMBOLS\r\n" - "#include ""windows.h""\r\n" - "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n" - "#include ""resource.h""\r\n" - "\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// DESIGNINFO -// - -#ifdef APSTUDIO_INVOKED -GUIDELINES DESIGNINFO -BEGIN - IDD_PROGRESS, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 227 - TOPMARGIN, 7 - BOTTOMMARGIN, 26 - END - - IDD_REPORT, DIALOG - BEGIN - RIGHTMARGIN, 292 - VERTGUIDE, 4 - BOTTOMMARGIN, 119 - HORZGUIDE, 4 - END -END -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// String Table -// - -STRINGTABLE -BEGIN - IDS_APP_TITLE "win_crash_logger" - IDS_HELLO "Hello World!" - IDC_WIN_CRASH_LOGGER "WIN_CRASH_LOGGER" -END - -#endif // English (U.S.) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - diff --git a/indra/win_updater/CMakeLists.txt b/indra/win_updater/CMakeLists.txt deleted file mode 100644 index dedb7cfcc..000000000 --- a/indra/win_updater/CMakeLists.txt +++ /dev/null @@ -1,35 +0,0 @@ -# -*- cmake -*- - -project(win_updater) - -include(00-Common) -include(LLCommon) -include(Linking) - -include_directories( - ${LLCOMMON_INCLUDE_DIRS} - ) - -set(win_updater_SOURCE_FILES updater.cpp) - -set(win_updater_HEADER_FILES CMakeLists.txt) - -set_source_files_properties(${win_updater_HEADER_FILES} - PROPERTIES HEADER_FILE_ONLY TRUE) - -list(APPEND win_updater_SOURCE_FILES ${win_updater_HEADER_FILES}) - -add_executable(windows-updater WIN32 ${win_updater_SOURCE_FILES}) - -target_link_libraries(windows-updater - wininet - user32 - gdi32 - shell32 - ) - -set_target_properties(windows-updater - PROPERTIES - LINK_FLAGS "/NODEFAULTLIB:LIBCMT" - LINK_FLAGS_DEBUG "/NODEFAULTLIB:\"LIBCMT;LIBCMTD;MSVCRT\"" - ) diff --git a/indra/win_updater/updater.cpp b/indra/win_updater/updater.cpp deleted file mode 100644 index 3937351d7..000000000 --- a/indra/win_updater/updater.cpp +++ /dev/null @@ -1,522 +0,0 @@ -/** - * @file updater.cpp - * @brief Windows auto-updater - * - * $LicenseInfo:firstyear=2002&license=viewergpl$ - * - * Copyright (c) 2002-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -// -// Usage: updater -url -// - -// We use dangerous fopen, strtok, mbstowcs, sprintf -// which generates warnings on VC2005. -// *TODO: Switch to fopen_s, strtok_s, etc. -#define _CRT_SECURE_NO_DEPRECATE - -#include -#include -#include -#include -#include -#include -#include -#include - -#define BUFSIZE 8192 - -int gTotalBytesRead = 0; -DWORD gTotalBytes = -1; -HWND gWindow = NULL; -WCHAR gProgress[256]; -char* gUpdateURL = NULL; - -#if _DEBUG -std::ofstream logfile; -#define DEBUG(expr) logfile << expr << std::endl -#else -#define DEBUG(expr) /**/ -#endif - -char* wchars_to_utf8chars(const WCHAR* in_chars) -{ - int tlen = 0; - const WCHAR* twc = in_chars; - while (*twc++ != 0) - { - tlen++; - } - char* outchars = new char[tlen]; - char* res = outchars; - for (int i=0; i - static RESULT check(const std::string& desc, RESULT result) - { - if (result) - { - // success, show caller - return result; - } - DWORD err = GetLastError(); - std::ostringstream out; - out << desc << " Failed: " << err; - DEBUG(out.str()); - throw InetError(out.str()); - } - - HINTERNET openUrl(const std::wstring& uri) const; - HINTERNET openInet() const; - - HINTERNET mInet, mDownload; -}; - -HINTERNET Fetcher::openInet() const -{ - DEBUG("Calling InternetOpen"); - // Init wininet subsystem - return check("InternetOpen", - InternetOpen(L"LindenUpdater", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0)); -} - -HINTERNET Fetcher::openUrl(const std::wstring& uri) const -{ - DEBUG("Calling InternetOpenUrl: " << wchars_to_utf8chars(uri.c_str())); - return check("InternetOpenUrl", - InternetOpenUrl(mInet, uri.c_str(), NULL, 0, INTERNET_FLAG_NEED_FILE, NULL)); -} - -unsigned long Fetcher::read(char* buffer, size_t bufflen) const -{ - unsigned long bytes_read = 0; - DEBUG("Calling InternetReadFile"); - check("InternetReadFile", - InternetReadFile(mDownload, buffer, bufflen, &bytes_read)); - return bytes_read; -} - -int WINAPI get_url_into_file(const std::wstring& uri, const std::string& path, int *cancelled) -{ - int success = FALSE; - *cancelled = FALSE; - - DEBUG("Opening '" << path << "'"); - - FILE* fp = fopen(path.c_str(), "wb"); /* Flawfinder: ignore */ - - if (!fp) - { - DEBUG("Failed to open '" << path << "'"); - return success; - } - - // Note, ctor can throw, since it uses check() function. - Fetcher fetcher(uri); - gTotalBytes = fetcher.getTotalBytes(); - -/*==========================================================================*| - // nobody uses total_bytes?!? What's this doing here? - DWORD total_bytes = 0; - success = check("InternetQueryDataAvailable", - InternetQueryDataAvailable(hdownload, &total_bytes, 0, 0)); -|*==========================================================================*/ - - success = FALSE; - while(!success && !(*cancelled)) - { - char data[BUFSIZE]; /* Flawfinder: ignore */ - unsigned long bytes_read = fetcher.read(data, sizeof(data)); - - if (!bytes_read) - { - DEBUG("InternetReadFile Read " << bytes_read << " bytes."); - } - - DEBUG("Reading Data, bytes_read = " << bytes_read); - - if (bytes_read == 0) - { - // If InternetFileRead returns TRUE AND bytes_read == 0 - // we've successfully downloaded the entire file - wsprintf(gProgress, L"Download complete."); - success = TRUE; - } - else - { - // write what we've got, then continue - fwrite(data, sizeof(char), bytes_read, fp); - - gTotalBytesRead += int(bytes_read); - - if (gTotalBytes != -1) - wsprintf(gProgress, L"Downloaded: %d%%", 100 * gTotalBytesRead / gTotalBytes); - else - wsprintf(gProgress, L"Downloaded: %dK", gTotalBytesRead / 1024); - - } - - DEBUG("Calling InvalidateRect"); - - // Mark the window as needing redraw (of the whole thing) - InvalidateRect(gWindow, NULL, TRUE); - - // Do the redraw - DEBUG("Calling UpdateWindow"); - UpdateWindow(gWindow); - - DEBUG("Calling PeekMessage"); - MSG msg; - while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) - { - TranslateMessage(&msg); - DispatchMessage(&msg); - - if (msg.message == WM_QUIT) - { - // bail out, user cancelled - *cancelled = TRUE; - } - } - } - - fclose(fp); - return success; -} - -LRESULT CALLBACK WinProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) -{ - HDC hdc; // Drawing context - PAINTSTRUCT ps; - - switch(message) - { - case WM_PAINT: - { - hdc = BeginPaint(hwnd, &ps); - - RECT rect; - GetClientRect(hwnd, &rect); - DrawText(hdc, gProgress, -1, &rect, - DT_SINGLELINE | DT_CENTER | DT_VCENTER); - - EndPaint(hwnd, &ps); - return 0; - } - case WM_CLOSE: - case WM_DESTROY: - // Get out of full screen - // full_screen_mode(false); - PostQuitMessage(0); - return 0; - } - return DefWindowProc(hwnd, message, wparam, lparam); -} - -#define win_class_name L"FullScreen" - -int parse_args(int argc, char **argv) -{ - int j; - - for (j = 1; j < argc; j++) - { - if ((!strcmp(argv[j], "-url")) && (++j < argc)) - { - gUpdateURL = argv[j]; - } - } - - // If nothing was set, let the caller know. - if (!gUpdateURL) - { - return 1; - } - return 0; -} - -int WINAPI -WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) -{ - // Parse the command line. - LPSTR cmd_line_including_exe_name = GetCommandLineA(); - - const int MAX_ARGS = 100; - int argc = 0; - char* argv[MAX_ARGS]; /* Flawfinder: ignore */ - -#if _DEBUG - logfile.open("updater.log", std::ios_base::out); - DEBUG("Parsing command arguments"); -#endif - - char *token = NULL; - if( cmd_line_including_exe_name[0] == '\"' ) - { - // Exe name is enclosed in quotes - token = strtok( cmd_line_including_exe_name, "\"" ); - argv[argc++] = token; - token = strtok( NULL, " \t," ); - } - else - { - // Exe name is not enclosed in quotes - token = strtok( cmd_line_including_exe_name, " \t," ); - } - - while( (token != NULL) && (argc < MAX_ARGS) ) - { - argv[argc++] = token; - /* Get next token: */ - if (*(token + strlen(token) + 1) == '\"') /* Flawfinder: ignore */ - { - token = strtok( NULL, "\""); - } - else - { - token = strtok( NULL, " \t," ); - } - } - - gUpdateURL = NULL; - - ///////////////////////////////////////// - // - // Process command line arguments - // - - DEBUG("Processing command arguments"); - - // - // Parse the command line arguments - // - int parse_args_result = parse_args(argc, argv); - - WNDCLASSEX wndclassex = { 0 }; - //DEVMODE dev_mode = { 0 }; - - const int WINDOW_WIDTH = 250; - const int WINDOW_HEIGHT = 100; - - wsprintf(gProgress, L"Connecting..."); - - /* Init the WNDCLASSEX */ - wndclassex.cbSize = sizeof(WNDCLASSEX); - wndclassex.style = CS_HREDRAW | CS_VREDRAW; - wndclassex.hInstance = hInstance; - wndclassex.lpfnWndProc = WinProc; - wndclassex.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH); - wndclassex.lpszClassName = win_class_name; - - RegisterClassEx(&wndclassex); - - // Get the size of the screen - //EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode); - - gWindow = CreateWindowEx(NULL, win_class_name, - L"Second Life Updater", - WS_OVERLAPPEDWINDOW, - CW_USEDEFAULT, - CW_USEDEFAULT, - WINDOW_WIDTH, - WINDOW_HEIGHT, - NULL, NULL, hInstance, NULL); - - ShowWindow(gWindow, nShowCmd); - UpdateWindow(gWindow); - - if (parse_args_result) - { - MessageBox(gWindow, - L"Usage: updater -url [-name ] [-program ] [-silent]", - L"Usage", MB_OK); - return parse_args_result; - } - - // Did we get a userserver to work with? - if (!gUpdateURL) - { - MessageBox(gWindow, L"Please specify the download url from the command line", - L"Error", MB_OK); - return 1; - } - - // Can't feed GetTempPath into GetTempFile directly - char temp_path[MAX_PATH]; /* Flawfinder: ignore */ - if (0 == GetTempPathA(sizeof(temp_path), temp_path)) - { - MessageBox(gWindow, L"Problem with GetTempPath()", - L"Error", MB_OK); - return 1; - } - std::string update_exec_path(temp_path); - update_exec_path.append("Second_Life_Updater.exe"); - - WCHAR update_uri[4096]; - mbstowcs(update_uri, gUpdateURL, sizeof(update_uri)); - - int success = 0; - int cancelled = 0; - - // Actually do the download - try - { - DEBUG("Calling get_url_into_file"); - success = get_url_into_file(update_uri, update_exec_path, &cancelled); - } - catch (const Fetcher::InetError& e) - { - (void)e; - success = FALSE; - DEBUG("Caught: " << e.what()); - } - - // WinInet can't tell us if we got a 404 or not. Therefor, we check - // for the size of the downloaded file, and assume that our installer - // will always be greater than 1MB. - if (gTotalBytesRead < (1024 * 1024) && ! cancelled) - { - MessageBox(gWindow, - L"The Second Life auto-update has failed.\n" - L"The problem may be caused by other software installed \n" - L"on your computer, such as a firewall.\n" - L"Please visit http://secondlife.com/download/ \n" - L"to download the latest version of Second Life.\n", - NULL, MB_OK); - return 1; - } - - if (cancelled) - { - // silently exit - return 0; - } - - if (!success) - { - MessageBox(gWindow, - L"Second Life download failed.\n" - L"Please try again later.", - NULL, MB_OK); - return 1; - } - - // TODO: Make updates silent (with /S to NSIS) - //char params[256]; /* Flawfinder: ignore */ - //sprintf(params, "/S"); /* Flawfinder: ignore */ - //MessageBox(gWindow, - // L"Updating Second Life.\n\nSecond Life will automatically start once the update is complete. This may take a minute...", - // L"Download Complete", - // MB_OK); - -/*==========================================================================*| - // DEV-31680: ShellExecuteA() causes McAfee-GW-Edition and AntiVir - // scanners to flag this executable as a probable virus vector. - // Less than or equal to 32 means failure - if (32 >= (int) ShellExecuteA(gWindow, "open", update_exec_path.c_str(), NULL, - "C:\\", SW_SHOWDEFAULT)) -|*==========================================================================*/ - // from http://msdn.microsoft.com/en-us/library/ms682512(VS.85).aspx - STARTUPINFOA si; - PROCESS_INFORMATION pi; - ZeroMemory(&si, sizeof(si)); - si.cb = sizeof(si); - ZeroMemory(&pi, sizeof(pi)); - - if (! CreateProcessA(update_exec_path.c_str(), // executable file - NULL, // command line - NULL, // process cannot be inherited - NULL, // thread cannot be inherited - FALSE, // do not inherit existing handles - 0, // process creation flags - NULL, // inherit parent's environment - NULL, // inherit parent's current dir - &si, // STARTUPINFO - &pi)) // PROCESS_INFORMATION - { - MessageBox(gWindow, L"Update failed. Please try again later.", NULL, MB_OK); - return 1; - } - - // Give installer some time to open a window - Sleep(1000); - - return 0; -} From d20b7815dfd9a5db196f6f579eb0d4da8b26ca69 Mon Sep 17 00:00:00 2001 From: Latif Khalifa Date: Wed, 2 Oct 2013 00:39:11 +0200 Subject: [PATCH 06/16] Check user pref for sending logs --- indra/newview/llcrashlogger.cpp | 18 ++++++++---------- indra/newview/llcrashlogger.h | 1 - 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/indra/newview/llcrashlogger.cpp b/indra/newview/llcrashlogger.cpp index 862f69588..fdc132d41 100644 --- a/indra/newview/llcrashlogger.cpp +++ b/indra/newview/llcrashlogger.cpp @@ -189,7 +189,7 @@ bool LLCrashLogger::readMinidump(std::string minidump_path) void LLCrashLogger::gatherFiles() { - updateApplication("Gathering logs..."); + llinfos << "Gathering logs..." << llendl; LLSD static_sd; LLSD dynamic_sd; @@ -241,7 +241,7 @@ void LLCrashLogger::gatherFiles() mCrashInfo["DebugLog"] = mDebugLog; mFileMap["StatsLog"] = gDirUtilp->getExpandedFilename(LL_PATH_DUMP,"stats.log"); - updateApplication("Encoding files..."); + llinfos << "Encoding files..." << llendl; for(std::map::iterator itr = mFileMap.begin(); itr != mFileMap.end(); ++itr) { @@ -330,7 +330,7 @@ bool LLCrashLogger::sendCrashLog(std::string dump_dir) LLSD post_data; post_data = constructPostData(); - updateApplication("Sending reports..."); + llinfos << "Sending reports..." << llendl; std::ofstream out_file(report_file.c_str()); LLSDSerialize::toPrettyXML(post_data, out_file); @@ -342,19 +342,17 @@ bool LLCrashLogger::sendCrashLog(std::string dump_dir) } -void LLCrashLogger::updateApplication(const std::string& message) -{ - if (!message.empty()) llinfos << message << llendl; -} - - void LLCrashLogger::checkCrashDump() { mCrashHost = gSavedSettings.getString("CrashHostUrl"); + std::string dumpDir = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "") + "singularity-debug"; if (gDirUtilp->fileExists(dumpDir)) { - sendCrashLog(dumpDir); + if (!mCrashHost.empty() && gSavedSettings.getS32("CrashSubmitBehavior") != 2) + { + sendCrashLog(dumpDir); + } gDirUtilp->deleteDirAndContents(dumpDir); } else diff --git a/indra/newview/llcrashlogger.h b/indra/newview/llcrashlogger.h index e23d5330c..4a83e5527 100644 --- a/indra/newview/llcrashlogger.h +++ b/indra/newview/llcrashlogger.h @@ -48,7 +48,6 @@ public: bool saveCrashBehaviorSetting(S32 crash_behavior); bool sendCrashLog(std::string dump_dir); LLSD constructPostData(); - virtual void updateApplication(const std::string& message = LLStringUtil::null); void setUserText(const std::string& text) { mCrashInfo["UserNotes"] = text; } S32 getCrashBehavior() { return mCrashBehavior; } bool readMinidump(std::string minidump_path); From b125ec8d510c961b05f0016f7fbf0f484266f192 Mon Sep 17 00:00:00 2001 From: Latif Khalifa Date: Wed, 2 Oct 2013 00:51:29 +0200 Subject: [PATCH 07/16] Breakpad: untested update to linux/mac specific parts of llappviewer --- indra/newview/llappviewerlinux.cpp | 335 ++-------------------------- indra/newview/llappviewerlinux.h | 3 +- indra/newview/llappviewermacosx.cpp | 136 ++--------- indra/newview/llappviewermacosx.h | 3 +- 4 files changed, 38 insertions(+), 439 deletions(-) diff --git a/indra/newview/llappviewerlinux.cpp b/indra/newview/llappviewerlinux.cpp index ce64710fa..ac2ffa771 100644 --- a/indra/newview/llappviewerlinux.cpp +++ b/indra/newview/llappviewerlinux.cpp @@ -46,27 +46,6 @@ #include -#if LL_LINUX -# include // RTLD_LAZY -# include // backtrace - glibc only -# include -# include -# include -# include -#elif LL_SOLARIS -# include -# include -# include -# include -#endif - -#ifdef LL_ELFBIN -# ifdef __GNUC__ -# include // for symbol demangling -# endif -# include "ELFIO/ELFIO.h" // for better backtraces -#endif - #if LL_DBUS_ENABLED # include "llappviewerlinux_api_dbus.h" @@ -90,8 +69,9 @@ static void exceptionTerminateHandler() // reinstall default terminate() handler in case we re-terminate. if (gOldTerminateHandler) std::set_terminate(gOldTerminateHandler); // treat this like a regular viewer crash, with nice stacktrace etc. - LLAppViewer::handleSyncViewerCrash(); - LLAppViewer::handleViewerCrash(); + long *null_ptr; + null_ptr = 0; + *null_ptr = 0xDEADBEEF; //Force an exception that will trigger breakpad. // we've probably been killed-off before now, but... gOldTerminateHandler(); // call old terminate() handler } @@ -114,7 +94,6 @@ int main( int argc, char **argv ) gOldTerminateHandler = std::set_terminate(exceptionTerminateHandler); // install crash handlers viewer_app_ptr->setErrorHandler(LLAppViewer::handleViewerCrash); - viewer_app_ptr->setSyncErrorHandler(LLAppViewer::handleSyncViewerCrash); bool ok = viewer_app_ptr->init(); if(!ok) @@ -144,201 +123,6 @@ int main( int argc, char **argv ) return 0; } -#ifdef LL_SOLARIS -static inline BOOL do_basic_glibc_backtrace() -{ - BOOL success = FALSE; - - std::string strace_filename = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stack_trace.log"); - llinfos << "Opening stack trace file " << strace_filename << llendl; - LLFILE* StraceFile = LLFile::fopen(strace_filename, "w"); - if (!StraceFile) - { - llinfos << "Opening stack trace file " << strace_filename << " failed. Using stderr." << llendl; - StraceFile = stderr; - } - - printstack(fileno(StraceFile)); - - if (StraceFile != stderr) - fclose(StraceFile); - - return success; -} -#else -#define MAX_STACK_TRACE_DEPTH 40 -// This uses glibc's basic built-in stack-trace functions for a not very -// amazing backtrace. -static inline BOOL do_basic_glibc_backtrace() -{ - void *stackarray[MAX_STACK_TRACE_DEPTH]; - size_t size; - char **strings; - size_t i; - BOOL success = FALSE; - - size = backtrace(stackarray, MAX_STACK_TRACE_DEPTH); - strings = backtrace_symbols(stackarray, size); - - std::string strace_filename = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stack_trace.log"); - llinfos << "Opening stack trace file " << strace_filename << llendl; - LLFILE* StraceFile = LLFile::fopen(strace_filename, "w"); // Flawfinder: ignore - if (!StraceFile) - { - llinfos << "Opening stack trace file " << strace_filename << " failed. Using stderr." << llendl; - StraceFile = stderr; - } - - if (size) - { - for (i = 0; i < size; i++) - { - // the format of the StraceFile is very specific, to allow (kludgy) machine-parsing - fprintf(StraceFile, "%-3lu ", (unsigned long)i); - fprintf(StraceFile, "%-32s\t", "unknown"); - fprintf(StraceFile, "%p ", stackarray[i]); - fprintf(StraceFile, "%s\n", strings[i]); - } - - success = TRUE; - } - - if (StraceFile != stderr) - fclose(StraceFile); - - free (strings); - return success; -} - -#if LL_ELFBIN -// This uses glibc's basic built-in stack-trace functions together with -// ELFIO's ability to parse the .symtab ELF section for better symbol -// extraction without exporting symbols (which'd cause subtle, fatal bugs). -static inline BOOL do_elfio_glibc_backtrace() -{ - void *stackarray[MAX_STACK_TRACE_DEPTH]; - size_t btsize; - char **strings; - BOOL success = FALSE; - - std::string appfilename = gDirUtilp->getExecutablePathAndName(); - - std::string strace_filename = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stack_trace.log"); - llinfos << "Opening stack trace file " << strace_filename << llendl; - LLFILE* StraceFile = LLFile::fopen(strace_filename, "w"); // Flawfinder: ignore - if (!StraceFile) - { - llinfos << "Opening stack trace file " << strace_filename << " failed. Using stderr." << llendl; - StraceFile = stderr; - } - - // get backtrace address list and basic symbol info - btsize = backtrace(stackarray, MAX_STACK_TRACE_DEPTH); - strings = backtrace_symbols(stackarray, btsize); - - // create ELF reader for our app binary - IELFI* pReader; - const IELFISection* pSec = NULL; - IELFISymbolTable* pSymTbl = 0; - if (ERR_ELFIO_NO_ERROR != ELFIO::GetInstance()->CreateELFI(&pReader) || - ERR_ELFIO_NO_ERROR != pReader->Load(appfilename.c_str()) || - // find symbol table, create reader-object - NULL == (pSec = pReader->GetSection( ".symtab" )) || - ERR_ELFIO_NO_ERROR != pReader->CreateSectionReader(IELFI::ELFI_SYMBOL, pSec, (void**)&pSymTbl) ) - { - // Failed to open our binary and read its symbol table somehow - llinfos << "Could not initialize ELF symbol reading - doing basic backtrace." << llendl; - if (StraceFile != stderr) - fclose(StraceFile); - // note that we may be leaking some of the above ELFIO - // objects now, but it's expected that we'll be dead soon - // and we want to tread delicately until we get *some* kind - // of useful backtrace. - return do_basic_glibc_backtrace(); - } - - // iterate over trace and symtab, looking for plausible symbols - std::string name; - Elf32_Addr value; - Elf32_Word ssize; - unsigned char bind; - unsigned char type; - Elf32_Half section; - int nSymNo = pSymTbl->GetSymbolNum(); - size_t btpos; - for (btpos = 0; btpos < btsize; ++btpos) - { - // the format of the StraceFile is very specific, to allow (kludgy) machine-parsing - fprintf(StraceFile, "%-3ld ", (long)btpos); - int symidx; - for (symidx = 0; symidx < nSymNo; ++symidx) - { - if (ERR_ELFIO_NO_ERROR == - pSymTbl->GetSymbol(symidx, name, value, ssize, - bind, type, section)) - { - // check if trace address within symbol range - if (uintptr_t(stackarray[btpos]) >= value && - uintptr_t(stackarray[btpos]) < value+ssize) - { - // symbol is inside viewer - fprintf(StraceFile, "%-32s\t", "com.secondlife.indra.viewer"); - fprintf(StraceFile, "%p ", stackarray[btpos]); - - char *demangled_str = NULL; - int demangle_result = 1; - demangled_str = - abi::__cxa_demangle - (name.c_str(), NULL, NULL, - &demangle_result); - if (0 == demangle_result && - NULL != demangled_str) { - fprintf(StraceFile, - "%s", demangled_str); - free(demangled_str); - } - else // failed demangle; print it raw - { - fprintf(StraceFile, - "%s", name.c_str()); - } - // print offset from symbol start - fprintf(StraceFile, - " + %lu\n", - uintptr_t(stackarray[btpos]) - - value); - goto got_sym; // early escape - } - } - } - // Fallback: - // Didn't find a suitable symbol in the binary - it's probably - // a symbol in a DSO; use glibc's idea of what it should be. - fprintf(StraceFile, "%-32s\t", "unknown"); - fprintf(StraceFile, "%p ", stackarray[btpos]); - fprintf(StraceFile, "%s\n", strings[btpos]); - got_sym:; - } - - if (StraceFile != stderr) - fclose(StraceFile); - - pSymTbl->Release(); - pSec->Release(); - pReader->Release(); - - free(strings); - - llinfos << "Finished generating stack trace." << llendl; - - success = TRUE; - return success; -} -#endif // LL_ELFBIN - -#endif // LL_SOLARIS - - LLAppViewerLinux::LLAppViewerLinux() { } @@ -355,7 +139,17 @@ bool LLAppViewerLinux::init() // really early in app startup! if (!g_thread_supported ()) g_thread_init (NULL); - return LLAppViewer::init(); + bool success = LLAppViewer::init(); + +#if LL_SEND_CRASH_REPORTS + if (success) + { + LLAppViewer* pApp = LLAppViewer::instance(); + pApp->initCrashReporting(); + } +#endif + + return success; } bool LLAppViewerLinux::restoreErrorTrap() @@ -547,101 +341,10 @@ bool LLAppViewerLinux::sendURLToOtherInstance(const std::string& url) } #endif // LL_DBUS_ENABLED -void LLAppViewerLinux::handleSyncCrashTrace() +void LLAppViewerLinux::initCrashReporting(bool reportFreeze) { - // This backtrace writes into stack_trace.log -# if LL_ELFBIN - do_elfio_glibc_backtrace(); // more useful backtrace -# else - do_basic_glibc_backtrace(); // only slightly useful backtrace -# endif // LL_ELFBIN -} - -void LLAppViewerLinux::handleCrashReporting(bool reportFreeze) -{ - std::string cmd =gDirUtilp->getAppRODataDir(); - cmd += gDirUtilp->getDirDelimiter(); -#if LL_LINUX - cmd += "linux-crash-logger.bin"; -#elif LL_SOLARIS - cmd += "solaris-crash-logger"; -#else -# error Unknown platform -#endif - - if(reportFreeze) - { - char* const cmdargv[] = - {(char*)cmd.c_str(), - (char*)"-previous", - NULL}; - - fflush(NULL); // flush all buffers before the child inherits them - pid_t pid = fork(); - if (pid == 0) - { // child - execv(cmd.c_str(), cmdargv); /* Flawfinder: Ignore */ - llwarns << "execv failure when trying to start " << cmd << llendl; - _exit(1); // avoid atexit() - } else { - if (pid > 0) - { - // wait for child proc to die - int childExitStatus; - waitpid(pid, &childExitStatus, 0); - } else { - llwarns << "fork failure." << llendl; - } - } - } - else - { - const S32 cb = gCrashSettings.getS32(CRASH_BEHAVIOR_SETTING); - - // Always generate the report, have the logger do the asking, and - // don't wait for the logger before exiting (-> total cleanup). - if (CRASH_BEHAVIOR_NEVER_SEND != cb) - { - // launch the actual crash logger - const char* ask_dialog = "-dialog"; - if (CRASH_BEHAVIOR_ASK != cb) - ask_dialog = ""; // omit '-dialog' option - const char * cmdargv[] = - {cmd.c_str(), - ask_dialog, - "-user", - (char*)LLViewerLogin::getInstance()->getGridLabel().c_str(), - "-name", - LLAppViewer::instance()->getSecondLifeTitle().c_str(), - NULL}; - fflush(NULL); - pid_t pid = fork(); - if (pid == 0) - { // child - execv(cmd.c_str(), (char* const*) cmdargv); /* Flawfinder: ignore */ - llwarns << "execv failure when trying to start " << cmd << llendl; - _exit(1); // avoid atexit() - } - else - { - if (pid > 0) - { - // DO NOT wait for child proc to die; we want - // the logger to outlive us while we quit to - // free up the screen/keyboard/etc. - ////int childExitStatus; - ////waitpid(pid, &childExitStatus, 0); - } - else - { - llwarns << "fork failure." << llendl; - } - } - } - // Sometimes signals don't seem to quit the viewer. Also, we may - // have been called explicitly instead of from a signal handler. - // Make sure we exit so as to not totally confuse the user. - _exit(1); // avoid atexit(), else we may re-crash in dtors. + // Singu Note: this is where original code forks crash logger process. + // Singularity doesn't need it } } @@ -676,7 +379,6 @@ bool LLAppViewerLinux::beingDebugged() base += 1; } - //should valgrind be added here? if (strcmp(base, "gdb") == 0) { debugged = yes; @@ -693,6 +395,8 @@ bool LLAppViewerLinux::beingDebugged() bool LLAppViewerLinux::initLogging() { // Remove the last stack trace, if any + // This file is no longer created, since the move to Google Breakpad + // The code is left here to clean out any old state in the log dir std::string old_stack_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stack_trace.log"); LLFile::remove(old_stack_file); @@ -739,6 +443,7 @@ std::string LLAppViewerLinux::generateSerialNumber() // trawl /dev/disk/by-uuid looking for a good-looking UUID to grab std::string this_name; + LLDirIterator iter(uuiddir, "*"); while (iter.next(this_name)) { diff --git a/indra/newview/llappviewerlinux.h b/indra/newview/llappviewerlinux.h index 365fcfeb6..6de13b81c 100644 --- a/indra/newview/llappviewerlinux.h +++ b/indra/newview/llappviewerlinux.h @@ -64,8 +64,7 @@ protected: virtual bool beingDebugged(); virtual bool restoreErrorTrap(); - virtual void handleCrashReporting(bool reportFreeze); - virtual void handleSyncCrashTrace(); + virtual void initCrashReporting(bool reportFreeze); virtual bool initLogging(); virtual bool initParseCommandLine(LLCommandLineParser& clp); diff --git a/indra/newview/llappviewermacosx.cpp b/indra/newview/llappviewermacosx.cpp index 029b0953e..f283b9c92 100644 --- a/indra/newview/llappviewermacosx.cpp +++ b/indra/newview/llappviewermacosx.cpp @@ -69,6 +69,19 @@ namespace } } +static void exceptionTerminateHandler() +{ + // reinstall default terminate() handler in case we re-terminate. + if (gOldTerminateHandler) std::set_terminate(gOldTerminateHandler); + // treat this like a regular viewer crash, with nice stacktrace etc. + long *null_ptr; + null_ptr = 0; + *null_ptr = 0xDEADBEEF; //Force an exception that will trigger breakpad. + //LLAppViewer::handleViewerCrash(); + // we've probably been killed-off before now, but... + gOldTerminateHandler(); // call old terminate() handler +} + int main( int argc, char **argv ) { #if LL_SOLARIS && defined(__sparc) @@ -262,11 +275,6 @@ bool LLAppViewerMacOSX::restoreErrorTrap() return reset_count == 0; } -void LLAppViewerMacOSX::handleSyncCrashTrace() -{ - // do nothing -} - static OSStatus CarbonEventHandler(EventHandlerCallRef inHandlerCallRef, EventRef inEvent, void* inUserData) @@ -294,122 +302,10 @@ static OSStatus CarbonEventHandler(EventHandlerCallRef inHandlerCallRef, return noErr; } -void LLAppViewerMacOSX::handleCrashReporting(bool reportFreeze) +void LLAppViewerMacOSX::initCrashReporting(bool reportFreeze) { - // This used to use fork&exec, but is switched to LSOpenApplication to - // Make sure the crash reporter launches in front of the SL window. - - std::string command_str; - //command_str = "open Second Life.app/Contents/Resources/mac-crash-logger.app"; - command_str = "mac-crash-logger.app/Contents/MacOS/mac-crash-logger"; - - FSRef appRef; - Boolean isDir = 0; - OSStatus os_result = FSPathMakeRef((UInt8*)command_str.c_str(), - &appRef, - &isDir); - if(os_result >= 0) - { - LSApplicationParameters appParams; - memset(&appParams, 0, sizeof(appParams)); - appParams.version = 0; - appParams.flags = kLSLaunchNoParams | kLSLaunchStartClassic; - appParams.application = &appRef; - - if(reportFreeze) - { - // Make sure freeze reporting launches the crash logger synchronously, lest - // Log files get changed by SL while the logger is running. - - // *NOTE:Mani A better way - make a copy of the data that the crash reporter will send - // and let SL go about its business. This way makes the mac work like windows and linux - // and is the smallest patch for the issue. - sCrashReporterIsRunning = false; - ProcessSerialNumber o_psn; - - static EventHandlerRef sCarbonEventsRef = NULL; - static const EventTypeSpec kEvents[] = - { - { kEventClassApplication, kEventAppTerminated } - }; - - // Install the handler to detect crash logger termination - InstallEventHandler(GetApplicationEventTarget(), - (EventHandlerUPP) CarbonEventHandler, - GetEventTypeCount(kEvents), - kEvents, - &o_psn, - &sCarbonEventsRef - ); - - // Remove, temporarily the quit handler - which has *crash* behavior before - // the mainloop gets running! - AERemoveEventHandler(kCoreEventClass, - kAEQuitApplication, - NewAEEventHandlerUPP(AEQuitHandler), - false); - - // Launch the crash reporter. - os_result = LSOpenApplication(&appParams, &o_psn); - - if(os_result >= 0) - { - sCrashReporterIsRunning = true; - } - - while(sCrashReporterIsRunning) - { - RunApplicationEventLoop(); - } - - // Re-install the apps quit handler. - AEInstallEventHandler(kCoreEventClass, - kAEQuitApplication, - NewAEEventHandlerUPP(AEQuitHandler), - 0, - false); - - // Remove the crash reporter quit handler. - RemoveEventHandler(sCarbonEventsRef); - } - else - { - appParams.flags |= kLSLaunchAsync; - clear_signals(); - - ProcessSerialNumber o_psn; - os_result = LSOpenApplication(&appParams, &o_psn); - } - - } - - if(!reportFreeze) - { - _exit(1); - } - - // TODO:palmer REMOVE THIS VERY SOON. THIS WILL NOT BE IN VIEWER 2.0 - // Remove the crash stack log from previous executions. - // Since we've started logging a new instance of the app, we can assume - // The old crash stack is invalid for the next crash report. - char path[MAX_PATH]; - FSRef folder; - if(FSFindFolder(kUserDomain, kLogsFolderType, false, &folder) == noErr) - { - // folder is an FSRef to ~/Library/Logs/ - if(FSRefMakePath(&folder, (UInt8*)&path, sizeof(path)) == noErr) - { - std::string pathname = std::string(path) + std::string("/CrashReporter/"); - std::string mask = "Second Life*"; - std::string file_name; - LLDirIterator iter(pathname, mask); - while(iter.next(file_name)) - { - LLFile::remove(pathname + file_name); - } - } - } - + // Singu Note: this is where original code forks crash logger process. + // Singularity doesn't need it } std::string LLAppViewerMacOSX::generateSerialNumber() diff --git a/indra/newview/llappviewermacosx.h b/indra/newview/llappviewermacosx.h index bc841fc3a..e94b297be 100644 --- a/indra/newview/llappviewermacosx.h +++ b/indra/newview/llappviewermacosx.h @@ -51,8 +51,7 @@ public: protected: virtual bool restoreErrorTrap(); - virtual void handleCrashReporting(bool reportFreeze); - virtual void handleSyncCrashTrace(); + virtual void initCrashReporting(bool reportFreeze); std::string generateSerialNumber(); virtual bool initParseCommandLine(LLCommandLineParser& clp); From 90e71db462029c6e7539d10beb340ebf8eedf261 Mon Sep 17 00:00:00 2001 From: Latif Khalifa Date: Wed, 2 Oct 2013 01:26:27 +0200 Subject: [PATCH 08/16] Breakpad: removed merge artifact, fixes Linux build --- indra/newview/llappviewerlinux.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/indra/newview/llappviewerlinux.cpp b/indra/newview/llappviewerlinux.cpp index ac2ffa771..c923462fd 100644 --- a/indra/newview/llappviewerlinux.cpp +++ b/indra/newview/llappviewerlinux.cpp @@ -345,7 +345,6 @@ void LLAppViewerLinux::initCrashReporting(bool reportFreeze) { // Singu Note: this is where original code forks crash logger process. // Singularity doesn't need it - } } bool LLAppViewerLinux::beingDebugged() From c8cb600ba690a2f2ae68b76b2cf641f2e7678244 Mon Sep 17 00:00:00 2001 From: Latif Khalifa Date: Wed, 2 Oct 2013 02:59:40 +0200 Subject: [PATCH 09/16] Breakpad: workaround for boost crash on Linux --- indra/llvfs/lldir.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/indra/llvfs/lldir.cpp b/indra/llvfs/lldir.cpp index bb35c4fe4..df87d1d34 100644 --- a/indra/llvfs/lldir.cpp +++ b/indra/llvfs/lldir.cpp @@ -179,8 +179,15 @@ S32 LLDir::deleteFilesInDir(const std::string &dirname, const std::string &mask) U32 LLDir::deleteDirAndContents(const std::string& dir_name) { - //Removes the directory and its contents. Returns number of files removed. - return boost::filesystem::remove_all(dir_name); + //Removes the directory and its contents. Returns number of files removed. +#if defined(LL_LINUX) + // Singu TODO: Workaround for boost crashing on linux + deleteFilesInDir(dir_name, "*"); + boost::filesystem::remove(dir_name); + return 1; +#else + return boost::filesystem::remove_all(dir_name); +#endif } const std::string LLDir::findFile(const std::string &filename, From 399a0038cba218e381cad204f5cfc5446a7896f4 Mon Sep 17 00:00:00 2001 From: Latif Khalifa Date: Wed, 2 Oct 2013 04:14:58 +0200 Subject: [PATCH 10/16] Breakpad: now working Mac OS X --- indra/newview/llappviewermacosx.cpp | 13 ------------- indra/newview/viewer_manifest.py | 3 ++- 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/indra/newview/llappviewermacosx.cpp b/indra/newview/llappviewermacosx.cpp index f283b9c92..084423880 100644 --- a/indra/newview/llappviewermacosx.cpp +++ b/indra/newview/llappviewermacosx.cpp @@ -69,19 +69,6 @@ namespace } } -static void exceptionTerminateHandler() -{ - // reinstall default terminate() handler in case we re-terminate. - if (gOldTerminateHandler) std::set_terminate(gOldTerminateHandler); - // treat this like a regular viewer crash, with nice stacktrace etc. - long *null_ptr; - null_ptr = 0; - *null_ptr = 0xDEADBEEF; //Force an exception that will trigger breakpad. - //LLAppViewer::handleViewerCrash(); - // we've probably been killed-off before now, but... - gOldTerminateHandler(); // call old terminate() handler -} - int main( int argc, char **argv ) { #if LL_SOLARIS && defined(__sparc) diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 44f7dddca..36ec91c73 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -522,7 +522,8 @@ class DarwinManifest(ViewerManifest): "libaprutil-1.0.dylib", "libcollada14dom.dylib", "libexpat.1.5.2.dylib", - "libGLOD.dylib"): + "libGLOD.dylib", + "libexception_handler.dylib"): self.path(os.path.join(libdir, libfile), libfile) # For using FMOD for sound...but, fmod is proprietary so some might not use it... From ba1b48202558299483cd5a4cc8730c6d3141ccbb Mon Sep 17 00:00:00 2001 From: Latif Khalifa Date: Wed, 2 Oct 2013 17:49:57 +0200 Subject: [PATCH 11/16] Also repackage bin folder --- scripts/repackage.sh | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/scripts/repackage.sh b/scripts/repackage.sh index e3c5db5a3..6865ca08f 100755 --- a/scripts/repackage.sh +++ b/scripts/repackage.sh @@ -13,6 +13,8 @@ PLATFORM can be one of windows, linux, linux64, mac. TMP="/tmp/pak$$" LIBPATH="" INCPATH="" +BINPATH="" + PWD=`pwd` if [ -z "$1" ]; then @@ -26,24 +28,28 @@ case "$1" in LIBPATH="libraries/i686-win32/lib/release" LIBDPATH="libraries/i686-win32/lib/debug" INCPATH="libraries/i686-win32/include" + BINPATH="libraries/i686-win32/bin" ;; --mac|--osx|--darwin|-x|mac|osx|darwin) MODE=osx LIBPATH="libraries/universal-darwin/lib/release" LIBDPATH="libraries/universal-darwin/lib/debug" INCPATH="libraries/universal-darwin/include" + BINPATH="libraries/universal-darwin/bin" ;; --lin|--linux|-l|linux) MODE=linux LIBPATH="libraries/i686-linux/lib/release" LIBDPATH="libraries/i686-linux/lib/debug" INCPATH="libraries/i686-linux/include" + BINPATH="libraries/i686-linux/bin" ;; --linux64|-6|linux64) MODE=linux64 LIBPATH="libraries/x86_64-linux/lib/release" LIBDPATH="libraries/x86_64-linux/lib/debug" INCPATH="libraries/x86_64-linux/include" + BINPATH="libraries/x86_64-linux/bin" ;; *) echo ERROR: No mode specified @@ -105,6 +111,10 @@ if [ -d include ]; then mkdir -p $INCPATH mv -f include/* $INCPATH fi +if [ -d bin ]; then + mkdir -p $BINPATH + mv -f bin/* $BINPATH +fi echo " Packing..." tar -cjvf "$FILEOUT" libraries LICENSES From a27dad4db0d23e90dc86fbc1625a68bbcfab4618 Mon Sep 17 00:00:00 2001 From: Latif Khalifa Date: Wed, 2 Oct 2013 18:23:19 +0200 Subject: [PATCH 12/16] Breakpad: added symbol extraction to the build. Add -DRELEASE_CRASH_REPORTING:BOOL=ON to enable symbol extraction on build time. Viewer without this set won't sent crash reports to the crash server --- indra/cmake/00-Common.cmake | 18 ++- indra/newview/CMakeLists.txt | 58 +++++++ indra/newview/generate_breakpad_symbols.py | 167 +++++++++++++++++++++ indra/newview/llcrashlogger.cpp | 4 +- install.xml | 16 +- 5 files changed, 252 insertions(+), 11 deletions(-) create mode 100644 indra/newview/generate_breakpad_symbols.py diff --git a/indra/cmake/00-Common.cmake b/indra/cmake/00-Common.cmake index 92c75a2a6..a45c07f69 100644 --- a/indra/cmake/00-Common.cmake +++ b/indra/cmake/00-Common.cmake @@ -12,11 +12,25 @@ include(Variables) set(CMAKE_CXX_FLAGS_DEBUG "-D_DEBUG -DLL_DEBUG=1") set(CMAKE_CXX_FLAGS_RELEASE - "-DLL_RELEASE=1 -DLL_RELEASE_FOR_DOWNLOAD=1 -D_SECURE_SCL=0 -DLL_SEND_CRASH_REPORTS=1 -DNDEBUG") + "-DLL_RELEASE=1 -DLL_RELEASE_FOR_DOWNLOAD=1 -D_SECURE_SCL=0 -DNDEBUG") set(CMAKE_C_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}") set(CMAKE_CXX_FLAGS_RELWITHDEBINFO - "-DLL_RELEASE=1 -D_SECURE_SCL=0 -DLL_SEND_CRASH_REPORTS=1 -DNDEBUG -DLL_RELEASE_WITH_DEBUG_INFO=1") + "-DLL_RELEASE=1 -D_SECURE_SCL=0 -DNDEBUG -DLL_RELEASE_WITH_DEBUG_INFO=1") + +# Configure crash reporting +set(RELEASE_CRASH_REPORTING OFF CACHE BOOL "Enable use of crash reporting in release builds") +set(NON_RELEASE_CRASH_REPORTING OFF CACHE BOOL "Enable use of crash reporting in developer builds") + +if(RELEASE_CRASH_REPORTING) + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -DLL_SEND_CRASH_REPORTS=1") +endif() + +if(NON_RELEASE_CRASH_REPORTING) + set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -DLL_SEND_CRASH_REPORTS=1") + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DLL_SEND_CRASH_REPORTS=1") +endif() + # Don't bother with a MinSizeRel build. diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 6d16d66a1..78bd4a771 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -1734,6 +1734,64 @@ if (INSTALL) include(${CMAKE_CURRENT_SOURCE_DIR}/ViewerInstall.cmake) endif (INSTALL) +if (PACKAGE) + set(SYMBOL_SEARCH_DIRS "") + if (WINDOWS) + list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}") + set(VIEWER_SYMBOL_FILE "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/secondlife-symbols-windows.tar.bz2") + # slplugin.exe failing symbols dump - need to debug, might have to do with updated version of google breakpad + # set(VIEWER_EXE_GLOBS "${VIEWER_BINARY_NAME}${CMAKE_EXECUTABLE_SUFFIX} slplugin.exe") + set(VIEWER_EXE_GLOBS "${VIEWER_BINARY_NAME}${CMAKE_EXECUTABLE_SUFFIX}") + set(VIEWER_LIB_GLOB "*${CMAKE_SHARED_MODULE_SUFFIX}") + set(VIEWER_COPY_MANIFEST copy_w_viewer_manifest) + endif (WINDOWS) + if (DARWIN) + list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}") + # *TODO: Generate these search dirs in the cmake files related to each binary. + list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_BINARY_DIR}/llplugin/slplugin/${CMAKE_CFG_INTDIR}") + list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_BINARY_DIR}/mac_crash_logger/${CMAKE_CFG_INTDIR}") + list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_BINARY_DIR}/media_plugins/gstreamer010/${CMAKE_CFG_INTDIR}") + list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_BINARY_DIR}/media_plugins/quicktime/${CMAKE_CFG_INTDIR}") + list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_BINARY_DIR}/media_plugins/webkit/${CMAKE_CFG_INTDIR}") + set(VIEWER_SYMBOL_FILE "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/secondlife-symbols-darwin.tar.bz2") + set(VIEWER_EXE_GLOBS "'Second Life' SLPlugin mac-crash-logger") + set(VIEWER_LIB_GLOB "*.dylib") + endif (DARWIN) + if (LINUX) + list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_CURRENT_BINARY_DIR}/packaged") + set(VIEWER_SYMBOL_FILE "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/secondlife-symbols-linux.tar.bz2") + set(VIEWER_EXE_GLOBS "do-not-directly-run-secondlife-bin SLPlugin") + set(VIEWER_LIB_GLOB "*${CMAKE_SHARED_MODULE_SUFFIX}*") + set(VIEWER_COPY_MANIFEST copy_l_viewer_manifest) + endif (LINUX) + + if(RELEASE_CRASH_REPORTING OR NON_RELEASE_CRASH_REPORTING) + if(CMAKE_CFG_INTDIR STREQUAL ".") + set(LLBUILD_CONFIG ${CMAKE_BUILD_TYPE}) + else(CMAKE_CFG_INTDIR STREQUAL ".") + # set LLBUILD_CONFIG to be a shell variable evaluated at build time + # reflecting the configuration we are currently building. + set(LLBUILD_CONFIG ${CMAKE_CFG_INTDIR}) + endif(CMAKE_CFG_INTDIR STREQUAL ".") + add_custom_command(OUTPUT "${VIEWER_SYMBOL_FILE}" + COMMAND "${PYTHON_EXECUTABLE}" + ARGS + "${CMAKE_CURRENT_SOURCE_DIR}/generate_breakpad_symbols.py" + "${LLBUILD_CONFIG}" + "${SYMBOL_SEARCH_DIRS}" + "${VIEWER_EXE_GLOBS}" + "${VIEWER_LIB_GLOB}" + "${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/bin/dump_syms" + "${VIEWER_SYMBOL_FILE}" + DEPENDS generate_breakpad_symbols.py + VERBATIM) + + add_custom_target(generate_breakpad_symbols DEPENDS "${VIEWER_SYMBOL_FILE}") + add_dependencies(generate_breakpad_symbols "${VIEWER_BINARY_NAME}" "${VIEWER_COPY_MANIFEST}") + add_dependencies(package generate_breakpad_symbols) + endif(RELEASE_CRASH_REPORTING OR NON_RELEASE_CRASH_REPORTING) +endif (PACKAGE) + # Add tests if (LL_TESTS) ADD_VIEWER_BUILD_TEST(llagentaccess viewer) diff --git a/indra/newview/generate_breakpad_symbols.py b/indra/newview/generate_breakpad_symbols.py new file mode 100644 index 000000000..4181e4ebb --- /dev/null +++ b/indra/newview/generate_breakpad_symbols.py @@ -0,0 +1,167 @@ +#!/usr/bin/env python +"""\ +@file generate_breakpad_symbols.py +@author Brad Kittenbrink +@brief Simple tool for generating google_breakpad symbol information + for the crash reporter. + +$LicenseInfo:firstyear=2010&license=viewerlgpl$ +Second Life Viewer Source Code +Copyright (C) 2010-2011, Linden Research, Inc. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; +version 2.1 of the License only. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +$/LicenseInfo$ +""" + + +import collections +import fnmatch +import itertools +import operator +import os +import re +import sys +import shlex +import subprocess +import tarfile +import StringIO +import pprint + +DEBUG=False + +def usage(): + print >>sys.stderr, "usage: %s search_dirs viewer_exes libs_suffix dump_syms_tool viewer_symbol_file" % sys.argv[0] + +class MissingModuleError(Exception): + def __init__(self, modules): + Exception.__init__(self, "Failed to find required modules: %r" % modules) + self.modules = modules + +def main(configuration, search_dirs, viewer_exes, libs_suffix, dump_syms_tool, viewer_symbol_file): + print "generate_breakpad_symbols run with args: %s" % str((configuration, search_dirs, viewer_exes, libs_suffix, dump_syms_tool, viewer_symbol_file)) + + if not re.match("release", configuration, re.IGNORECASE): + print "skipping breakpad symbol generation for non-release build." + return 0 + + # split up list of viewer_exes + # "'Second Life' SLPlugin" becomes ['Second Life', 'SLPlugin'] + viewer_exes = shlex.split(viewer_exes) + + found_required = dict([(module, False) for module in viewer_exes]) + + def matches(f): + if f in viewer_exes: + found_required[f] = True + return True + return fnmatch.fnmatch(f, libs_suffix) + + search_dirs = search_dirs.split(";") + + def list_files(): + for search_dir in search_dirs: + for (dirname, subdirs, filenames) in os.walk(search_dir): + if DEBUG: + print "scanning '%s' for modules..." % dirname + for f in itertools.ifilter(matches, filenames): + yield os.path.join(dirname, f) + + def dump_module(m): + print "dumping module '%s' with '%s'..." % (m, dump_syms_tool) + dsym_full_path = m + child = subprocess.Popen([dump_syms_tool, dsym_full_path] , stdout=subprocess.PIPE) + out, err = child.communicate() + return (m,child.returncode, out, err) + + + modules = {} + + for m in list_files(): + if DEBUG: + print "examining module '%s' ... " % m, + filename=os.path.basename(m) + if -1 != m.find("DWARF"): + # Just use this module; it has the symbols we want. + modules[filename] = m + if DEBUG: + print "found dSYM entry" + elif filename not in modules: + # Only use this if we don't already have a (possibly better) entry. + modules[filename] = m + if DEBUG: + print "found new entry" + elif DEBUG: + print "ignoring entry" + + + print "Found these following modules:" + pprint.pprint( modules ) + + out = tarfile.open(viewer_symbol_file, 'w:bz2') + for (filename,status,symbols,err) in itertools.imap(dump_module, modules.values()): + if status == 0: + module_line = symbols[:symbols.index('\n')] + module_line = module_line.split() + hash_id = module_line[3] + module = ' '.join(module_line[4:]) + if sys.platform in ['win32', 'cygwin']: + mod_name = module[:module.rindex('.pdb')] + else: + mod_name = module + symbolfile = StringIO.StringIO(symbols) + info = tarfile.TarInfo("%(module)s/%(hash_id)s/%(mod_name)s.sym" % dict(module=module, hash_id=hash_id, mod_name=mod_name)) + info.size = symbolfile.len + out.addfile(info, symbolfile) + else: + print >>sys.stderr, "warning: failed to dump symbols for '%s': %s" % (filename, err) + + out.close() + + missing_modules = [m for (m,_) in + itertools.ifilter(lambda (k,v): not v, found_required.iteritems()) + ] + if missing_modules: + print >> sys.stderr, "failed to generate %s" % viewer_symbol_file + os.remove(viewer_symbol_file) + raise MissingModuleError(missing_modules) + + symbols = tarfile.open(viewer_symbol_file, 'r:bz2') + tarfile_members = symbols.getnames() + symbols.close() + + for required_module in viewer_exes: + def match_module_basename(m): + return os.path.splitext(required_module)[0].lower() \ + == os.path.splitext(os.path.basename(m))[0].lower() + # there must be at least one .sym file in tarfile_members that matches + # each required module (ignoring file extensions) + if not reduce(operator.or_, itertools.imap(match_module_basename, tarfile_members)): + print >> sys.stderr, "failed to find required %s in generated %s" \ + % (required_module, viewer_symbol_file) + os.remove(viewer_symbol_file) + raise MissingModuleError([required_module]) + + print "successfully generated %s including required modules '%s'" % (viewer_symbol_file, viewer_exes) + + return 0 + +if __name__ == "__main__": + if len(sys.argv) != 7: + usage() + sys.exit(1) + sys.exit(main(*sys.argv[1:])) + diff --git a/indra/newview/llcrashlogger.cpp b/indra/newview/llcrashlogger.cpp index fdc132d41..bd5d5234a 100644 --- a/indra/newview/llcrashlogger.cpp +++ b/indra/newview/llcrashlogger.cpp @@ -248,7 +248,7 @@ void LLCrashLogger::gatherFiles() std::ifstream f((*itr).second.c_str()); if(!f.is_open()) { - std::cout << "Can't find file " << (*itr).second << std::endl; + llinfos << "Can't find file " << (*itr).second << llendl; continue; } std::stringstream s; @@ -349,10 +349,12 @@ void LLCrashLogger::checkCrashDump() std::string dumpDir = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "") + "singularity-debug"; if (gDirUtilp->fileExists(dumpDir)) { +#if LL_SEND_CRASH_REPORTS if (!mCrashHost.empty() && gSavedSettings.getS32("CrashSubmitBehavior") != 2) { sendCrashLog(dumpDir); } +#endif gDirUtilp->deleteDirAndContents(dumpDir); } else diff --git a/install.xml b/install.xml index 43772ce31..809cb3a1f 100644 --- a/install.xml +++ b/install.xml @@ -571,30 +571,30 @@ darwin md5sum - 723cd70d5090e448319b485b88aea379 + 5a5c90d28fd9bdc4244c56fef4216998 url - https://bitbucket.org/SingularityViewer/libraries/downloads/google_breakpad-0.0.0-rev1099-darwin-20130329.tar.bz2 + https://bitbucket.org/SingularityViewer/libraries/downloads/google_breakpad-0.0.0-rev1099-darwin-20131002.tar.bz2 linux md5sum - 849241f3b638ee90b553a2ef6346107c + 03852edfa946bdc365b5fbd1a373b17f url - https://bitbucket.org/SingularityViewer/libraries/downloads/google_breakpad-0.0.0-rev1099-linux-20130329.tar.bz2 + https://bitbucket.org/SingularityViewer/libraries/downloads/google_breakpad-0.0.0-rev1099-linux-20131002.tar.bz2 linux64 md5sum - cf5300008895efcfcfcfacef05f32bff + e2e8d8068eceaad66758bb5f031d5246 url - https://bitbucket.org/SingularityViewer/libraries/downloads/google_breakpad-0.0.0-rev1099-linux64-20130506.tar.bz2 + https://bitbucket.org/SingularityViewer/libraries/downloads/google_breakpad-0.0.0-rev1099-linux64-20131002.tar.bz2 windows md5sum - 7c33a10f132864f8492fd9ef9b6a4ccc + 37d1f91f486e357c9a74e6b4af91fe13 url - https://bitbucket.org/SingularityViewer/libraries/downloads/google_breakpad-0.0.0-rev1099-windows-20130813.tar.bz2 + https://bitbucket.org/SingularityViewer/libraries/downloads/google_breakpad-0.0.0-rev1099-windows-20131002.tar.bz2 From 3447e9bd780717737691b36e43376395833418ac Mon Sep 17 00:00:00 2001 From: Latif Khalifa Date: Thu, 3 Oct 2013 00:26:54 +0200 Subject: [PATCH 13/16] Brealpad: fixed symbol extraction on Mac --- indra/newview/CMakeLists.txt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 78bd4a771..d2203c687 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -1635,7 +1635,7 @@ if (LINUX) if (PACKAGE) add_custom_target(package ALL DEPENDS ${product}.tar.bz2) - add_dependencies(package linux-crash-logger-strip-target) +# add_dependencies(package linux-crash-logger-strip-target) endif (PACKAGE) endif (LINUX) @@ -1749,12 +1749,11 @@ if (PACKAGE) list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}") # *TODO: Generate these search dirs in the cmake files related to each binary. list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_BINARY_DIR}/llplugin/slplugin/${CMAKE_CFG_INTDIR}") - list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_BINARY_DIR}/mac_crash_logger/${CMAKE_CFG_INTDIR}") list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_BINARY_DIR}/media_plugins/gstreamer010/${CMAKE_CFG_INTDIR}") list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_BINARY_DIR}/media_plugins/quicktime/${CMAKE_CFG_INTDIR}") list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_BINARY_DIR}/media_plugins/webkit/${CMAKE_CFG_INTDIR}") set(VIEWER_SYMBOL_FILE "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/secondlife-symbols-darwin.tar.bz2") - set(VIEWER_EXE_GLOBS "'Second Life' SLPlugin mac-crash-logger") + set(VIEWER_EXE_GLOBS "'Singularity' SLPlugin") set(VIEWER_LIB_GLOB "*.dylib") endif (DARWIN) if (LINUX) From 9d4b978474613cf711d5a3abc01b27ec761c1cbc Mon Sep 17 00:00:00 2001 From: Latif Khalifa Date: Thu, 3 Oct 2013 02:18:53 +0200 Subject: [PATCH 14/16] Breaking pad: Linux symbol dumping --- indra/newview/CMakeLists.txt | 29 +++++++++++++++++++++++++++-- indra/newview/viewer_manifest.py | 10 ++++++---- 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index d2203c687..568113070 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -1631,11 +1631,36 @@ if (LINUX) ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py ) + add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/.${product}.copy_touched + COMMAND ${PYTHON_EXECUTABLE} + ARGS + ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py + --arch=${ARCH} + --actions=copy + --artwork=${ARTWORK_DIR} + --branding_id=${VIEWER_BRANDING_ID} + --build=${CMAKE_CURRENT_BINARY_DIR} + --buildtype=${CMAKE_BUILD_TYPE} + --channel=${VIEWER_CHANNEL} + --dest=${CMAKE_CURRENT_BINARY_DIR}/packaged + --grid=${GRID} + --installer_name=${product} + --login_channel=${VIEWER_LOGIN_CHANNEL} + --source=${CMAKE_CURRENT_SOURCE_DIR} + --standalone=${STANDALONE} + ${MANIFEST_LIBRARIES} + DEPENDS + secondlife-stripped + ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py + ) + add_dependencies(${VIEWER_BINARY_NAME} SLPlugin media_plugin_gstreamer010 media_plugin_webkit basic_plugin_filepicker) + add_custom_target(copy_l_viewer_manifest ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/.${product}.copy_touched) if (PACKAGE) add_custom_target(package ALL DEPENDS ${product}.tar.bz2) -# add_dependencies(package linux-crash-logger-strip-target) + add_dependencies(package copy_l_viewer_manifest) endif (PACKAGE) endif (LINUX) @@ -1759,7 +1784,7 @@ if (PACKAGE) if (LINUX) list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_CURRENT_BINARY_DIR}/packaged") set(VIEWER_SYMBOL_FILE "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/secondlife-symbols-linux.tar.bz2") - set(VIEWER_EXE_GLOBS "do-not-directly-run-secondlife-bin SLPlugin") + set(VIEWER_EXE_GLOBS "singularity-do-not-run-directly SLPlugin") set(VIEWER_LIB_GLOB "*${CMAKE_SHARED_MODULE_SUFFIX}*") set(VIEWER_COPY_MANIFEST copy_l_viewer_manifest) endif (LINUX) diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 36ec91c73..50e0a2f30 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -704,10 +704,12 @@ class LinuxManifest(ViewerManifest): # Create an appropriate gridargs.dat for this package, denoting required grid. self.put_in_file(self.flags_list(), 'gridargs.dat') - if self.buildtype().lower()=='release': - self.path("secondlife-stripped","bin/"+self.binary_name()) - else: - self.path("secondlife-bin","bin/"+self.binary_name()) + ## Singu note: we'll go strip crazy later on + #if self.buildtype().lower()=='release': + # self.path("secondlife-stripped","bin/"+self.binary_name()) + #else: + # self.path("secondlife-bin","bin/"+self.binary_name()) + self.path("secondlife-bin","bin/"+self.binary_name()) self.path("../llplugin/slplugin/SLPlugin", "bin/SLPlugin") if self.prefix("res-sdl"): From 60cd95b31f2a8bdf5b10ceee1b2def67b37ecf11 Mon Sep 17 00:00:00 2001 From: Latif Khalifa Date: Thu, 3 Oct 2013 06:09:49 +0200 Subject: [PATCH 15/16] Breaking pad: more cmake fun --- indra/newview/CMakeLists.txt | 24 ++++++++++++++ indra/newview/app_settings/settings.xml | 13 +++++++- .../app_settings/settings_crash_behavior.xml | 33 ------------------- indra/newview/llappviewer.cpp | 25 +++++++------- indra/newview/llcrashlogger.cpp | 9 +++-- indra/newview/llcrashlogger.h | 1 - indra/newview/llfloaterpreference.cpp | 3 +- indra/newview/llpanelgeneral.cpp | 4 +-- indra/newview/viewer_manifest.py | 2 ++ 9 files changed, 61 insertions(+), 53 deletions(-) diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 568113070..19f85ed23 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -1530,10 +1530,34 @@ if (WINDOWS) ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py ) + add_custom_command( + OUTPUT ${CMAKE_CFG_INTDIR}/copy_touched.bat + COMMAND ${PYTHON_EXECUTABLE} + ARGS + ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py + --artwork=${ARTWORK_DIR} + --actions=copy + --branding_id=${VIEWER_BRANDING_ID} + --build=${CMAKE_CURRENT_BINARY_DIR} + --channel=${VIEWER_CHANNEL} + --configuration=${CMAKE_CFG_INTDIR} + --dest=${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR} + --grid=${GRID} + --login_channel=${VIEWER_LOGIN_CHANNEL} + --source=${CMAKE_CURRENT_SOURCE_DIR} + --touch=${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/copy_touched.bat + ${MANIFEST_LIBRARIES} + DEPENDS + ${VIEWER_BINARY_NAME} + ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py + COMMENT "Performing viewer_manifest copy" + ) + add_dependencies(${VIEWER_BINARY_NAME} SLPlugin media_plugin_quicktime media_plugin_webkit basic_plugin_filepicker winmm_shim) if (PACKAGE) add_custom_target(package ALL DEPENDS ${CMAKE_CFG_INTDIR}/touched.bat) + add_custom_target(copy_w_viewer_manifest ALL DEPENDS ${CMAKE_CFG_INTDIR}/copy_touched.bat) endif (PACKAGE) endif (WINDOWS) diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 9748e07a8..2de3bd7a4 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -2199,7 +2199,7 @@ This should be as low as possible, but too low may break functionality Type String Value - http://crash.singularityviewer.org/submit.php> + http://crash.singularityviewer.org/report.php> AFKTimeout @@ -17709,6 +17709,17 @@ This should be as low as possible, but too low may break functionality Value 0 + CrashSubmitBehavior + + Comment + Controls behavior when viewer crashes (0 = ask before sending crash report, 1 = always send crash report, 2 = never send crash report) + Persist + 2 + Type + S32 + Value + 1 + diff --git a/indra/newview/app_settings/settings_crash_behavior.xml b/indra/newview/app_settings/settings_crash_behavior.xml index d259b4381..74704f8ad 100644 --- a/indra/newview/app_settings/settings_crash_behavior.xml +++ b/indra/newview/app_settings/settings_crash_behavior.xml @@ -11,38 +11,5 @@ Value 1 - CurlMaxTotalConcurrentConnections - - Comment - Maximum total number of simultaneous curl connections - Persist - 1 - Type - U32 - Value - 64 - - CurlConcurrentConnectionsPerService - - Comment - Maximum number of simultaneous curl connections per host:port service - Persist - 0 - Type - U32 - Value - 8 - - NoVerifySSLCert - - Comment - Do not verify SSL certificates. - Persist - 1 - Type - Boolean - Value - 1 - diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index df48dc69a..88307e49b 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -640,18 +640,6 @@ bool LLAppViewer::init() initMaxHeapSize() ; LLPrivateMemoryPoolManager::initClass((BOOL)gSavedSettings.getBOOL("MemoryPrivatePoolEnabled"), (U32)gSavedSettings.getU32("MemoryPrivatePoolSize")) ; - // Check if we have a crash report to send - LLCrashLogger crashLogger; - crashLogger.checkCrashDump(); - - // write Google Breakpad minidump files to a per-run dump directory to avoid multiple viewer issues. - std::string logdir = gDirUtilp->getExpandedFilename(LL_PATH_DUMP, ""); - mDumpPath = logdir; - setMiniDumpDir(logdir); - logdir += gDirUtilp->getDirDelimiter(); - setDebugFileNames(logdir); - - mAlloc.setProfilingEnabled(gSavedSettings.getBOOL("MemProfiling")); AIEngine::setMaxCount(gSavedSettings.getU32("StateMachineMaxTime")); @@ -668,6 +656,19 @@ bool LLAppViewer::init() ); AIHTTPTimeoutPolicy::setDefaultCurlTimeout(policy_tmp); } + + // Check if we have a crash report to send + LLCrashLogger crashLogger; + crashLogger.checkCrashDump(); + + // write Google Breakpad minidump files to a per-run dump directory to avoid multiple viewer issues. + std::string logdir = gDirUtilp->getExpandedFilename(LL_PATH_DUMP, ""); + mDumpPath = logdir; + setMiniDumpDir(logdir); + logdir += gDirUtilp->getDirDelimiter(); + setDebugFileNames(logdir); + + mAlloc.setProfilingEnabled(gSavedSettings.getBOOL("MemProfiling")); { // Viewer metrics initialization //static LLCachedControl metrics_submode(gSavedSettings, diff --git a/indra/newview/llcrashlogger.cpp b/indra/newview/llcrashlogger.cpp index bd5d5234a..96abf21a3 100644 --- a/indra/newview/llcrashlogger.cpp +++ b/indra/newview/llcrashlogger.cpp @@ -59,7 +59,12 @@ public: virtual void result(const LLSD& content) { - llinfos << "Crash report successfully sent" << llendl; + std::string msg = "Crash report successfully sent"; + if (content.has("message")) + { + msg += ": " + content["message"].asString(); + } + llinfos << msg << llendl; } virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const @@ -76,7 +81,6 @@ public: LLCrashLogger::LLCrashLogger() : mCrashBehavior(CRASH_BEHAVIOR_ALWAYS_SEND), mCrashInPreviousExec(false), - mCrashSettings("CrashSettings"), mCrashHost("") { } @@ -355,7 +359,6 @@ void LLCrashLogger::checkCrashDump() sendCrashLog(dumpDir); } #endif - gDirUtilp->deleteDirAndContents(dumpDir); } else { diff --git a/indra/newview/llcrashlogger.h b/indra/newview/llcrashlogger.h index 4a83e5527..c510acb98 100644 --- a/indra/newview/llcrashlogger.h +++ b/indra/newview/llcrashlogger.h @@ -58,7 +58,6 @@ protected: BOOL mCrashInPreviousExec; std::map mFileMap; std::string mGridName; - LLControlGroup mCrashSettings; std::string mProductName; LLSD mCrashInfo; std::string mCrashHost; diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index dbbd06f76..b6d3d5e81 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -461,7 +461,8 @@ void LLFloaterPreference::onBtnOK( void* userdata ) std::string crash_settings_filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, CRASH_SETTINGS_FILE); // save all settings, even if equals defaults - gCrashSettings.saveToFile(crash_settings_filename, FALSE); + // Singu Note: crash settings no longer separate + // gCrashSettings.saveToFile(crash_settings_filename, FALSE); } else { diff --git a/indra/newview/llpanelgeneral.cpp b/indra/newview/llpanelgeneral.cpp index 812cbc80f..cf339762a 100644 --- a/indra/newview/llpanelgeneral.cpp +++ b/indra/newview/llpanelgeneral.cpp @@ -87,7 +87,7 @@ BOOL LLPanelGeneral::postBuild() childSetValue("ui_auto_scale", gSavedSettings.getBOOL("UIAutoScale")); LLComboBox* crash_behavior_combobox = getChild("crash_behavior_combobox"); - crash_behavior_combobox->setCurrentByIndex(gCrashSettings.getS32(CRASH_BEHAVIOR_SETTING)); + crash_behavior_combobox->setCurrentByIndex(gSavedSettings.getS32(CRASH_BEHAVIOR_SETTING)); childSetValue("language_combobox", gSavedSettings.getString("Language")); @@ -174,7 +174,7 @@ void LLPanelGeneral::apply() gSavedSettings.setString("Language", childGetValue("language_combobox")); LLComboBox* crash_behavior_combobox = getChild("crash_behavior_combobox"); - gCrashSettings.setS32(CRASH_BEHAVIOR_SETTING, crash_behavior_combobox->getCurrentIndex()); + gSavedSettings.setS32(CRASH_BEHAVIOR_SETTING, crash_behavior_combobox->getCurrentIndex()); } void LLPanelGeneral::cancel() diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 50e0a2f30..2cdf9a4a5 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -339,6 +339,8 @@ class WindowsManifest(ViewerManifest): self.path(path_pair[1]) self.end_prefix() + self.package_file = 'npne' + def nsi_file_commands(self, install=True): def wpath(path): From c49907e5a4c16cac29e3ae6c9ed06d8173ec95a4 Mon Sep 17 00:00:00 2001 From: Latif Khalifa Date: Thu, 3 Oct 2013 06:20:14 +0200 Subject: [PATCH 16/16] Breaking pad: typofix --- indra/newview/app_settings/settings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 2de3bd7a4..33aadba64 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -17714,7 +17714,7 @@ This should be as low as possible, but too low may break functionality Comment Controls behavior when viewer crashes (0 = ask before sending crash report, 1 = always send crash report, 2 = never send crash report) Persist - 2 + 1 Type S32 Value