Merge branch 'breakpad3'
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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=0 -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.
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -59,7 +61,6 @@ set(cmake_SOURCE_FILES
|
||||
LLAudio.cmake
|
||||
LLCharacter.cmake
|
||||
LLCommon.cmake
|
||||
LLCrashLogger.cmake
|
||||
LLImage.cmake
|
||||
LLImageJ2COJ.cmake
|
||||
LLInventory.cmake
|
||||
@@ -69,6 +70,7 @@ set(cmake_SOURCE_FILES
|
||||
LLPlugin.cmake
|
||||
LLPrimitive.cmake
|
||||
LLPhysicsExtensions.cmake
|
||||
LLSharedLibs.cmake
|
||||
LLQtWebkit.cmake
|
||||
LLRender.cmake
|
||||
LLUI.cmake
|
||||
|
||||
40
indra/cmake/FindGoogleBreakpad.cmake
Normal file
40
indra/cmake/FindGoogleBreakpad.cmake
Normal file
@@ -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
|
||||
)
|
||||
21
indra/cmake/GoogleBreakpad.cmake
Normal file
21
indra/cmake/GoogleBreakpad.cmake
Normal file
@@ -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)
|
||||
@@ -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)
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
# -*- cmake -*-
|
||||
|
||||
set(LLCRASHLOGGER_INCLUDE_DIRS
|
||||
${LIBS_OPEN_DIR}/llcrashlogger
|
||||
)
|
||||
|
||||
set(LLCRASHLOGGER_LIBRARIES llcrashlogger)
|
||||
73
indra/cmake/LLSharedLibs.cmake
Normal file
73
indra/cmake/LLSharedLibs.cmake
Normal file
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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 <iostream>
|
||||
|
||||
#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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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}
|
||||
|
||||
@@ -27,6 +27,14 @@
|
||||
#include "linden_common.h"
|
||||
#include "llapp.h"
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#ifdef LL_DARWIN
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/sysctl.h>
|
||||
#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 <signal.h>
|
||||
# include <unistd.h> // 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: <dump_dir>/<minidump_id>.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: <dump_dir>/<minidump_id>.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<size_t>(remaining));
|
||||
remaining -= bytesUsed;
|
||||
path += bytesUsed;
|
||||
if(remaining > 0 && bytesUsed > 0 && path[-1] != '\\')
|
||||
{
|
||||
*path++ = '\\';
|
||||
--remaining;
|
||||
}
|
||||
if(remaining > 0)
|
||||
{
|
||||
bytesUsed = wcstombs(path, minidump_id, static_cast<size_t>(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
|
||||
|
||||
@@ -37,14 +37,10 @@ template <typename Type> class LLAtomic32;
|
||||
typedef LLAtomic32<U32> LLAtomicU32;
|
||||
class LLErrorThread;
|
||||
class LLLiveFile;
|
||||
|
||||
|
||||
#if LL_LINUX
|
||||
#include <signal.h>
|
||||
//typedef struct siginfo siginfo_t; //Removed as per changes in glibc 2.16 - Drake Arconis
|
||||
#include <signal.h>
|
||||
#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<std::string, std::string> 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
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -1,36 +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
|
||||
)
|
||||
|
||||
set(llcrashlogger_HEADER_FILES
|
||||
CMakeLists.txt
|
||||
|
||||
llcrashlogger.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)
|
||||
@@ -1,425 +0,0 @@
|
||||
/**
|
||||
* @file llcrashlogger.cpp
|
||||
* @brief 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 <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <sstream>
|
||||
#include <map>
|
||||
|
||||
#include "llcrashlogger.h"
|
||||
#include "llstring.h"
|
||||
#include "indra_constants.h" // CRASH_BEHAVIOR_ASK, CRASH_SETTING_NAME
|
||||
#include "llerror.h"
|
||||
#include "lltimer.h"
|
||||
#include "lldir.h"
|
||||
#include "llsdserialize.h"
|
||||
#include "lliopipe.h"
|
||||
#include "llpumpio.h"
|
||||
#include "llhttpclient.h"
|
||||
#include "llsdserialize.h"
|
||||
#include "llcurl.h"
|
||||
#include "aistatemachine.h"
|
||||
|
||||
LLPumpIO* gServicePump;
|
||||
BOOL gBreak = false;
|
||||
BOOL gSent = false;
|
||||
|
||||
class AIHTTPTimeoutPolicy;
|
||||
extern AIHTTPTimeoutPolicy crashLoggerResponder_timeout;
|
||||
extern void startEngineThread(void);
|
||||
|
||||
class LLCrashLoggerResponder : public LLHTTPClient::ResponderWithResult
|
||||
{
|
||||
public:
|
||||
LLCrashLoggerResponder()
|
||||
{
|
||||
}
|
||||
|
||||
/*virtual*/ void error(U32 status, const std::string& reason)
|
||||
{
|
||||
gBreak = true;
|
||||
}
|
||||
|
||||
/*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"; }
|
||||
};
|
||||
|
||||
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),
|
||||
mCrashInPreviousExec(false),
|
||||
mSentCrashLogs(false),
|
||||
mCrashHost(""),
|
||||
mCrashSettings("CrashSettings")
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
LLCrashLogger::~LLCrashLogger()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// TRIM_SIZE must remain larger than LINE_SEARCH_SIZE.
|
||||
const int TRIM_SIZE = 128000;
|
||||
const int LINE_SEARCH_DIST = 500;
|
||||
const std::string SKIP_TEXT = "\n ...Skipping... \n";
|
||||
void trimSLLog(std::string& sllog)
|
||||
{
|
||||
if(sllog.length() > TRIM_SIZE * 2)
|
||||
{
|
||||
std::string::iterator head = sllog.begin() + TRIM_SIZE;
|
||||
std::string::iterator tail = sllog.begin() + sllog.length() - TRIM_SIZE;
|
||||
std::string::iterator new_head = std::find(head, head - LINE_SEARCH_DIST, '\n');
|
||||
if(new_head != head - LINE_SEARCH_DIST)
|
||||
{
|
||||
head = new_head;
|
||||
}
|
||||
|
||||
std::string::iterator new_tail = std::find(tail, tail + LINE_SEARCH_DIST, '\n');
|
||||
if(new_tail != tail + LINE_SEARCH_DIST)
|
||||
{
|
||||
tail = new_tail;
|
||||
}
|
||||
|
||||
sllog.erase(head, tail);
|
||||
sllog.insert(head, SKIP_TEXT.begin(), SKIP_TEXT.end());
|
||||
}
|
||||
}
|
||||
|
||||
std::string getStartupStateFromLog(std::string& sllog)
|
||||
{
|
||||
std::string startup_state = "STATE_FIRST";
|
||||
std::string startup_token = "Startup state changing from ";
|
||||
|
||||
int index = sllog.rfind(startup_token);
|
||||
if (index < 0 || index + startup_token.length() > sllog.length()) {
|
||||
return startup_state;
|
||||
}
|
||||
|
||||
// find new line
|
||||
char cur_char = sllog[index + startup_token.length()];
|
||||
std::string::size_type newline_loc = index + startup_token.length();
|
||||
while(cur_char != '\n' && newline_loc < sllog.length())
|
||||
{
|
||||
newline_loc++;
|
||||
cur_char = sllog[newline_loc];
|
||||
}
|
||||
|
||||
// get substring and find location of " to "
|
||||
std::string state_line = sllog.substr(index, newline_loc - index);
|
||||
std::string::size_type state_index = state_line.find(" to ");
|
||||
startup_state = state_line.substr(state_index + 4, state_line.length() - state_index - 4);
|
||||
|
||||
return startup_state;
|
||||
}
|
||||
|
||||
void LLCrashLogger::gatherFiles()
|
||||
{
|
||||
|
||||
/*
|
||||
//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());
|
||||
|
||||
// Look for it in the debug_info.log file
|
||||
if (debug_log_file.is_open())
|
||||
{
|
||||
LLSDSerialize::fromXML(mDebugLog, debug_log_file);
|
||||
|
||||
mCrashInPreviousExec = mDebugLog["CrashNotHandled"].asBoolean();
|
||||
|
||||
mFileMap["SecondLifeLog"] = mDebugLog["SLLog"].asString();
|
||||
mFileMap["SettingsXml"] = mDebugLog["SettingsFilename"].asString();
|
||||
if(mDebugLog.has("CAFilename"))
|
||||
{
|
||||
LLCurl::setCAFile(mDebugLog["CAFilename"].asString());
|
||||
}
|
||||
else
|
||||
{
|
||||
LLCurl::setCAFile(gDirUtilp->getCAFile());
|
||||
}
|
||||
|
||||
llinfos << "Using log file from debug log " << mFileMap["SecondLifeLog"] << llendl;
|
||||
llinfos << "Using settings file from debug log " << mFileMap["SettingsXml"] << llendl;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Figure out the filename of the second life log
|
||||
LLCurl::setCAFile(gDirUtilp->getCAFile());
|
||||
mFileMap["SecondLifeLog"] = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"SecondLife.log");
|
||||
mFileMap["SettingsXml"] = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS,"settings.xml");
|
||||
}
|
||||
|
||||
#if !LL_DARWIN
|
||||
if(mCrashInPreviousExec)
|
||||
#else
|
||||
#endif
|
||||
{
|
||||
// Replace the log file ext with .old, since the
|
||||
// instance that launched this process has overwritten
|
||||
// SecondLife.log
|
||||
std::string log_filename = mFileMap["SecondLifeLog"];
|
||||
log_filename.replace(log_filename.size() - 4, 4, ".old");
|
||||
mFileMap["SecondLifeLog"] = log_filename;
|
||||
}
|
||||
|
||||
gatherPlatformSpecificFiles();
|
||||
|
||||
//Use the debug log to reconstruct the URL to send the crash report to
|
||||
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_LOGS,"stats.log");
|
||||
mFileMap["StackTrace"] = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stack_trace.log");
|
||||
|
||||
updateApplication("Encoding files...");
|
||||
|
||||
for(std::map<std::string, std::string>::iterator itr = mFileMap.begin(); itr != mFileMap.end(); ++itr)
|
||||
{
|
||||
std::ifstream f((*itr).second.c_str());
|
||||
if(!f.is_open())
|
||||
{
|
||||
std::cout << "Can't find file " << (*itr).second << std::endl;
|
||||
continue;
|
||||
}
|
||||
std::stringstream s;
|
||||
s << f.rdbuf();
|
||||
|
||||
std::string crash_info = s.str();
|
||||
if(itr->first == "SecondLifeLog")
|
||||
{
|
||||
if(!mCrashInfo["DebugLog"].has("StartupState"))
|
||||
{
|
||||
mCrashInfo["DebugLog"]["StartupState"] = getStartupStateFromLog(crash_info);
|
||||
}
|
||||
trimSLLog(crash_info);
|
||||
}
|
||||
|
||||
mCrashInfo[(*itr).first] = rawstr_to_utf8(crash_info);
|
||||
}
|
||||
}
|
||||
|
||||
LLSD LLCrashLogger::constructPostData()
|
||||
{
|
||||
LLSD ret;
|
||||
return mCrashInfo;
|
||||
}
|
||||
|
||||
S32 LLCrashLogger::loadCrashBehaviorSetting()
|
||||
{
|
||||
std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, CRASH_SETTINGS_FILE);
|
||||
|
||||
mCrashSettings.loadFromFile(filename);
|
||||
|
||||
S32 value = mCrashSettings.getS32(CRASH_BEHAVIOR_SETTING);
|
||||
|
||||
if (value < CRASH_BEHAVIOR_ASK || CRASH_BEHAVIOR_NEVER_SEND < value) return CRASH_BEHAVIOR_ASK;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
bool LLCrashLogger::saveCrashBehaviorSetting(S32 crash_behavior)
|
||||
{
|
||||
if (crash_behavior != CRASH_BEHAVIOR_ASK && crash_behavior != CRASH_BEHAVIOR_ALWAYS_SEND) return false;
|
||||
|
||||
mCrashSettings.setS32(CRASH_BEHAVIOR_SETTING, 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)
|
||||
{
|
||||
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);
|
||||
while(!gBreak)
|
||||
{
|
||||
updateApplication(status_message);
|
||||
}
|
||||
if(gSent)
|
||||
{
|
||||
return gSent;
|
||||
}
|
||||
}
|
||||
return gSent;
|
||||
}
|
||||
|
||||
bool LLCrashLogger::sendCrashLogs()
|
||||
{
|
||||
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
|
||||
if(mCrashHost != "")
|
||||
{
|
||||
sent = runCrashLogPost(mCrashHost, post_data, std::string("Sending to server"), 3);
|
||||
}
|
||||
|
||||
if(!sent)
|
||||
{
|
||||
sent = runCrashLogPost(mAltCrashHost, post_data, std::string("Sending to alternate server"), 3);
|
||||
}
|
||||
|
||||
mSentCrashLogs = sent;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void LLCrashLogger::updateApplication(const std::string& message)
|
||||
{
|
||||
gServicePump->pump();
|
||||
gServicePump->callback();
|
||||
gMainThreadEngine.mainloop();
|
||||
}
|
||||
|
||||
bool LLCrashLogger::init()
|
||||
{
|
||||
// Initialize curl
|
||||
AICurlInterface::initCurl();
|
||||
|
||||
// Initialize state machine engines.
|
||||
AIEngine::setMaxCount(100); // StateMachineMaxTime
|
||||
|
||||
// Start state machine thread.
|
||||
startEngineThread();
|
||||
|
||||
// We assume that all the logs we're looking for reside on the current drive
|
||||
gDirUtilp->initAppDirs("SecondLife");
|
||||
|
||||
// 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)");
|
||||
|
||||
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 );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
/**
|
||||
* @file llcrashlogger.h
|
||||
* @brief 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 LLCRASHLOGGER_H
|
||||
#define LLCRASHLOGGER_H
|
||||
|
||||
#include "linden_common.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "llapp.h"
|
||||
#include "llsd.h"
|
||||
#include "llcontrol.h"
|
||||
|
||||
class AIHTTPTimeoutPolicy;
|
||||
|
||||
class LLCrashLogger : public LLApp
|
||||
{
|
||||
public:
|
||||
LLCrashLogger();
|
||||
virtual ~LLCrashLogger();
|
||||
S32 loadCrashBehaviorSetting();
|
||||
void gatherFiles();
|
||||
virtual void gatherPlatformSpecificFiles() {}
|
||||
bool saveCrashBehaviorSetting(S32 crash_behavior);
|
||||
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; }
|
||||
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);
|
||||
protected:
|
||||
S32 mCrashBehavior;
|
||||
BOOL mCrashInPreviousExec;
|
||||
std::map<std::string, std::string> mFileMap;
|
||||
std::string mGridName;
|
||||
LLControlGroup mCrashSettings;
|
||||
std::string mProductName;
|
||||
LLSD mCrashInfo;
|
||||
std::string mCrashHost;
|
||||
std::string mAltCrashHost;
|
||||
LLSD mDebugLog;
|
||||
bool mSentCrashLogs;
|
||||
};
|
||||
|
||||
class LLCrashLoggerText : public LLCrashLogger
|
||||
{
|
||||
public:
|
||||
LLCrashLoggerText(void) {}
|
||||
~LLCrashLoggerText(void) {}
|
||||
|
||||
virtual bool mainLoop();
|
||||
virtual void updateApplication(const std::string& message = LLStringUtil::null);
|
||||
};
|
||||
|
||||
|
||||
#endif //LLCRASHLOGGER_H
|
||||
@@ -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);
|
||||
@@ -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 <boost/filesystem.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/range/begin.hpp>
|
||||
#include <boost/range/end.hpp>
|
||||
@@ -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<std::string> LLDir::getFilesInDir(const std::string &dirname)
|
||||
{
|
||||
//Returns a vector of fullpath filenames.
|
||||
|
||||
boost::filesystem::path p (dirname);
|
||||
std::vector<std::string> 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,19 @@ 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.
|
||||
#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,
|
||||
const std::string& searchPath1,
|
||||
const std::string& searchPath2,
|
||||
@@ -235,6 +277,34 @@ 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() )
|
||||
{
|
||||
/* 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);
|
||||
}
|
||||
|
||||
return LLDir::sDumpDir;
|
||||
}
|
||||
|
||||
const std::string &LLDir::getPerAccountChatLogsDir() const
|
||||
{
|
||||
return mPerAccountChatLogsDir;
|
||||
@@ -396,12 +466,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:
|
||||
|
||||
@@ -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<std::string> 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);
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IBVersion</key>
|
||||
<string>1</string>
|
||||
</dict>
|
||||
</plist>
|
||||
18
indra/mac_crash_logger/CrashReporter.nib/info.nib
generated
18
indra/mac_crash_logger/CrashReporter.nib/info.nib
generated
@@ -1,18 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IBFramework Version</key>
|
||||
<string>629</string>
|
||||
<key>IBLastKnownRelativeProjectPath</key>
|
||||
<string>../../build-darwin-i386/SecondLife.xcodeproj</string>
|
||||
<key>IBOldestOS</key>
|
||||
<integer>5</integer>
|
||||
<key>IBOpenObjects</key>
|
||||
<array/>
|
||||
<key>IBSystem Version</key>
|
||||
<string>9E17</string>
|
||||
<key>targetFramework</key>
|
||||
<string>IBCarbonFramework</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -1,68 +0,0 @@
|
||||
<?xml version="1.0" standalone="yes"?>
|
||||
<object class="NSIBObjectData">
|
||||
<object name="rootObject" class="NSCustomObject" id="1">
|
||||
</object>
|
||||
<array count="7" name="allObjects">
|
||||
<object class="IBCarbonButton" id="182">
|
||||
<ostype name="command">ok </ostype>
|
||||
<string name="title">Send Report</string>
|
||||
<string name="bounds">414 273 434 378 </string>
|
||||
</object>
|
||||
<object class="IBCarbonButton" id="183">
|
||||
<ostype name="command">not!</ostype>
|
||||
<int name="buttonType">2</int>
|
||||
<string name="title">Don't Send</string>
|
||||
<string name="bounds">414 390 434 487 </string>
|
||||
</object>
|
||||
<object class="IBCarbonStaticText" id="181">
|
||||
<string name="title">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. </string>
|
||||
<string name="bounds">20 20 231 487 </string>
|
||||
</object>
|
||||
<object class="IBCarbonWindow" id="166">
|
||||
<int name="carbonWindowClass">2</int>
|
||||
<int name="themeBrush">3</int>
|
||||
<int name="windowPosition">7</int>
|
||||
<string name="title">Second Life Crash Logger</string>
|
||||
<object name="rootControl" class="IBCarbonRootControl" id="167">
|
||||
<array count="5" name="subviews">
|
||||
<reference idRef="181"/>
|
||||
<reference idRef="182"/>
|
||||
<reference idRef="183"/>
|
||||
<object class="IBCarbonEditText" id="185">
|
||||
<ostype name="controlSignature">text</ostype>
|
||||
<boolean name="isUnicode">TRUE</boolean>
|
||||
<string name="bounds">242 23 391 484 </string>
|
||||
</object>
|
||||
<object class="IBCarbonCheckBox" id="193">
|
||||
<ostype name="controlSignature">remb</ostype>
|
||||
<string name="title">Remember This Choice</string>
|
||||
<string name="bounds">415 20 433 186 </string>
|
||||
</object>
|
||||
</array>
|
||||
<string name="bounds">0 0 454 507 </string>
|
||||
</object>
|
||||
<string name="windowRect">257 653 711 1160 </string>
|
||||
<string name="ScreenRectAtEncodeTime">0 0 768 1024 </string>
|
||||
</object>
|
||||
<reference idRef="185"/>
|
||||
<reference idRef="167"/>
|
||||
<reference idRef="193"/>
|
||||
</array>
|
||||
<array count="7" name="allParents">
|
||||
<reference idRef="167"/>
|
||||
<reference idRef="167"/>
|
||||
<reference idRef="167"/>
|
||||
<reference idRef="1"/>
|
||||
<reference idRef="167"/>
|
||||
<reference idRef="166"/>
|
||||
<reference idRef="167"/>
|
||||
</array>
|
||||
<dictionary count="2" name="nameTable">
|
||||
<string>CrashReporter</string>
|
||||
<reference idRef="166"/>
|
||||
<string>File's Owner</string>
|
||||
<reference idRef="1"/>
|
||||
</dictionary>
|
||||
<string name="targetFramework">IBCarbonFramework</string>
|
||||
<unsigned_int name="nextObjectID">194</unsigned_int>
|
||||
</object>
|
||||
@@ -1,26 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>English</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>mac-crash-logger</string>
|
||||
<key>CFBundleGetInfoString</key>
|
||||
<string></string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string></string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.secondlife.indra.crashreporter</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string></string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1.0.0</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -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 <Carbon/Carbon.h>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
#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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
4
indra/mac_updater/AutoUpdater.nib/classes.nib
generated
4
indra/mac_updater/AutoUpdater.nib/classes.nib
generated
@@ -1,4 +0,0 @@
|
||||
{
|
||||
IBClasses = ();
|
||||
IBVersion = 1;
|
||||
}
|
||||
14
indra/mac_updater/AutoUpdater.nib/info.nib
generated
14
indra/mac_updater/AutoUpdater.nib/info.nib
generated
@@ -1,14 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IBDocumentLocation</key>
|
||||
<string>103 138 356 240 0 0 1280 1002 </string>
|
||||
<key>IBFramework Version</key>
|
||||
<string>362.0</string>
|
||||
<key>IBSystem Version</key>
|
||||
<string>7D24</string>
|
||||
<key>targetFramework</key>
|
||||
<string>IBCarbonFramework</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -1,56 +0,0 @@
|
||||
<?xml version="1.0" standalone="yes"?>
|
||||
<object class="NSIBObjectData">
|
||||
<string name="targetFramework">IBCarbonFramework</string>
|
||||
<object name="rootObject" class="NSCustomObject" id="1">
|
||||
<string name="customClass">NSApplication</string>
|
||||
</object>
|
||||
<array count="5" name="allObjects">
|
||||
<object class="IBCarbonWindow" id="166">
|
||||
<string name="windowRect">405 222 533 663 </string>
|
||||
<string name="title">Second Life Updater</string>
|
||||
<object name="rootControl" class="IBCarbonRootControl" id="167">
|
||||
<string name="bounds">0 0 128 441 </string>
|
||||
<array count="3" name="subviews">
|
||||
<object class="IBCarbonStaticText" id="181">
|
||||
<string name="bounds">20 20 44 421 </string>
|
||||
<ostype name="controlSignature">what</ostype>
|
||||
<string name="title">Initializing…</string>
|
||||
</object>
|
||||
<object class="IBCarbonButton" id="183">
|
||||
<string name="bounds">88 351 108 421 </string>
|
||||
<string name="title">Cancel</string>
|
||||
<ostype name="command">not!</ostype>
|
||||
<int name="buttonType">2</int>
|
||||
</object>
|
||||
<object class="IBCarbonProgressBar" id="193">
|
||||
<string name="bounds">51 19 70 422 </string>
|
||||
<ostype name="controlSignature">prog</ostype>
|
||||
<int name="initialValue">50</int>
|
||||
</object>
|
||||
</array>
|
||||
</object>
|
||||
<boolean name="isResizable">FALSE</boolean>
|
||||
<int name="carbonWindowClass">2</int>
|
||||
<int name="themeBrush">3</int>
|
||||
<int name="windowPosition">7</int>
|
||||
</object>
|
||||
<reference idRef="167"/>
|
||||
<reference idRef="181"/>
|
||||
<reference idRef="183"/>
|
||||
<reference idRef="193"/>
|
||||
</array>
|
||||
<array count="5" name="allParents">
|
||||
<reference idRef="1"/>
|
||||
<reference idRef="166"/>
|
||||
<reference idRef="167"/>
|
||||
<reference idRef="167"/>
|
||||
<reference idRef="167"/>
|
||||
</array>
|
||||
<dictionary count="2" name="nameTable">
|
||||
<string>File's Owner</string>
|
||||
<reference idRef="1"/>
|
||||
<string>Updater</string>
|
||||
<reference idRef="166"/>
|
||||
</dictionary>
|
||||
<unsigned_int name="nextObjectID">194</unsigned_int>
|
||||
</object>
|
||||
@@ -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
|
||||
)
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>English</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>mac-updater</string>
|
||||
<key>CFBundleGetInfoString</key>
|
||||
<string></string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string></string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.secondlife.indra.autoupdater</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string></string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1.0.0</string>
|
||||
</dict>
|
||||
</plist>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
@@ -1528,11 +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_dependencies(package windows-updater windows-crash-logger)
|
||||
add_custom_target(copy_w_viewer_manifest ALL DEPENDS ${CMAKE_CFG_INTDIR}/copy_touched.bat)
|
||||
endif (PACKAGE)
|
||||
endif (WINDOWS)
|
||||
|
||||
@@ -1630,11 +1655,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)
|
||||
|
||||
@@ -1684,7 +1734,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
|
||||
@@ -1734,6 +1783,63 @@ 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}/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 "'Singularity' SLPlugin")
|
||||
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 "singularity-do-not-run-directly 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)
|
||||
|
||||
@@ -2190,6 +2190,17 @@ This should be as low as possible, but too low may break functionality</string>
|
||||
<integer>1</integer>
|
||||
</map>
|
||||
<!-- Standard SL options (To my knowledge) -->
|
||||
<key>CrashHostUrl</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>A URL pointing to a crash report handler; overrides cluster negotiation to locate crash handler.</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>String</string>
|
||||
<key>Value</key>
|
||||
<string>http://crash.singularityviewer.org/report.php</string>>
|
||||
</map>
|
||||
<key>AFKTimeout</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
@@ -17698,6 +17709,17 @@ This should be as low as possible, but too low may break functionality</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>CrashSubmitBehavior</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Controls behavior when viewer crashes (0 = ask before sending crash report, 1 = always send crash report, 2 = never send crash report)</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>S32</string>
|
||||
<key>Value</key>
|
||||
<integer>1</integer>
|
||||
</map>
|
||||
</map>
|
||||
</llsd>
|
||||
|
||||
|
||||
@@ -9,39 +9,6 @@
|
||||
<key>Type</key>
|
||||
<string>S32</string>
|
||||
<key>Value</key>
|
||||
<integer>2</integer>
|
||||
</map>
|
||||
<key>CurlMaxTotalConcurrentConnections</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Maximum total number of simultaneous curl connections</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>U32</string>
|
||||
<key>Value</key>
|
||||
<integer>64</integer>
|
||||
</map>
|
||||
<key>CurlConcurrentConnectionsPerService</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Maximum number of simultaneous curl connections per host:port service</string>
|
||||
<key>Persist</key>
|
||||
<integer>0</integer>
|
||||
<key>Type</key>
|
||||
<string>U32</string>
|
||||
<key>Value</key>
|
||||
<integer>8</integer>
|
||||
</map>
|
||||
<key>NoVerifySSLCert</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Do not verify SSL certificates.</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>1</integer>
|
||||
</map>
|
||||
</map>
|
||||
|
||||
167
indra/newview/generate_breakpad_symbols.py
Normal file
167
indra/newview/generate_breakpad_symbols.py
Normal file
@@ -0,0 +1,167 @@
|
||||
#!/usr/bin/env python
|
||||
"""\
|
||||
@file generate_breakpad_symbols.py
|
||||
@author Brad Kittenbrink <brad@lindenlab.com>
|
||||
@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:]))
|
||||
|
||||
@@ -86,7 +86,7 @@
|
||||
#include "llvocache.h"
|
||||
#include "llvopartgroup.h"
|
||||
#include "llfloaterteleporthistory.h"
|
||||
|
||||
#include "llcrashlogger.h"
|
||||
#include "llweb.h"
|
||||
#include "llsecondlifeurls.h"
|
||||
|
||||
@@ -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");
|
||||
@@ -637,8 +641,6 @@ bool LLAppViewer::init()
|
||||
|
||||
LLPrivateMemoryPoolManager::initClass((BOOL)gSavedSettings.getBOOL("MemoryPrivatePoolEnabled"), (U32)gSavedSettings.getU32("MemoryPrivatePoolSize")) ;
|
||||
|
||||
mAlloc.setProfilingEnabled(gSavedSettings.getBOOL("MemProfiling"));
|
||||
|
||||
AIEngine::setMaxCount(gSavedSettings.getU32("StateMachineMaxTime"));
|
||||
|
||||
{
|
||||
@@ -654,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<bool> metrics_submode(gSavedSettings,
|
||||
@@ -1448,6 +1463,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 +1748,7 @@ bool LLAppViewer::cleanup()
|
||||
}
|
||||
// </edit>
|
||||
|
||||
removeDumpDir();
|
||||
writeDebugInfo();
|
||||
|
||||
if(!gDirUtilp->getLindenUserDir(true).empty())
|
||||
@@ -2449,7 +2473,6 @@ bool LLAppViewer::initConfiguration()
|
||||
|
||||
initMarkerFile();
|
||||
|
||||
checkForCrash();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2469,10 +2492,6 @@ bool LLAppViewer::initConfiguration()
|
||||
|
||||
initMarkerFile();
|
||||
|
||||
if(!mSecondInstance)
|
||||
{
|
||||
checkForCrash();
|
||||
}
|
||||
}
|
||||
|
||||
// need to do this here - need to have initialized global settings first
|
||||
@@ -2488,62 +2507,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 +2576,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 +2641,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 +2682,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<std::string>("CrashHostUrl");
|
||||
if(crashHostUrl != "")
|
||||
{
|
||||
gDebugInfo["CrashHostUrl"] = crashHostUrl;
|
||||
}
|
||||
|
||||
// Dump some debugging info
|
||||
LL_INFOS("SystemInfo") << LLTrans::getString("APP_NAME")
|
||||
@@ -2730,13 +2715,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 +2746,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<std::string>("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 +2765,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 +2777,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 +2794,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 +2832,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 +2859,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 +2876,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 +3000,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 +3584,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 +3602,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.
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -46,27 +46,6 @@
|
||||
|
||||
#include <exception>
|
||||
|
||||
#if LL_LINUX
|
||||
# include <dlfcn.h> // RTLD_LAZY
|
||||
# include <execinfo.h> // backtrace - glibc only
|
||||
# include <sys/types.h>
|
||||
# include <unistd.h>
|
||||
# include <dirent.h>
|
||||
# include <boost/algorithm/string.hpp>
|
||||
#elif LL_SOLARIS
|
||||
# include <sys/types.h>
|
||||
# include <unistd.h>
|
||||
# include <fcntl.h>
|
||||
# include <ucontext.h>
|
||||
#endif
|
||||
|
||||
#ifdef LL_ELFBIN
|
||||
# ifdef __GNUC__
|
||||
# include <cxxabi.h> // 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,102 +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
|
||||
}
|
||||
|
||||
bool LLAppViewerLinux::beingDebugged()
|
||||
@@ -676,7 +378,6 @@ bool LLAppViewerLinux::beingDebugged()
|
||||
base += 1;
|
||||
}
|
||||
|
||||
//should valgrind be added here?
|
||||
if (strcmp(base, "gdb") == 0)
|
||||
{
|
||||
debugged = yes;
|
||||
@@ -693,6 +394,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 +442,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))
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -262,11 +262,6 @@ bool LLAppViewerMacOSX::restoreErrorTrap()
|
||||
return reset_count == 0;
|
||||
}
|
||||
|
||||
void LLAppViewerMacOSX::handleSyncCrashTrace()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
static OSStatus CarbonEventHandler(EventHandlerCallRef inHandlerCallRef,
|
||||
EventRef inEvent,
|
||||
void* inUserData)
|
||||
@@ -294,122 +289,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()
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,68 @@ 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)
|
||||
{
|
||||
/* 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();
|
||||
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
|
||||
|
||||
@@ -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:
|
||||
|
||||
367
indra/newview/llcrashlogger.cpp
Normal file
367
indra/newview/llcrashlogger.cpp
Normal file
@@ -0,0 +1,367 @@
|
||||
/**
|
||||
* @file llcrashlogger.cpp
|
||||
* @brief 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 "llviewerprecompiledheaders.h"
|
||||
|
||||
#include "llcrashlogger.h"
|
||||
#include "linden_common.h"
|
||||
#include "llstring.h"
|
||||
#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 "llproxy.h"
|
||||
#include "aistatemachine.h"
|
||||
|
||||
class AIHTTPTimeoutPolicy;
|
||||
extern AIHTTPTimeoutPolicy crashLoggerResponder_timeout;
|
||||
|
||||
class LLCrashLoggerResponder : public LLHTTPClient::ResponderWithResult
|
||||
{
|
||||
public:
|
||||
LLCrashLoggerResponder()
|
||||
{
|
||||
}
|
||||
|
||||
virtual void error(U32 status, const std::string& reason)
|
||||
{
|
||||
llwarns << "Crash report sending failed: " << reason << llendl;
|
||||
}
|
||||
|
||||
virtual void result(const LLSD& content)
|
||||
{
|
||||
std::string msg = "Crash report successfully sent";
|
||||
if (content.has("message"))
|
||||
{
|
||||
msg += ": " + content["message"].asString();
|
||||
}
|
||||
llinfos << msg << llendl;
|
||||
}
|
||||
|
||||
virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const
|
||||
{
|
||||
return crashLoggerResponder_timeout;
|
||||
}
|
||||
|
||||
virtual char const* getName(void) const
|
||||
{
|
||||
return "LLCrashLoggerResponder";
|
||||
}
|
||||
};
|
||||
|
||||
LLCrashLogger::LLCrashLogger() :
|
||||
mCrashBehavior(CRASH_BEHAVIOR_ALWAYS_SEND),
|
||||
mCrashInPreviousExec(false),
|
||||
mCrashHost("")
|
||||
{
|
||||
}
|
||||
|
||||
LLCrashLogger::~LLCrashLogger()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// TRIM_SIZE must remain larger than LINE_SEARCH_SIZE.
|
||||
const int TRIM_SIZE = 128000;
|
||||
const int LINE_SEARCH_DIST = 500;
|
||||
const std::string SKIP_TEXT = "\n ...Skipping... \n";
|
||||
void trimSLLog(std::string& sllog)
|
||||
{
|
||||
if(sllog.length() > TRIM_SIZE * 2)
|
||||
{
|
||||
std::string::iterator head = sllog.begin() + TRIM_SIZE;
|
||||
std::string::iterator tail = sllog.begin() + sllog.length() - TRIM_SIZE;
|
||||
std::string::iterator new_head = std::find(head, head - LINE_SEARCH_DIST, '\n');
|
||||
if(new_head != head - LINE_SEARCH_DIST)
|
||||
{
|
||||
head = new_head;
|
||||
}
|
||||
|
||||
std::string::iterator new_tail = std::find(tail, tail + LINE_SEARCH_DIST, '\n');
|
||||
if(new_tail != tail + LINE_SEARCH_DIST)
|
||||
{
|
||||
tail = new_tail;
|
||||
}
|
||||
|
||||
sllog.erase(head, tail);
|
||||
sllog.insert(head, SKIP_TEXT.begin(), SKIP_TEXT.end());
|
||||
}
|
||||
}
|
||||
|
||||
std::string getStartupStateFromLog(std::string& sllog)
|
||||
{
|
||||
std::string startup_state = "STATE_FIRST";
|
||||
std::string startup_token = "Startup state changing from ";
|
||||
|
||||
int index = sllog.rfind(startup_token);
|
||||
if (index < 0 || index + startup_token.length() > sllog.length()) {
|
||||
return startup_state;
|
||||
}
|
||||
|
||||
// find new line
|
||||
char cur_char = sllog[index + startup_token.length()];
|
||||
std::string::size_type newline_loc = index + startup_token.length();
|
||||
while(cur_char != '\n' && newline_loc < sllog.length())
|
||||
{
|
||||
newline_loc++;
|
||||
cur_char = sllog[newline_loc];
|
||||
}
|
||||
|
||||
// get substring and find location of " to "
|
||||
std::string state_line = sllog.substr(index, newline_loc - index);
|
||||
std::string::size_type state_index = state_line.find(" to ");
|
||||
startup_state = state_line.substr(state_index + 4, state_line.length() - state_index - 4);
|
||||
|
||||
return startup_state;
|
||||
}
|
||||
|
||||
bool LLCrashLogger::readDebugFromXML(LLSD& dest, const std::string& filename )
|
||||
{
|
||||
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(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<char *>(&(data[0])),length);
|
||||
minidump_stream.close();
|
||||
|
||||
mCrashInfo["Minidump"] = data;
|
||||
}
|
||||
return (length>0?true:false);
|
||||
}
|
||||
|
||||
void LLCrashLogger::gatherFiles()
|
||||
{
|
||||
llinfos << "Gathering logs..." << llendl;
|
||||
|
||||
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();
|
||||
mFileMap["SettingsXml"] = mDebugLog["SettingsFilename"].asString();
|
||||
if(mDebugLog.has("CAFilename"))
|
||||
{
|
||||
LLCurl::setCAFile(mDebugLog["CAFilename"].asString());
|
||||
}
|
||||
else
|
||||
{
|
||||
LLCurl::setCAFile(gDirUtilp->getCAFile());
|
||||
}
|
||||
|
||||
llinfos << "Using log file from debug log " << mFileMap["SecondLifeLog"] << llendl;
|
||||
llinfos << "Using settings file from debug log " << mFileMap["SettingsXml"] << llendl;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Figure out the filename of the second life log
|
||||
LLCurl::setCAFile(gDirUtilp->getCAFile());
|
||||
mFileMap["SecondLifeLog"] = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"SecondLife.log");
|
||||
mFileMap["SettingsXml"] = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS,"settings.xml");
|
||||
}
|
||||
|
||||
if(mCrashInPreviousExec)
|
||||
{
|
||||
// Restarting after freeze.
|
||||
// Replace the log file ext with .old, since the
|
||||
// instance that launched this process has overwritten
|
||||
// SecondLife.log
|
||||
std::string log_filename = mFileMap["SecondLifeLog"];
|
||||
log_filename.replace(log_filename.size() - 4, 4, ".old");
|
||||
mFileMap["SecondLifeLog"] = log_filename;
|
||||
}
|
||||
|
||||
gatherPlatformSpecificFiles();
|
||||
|
||||
mCrashInfo["DebugLog"] = mDebugLog;
|
||||
mFileMap["StatsLog"] = gDirUtilp->getExpandedFilename(LL_PATH_DUMP,"stats.log");
|
||||
|
||||
llinfos << "Encoding files..." << llendl;
|
||||
|
||||
for(std::map<std::string, std::string>::iterator itr = mFileMap.begin(); itr != mFileMap.end(); ++itr)
|
||||
{
|
||||
std::ifstream f((*itr).second.c_str());
|
||||
if(!f.is_open())
|
||||
{
|
||||
llinfos << "Can't find file " << (*itr).second << llendl;
|
||||
continue;
|
||||
}
|
||||
std::stringstream s;
|
||||
s << f.rdbuf();
|
||||
|
||||
std::string crash_info = s.str();
|
||||
if(itr->first == "SecondLifeLog")
|
||||
{
|
||||
if(!mCrashInfo["DebugLog"].has("StartupState"))
|
||||
{
|
||||
mCrashInfo["DebugLog"]["StartupState"] = getStartupStateFromLog(crash_info);
|
||||
}
|
||||
trimSLLog(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<std::string> 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()
|
||||
{
|
||||
return mCrashInfo;
|
||||
}
|
||||
|
||||
|
||||
bool LLCrashLogger::sendCrashLog(std::string dump_dir)
|
||||
{
|
||||
gDirUtilp->setDumpDir( dump_dir );
|
||||
|
||||
std::string dump_path = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,
|
||||
"SingularityCrashReport");
|
||||
std::string report_file = dump_path + ".log";
|
||||
|
||||
gatherFiles();
|
||||
|
||||
LLSD post_data;
|
||||
post_data = constructPostData();
|
||||
|
||||
llinfos << "Sending reports..." << llendl;
|
||||
|
||||
std::ofstream out_file(report_file.c_str());
|
||||
LLSDSerialize::toPrettyXML(post_data, out_file);
|
||||
out_file.close();
|
||||
|
||||
LLHTTPClient::post(mCrashHost, post_data, new LLCrashLoggerResponder());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void LLCrashLogger::checkCrashDump()
|
||||
{
|
||||
mCrashHost = gSavedSettings.getString("CrashHostUrl");
|
||||
|
||||
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
|
||||
}
|
||||
else
|
||||
{
|
||||
llinfos << "No crash dump found frome previous run, not sending report" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
67
indra/newview/llcrashlogger.h
Normal file
67
indra/newview/llcrashlogger.h
Normal file
@@ -0,0 +1,67 @@
|
||||
/**
|
||||
* @file llcrashlogger.h
|
||||
* @brief 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 LLCRASHLOGGER_H
|
||||
#define LLCRASHLOGGER_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "llapp.h"
|
||||
#include "llsd.h"
|
||||
#include "llcontrol.h"
|
||||
|
||||
class LLCrashLogger
|
||||
{
|
||||
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);
|
||||
LLSD constructPostData();
|
||||
void setUserText(const std::string& text) { mCrashInfo["UserNotes"] = text; }
|
||||
S32 getCrashBehavior() { return mCrashBehavior; }
|
||||
bool readMinidump(std::string minidump_path);
|
||||
void checkCrashDump();
|
||||
|
||||
protected:
|
||||
S32 mCrashBehavior;
|
||||
BOOL mCrashInPreviousExec;
|
||||
std::map<std::string, std::string> mFileMap;
|
||||
std::string mGridName;
|
||||
std::string mProductName;
|
||||
LLSD mCrashInfo;
|
||||
std::string mCrashHost;
|
||||
LLSD mDebugLog;
|
||||
};
|
||||
|
||||
#endif //LLCRASHLOGGER_H
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -87,7 +87,7 @@ BOOL LLPanelGeneral::postBuild()
|
||||
childSetValue("ui_auto_scale", gSavedSettings.getBOOL("UIAutoScale"));
|
||||
|
||||
LLComboBox* crash_behavior_combobox = getChild<LLComboBox>("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<LLComboBox>("crash_behavior_combobox");
|
||||
gCrashSettings.setS32(CRASH_BEHAVIOR_SETTING, crash_behavior_combobox->getCurrentIndex());
|
||||
gSavedSettings.setS32(CRASH_BEHAVIOR_SETTING, crash_behavior_combobox->getCurrentIndex());
|
||||
}
|
||||
|
||||
void LLPanelGeneral::cancel()
|
||||
|
||||
@@ -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 <tchar.h>
|
||||
#include <tlhelp32.h>
|
||||
#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
|
||||
<llsd>
|
||||
<map>
|
||||
<key>Platform</key>
|
||||
<string></string>
|
||||
<key>Process</key>
|
||||
<string></string>
|
||||
<key>Module</key>
|
||||
<string></string>
|
||||
<key>DateModified</key>
|
||||
<string></string>
|
||||
<key>ExceptionCode</key>
|
||||
<string></string>
|
||||
<key>ExceptionRead/WriteAddress</key>
|
||||
<string></string>
|
||||
<key>Instruction</key>
|
||||
<string></string>
|
||||
<key>Registers</key>
|
||||
<map>
|
||||
<!-- Continued for all registers -->
|
||||
<key>EIP</key>
|
||||
<string>...</string>
|
||||
<!-- ... -->
|
||||
</map>
|
||||
<key>Call Stack</key>
|
||||
<array>
|
||||
<!-- One map per stack frame -->
|
||||
<map>
|
||||
<key>ModuleName</key>
|
||||
<string></string>
|
||||
<key>ModuleBaseAddress</key>
|
||||
<string></string>
|
||||
<key>ModuleOffsetAddress</key>
|
||||
<string></string>
|
||||
<key>Parameters</key>
|
||||
<array>
|
||||
<string></string>
|
||||
</array>
|
||||
</map>
|
||||
<!-- ... -->
|
||||
</array>
|
||||
</map>
|
||||
</llsd>
|
||||
|
||||
*/
|
||||
|
||||
|
||||
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<DWORD>& 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<DWORD> thread_ids;
|
||||
GetProcessThreadIDs(GetCurrentProcessId(), thread_ids);
|
||||
|
||||
for(std::vector<DWORD>::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);
|
||||
}
|
||||
|
||||
@@ -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 <dbghelp.h>
|
||||
|
||||
class LLWinDebug
|
||||
class LLWinDebug:
|
||||
public LLSingleton<LLWinDebug>
|
||||
{
|
||||
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
|
||||
|
||||
@@ -339,9 +339,7 @@ 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")
|
||||
self.package_file = 'npne'
|
||||
|
||||
|
||||
def nsi_file_commands(self, install=True):
|
||||
@@ -526,7 +524,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...
|
||||
@@ -545,18 +544,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",
|
||||
@@ -715,12 +706,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())
|
||||
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")
|
||||
## 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"):
|
||||
|
||||
@@ -1,89 +0,0 @@
|
||||
# -*- cmake -*-
|
||||
|
||||
project(win_crash_logger)
|
||||
|
||||
include(00-Common)
|
||||
include(DirectX)
|
||||
include(LLCommon)
|
||||
include(LLCrashLogger)
|
||||
include(LLMath)
|
||||
include(LLMessage)
|
||||
include(LLVFS)
|
||||
include(LLWindow)
|
||||
include(LLXML)
|
||||
include(Linking)
|
||||
|
||||
include_directories(
|
||||
${LLCOMMON_INCLUDE_DIRS}
|
||||
${LLCRASHLOGGER_INCLUDE_DIRS}
|
||||
${LLMATH_INCLUDE_DIRS}
|
||||
${LLWINDOW_INCLUDE_DIRS}
|
||||
${LLXML_INCLUDE_DIRS}
|
||||
${LLVFS_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
|
||||
snowglobe_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
|
||||
${LLCRASHLOGGER_LIBRARIES}
|
||||
${LLWINDOW_LIBRARIES}
|
||||
${LLVFS_LIBRARIES}
|
||||
${LLXML_LIBRARIES}
|
||||
${LLMESSAGE_LIBRARIES}
|
||||
${LLMATH_LIBRARIES}
|
||||
${LLCOMMON_LIBRARIES}
|
||||
${WINDOWS_LIBRARIES}
|
||||
${DXGUID_LIBRARY}
|
||||
user32
|
||||
gdi32
|
||||
ole32
|
||||
oleaut32
|
||||
Wldap32
|
||||
)
|
||||
|
||||
if (WINDOWS)
|
||||
set_target_properties(windows-crash-logger
|
||||
PROPERTIES
|
||||
LINK_FLAGS "/NODEFAULTLIB:LIBCMT"
|
||||
LINK_FLAGS_DEBUG "/NODEFAULTLIB:\"LIBCMT;LIBCMTD;MSVCRT\""
|
||||
)
|
||||
endif (WINDOWS)
|
||||
@@ -1,40 +0,0 @@
|
||||
/**
|
||||
* @file StdAfx.cpp
|
||||
* @brief windows crash logger source file for includes
|
||||
*
|
||||
* $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$
|
||||
*/
|
||||
|
||||
// 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
|
||||
@@ -1,63 +0,0 @@
|
||||
/**
|
||||
* @file StdAfx.h
|
||||
* @brief standard system includes
|
||||
*
|
||||
* $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$
|
||||
*/
|
||||
|
||||
// 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 <windows.h>
|
||||
|
||||
// C RunTime Header Files
|
||||
#include <stdlib.h>
|
||||
#include <malloc.h>
|
||||
#include <memory.h>
|
||||
|
||||
// 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_)
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 2.2 KiB |
@@ -1,383 +0,0 @@
|
||||
/**
|
||||
* @file llcrashloggerwindows.cpp
|
||||
* @brief Windows 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 "stdafx.h"
|
||||
#include "resource.h"
|
||||
#include "llcrashloggerwindows.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include "boost/tokenizer.hpp"
|
||||
|
||||
#include "dbghelp.h"
|
||||
#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"
|
||||
|
||||
#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;
|
||||
|
||||
|
||||
//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)
|
||||
{
|
||||
}
|
||||
|
||||
LLCrashLoggerWindows::~LLCrashLoggerWindows(void)
|
||||
{
|
||||
}
|
||||
|
||||
bool LLCrashLoggerWindows::init(void)
|
||||
{
|
||||
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();
|
||||
mFileMap["CrashLog"] = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"SecondLifeException.log");
|
||||
}
|
||||
|
||||
bool LLCrashLoggerWindows::mainLoop()
|
||||
{
|
||||
|
||||
// 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)
|
||||
{
|
||||
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();
|
||||
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);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
/**
|
||||
* @file llcrashloggerwindows.h
|
||||
* @brief Windows 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 LLCRASHLOGGERWINDOWS_H
|
||||
#define LLCRASHLOGGERWINDOWS_H
|
||||
|
||||
#include "llcrashlogger.h"
|
||||
#include "windows.h"
|
||||
#include "llstring.h"
|
||||
|
||||
class LLCrashLoggerWindows : public LLCrashLogger
|
||||
{
|
||||
public:
|
||||
LLCrashLoggerWindows(void);
|
||||
~LLCrashLoggerWindows(void);
|
||||
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; }
|
||||
private:
|
||||
void ProcessDlgItemText(HWND hWnd, int nIDDlgItem);
|
||||
void ProcessCaption(HWND hWnd);
|
||||
HINSTANCE mhInst;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,69 +0,0 @@
|
||||
/**
|
||||
* @file resource.h
|
||||
* @brief Windows crash logger windows resources
|
||||
*
|
||||
* $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$
|
||||
*/
|
||||
|
||||
//{{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
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 4.2 KiB |
@@ -1,80 +0,0 @@
|
||||
/**
|
||||
* @file win_crash_logger.cpp
|
||||
* @brief Windows 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$
|
||||
*/
|
||||
|
||||
// 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 <stdlib.h>
|
||||
|
||||
#include "llcrashloggerwindows.h"
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Implementation
|
||||
//
|
||||
|
||||
int APIENTRY WinMain(HINSTANCE hInstance,
|
||||
HINSTANCE hPrevInstance,
|
||||
LPSTR lpCmdLine,
|
||||
int nCmdShow)
|
||||
{
|
||||
llinfos << "Starting crash reporter" << llendl;
|
||||
|
||||
LLCrashLoggerWindows app;
|
||||
app.setHandle(hInstance);
|
||||
bool ok = app.init();
|
||||
if(!ok)
|
||||
{
|
||||
llwarns << "Unable to initialize application." << llendl;
|
||||
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();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
/**
|
||||
* @file win_crash_logger.h
|
||||
* @brief Windows crash logger project includes
|
||||
*
|
||||
* $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$
|
||||
*/
|
||||
|
||||
|
||||
#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_)
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 1.1 KiB |
@@ -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
|
||||
|
||||
@@ -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\""
|
||||
)
|
||||
@@ -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 <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 <windows.h>
|
||||
#include <wininet.h>
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
|
||||
#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<tlen; i++)
|
||||
{
|
||||
int cur_char = (int)(*in_chars++);
|
||||
if (cur_char < 0x80)
|
||||
{
|
||||
*outchars++ = (char)cur_char;
|
||||
}
|
||||
else
|
||||
{
|
||||
*outchars++ = '?';
|
||||
}
|
||||
}
|
||||
*outchars = 0;
|
||||
return res;
|
||||
}
|
||||
|
||||
class Fetcher
|
||||
{
|
||||
public:
|
||||
Fetcher(const std::wstring& uri)
|
||||
{
|
||||
// These actions are broken out as separate methods not because it
|
||||
// makes the code clearer, but to avoid triggering AntiVir and
|
||||
// McAfee-GW-Edition virus scanners (DEV-31680).
|
||||
mInet = openInet();
|
||||
mDownload = openUrl(uri);
|
||||
}
|
||||
|
||||
~Fetcher()
|
||||
{
|
||||
DEBUG("Calling InternetCloseHandle");
|
||||
InternetCloseHandle(mDownload);
|
||||
InternetCloseHandle(mInet);
|
||||
}
|
||||
|
||||
unsigned long read(char* buffer, size_t bufflen) const;
|
||||
|
||||
DWORD getTotalBytes() const
|
||||
{
|
||||
DWORD totalBytes;
|
||||
DWORD sizeof_total_bytes = sizeof(totalBytes);
|
||||
HttpQueryInfo(mDownload, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER,
|
||||
&totalBytes, &sizeof_total_bytes, NULL);
|
||||
return totalBytes;
|
||||
}
|
||||
|
||||
struct InetError: public std::runtime_error
|
||||
{
|
||||
InetError(const std::string& what): std::runtime_error(what) {}
|
||||
};
|
||||
|
||||
private:
|
||||
// We test results from a number of different MS functions with different
|
||||
// return types -- but the common characteristic is that 0 (i.e. (! result))
|
||||
// means an error of some kind.
|
||||
template <typename RESULT>
|
||||
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 <url> [-name <window_title>] [-program <program_name>] [-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;
|
||||
}
|
||||
36
install.xml
36
install.xml
@@ -562,6 +562,42 @@
|
||||
</map>
|
||||
</map>
|
||||
</map>
|
||||
<key>google_breakpad</key>
|
||||
<map>
|
||||
<key>license</key>
|
||||
<string>bsd</string>
|
||||
<key>packages</key>
|
||||
<map>
|
||||
<key>darwin</key>
|
||||
<map>
|
||||
<key>md5sum</key>
|
||||
<string>5a5c90d28fd9bdc4244c56fef4216998</string>
|
||||
<key>url</key>
|
||||
<uri>https://bitbucket.org/SingularityViewer/libraries/downloads/google_breakpad-0.0.0-rev1099-darwin-20131002.tar.bz2</uri>
|
||||
</map>
|
||||
<key>linux</key>
|
||||
<map>
|
||||
<key>md5sum</key>
|
||||
<string>03852edfa946bdc365b5fbd1a373b17f</string>
|
||||
<key>url</key>
|
||||
<uri>https://bitbucket.org/SingularityViewer/libraries/downloads/google_breakpad-0.0.0-rev1099-linux-20131002.tar.bz2</uri>
|
||||
</map>
|
||||
<key>linux64</key>
|
||||
<map>
|
||||
<key>md5sum</key>
|
||||
<string>e2e8d8068eceaad66758bb5f031d5246</string>
|
||||
<key>url</key>
|
||||
<uri>https://bitbucket.org/SingularityViewer/libraries/downloads/google_breakpad-0.0.0-rev1099-linux64-20131002.tar.bz2</uri>
|
||||
</map>
|
||||
<key>windows</key>
|
||||
<map>
|
||||
<key>md5sum</key>
|
||||
<string>37d1f91f486e357c9a74e6b4af91fe13</string>
|
||||
<key>url</key>
|
||||
<uri>https://bitbucket.org/SingularityViewer/libraries/downloads/google_breakpad-0.0.0-rev1099-windows-20131002.tar.bz2</uri>
|
||||
</map>
|
||||
</map>
|
||||
</map>
|
||||
<key>gperftools</key>
|
||||
<map>
|
||||
<key>copyright</key>
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user