Port Crashpad support from alchemy, with some small tweaks
Moved initCrashReporting into LLAppViewer, everything we use there is crossplatform enough that duplicating code is silly Removes unused gCrashSettings Adds MBFatalError, that's right, Crash Loop is now translatable! Adds consent notification prompt to first login... enjoy that, everyone.
This commit is contained in:
146
autobuild.xml
146
autobuild.xml
@@ -389,6 +389,54 @@
|
||||
<key>version</key>
|
||||
<string>2.3</string>
|
||||
</map>
|
||||
<key>crashpad</key>
|
||||
<map>
|
||||
<key>canonical_repo</key>
|
||||
<string>https://git.alchemyviewer.org/alchemy/thirdparty/3p-crashpad</string>
|
||||
<key>copyright</key>
|
||||
<string>Copyright 2014 The Crashpad Authors. All rights reserved.</string>
|
||||
<key>description</key>
|
||||
<string>Crashpad is a crash-reporting system.</string>
|
||||
<key>license</key>
|
||||
<string>Apache 2.0</string>
|
||||
<key>license_file</key>
|
||||
<string>LICENSES/crashpad.txt</string>
|
||||
<key>name</key>
|
||||
<string>crashpad</string>
|
||||
<key>platforms</key>
|
||||
<map>
|
||||
<key>windows</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>849f515d4d77162c15614ebff8599c13</string>
|
||||
<key>hash_algorithm</key>
|
||||
<string>md5</string>
|
||||
<key>url</key>
|
||||
<string>https://pkg.alchemyviewer.org/repository/autobuild-external/crashpad/windows/crashpad-365c520b.6-windows-6.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>windows</string>
|
||||
</map>
|
||||
<key>windows64</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>7ea820b6a2cfa172f47d673c07dfa62c</string>
|
||||
<key>hash_algorithm</key>
|
||||
<string>md5</string>
|
||||
<key>url</key>
|
||||
<string>https://pkg.alchemyviewer.org/repository/autobuild-external/crashpad/windows64/crashpad-365c520b.6-windows64-6.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>windows64</string>
|
||||
</map>
|
||||
</map>
|
||||
<key>version</key>
|
||||
<string>365c520b.6</string>
|
||||
</map>
|
||||
<key>curl</key>
|
||||
<map>
|
||||
<key>copyright</key>
|
||||
@@ -1237,104 +1285,6 @@
|
||||
<key>version</key>
|
||||
<string>1.0pre3.190390340</string>
|
||||
</map>
|
||||
<key>google_breakpad</key>
|
||||
<map>
|
||||
<key>copyright</key>
|
||||
<string>Copyright (c) 2006, Google Inc.</string>
|
||||
<key>description</key>
|
||||
<string>Breakpad is a crossplatform library for capturing crash callstacks and runtime data.</string>
|
||||
<key>license</key>
|
||||
<string>bsd</string>
|
||||
<key>license_file</key>
|
||||
<string>LICENSES/google_breakpad.txt</string>
|
||||
<key>name</key>
|
||||
<string>google_breakpad</string>
|
||||
<key>platforms</key>
|
||||
<map>
|
||||
<key>darwin</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>9f963eb1728e6d5077d4feba805d4896</string>
|
||||
<key>hash_algorithm</key>
|
||||
<string>md5</string>
|
||||
<key>url</key>
|
||||
<string>https://bitbucket.org/alchemyviewer/publiclibs-darwin/downloads/google_breakpad-9e60a27-darwin-201511222009.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>darwin</string>
|
||||
</map>
|
||||
<key>darwin64</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>2d43c6a149cd9c89ba19e884579b1e25</string>
|
||||
<key>url</key>
|
||||
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/1836/4096/google_breakpad-1413.501824-darwin64-501824.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>darwin64</string>
|
||||
</map>
|
||||
<key>linux</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>52257e5eb166a0b69c9c0c38f6e1920e</string>
|
||||
<key>url</key>
|
||||
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-google-breakpad/rev/273079/arch/Linux/installer/google_breakpad-0.0.0-rev1099-linux-20130329.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>linux</string>
|
||||
</map>
|
||||
<key>linux64</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>3709a51d4d5dff5ec0c4656623eaa05d</string>
|
||||
<key>hash_algorithm</key>
|
||||
<string>md5</string>
|
||||
<key>url</key>
|
||||
<string>http://depot.alchemyviewer.org/pub/linux64/lib-trusty/google_breakpad-9e60a27-linux64-201603240004.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>linux64</string>
|
||||
</map>
|
||||
<key>windows</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>fa7f683ba4ddd7db777c78c8213d2e46</string>
|
||||
<key>hash_algorithm</key>
|
||||
<string>md5</string>
|
||||
<key>url</key>
|
||||
<string>https://depot.alchemyviewer.org/pub/windows/lib-vc141/google_breakpad-7398ce15b79da-windows-201703090621.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>windows</string>
|
||||
</map>
|
||||
<key>windows64</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>71ffc5cae4da7e2e7aac856da44cb8c4</string>
|
||||
<key>hash_algorithm</key>
|
||||
<string>md5</string>
|
||||
<key>url</key>
|
||||
<string>https://depot.alchemyviewer.org/pub/windows64/lib-vc141/google_breakpad-7398ce15b79da-windows64-201703081616.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>windows64</string>
|
||||
</map>
|
||||
</map>
|
||||
<key>version</key>
|
||||
<string>9e60a27</string>
|
||||
</map>
|
||||
<key>gperftools</key>
|
||||
<map>
|
||||
<key>copyright</key>
|
||||
|
||||
@@ -17,19 +17,6 @@ set(CMAKE_C_FLAGS_RELEASE
|
||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO
|
||||
"-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.
|
||||
set(CMAKE_CONFIGURATION_TYPES "RelWithDebInfo;Release;Debug" CACHE STRING
|
||||
"Supported build types." FORCE)
|
||||
@@ -55,6 +42,14 @@ if (WINDOWS)
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /LARGEADDRESSAWARE")
|
||||
endif (WORD_SIZE EQUAL 32)
|
||||
|
||||
if (FULL_DEBUG_SYMS OR USE_CRASHPAD)
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /DEBUG:FULL")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /DEBUG:FULL")
|
||||
else ()
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /DEBUG:FASTLINK")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /DEBUG:FASTLINK")
|
||||
endif ()
|
||||
|
||||
if (USE_LTO)
|
||||
if(INCREMENTAL_LINK)
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /LTCG:INCREMENTAL")
|
||||
@@ -306,6 +301,13 @@ endif (LINUX OR DARWIN)
|
||||
if (STANDALONE)
|
||||
add_definitions(-DLL_STANDALONE=1)
|
||||
else (STANDALONE)
|
||||
#Enforce compile-time correctness for fmt strings
|
||||
add_definitions(-DFMT_STRING_ALIAS=1)
|
||||
|
||||
if(USE_CRASHPAD)
|
||||
add_definitions(-DUSE_CRASHPAD=1 -DCRASHPAD_URL="${CRASHPAD_URL}")
|
||||
endif()
|
||||
|
||||
set(${ARCH}_linux_INCLUDES
|
||||
atk-1.0
|
||||
cairo
|
||||
|
||||
@@ -22,6 +22,7 @@ set(cmake_SOURCE_FILES
|
||||
ConfigurePkgConfig.cmake
|
||||
CURL.cmake
|
||||
Copy3rdPartyLibs.cmake
|
||||
CrashPad.cmake
|
||||
Cwdebug.cmake
|
||||
DBusGlib.cmake
|
||||
DeploySharedLibs.cmake
|
||||
@@ -32,7 +33,6 @@ set(cmake_SOURCE_FILES
|
||||
FindCARes.cmake
|
||||
FindColladadom.cmake
|
||||
FindGLOD.cmake
|
||||
FindGoogleBreakpad.cmake
|
||||
FindGooglePerfTools.cmake
|
||||
FindHunSpell.cmake
|
||||
FindNDOF.cmake
|
||||
@@ -47,7 +47,6 @@ set(cmake_SOURCE_FILES
|
||||
GStreamer010Plugin.cmake
|
||||
Glui.cmake
|
||||
Glut.cmake
|
||||
GoogleBreakpad.cmake
|
||||
GooglePerfTools.cmake
|
||||
Hunspell.cmake
|
||||
JPEG.cmake
|
||||
|
||||
22
indra/cmake/CrashPad.cmake
Normal file
22
indra/cmake/CrashPad.cmake
Normal file
@@ -0,0 +1,22 @@
|
||||
# -*- cmake -*-
|
||||
include(Prebuilt)
|
||||
include(Variables)
|
||||
|
||||
if(USE_CRASHPAD)
|
||||
|
||||
if (USESYSTEMLIBS)
|
||||
else (USESYSTEMLIBS)
|
||||
use_prebuilt_binary(crashpad)
|
||||
if (WINDOWS)
|
||||
set(CRASHPAD_LIBRARIES
|
||||
debug client.lib util.lib base.lib
|
||||
optimized client.lib util.lib base.lib)
|
||||
elseif (LINUX)
|
||||
|
||||
else (DARWIN)
|
||||
|
||||
endif ()
|
||||
set(CRASHPAD_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include/crashpad)
|
||||
endif (USESYSTEMLIBS)
|
||||
|
||||
endif()
|
||||
@@ -1,40 +0,0 @@
|
||||
# -*- cmake -*-
|
||||
|
||||
# - Find Google BreakPad
|
||||
# Find the Google BreakPad includes and library
|
||||
# This module defines
|
||||
# BREAKPAD_INCLUDE_DIRECTORIES, where to find the Goole BreakPad includes.
|
||||
# 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_INCLUDE_DIRECTORIES common/using_std_string.h PATH_SUFFIXES google_breakpad)
|
||||
|
||||
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_INCLUDE_DIRECTORIES)
|
||||
SET(BREAKPAD_EXCEPTION_HANDLER_LIBRARIES ${BREAKPAD_EXCEPTION_HANDLER_LIBRARY})
|
||||
SET(BREAKPAD_EXCEPTION_HANDLER_FOUND "YES")
|
||||
ELSE (BREAKPAD_EXCEPTION_HANDLER_LIBRARY AND BREAKPAD_INCLUDE_DIRECTORIES)
|
||||
SET(BREAKPAD_EXCEPTION_HANDLER_FOUND "NO")
|
||||
ENDIF (BREAKPAD_EXCEPTION_HANDLER_LIBRARY AND BREAKPAD_INCLUDE_DIRECTORIES)
|
||||
|
||||
|
||||
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_INCLUDE_DIRECTORIES
|
||||
)
|
||||
@@ -1,26 +0,0 @@
|
||||
# -*- 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
|
||||
# I think it's incorrect: the second one should go --Aleric
|
||||
set(BREAKPAD_INCLUDE_DIRECTORIES
|
||||
${LIBS_PREBUILT_DIR}/include/google_breakpad
|
||||
${LIBS_PREBUILT_LEGACY_DIR}/include/google_breakpad
|
||||
${LIBS_PREBUILT_DIR}/include/google_breakpad/google_breakpad
|
||||
${LIBS_PREBUILT_LEGACY_DIR}/include/google_breakpad/google_breakpad
|
||||
)
|
||||
endif (STANDALONE)
|
||||
@@ -36,6 +36,11 @@ option(USE_PRECOMPILED_HEADERS "Enable use of precompiled header directives wher
|
||||
option(USE_LTO "Enable Whole Program Optimization and related folding and binary reduction routines" OFF)
|
||||
option(UNATTENDED "Disable use of uneeded tooling for automated builds" OFF)
|
||||
|
||||
# Configure crash reporting
|
||||
option(USE_CRASHPAD "Build support for crashpad reporting engine" OFF)
|
||||
set(CRASHPAD_URL "" CACHE STRING "Crashpad endpoint url")
|
||||
set(VIEWER_SYMBOL_FILE "" CACHE STRING "Name of tarball into which to place symbol files")
|
||||
|
||||
# Media Plugins
|
||||
option(ENABLE_MEDIA_PLUGINS "Turn off building media plugins if they are imported by third-party library mechanism" ON)
|
||||
option(LIBVLCPLUGIN "Turn off building support for libvlc plugin" ON)
|
||||
|
||||
@@ -13,7 +13,6 @@ include(Boost)
|
||||
include(OpenSSL)
|
||||
include(LLSharedLibs)
|
||||
include(Json)
|
||||
include(GoogleBreakpad)
|
||||
include(Copy3rdPartyLibs)
|
||||
include(ZLIB)
|
||||
include(URIPARSER)
|
||||
@@ -291,7 +290,6 @@ target_link_libraries(
|
||||
llcommon
|
||||
PUBLIC
|
||||
absl::hash
|
||||
${BREAKPAD_EXCEPTION_HANDLER_LIBRARIES}
|
||||
${APRUTIL_LIBRARIES}
|
||||
${APR_LIBRARIES}
|
||||
${EXPAT_LIBRARIES}
|
||||
|
||||
@@ -368,13 +368,6 @@ const U32 MAP_ITEM_CLASSIFIED = 0x08;
|
||||
const U32 MAP_ITEM_ADULT_EVENT = 0x09;
|
||||
const U32 MAP_ITEM_LAND_FOR_SALE_ADULT = 0x0a;
|
||||
|
||||
// Crash reporter behavior
|
||||
const char* const CRASH_SETTINGS_FILE = "settings_crash_behavior.xml";
|
||||
const char* const CRASH_BEHAVIOR_SETTING = "CrashSubmitBehavior";
|
||||
const S32 CRASH_BEHAVIOR_ASK = 0;
|
||||
const S32 CRASH_BEHAVIOR_ALWAYS_SEND = 1;
|
||||
const S32 CRASH_BEHAVIOR_NEVER_SEND = 2;
|
||||
|
||||
// Export/Import return values
|
||||
const S32 EXPORT_SUCCESS = 0;
|
||||
const S32 EXPORT_ERROR_PERMISSIONS = -1;
|
||||
|
||||
@@ -25,9 +25,8 @@
|
||||
*/
|
||||
|
||||
#include "linden_common.h"
|
||||
#include "llapp.h"
|
||||
|
||||
#include <cstdlib>
|
||||
#include "llapp.h"
|
||||
|
||||
#ifdef LL_DARWIN
|
||||
#include <sys/types.h>
|
||||
@@ -45,7 +44,6 @@
|
||||
#include "llstl.h" // for DeletePointer()
|
||||
#include "llstring.h"
|
||||
#include "lleventtimer.h"
|
||||
#include "exception_handler.h"
|
||||
|
||||
//
|
||||
// Signal handling
|
||||
@@ -57,12 +55,6 @@
|
||||
|
||||
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()
|
||||
@@ -70,18 +62,6 @@ bool windows_post_minidump_callback(const wchar_t* dump_path,
|
||||
void setup_signals();
|
||||
void default_unix_signal_handler(int signum, siginfo_t *info, void *);
|
||||
|
||||
#if LL_LINUX
|
||||
#include "client/linux/handler/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;
|
||||
@@ -98,7 +78,7 @@ S32 LL_HEARTBEAT_SIGNAL = (SIGRTMAX >= 0) ? (SIGRTMAX-0) : SIGUSR2;
|
||||
#endif // LL_WINDOWS
|
||||
|
||||
// the static application instance
|
||||
LLApp* LLApp::sApplication = NULL;
|
||||
LLApp* LLApp::sApplication = nullptr;
|
||||
|
||||
// Allows the generation of core files for post mortem under gdb
|
||||
// and disables crashlogger
|
||||
@@ -110,7 +90,7 @@ BOOL LLApp::sLogInSignal = FALSE;
|
||||
|
||||
// static
|
||||
LLApp::EAppStatus LLApp::sStatus = LLApp::APP_STATUS_STOPPED; // Keeps track of application status
|
||||
LLAppErrorHandler LLApp::sErrorHandler = NULL;
|
||||
LLAppErrorHandler LLApp::sErrorHandler = nullptr;
|
||||
BOOL LLApp::sErrorThreadRunning = FALSE;
|
||||
#if !LL_WINDOWS
|
||||
LLApp::child_map LLApp::sChildMap;
|
||||
@@ -119,13 +99,12 @@ LLAppChildCallback LLApp::sDefaultChildCallback = NULL;
|
||||
#endif
|
||||
|
||||
|
||||
LLApp::LLApp() : mThreadErrorp(NULL)
|
||||
LLApp::LLApp()
|
||||
: mThreadErrorp(nullptr)
|
||||
{
|
||||
commonCtor();
|
||||
}
|
||||
|
||||
static void* sCrashLoggerReserve = NULL;
|
||||
|
||||
void LLApp::commonCtor()
|
||||
{
|
||||
// Set our status to running
|
||||
@@ -150,34 +129,11 @@ void LLApp::commonCtor()
|
||||
// Set the application to this instance.
|
||||
sApplication = this;
|
||||
|
||||
mExceptionHandler = 0;
|
||||
|
||||
#if LL_WINDOWS
|
||||
sCrashLoggerReserve = VirtualAlloc(NULL, 512*1024, MEM_COMMIT|MEM_RESERVE, PAGE_NOACCESS);
|
||||
#else
|
||||
sCrashLoggerReserve = malloc(512*1024);
|
||||
#endif
|
||||
|
||||
// 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";
|
||||
}
|
||||
|
||||
#if LL_WINDOWS
|
||||
static bool clear_CrashLoggerReserve_callback(void* context, EXCEPTION_POINTERS* exinfo, MDRawAssertionInfo* assertion)
|
||||
{
|
||||
VirtualFree(sCrashLoggerReserve, 0, MEM_RELEASE);
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
static bool clear_CrashLoggerReserve_callback(void* context)
|
||||
{
|
||||
free(sCrashLoggerReserve);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
LLApp::LLApp(LLErrorThread *error_thread) :
|
||||
mThreadErrorp(error_thread)
|
||||
{
|
||||
@@ -198,11 +154,9 @@ LLApp::~LLApp()
|
||||
if (mThreadErrorp)
|
||||
{
|
||||
delete mThreadErrorp;
|
||||
mThreadErrorp = NULL;
|
||||
mThreadErrorp = nullptr;
|
||||
}
|
||||
|
||||
if(mExceptionHandler != 0) delete mExceptionHandler;
|
||||
|
||||
LLCommon::cleanupClass();
|
||||
}
|
||||
|
||||
@@ -216,8 +170,8 @@ LLApp* LLApp::instance()
|
||||
LLSD LLApp::getOption(const std::string& name) const
|
||||
{
|
||||
LLSD rv;
|
||||
LLSD::array_const_iterator iter = mOptions.beginArray();
|
||||
LLSD::array_const_iterator end = mOptions.endArray();
|
||||
auto iter = mOptions.beginArray();
|
||||
auto end = mOptions.endArray();
|
||||
for(; iter != end; ++iter)
|
||||
{
|
||||
rv = (*iter)[name];
|
||||
@@ -264,9 +218,9 @@ bool LLApp::parseCommandOptions(int argc, char** argv)
|
||||
|
||||
#if LL_WINDOWS
|
||||
//Windows changed command line parsing. Deal with it.
|
||||
S32 slen = value.length() - 1;
|
||||
S32 start = 0;
|
||||
S32 end = slen;
|
||||
size_t slen = value.length() - 1;
|
||||
size_t start = 0;
|
||||
size_t end = slen;
|
||||
if (argv[ii][start]=='"')start++;
|
||||
if (argv[ii][end]=='"')end--;
|
||||
if (start!=0 || end!=slen)
|
||||
@@ -343,92 +297,17 @@ void LLApp::setupErrorHandling()
|
||||
// Error handling is done by starting up an error handling thread, which just sleeps and
|
||||
// occasionally checks to see if the app is in an error state, and sees if it needs to be run.
|
||||
|
||||
#if LL_WINDOWS
|
||||
|
||||
#if LL_SEND_CRASH_REPORTS
|
||||
EnableCrashingOnCrashes();
|
||||
|
||||
// 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)
|
||||
{
|
||||
mExceptionHandler = new google_breakpad::ExceptionHandler(
|
||||
std::wstring(mDumpPath.begin(),mDumpPath.end()), //Dump path
|
||||
clear_CrashLoggerReserve_callback,
|
||||
windows_post_minidump_callback,
|
||||
0,
|
||||
google_breakpad::ExceptionHandler::HANDLER_ALL);
|
||||
if (mExceptionHandler)
|
||||
{
|
||||
mExceptionHandler->set_handle_debug_exceptions(true);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
#if !LL_WINDOWS
|
||||
//
|
||||
// Start up signal handling.
|
||||
//
|
||||
// There are two different classes of signals. Synchronous signals are delivered to a specific
|
||||
// thread, asynchronous signals can be delivered to any thread (in theory)
|
||||
//
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if(installHandler && (mExceptionHandler == 0))
|
||||
{
|
||||
mExceptionHandler = new google_breakpad::ExceptionHandler(mDumpPath, clear_CrashLoggerReserve_callback, &unix_post_minidump_callback, 0, true, 0);
|
||||
}
|
||||
#endif
|
||||
#elif LL_LINUX
|
||||
if(installHandler && (mExceptionHandler == 0))
|
||||
{
|
||||
if (mDumpPath.empty())
|
||||
{
|
||||
mDumpPath = "/tmp";
|
||||
}
|
||||
google_breakpad::MinidumpDescriptor desc(mDumpPath);
|
||||
mExceptionHandler = new google_breakpad::ExceptionHandler(desc, clear_CrashLoggerReserve_callback, unix_minidump_callback, NULL, true, -1);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // ! LL_WINDOWS
|
||||
#if !defined(USE_CRASHPAD)
|
||||
startErrorThread();
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -466,7 +345,6 @@ void LLApp::setErrorHandler(LLAppErrorHandler handler)
|
||||
LLApp::sErrorHandler = handler;
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
void LLApp::runErrorHandler()
|
||||
{
|
||||
@@ -479,7 +357,6 @@ void LLApp::runErrorHandler()
|
||||
LLApp::setStopped();
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
void LLApp::setStatus(EAppStatus status)
|
||||
{
|
||||
@@ -494,43 +371,12 @@ void LLApp::setError()
|
||||
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()
|
||||
{
|
||||
@@ -585,13 +431,6 @@ bool LLApp::isExiting()
|
||||
|
||||
void LLApp::disableCrashlogger()
|
||||
{
|
||||
// Disable Breakpad exception handler.
|
||||
if (mExceptionHandler != 0)
|
||||
{
|
||||
delete mExceptionHandler;
|
||||
mExceptionHandler = 0;
|
||||
}
|
||||
|
||||
sDisableCrashlogger = TRUE;
|
||||
}
|
||||
|
||||
@@ -660,12 +499,6 @@ LONG WINAPI default_windows_exception_handler(struct _EXCEPTION_POINTERS *except
|
||||
ms_sleep(10);
|
||||
}
|
||||
|
||||
//
|
||||
// Generate a minidump if we can.
|
||||
//
|
||||
// TODO: This needs to be ported over form the viewer-specific
|
||||
// LLWinDebug class
|
||||
|
||||
//
|
||||
// At this point, we always want to exit the app. There's no graceful
|
||||
// recovery for an unhandled exception.
|
||||
@@ -965,150 +798,4 @@ 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);
|
||||
|
||||
LL_INFOS() << "generated minidump: " << LLApp::instance()->getMiniDumpFilename() << LL_ENDL;
|
||||
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);
|
||||
}
|
||||
|
||||
LL_INFOS() << "generated minidump: " << path << LL_ENDL;
|
||||
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);
|
||||
}
|
||||
|
||||
LL_INFOS() << "generated minidump: " << LLApp::instance()->getMiniDumpFilename() << LL_ENDL;
|
||||
// *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
|
||||
LL_INFOS() << "Entering Windows Exception Handler..." << LL_ENDL;
|
||||
|
||||
if (LLApp::isError())
|
||||
{
|
||||
LL_WARNS() << "Got another fatal signal while in the error handler, die now!" << LL_ENDL;
|
||||
}
|
||||
|
||||
// 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
|
||||
|
||||
@@ -60,10 +60,6 @@ public:
|
||||
};
|
||||
#endif
|
||||
|
||||
namespace google_breakpad {
|
||||
class ExceptionHandler; // See exception_handler.h
|
||||
}
|
||||
|
||||
class LL_COMMON_API LLApp : public LLOptionInterface
|
||||
{
|
||||
friend class LLErrorThread;
|
||||
@@ -233,22 +229,11 @@ public:
|
||||
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)
|
||||
@@ -281,8 +266,6 @@ protected:
|
||||
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.
|
||||
typedef std::map<pid_t, LLChildInfo> child_map; // Map key is a PID
|
||||
@@ -290,16 +273,13 @@ protected:
|
||||
static LLAppChildCallback sDefaultChildCallback;
|
||||
#endif
|
||||
|
||||
void startErrorThread();
|
||||
|
||||
/**
|
||||
* @brief This method is called at the end, just prior to deinitializing curl.
|
||||
*/
|
||||
void stopErrorThread();
|
||||
|
||||
private:
|
||||
// Contains the filename of the minidump file after a crash.
|
||||
char mMinidumpPath[MAX_MINDUMP_PATH_LENGTH];
|
||||
void startErrorThread();
|
||||
|
||||
std::string mStaticDebugFileName;
|
||||
std::string mDynamicDebugFileName;
|
||||
@@ -323,11 +303,8 @@ private:
|
||||
std::vector<LLLiveFile*> mLiveFiles;
|
||||
//@}
|
||||
|
||||
private:
|
||||
// the static application instance if it was created.
|
||||
static LLApp* sApplication;
|
||||
google_breakpad::ExceptionHandler * mExceptionHandler;
|
||||
|
||||
|
||||
#if !LL_WINDOWS
|
||||
friend void default_unix_signal_handler(int signum, siginfo_t *info, void *);
|
||||
|
||||
@@ -960,5 +960,4 @@ P(webProfileResponders);
|
||||
P(wholeModelFeeResponder);
|
||||
P(wholeModelUploadResponder);
|
||||
P2(XMLRPCResponder, connect_40s);
|
||||
P2(crashLoggerResponder, transfer_300s);
|
||||
P(getUpdateInfoResponder);
|
||||
@@ -12,6 +12,7 @@ include(BuildPackagesInfo)
|
||||
include(BuildVersion)
|
||||
include(BuildBranding)
|
||||
include(CMakeCopyIfDifferent)
|
||||
include(CrashPad)
|
||||
include(DBusGlib)
|
||||
include(FMODSTUDIO)
|
||||
include(GeneratePrecompiledHeader)
|
||||
@@ -49,6 +50,11 @@ include(WinManifest)
|
||||
include(ZLIB)
|
||||
include(URIPARSER)
|
||||
|
||||
|
||||
if(USE_CRASHPAD)
|
||||
include_directories(${CRASHPAD_INCLUDE_DIRS})
|
||||
endif(USE_CRASHPAD)
|
||||
|
||||
include_directories(
|
||||
${STATEMACHINE_INCLUDE_DIRS}
|
||||
${DBUSGLIB_INCLUDE_DIRS}
|
||||
@@ -143,7 +149,6 @@ set(viewer_SOURCE_FILES
|
||||
llconfirmationmanager.cpp
|
||||
llconsole.cpp
|
||||
llcontrolavatar.cpp
|
||||
llcrashlogger.cpp
|
||||
llcurrencyuimanager.cpp
|
||||
llcylinder.cpp
|
||||
lldaycyclemanager.cpp
|
||||
@@ -681,7 +686,6 @@ set(viewer_HEADER_FILES
|
||||
llconfirmationmanager.h
|
||||
llconsole.h
|
||||
llcontrolavatar.h
|
||||
llcrashlogger.h
|
||||
llcurrencyuimanager.h
|
||||
llcylinder.h
|
||||
lldaycyclemanager.h
|
||||
@@ -1375,7 +1379,6 @@ set(viewer_APPSETTINGS_FILES
|
||||
app_settings/settings.xml
|
||||
app_settings/settings_ascent.xml
|
||||
app_settings/settings_ascent_coa.xml
|
||||
app_settings/settings_crash_behavior.xml
|
||||
app_settings/settings_files.xml
|
||||
app_settings/settings_per_account.xml
|
||||
app_settings/settings_sh.xml
|
||||
@@ -1624,6 +1627,7 @@ target_link_libraries(${VIEWER_BINARY_NAME}
|
||||
${PNG_PRELOAD_ARCHIVES}
|
||||
${ZLIB_PRELOAD_ARCHIVES}
|
||||
${GOOGLE_PERFTOOLS_LIBRARIES}
|
||||
${CRASHPAD_LIBRARIES}
|
||||
${LLAUDIO_LIBRARIES}
|
||||
${LLAUDIO_VORBIS_LIBRARIES}
|
||||
${LLCHARACTER_LIBRARIES}
|
||||
@@ -1823,8 +1827,10 @@ if (INSTALL)
|
||||
include(${CMAKE_CURRENT_SOURCE_DIR}/ViewerInstall.cmake)
|
||||
endif (INSTALL)
|
||||
|
||||
if (PACKAGE)
|
||||
if (PACKAGE AND USE_CRASHPAD)
|
||||
# Breakpad symbol-file generation
|
||||
set(SYMBOL_NAME ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${VIEWER_CHANNEL_NOSPACE}-${VIEWER_SHORT_VERSION}.${VIEWER_VERSION_REVISION}-symbols)
|
||||
|
||||
set(SYMBOL_SEARCH_DIRS "")
|
||||
if (WINDOWS)
|
||||
list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}")
|
||||
@@ -1854,7 +1860,6 @@ if (PACKAGE)
|
||||
set(VIEWER_COPY_MANIFEST copy_l_viewer_manifest)
|
||||
endif (LINUX)
|
||||
|
||||
if(RELEASE_CRASH_REPORTING OR NON_RELEASE_CRASH_REPORTING)
|
||||
if(GEN_IS_MULTI_CONFIG)
|
||||
set(LLBUILD_CONFIG ${CMAKE_BUILD_TYPE})
|
||||
else()
|
||||
@@ -1875,14 +1880,14 @@ if (PACKAGE)
|
||||
DEPENDS generate_breakpad_symbols.py
|
||||
VERBATIM)
|
||||
|
||||
add_custom_target(generate_breakpad_symbols DEPENDS "${VIEWER_SYMBOL_FILE}")
|
||||
add_dependencies(generate_breakpad_symbols ${VIEWER_BINARY_NAME})
|
||||
if(VIEWER_COPY_MANIFEST)
|
||||
add_dependencies(generate_breakpad_symbols ${VIEWER_COPY_MANIFEST})
|
||||
endif(VIEWER_COPY_MANIFEST)
|
||||
add_dependencies(llpackage generate_breakpad_symbols)
|
||||
endif(RELEASE_CRASH_REPORTING OR NON_RELEASE_CRASH_REPORTING)
|
||||
endif (PACKAGE)
|
||||
add_custom_target(generate_symbols DEPENDS "${VIEWER_SYMBOL_FILE}" ${VIEWER_BINARY_NAME} "${VIEWER_COPY_MANIFEST}")
|
||||
add_dependencies(generate_symbols ${VIEWER_BINARY_NAME})
|
||||
if (WINDOWS OR LINUX)
|
||||
add_dependencies(generate_symbols "${VIEWER_COPY_MANIFEST}")
|
||||
endif (WINDOWS OR LINUX)
|
||||
|
||||
add_dependencies(llpackage generate_symbols)
|
||||
endif ()
|
||||
|
||||
# Add tests
|
||||
if (LL_TESTS)
|
||||
|
||||
@@ -2538,17 +2538,6 @@ 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>
|
||||
@@ -18971,24 +18960,13 @@ This should be as low as possible, but too low may break functionality</string>
|
||||
<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>
|
||||
<string>Controls behavior when viewer crashes (0 = never send crash report, 1 = always send crash report)</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>S32</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>CrashReportID</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>ID of the last crash report sent. Zero indicates that no crash report has been sent. Non-zero value can be useful infermation for developers to track a specific issue</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>S32</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
<integer>-1</integer>
|
||||
</map>
|
||||
|
||||
<key>EveryoneCopy</key>
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
<llsd>
|
||||
<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>2</integer>
|
||||
<key>Type</key>
|
||||
<string>S32</string>
|
||||
<key>Value</key>
|
||||
<integer>1</integer>
|
||||
</map>
|
||||
</map>
|
||||
</llsd>
|
||||
@@ -43,13 +43,6 @@
|
||||
<key>Requirement</key>
|
||||
<integer>1</integer>
|
||||
</map>
|
||||
<key>CrashSettings</key>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>settings_crash_behavior.xml</string>
|
||||
<key>Requirement</key>
|
||||
<integer>1</integer>
|
||||
</map>
|
||||
</map>
|
||||
</map>
|
||||
<key>User</key>
|
||||
@@ -65,11 +58,6 @@
|
||||
<key>NameFromSetting</key>
|
||||
<string>ClientSettingsFile</string>
|
||||
</map>
|
||||
<key>CrashSettings</key>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>settings_crash_behavior.xml</string>
|
||||
</map>
|
||||
</map>
|
||||
</map>
|
||||
<key>Account</key>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -76,6 +76,7 @@ public:
|
||||
|
||||
bool quitRequested() { return mQuitRequested; }
|
||||
bool logoutRequestSent() { return mLogoutRequestSent; }
|
||||
bool isSecondInstance() { return mSecondInstance; }
|
||||
|
||||
void writeDebugInfo(bool isStatic=true);
|
||||
|
||||
@@ -86,7 +87,7 @@ public:
|
||||
|
||||
virtual bool restoreErrorTrap() = 0; // Require platform specific override to reset error handling mechanism.
|
||||
// return false if the error trap needed restoration.
|
||||
virtual void initCrashReporting(bool reportFreeze = false) = 0; // What to do with crash report?
|
||||
void initCrashReporting(); // What to do with crash report?
|
||||
static void handleViewerCrash(); // Hey! The viewer crashed. Do this, soon.
|
||||
|
||||
// Thread accessors
|
||||
@@ -113,7 +114,7 @@ public:
|
||||
void loadNameCache();
|
||||
void saveNameCache();
|
||||
|
||||
void removeMarkerFile(bool leave_logout_marker = false);
|
||||
void removeMarkerFiles();
|
||||
|
||||
void removeDumpDir();
|
||||
// LLAppViewer testing helpers.
|
||||
@@ -125,14 +126,13 @@ public:
|
||||
virtual void forceErrorSoftwareException();
|
||||
virtual void forceErrorDriverCrash();
|
||||
|
||||
// *NOTE: There are currently 3 settings files:
|
||||
// "Global", "PerAccount" and "CrashSettings"
|
||||
// *NOTE: There are currently 2 settings files:
|
||||
// "Global", and "PerAccount"
|
||||
// The list is found in app_settings/settings_files.xml
|
||||
// but since they are used explicitly in code,
|
||||
// the follow consts should also do the trick.
|
||||
static const std::string sGlobalSettingsName;
|
||||
static const std::string sPerAccountSettingsName;
|
||||
static const std::string sCrashSettingsName;
|
||||
|
||||
// Load settings from the location specified by loction_key.
|
||||
// Key availale and rules for loading, are specified in
|
||||
@@ -158,6 +158,7 @@ public:
|
||||
void handleLoginComplete();
|
||||
|
||||
LLAllocator & getAllocator() { return mAlloc; }
|
||||
|
||||
// On LoginCompleted callback
|
||||
typedef boost::signals2::signal<void (void)> login_completed_signal_t;
|
||||
login_completed_signal_t mOnLoginCompleted;
|
||||
@@ -172,7 +173,8 @@ public:
|
||||
static void metricsSend(bool enable_reporting);
|
||||
protected:
|
||||
virtual bool initWindow(); // Initialize the viewer's window.
|
||||
virtual bool initLogging(); // Initialize log files, logging system, return false on failure.
|
||||
virtual void initLoggingAndGetLastDuration(); // Initialize log files, logging system
|
||||
void initLoggingInternal();
|
||||
virtual void initConsole() {}; // Initialize OS level debugging console.
|
||||
virtual bool initHardwareTest() { return true; } // A false result indicates the app should quit.
|
||||
virtual bool initSLURLHandler();
|
||||
@@ -189,7 +191,6 @@ private:
|
||||
void initMaxHeapSize();
|
||||
bool initThreads(); // Initialize viewer threads, return false on failure.
|
||||
bool initConfiguration(); // Initialize settings from the command line/config file.
|
||||
|
||||
bool initCache(); // Initialize local client cache.
|
||||
void checkMemory() ;
|
||||
|
||||
@@ -202,8 +203,9 @@ private:
|
||||
|
||||
void writeSystemInfo(); // Write system info to "debug_info.log"
|
||||
|
||||
bool anotherInstanceRunning();
|
||||
void initMarkerFile();
|
||||
void processMarkerFiles();
|
||||
static void recordMarkerVersion(LLAPRFile& marker_file);
|
||||
bool markerIsSameVersion(const std::string& marker_name) const;
|
||||
|
||||
void idle();
|
||||
void idleShutdown();
|
||||
@@ -226,8 +228,7 @@ private:
|
||||
LLAPRFile mMarkerFile; // A file created to indicate the app is running.
|
||||
|
||||
std::string mLogoutMarkerFileName;
|
||||
apr_file_t* mLogoutMarkerFile; // A file created to indicate the app is running.
|
||||
|
||||
LLAPRFile mLogoutMarkerFile; // A file created to indicate the app is running.
|
||||
|
||||
LLOSInfo mSysOSInfo;
|
||||
bool mReportedCrash;
|
||||
|
||||
@@ -119,7 +119,6 @@ int main( int argc, char **argv )
|
||||
}
|
||||
delete viewer_app_ptr;
|
||||
viewer_app_ptr = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -143,20 +142,12 @@ bool LLAppViewerLinux::init()
|
||||
|
||||
bool success = LLAppViewer::init();
|
||||
|
||||
#if LL_SEND_CRASH_REPORTS
|
||||
if (success)
|
||||
{
|
||||
LLAppViewer* pApp = LLAppViewer::instance();
|
||||
pApp->initCrashReporting();
|
||||
}
|
||||
#endif
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
bool LLAppViewerLinux::restoreErrorTrap()
|
||||
{
|
||||
// *NOTE:Mani there is a case for implementing this or the mac.
|
||||
// *NOTE:Mani there is a case for implementing this on the mac.
|
||||
// Linux doesn't need it to my knowledge.
|
||||
return true;
|
||||
}
|
||||
@@ -347,12 +338,6 @@ bool LLAppViewerLinux::sendURLToOtherInstance(const std::string& url)
|
||||
}
|
||||
#endif // LL_DBUS_ENABLED
|
||||
|
||||
void LLAppViewerLinux::initCrashReporting(bool reportFreeze)
|
||||
{
|
||||
// Singu Note: this is where original code forks crash logger process.
|
||||
// Singularity doesn't need it
|
||||
}
|
||||
|
||||
bool LLAppViewerLinux::beingDebugged()
|
||||
{
|
||||
static enum {unknown, no, yes} debugged = unknown;
|
||||
@@ -397,7 +382,7 @@ bool LLAppViewerLinux::beingDebugged()
|
||||
#endif
|
||||
}
|
||||
|
||||
bool LLAppViewerLinux::initLogging()
|
||||
void LLAppViewerLinux::initLoggingAndGetLastDuration()
|
||||
{
|
||||
// Remove the last stack trace, if any
|
||||
// This file is no longer created, since the move to Google Breakpad
|
||||
@@ -406,7 +391,7 @@ bool LLAppViewerLinux::initLogging()
|
||||
gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stack_trace.log");
|
||||
LLFile::remove(old_stack_file);
|
||||
|
||||
return LLAppViewer::initLogging();
|
||||
LLAppViewer::initLoggingAndGetLastDuration();
|
||||
}
|
||||
|
||||
bool LLAppViewerLinux::initParseCommandLine(LLCommandLineParser& clp)
|
||||
|
||||
@@ -66,7 +66,7 @@ protected:
|
||||
virtual bool restoreErrorTrap();
|
||||
virtual void initCrashReporting(bool reportFreeze);
|
||||
|
||||
virtual bool initLogging();
|
||||
virtual void initLoggingAndGetLastDuration();
|
||||
virtual bool initParseCommandLine(LLCommandLineParser& clp);
|
||||
|
||||
virtual bool initSLURLHandler();
|
||||
|
||||
@@ -260,12 +260,6 @@ bool LLAppViewerMacOSX::restoreErrorTrap()
|
||||
return reset_count == 0;
|
||||
}
|
||||
|
||||
void LLAppViewerMacOSX::initCrashReporting(bool reportFreeze)
|
||||
{
|
||||
// Singu Note: this is where original code forks crash logger process.
|
||||
// Singularity doesn't need it
|
||||
}
|
||||
|
||||
std::string LLAppViewerMacOSX::generateSerialNumber()
|
||||
{
|
||||
char serial_md5[MD5HEX_STR_SIZE]; // Flawfinder: ignore
|
||||
|
||||
@@ -32,12 +32,6 @@
|
||||
|
||||
#include "llviewerprecompiledheaders.h"
|
||||
|
||||
#if defined(_DEBUG)
|
||||
# if _MSC_VER >= 1400 // Visual C++ 2005 or later
|
||||
# define WINDOWS_CRT_MEM_CHECKS 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include "llwindowwin32.h" // *FIX: for setting gIconResource.
|
||||
|
||||
#include "llappviewerwin32.h"
|
||||
@@ -73,19 +67,6 @@
|
||||
#include "llcommandlineparser.h"
|
||||
#include "lltrans.h"
|
||||
|
||||
// *FIX:Mani - This hack is to fix a linker issue with libndofdev.lib
|
||||
// The lib was compiled under VS2005 - in VS2003 we need to remap assert
|
||||
#ifdef LL_DEBUG
|
||||
#ifdef LL_MSVC7
|
||||
extern "C" {
|
||||
void _wassert(const wchar_t * _Message, const wchar_t *_File, unsigned _Line)
|
||||
{
|
||||
LL_ERRS() << _Message << LL_ENDL;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
const std::string LLAppViewerWin32::sWindowClass = "Second Life";
|
||||
|
||||
// Create app mutex creates a unique global windows object.
|
||||
@@ -101,7 +82,7 @@ bool create_app_mutex()
|
||||
bool result = true;
|
||||
LPCWSTR unique_mutex_name = L"SecondLifeAppMutex";
|
||||
HANDLE hMutex;
|
||||
hMutex = CreateMutex(NULL, TRUE, unique_mutex_name);
|
||||
hMutex = CreateMutex(nullptr, TRUE, unique_mutex_name);
|
||||
if(GetLastError() == ERROR_ALREADY_EXISTS)
|
||||
{
|
||||
result = false;
|
||||
@@ -240,7 +221,9 @@ int APIENTRY WINMAIN(HINSTANCE hInstance,
|
||||
|
||||
LLAppViewerWin32* viewer_app_ptr = new LLAppViewerWin32(lpCmdLine);
|
||||
|
||||
#if !defined(USE_CRASHPAD)
|
||||
viewer_app_ptr->setErrorHandler(LLAppViewer::handleViewerCrash);
|
||||
#endif
|
||||
|
||||
// Set a debug info flag to indicate if multiple instances are running.
|
||||
bool found_other_instance = !create_app_mutex();
|
||||
@@ -332,7 +315,7 @@ int APIENTRY WINMAIN(HINSTANCE hInstance,
|
||||
|
||||
}
|
||||
delete viewer_app_ptr;
|
||||
viewer_app_ptr = NULL;
|
||||
viewer_app_ptr = nullptr;
|
||||
|
||||
//start updater
|
||||
if(LLAppViewer::sUpdaterInfo)
|
||||
@@ -392,13 +375,13 @@ void LLAppViewerWin32::disableWinErrorReporting()
|
||||
|
||||
const S32 MAX_CONSOLE_LINES = 500;
|
||||
|
||||
void create_console()
|
||||
static bool create_console()
|
||||
{
|
||||
|
||||
CONSOLE_SCREEN_BUFFER_INFO coninfo;
|
||||
|
||||
// allocate a console for this app
|
||||
AllocConsole();
|
||||
const bool isConsoleAllocated = AllocConsole();
|
||||
|
||||
// set the screen buffer to be big enough to let us scroll text
|
||||
GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &coninfo);
|
||||
@@ -410,16 +393,16 @@ void create_console()
|
||||
freopen("CONOUT$", "w", stdout);
|
||||
freopen("CONOUT$", "w", stderr);
|
||||
|
||||
setvbuf( stdin, NULL, _IONBF, 0 );
|
||||
setvbuf( stdout, NULL, _IONBF, 0 );
|
||||
setvbuf( stderr, NULL, _IONBF, 0 );
|
||||
|
||||
setvbuf( stdin, nullptr, _IONBF, 0 );
|
||||
setvbuf( stdout, nullptr, _IONBF, 0 );
|
||||
setvbuf( stderr, nullptr, _IONBF, 0 );
|
||||
|
||||
return isConsoleAllocated;
|
||||
}
|
||||
|
||||
|
||||
LLAppViewerWin32::LLAppViewerWin32(const char* cmd_line) :
|
||||
mCmdLine(cmd_line)
|
||||
mCmdLine(cmd_line),
|
||||
mIsConsoleAllocated(false)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -442,15 +425,6 @@ bool LLAppViewerWin32::init()
|
||||
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;
|
||||
@@ -462,18 +436,24 @@ bool LLAppViewerWin32::cleanup()
|
||||
|
||||
gDXHardware.cleanup();
|
||||
|
||||
if (mIsConsoleAllocated)
|
||||
{
|
||||
FreeConsole();
|
||||
mIsConsoleAllocated = false;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool LLAppViewerWin32::initLogging()
|
||||
void LLAppViewerWin32::initLoggingAndGetLastDuration()
|
||||
{
|
||||
return LLAppViewer::initLogging();
|
||||
LLAppViewer::initLoggingAndGetLastDuration();
|
||||
}
|
||||
|
||||
void LLAppViewerWin32::initConsole()
|
||||
{
|
||||
// pop up debug console
|
||||
create_console();
|
||||
mIsConsoleAllocated = create_console();
|
||||
return LLAppViewer::initConsole();
|
||||
}
|
||||
|
||||
@@ -571,7 +551,7 @@ bool LLAppViewerWin32::initParseCommandLine(LLCommandLineParser& clp)
|
||||
}
|
||||
|
||||
// Find the system language.
|
||||
FL_Locale *locale = NULL;
|
||||
FL_Locale *locale = nullptr;
|
||||
FL_Success success = FL_FindLocale(&locale, FL_MESSAGES);
|
||||
if (success != 0)
|
||||
{
|
||||
@@ -595,12 +575,6 @@ bool LLAppViewerWin32::initParseCommandLine(LLCommandLineParser& clp)
|
||||
bool LLAppViewerWin32::restoreErrorTrap()
|
||||
{
|
||||
return true;
|
||||
//return LLWinDebug::checkExceptionHandler();
|
||||
}
|
||||
|
||||
void LLAppViewerWin32::initCrashReporting(bool reportFreeze)
|
||||
{
|
||||
// Singu Note: we don't fork the crash logger on start
|
||||
}
|
||||
|
||||
//virtual
|
||||
@@ -610,9 +584,9 @@ bool LLAppViewerWin32::sendURLToOtherInstance(const std::string& url)
|
||||
mbstowcs(window_class, sWindowClass.c_str(), 255);
|
||||
window_class[255] = 0;
|
||||
// Use the class instead of the window name.
|
||||
HWND other_window = FindWindow(window_class, NULL);
|
||||
HWND other_window = FindWindow(window_class, nullptr);
|
||||
|
||||
if (other_window != NULL)
|
||||
if (other_window != nullptr)
|
||||
{
|
||||
LL_DEBUGS() << "Found other window with the name '" << getWindowTitle() << "'" << LL_ENDL;
|
||||
COPYDATASTRUCT cds;
|
||||
@@ -638,13 +612,13 @@ std::string LLAppViewerWin32::generateSerialNumber()
|
||||
DWORD serial = 0;
|
||||
DWORD flags = 0;
|
||||
BOOL success = GetVolumeInformation(
|
||||
L"C:\\",
|
||||
NULL, // volume name buffer
|
||||
TEXT("C:\\"),
|
||||
nullptr, // volume name buffer
|
||||
0, // volume name buffer size
|
||||
&serial, // volume serial
|
||||
NULL, // max component length
|
||||
nullptr, // max component length
|
||||
&flags, // file system flags
|
||||
NULL, // file system name buffer
|
||||
nullptr, // file system name buffer
|
||||
0); // file system name buffer size
|
||||
if (success)
|
||||
{
|
||||
|
||||
@@ -46,22 +46,20 @@ public:
|
||||
//
|
||||
// Main application logic
|
||||
//
|
||||
virtual bool init(); // Override to do application initialization
|
||||
virtual bool cleanup();
|
||||
bool init() override; // Override to do application initialization
|
||||
bool cleanup() override;
|
||||
|
||||
protected:
|
||||
virtual bool initLogging(); // Override to clean stack_trace info.
|
||||
virtual void initConsole(); // Initialize OS level debugging console.
|
||||
virtual bool initHardwareTest(); // Win32 uses DX9 to test hardware.
|
||||
virtual bool initParseCommandLine(LLCommandLineParser& clp);
|
||||
void initLoggingAndGetLastDuration() override; // Override to clean stack_trace info.
|
||||
void initConsole() override; // Initialize OS level debugging console.
|
||||
bool initHardwareTest() override; // Win32 uses DX9 to test hardware.
|
||||
bool initParseCommandLine(LLCommandLineParser& clp) override;
|
||||
|
||||
virtual bool restoreErrorTrap();
|
||||
virtual void initCrashReporting(bool reportFreeze);
|
||||
bool restoreErrorTrap() override;
|
||||
|
||||
virtual bool sendURLToOtherInstance(const std::string& url);
|
||||
|
||||
std::string generateSerialNumber();
|
||||
bool sendURLToOtherInstance(const std::string& url) override;
|
||||
|
||||
std::string generateSerialNumber() override;
|
||||
|
||||
static const std::string sWindowClass;
|
||||
|
||||
@@ -69,6 +67,7 @@ private:
|
||||
void disableWinErrorReporting();
|
||||
|
||||
std::string mCmdLine;
|
||||
bool mIsConsoleAllocated;
|
||||
};
|
||||
|
||||
#endif // LL_LLAPPVIEWERWIN32_H
|
||||
|
||||
@@ -1,418 +0,0 @@
|
||||
/**
|
||||
* @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 "llwindow.h"
|
||||
#include "lltrans.h"
|
||||
#include "aistatemachine.h"
|
||||
#include "boost/filesystem.hpp"
|
||||
|
||||
class AIHTTPTimeoutPolicy;
|
||||
extern AIHTTPTimeoutPolicy crashLoggerResponder_timeout;
|
||||
extern const std::string OLD_LOG_FILE;
|
||||
|
||||
class LLCrashLoggerResponder : public LLHTTPClient::ResponderWithResult
|
||||
{
|
||||
public:
|
||||
LLCrashLoggerResponder()
|
||||
{
|
||||
}
|
||||
|
||||
virtual void httpFailure(void)
|
||||
{
|
||||
LL_WARNS() << "Crash report sending failed: " << mReason << LL_ENDL;
|
||||
}
|
||||
|
||||
virtual void httpSuccess(void)
|
||||
{
|
||||
std::string msg = "Crash report successfully sent";
|
||||
if (mContent.has("message"))
|
||||
{
|
||||
msg += ": " + mContent["message"].asString();
|
||||
}
|
||||
LL_INFOS() << msg << LL_ENDL;
|
||||
|
||||
if (mContent.has("report_id"))
|
||||
{
|
||||
gSavedSettings.setS32("CrashReportID", mContent["report_id"].asInteger());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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 miniDumpExists(const std::string& dumpDir)
|
||||
{
|
||||
bool found = false;
|
||||
|
||||
try
|
||||
{
|
||||
if (!boost::filesystem::exists(dumpDir))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
boost::filesystem::directory_iterator end_itr;
|
||||
for (boost::filesystem::directory_iterator i(dumpDir); i != end_itr; ++i)
|
||||
{
|
||||
if (!boost::filesystem::is_regular_file(i->status())) continue;
|
||||
if (".dmp" == i->path().extension())
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const boost::filesystem::filesystem_error& e)
|
||||
{
|
||||
LL_WARNS() << "Failed to determine existance of the minidump file: '" + e.code().message() +"'" << LL_ENDL;
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
LL_INFOS() << "Gathering logs..." << LL_ENDL;
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
LL_INFOS() << "Using log file from debug log " << mFileMap["SecondLifeLog"] << LL_ENDL;
|
||||
LL_INFOS() << "Using settings file from debug log " << mFileMap["SettingsXml"] << LL_ENDL;
|
||||
}
|
||||
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");
|
||||
// Singu Note: we have just started again, log has been renamed
|
||||
mFileMap["SecondLifeLog"] = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, OLD_LOG_FILE);
|
||||
|
||||
LL_INFOS() << "Encoding files..." << LL_ENDL;
|
||||
|
||||
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())
|
||||
{
|
||||
LL_INFOS() << "Can't find file " << (*itr).second << LL_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] = 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();
|
||||
|
||||
LL_INFOS() << "Sending reports..." << LL_ENDL;
|
||||
|
||||
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()
|
||||
{
|
||||
#if LL_SEND_CRASH_REPORTS
|
||||
// 0 - ask, 1 - always send, 2 - never send
|
||||
S32 pref = gSavedSettings.getS32("CrashSubmitBehavior");
|
||||
if (pref == 2) return; //never send
|
||||
|
||||
mCrashHost = gSavedSettings.getString("CrashHostUrl");
|
||||
std::string dumpDir = gDirUtilp->getDumpDir();
|
||||
|
||||
// Do we have something to send, and somewhere to send it
|
||||
if (!mCrashHost.empty() && miniDumpExists(dumpDir))
|
||||
{
|
||||
if (pref == 1) // always send
|
||||
{
|
||||
sendCrashLog(dumpDir);
|
||||
}
|
||||
else // ask
|
||||
{
|
||||
U32 response = OSMessageBox(LLTrans::getString("MBFrozenCrashed"), LLTrans::getString("MBAlert"), OSMB_YESNO);
|
||||
if (response == OSBTN_YES)
|
||||
{
|
||||
sendCrashLog(dumpDir);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
/**
|
||||
* @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
|
||||
@@ -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(gSavedSettings.getS32(CRASH_BEHAVIOR_SETTING));
|
||||
crash_behavior_combobox->setValue(gSavedSettings.getS32("CrashSubmitBehavior"));
|
||||
|
||||
childSetValue("language_combobox", gSavedSettings.getString("Language"));
|
||||
|
||||
@@ -163,7 +163,7 @@ void LLPanelGeneral::apply()
|
||||
gSavedSettings.setString("Language", childGetValue("language_combobox"));
|
||||
|
||||
LLComboBox* crash_behavior_combobox = getChild<LLComboBox>("crash_behavior_combobox");
|
||||
gSavedSettings.setS32(CRASH_BEHAVIOR_SETTING, crash_behavior_combobox->getCurrentIndex());
|
||||
gSavedSettings.setS32("CrashSubmitBehavior", crash_behavior_combobox->getValue());
|
||||
}
|
||||
|
||||
void LLPanelGeneral::cancel()
|
||||
|
||||
@@ -94,7 +94,6 @@ AIThreadSafeDC<settings_map_type> gSettings;
|
||||
LLControlGroup gSavedSettings("Global"); // saved at end of session
|
||||
LLControlGroup gSavedPerAccountSettings("PerAccount"); // saved at end of session
|
||||
LLControlGroup gColors("Colors"); // saved at end of session
|
||||
LLControlGroup gCrashSettings("CrashSettings"); // saved at end of session
|
||||
|
||||
std::string gLastRunVersion;
|
||||
|
||||
|
||||
@@ -62,9 +62,6 @@ void create_graphics_group(LLControlGroup& group);
|
||||
// Read-only
|
||||
extern LLControlGroup gColors;
|
||||
|
||||
// Saved at end of session
|
||||
extern LLControlGroup gCrashSettings;
|
||||
|
||||
// Set after settings loaded
|
||||
extern std::string gLastRunVersion;
|
||||
|
||||
|
||||
@@ -11450,6 +11450,19 @@ Do you wish to export anyway?
|
||||
Object successfully exported to: [FILENAME]
|
||||
</notification>
|
||||
|
||||
<notification
|
||||
icon="alertmodal.tga"
|
||||
name="SubmitCrashReports"
|
||||
type="alertmodal">
|
||||
Would you like to help improve [SHORT_APP_NAME] by sending crash reports?
|
||||
|
||||
(You can change your answer in Preferences -> General -> Crash reports)
|
||||
<usetemplate
|
||||
name="okcancelbuttons"
|
||||
notext="No"
|
||||
yestext="Yes"/>
|
||||
</notification>
|
||||
|
||||
<notification
|
||||
icon="alertmodal.tga"
|
||||
name="SupportChatShowInfo"
|
||||
|
||||
@@ -67,9 +67,8 @@
|
||||
</combo_box>
|
||||
<string name="region_name_prompt"><Type region name></string>
|
||||
<combo_box bottom="-328" height="18" left="103" name="crash_behavior_combobox" width="140">
|
||||
<combo_item name="Askbeforesending" value="Ask before sending">Ask before sending</combo_item>
|
||||
<combo_item name="Alwayssend" value="Always send">Always send</combo_item>
|
||||
<combo_item name="Neversend" value="Never send">Never send</combo_item>
|
||||
<combo_item name="Neversend" value="0">Never send</combo_item>
|
||||
<combo_item name="Alwayssend" value="1">Always send</combo_item>
|
||||
</combo_box>
|
||||
<check_box bottom="-385" height="16" initial_value="false" label="Share language with objects" left="101" name="language_is_public" tool_tip="This lets in-world objects know your preferred language."/>
|
||||
<button bottom="-425" height="25" label="Reset All Settings" name="clear_settings" width="200" />
|
||||
|
||||
@@ -3833,6 +3833,7 @@ This can be because you somehow have multiple copies running, or your system inc
|
||||
If this message persists, restart your computer and try again.
|
||||
If it continues to persist, you may need to completely uninstall [APP_NAME] and reinstall it.
|
||||
</string>
|
||||
<string name="MBFatalError">Fatal Error. Crash and Loop?</string>
|
||||
<string name="MBAlreadyRunning">
|
||||
[APP_NAME] is already running.
|
||||
Check your task bar for a minimized copy of the program.
|
||||
|
||||
@@ -525,6 +525,12 @@ class WindowsManifest(ViewerManifest):
|
||||
except:
|
||||
print "Skipping msvc redist files"
|
||||
|
||||
# For crashpad
|
||||
with self.prefix(src=pkgbindir):
|
||||
self.path("crashpad_handler.exe")
|
||||
if not self.is_packaging_viewer():
|
||||
self.path("crashpad_handler.pdb")
|
||||
|
||||
self.path(src="licenses-win32.txt", dst="licenses.txt")
|
||||
self.path("featuretable.txt")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user