mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-07-08 01:01:56 +02:00
extirpate bugsplat
This commit is contained in:
parent
ced5aad1d1
commit
47f44eb21f
6 changed files with 2 additions and 298 deletions
|
@ -1,34 +0,0 @@
|
||||||
#
|
|
||||||
# AddBugSplat.cmake
|
|
||||||
# cmake/macros
|
|
||||||
#
|
|
||||||
# Created by Ryan Huffman on 02/09/16.
|
|
||||||
# Copyright 2016 High Fidelity, Inc.
|
|
||||||
#
|
|
||||||
# Distributed under the Apache License, Version 2.0.
|
|
||||||
# See the accompanying file LICENSE or http:#www.apache.org/licenses/LICENSE-2.0.html
|
|
||||||
#
|
|
||||||
|
|
||||||
macro(add_bugsplat)
|
|
||||||
get_property(BUGSPLAT_CHECKED GLOBAL PROPERTY CHECKED_FOR_BUGSPLAT_ONCE)
|
|
||||||
|
|
||||||
if (NOT BUGSPLAT_CHECKED)
|
|
||||||
find_package(BugSplat)
|
|
||||||
set_property(GLOBAL PROPERTY CHECKED_FOR_BUGSPLAT_ONCE TRUE)
|
|
||||||
endif ()
|
|
||||||
|
|
||||||
if (BUGSPLAT_FOUND)
|
|
||||||
add_definitions(-DHAS_BUGSPLAT)
|
|
||||||
|
|
||||||
target_include_directories(${TARGET_NAME} PRIVATE ${BUGSPLAT_INCLUDE_DIRS})
|
|
||||||
target_link_libraries(${TARGET_NAME} ${BUGSPLAT_LIBRARIES})
|
|
||||||
add_paths_to_fixup_libs(${BUGSPLAT_DLL_PATH})
|
|
||||||
|
|
||||||
add_custom_command(TARGET ${TARGET_NAME}
|
|
||||||
POST_BUILD
|
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy ${BUGSPLAT_RC_DLL_PATH} "$<TARGET_FILE_DIR:${TARGET_NAME}>/")
|
|
||||||
add_custom_command(TARGET ${TARGET_NAME}
|
|
||||||
POST_BUILD
|
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy ${BUGSPLAT_EXE_PATH} "$<TARGET_FILE_DIR:${TARGET_NAME}>/")
|
|
||||||
endif ()
|
|
||||||
endmacro()
|
|
|
@ -1,30 +0,0 @@
|
||||||
#
|
|
||||||
# FindBugSplat.cmake
|
|
||||||
# cmake/modules
|
|
||||||
#
|
|
||||||
# Created by Ryan Huffman on 02/09/16.
|
|
||||||
# Copyright 2016 High Fidelity, Inc.
|
|
||||||
#
|
|
||||||
# Distributed under the Apache License, Version 2.0.
|
|
||||||
# See the accompanying file LICENSE or http:#www.apache.org/licenses/LICENSE-2.0.html
|
|
||||||
#
|
|
||||||
|
|
||||||
if (WIN32)
|
|
||||||
include("${MACRO_DIR}/HifiLibrarySearchHints.cmake")
|
|
||||||
hifi_library_search_hints("BugSplat")
|
|
||||||
|
|
||||||
find_path(BUGSPLAT_INCLUDE_DIRS NAMES BugSplat.h PATH_SUFFIXES inc HINTS ${BUGSPLAT_SEARCH_DIRS})
|
|
||||||
|
|
||||||
find_library(BUGSPLAT_LIBRARY_RELEASE "BugSplat64.lib" PATH_SUFFIXES "lib64" HINTS ${BUGSPLAT_SEARCH_DIRS})
|
|
||||||
find_path(BUGSPLAT_DLL_PATH NAMES "BugSplat64.dll" PATH_SUFFIXES "bin64" HINTS ${BUGSPLAT_SEARCH_DIRS})
|
|
||||||
find_file(BUGSPLAT_RC_DLL_PATH NAMES "BugSplatRc64.dll" PATH_SUFFIXES "bin64" HINTS ${BUGSPLAT_SEARCH_DIRS})
|
|
||||||
find_file(BUGSPLAT_EXE_PATH NAMES "BsSndRpt64.exe" PATH_SUFFIXES "bin64" HINTS ${BUGSPLAT_SEARCH_DIRS})
|
|
||||||
|
|
||||||
include(SelectLibraryConfigurations)
|
|
||||||
select_library_configurations(BUGSPLAT)
|
|
||||||
|
|
||||||
set(BUGSPLAT_LIBRARIES ${BUGSPLAT_LIBRARY_RELEASE})
|
|
||||||
endif ()
|
|
||||||
|
|
||||||
set(BUGSPLAT_REQUIREMENTS BUGSPLAT_INCLUDE_DIRS BUGSPLAT_LIBRARIES BUGSPLAT_DLL_PATH BUGSPLAT_RC_DLL_PATH BUGSPLAT_EXE_PATH)
|
|
||||||
find_package_handle_standard_args(BugSplat DEFAULT_MSG ${BUGSPLAT_REQUIREMENTS})
|
|
|
@ -347,8 +347,6 @@ if (SCRIPTS_INSTALL_DIR)
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_bugsplat()
|
|
||||||
|
|
||||||
package_crashpad_for_deployment()
|
package_crashpad_for_deployment()
|
||||||
|
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
|
|
|
@ -1,166 +0,0 @@
|
||||||
//
|
|
||||||
// CrashReporter.cpp
|
|
||||||
// interface/src
|
|
||||||
//
|
|
||||||
// Created by Ryan Huffman on 11 April 2016.
|
|
||||||
// Copyright 2016 High Fidelity, Inc.
|
|
||||||
//
|
|
||||||
// Distributed under the Apache License, Version 2.0.
|
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
#include "Application.h"
|
|
||||||
#include "CrashReporter.h"
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
#include <new.h>
|
|
||||||
#include <Windows.h>
|
|
||||||
#include <DbgHelp.h>
|
|
||||||
|
|
||||||
#include <csignal>
|
|
||||||
#include <QDebug>
|
|
||||||
|
|
||||||
|
|
||||||
#pragma comment(lib, "Dbghelp.lib")
|
|
||||||
|
|
||||||
// SetUnhandledExceptionFilter can be overridden by the CRT at the point that an error occurs. More information
|
|
||||||
// can be found here: http://www.codeproject.com/Articles/154686/SetUnhandledExceptionFilter-and-the-C-C-Runtime-Li
|
|
||||||
// A fairly common approach is to patch the SetUnhandledExceptionFilter so that it cannot be overridden and so
|
|
||||||
// that the applicaiton can handle it itself.
|
|
||||||
// The CAPIHook class referenced in the above article is not openly available, but a similar implementation
|
|
||||||
// can be found here: http://blog.kalmbach-software.de/2008/04/02/unhandled-exceptions-in-vc8-and-above-for-x86-and-x64/
|
|
||||||
// The below has been adapted to work with different library and functions.
|
|
||||||
BOOL redirectLibraryFunctionToFunction(char* library, char* function, void* fn)
|
|
||||||
{
|
|
||||||
HMODULE lib = LoadLibrary(library);
|
|
||||||
if (lib == NULL) return FALSE;
|
|
||||||
void *pOrgEntry = GetProcAddress(lib, function);
|
|
||||||
if (pOrgEntry == NULL) return FALSE;
|
|
||||||
|
|
||||||
DWORD dwOldProtect = 0;
|
|
||||||
SIZE_T jmpSize = 5;
|
|
||||||
#ifdef _M_X64
|
|
||||||
jmpSize = 13;
|
|
||||||
#endif
|
|
||||||
BOOL bProt = VirtualProtect(pOrgEntry, jmpSize,
|
|
||||||
PAGE_EXECUTE_READWRITE, &dwOldProtect);
|
|
||||||
BYTE newJump[20];
|
|
||||||
void *pNewFunc = fn;
|
|
||||||
#ifdef _M_IX86
|
|
||||||
DWORD dwOrgEntryAddr = (DWORD)pOrgEntry;
|
|
||||||
dwOrgEntryAddr += jmpSize; // add 5 for 5 op-codes for jmp rel32
|
|
||||||
DWORD dwNewEntryAddr = (DWORD)pNewFunc;
|
|
||||||
DWORD dwRelativeAddr = dwNewEntryAddr - dwOrgEntryAddr;
|
|
||||||
// JMP rel32: Jump near, relative, displacement relative to next instruction.
|
|
||||||
newJump[0] = 0xE9; // JMP rel32
|
|
||||||
memcpy(&newJump[1], &dwRelativeAddr, sizeof(pNewFunc));
|
|
||||||
#elif _M_X64
|
|
||||||
// We must use R10 or R11, because these are "scratch" registers
|
|
||||||
// which need not to be preserved accross function calls
|
|
||||||
// For more info see: Register Usage for x64 64-Bit
|
|
||||||
// http://msdn.microsoft.com/en-us/library/ms794547.aspx
|
|
||||||
// Thanks to Matthew Smith!!!
|
|
||||||
newJump[0] = 0x49; // MOV R11, ...
|
|
||||||
newJump[1] = 0xBB; // ...
|
|
||||||
memcpy(&newJump[2], &pNewFunc, sizeof(pNewFunc));
|
|
||||||
//pCur += sizeof (ULONG_PTR);
|
|
||||||
newJump[10] = 0x41; // JMP R11, ...
|
|
||||||
newJump[11] = 0xFF; // ...
|
|
||||||
newJump[12] = 0xE3; // ...
|
|
||||||
#endif
|
|
||||||
SIZE_T bytesWritten;
|
|
||||||
BOOL bRet = WriteProcessMemory(GetCurrentProcess(),
|
|
||||||
pOrgEntry, newJump, jmpSize, &bytesWritten);
|
|
||||||
|
|
||||||
if (bProt != FALSE)
|
|
||||||
{
|
|
||||||
DWORD dwBuf;
|
|
||||||
VirtualProtect(pOrgEntry, jmpSize, dwOldProtect, &dwBuf);
|
|
||||||
}
|
|
||||||
return bRet;
|
|
||||||
}
|
|
||||||
|
|
||||||
void printStackTrace(ULONG framesToSkip = 1) {
|
|
||||||
HANDLE process = GetCurrentProcess();
|
|
||||||
SymInitialize(process, NULL, TRUE);
|
|
||||||
void* stack[100];
|
|
||||||
uint16_t frames = CaptureStackBackTrace(framesToSkip, 100, stack, NULL);
|
|
||||||
SYMBOL_INFO* symbol = (SYMBOL_INFO *)calloc(sizeof(SYMBOL_INFO) + 256 * sizeof(char), 1);
|
|
||||||
symbol->MaxNameLen = 255;
|
|
||||||
symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
|
|
||||||
|
|
||||||
for (uint16_t i = 0; i < frames; ++i) {
|
|
||||||
SymFromAddr(process, (DWORD64)(stack[i]), 0, symbol);
|
|
||||||
qWarning() << QString("%1: %2 - 0x%0X").arg(QString::number(frames - i - 1), QString(symbol->Name), QString::number(symbol->Address, 16));
|
|
||||||
}
|
|
||||||
|
|
||||||
free(symbol);
|
|
||||||
|
|
||||||
// Try to force the log to sync to the filesystem
|
|
||||||
auto app = qApp;
|
|
||||||
if (app && app->getLogger()) {
|
|
||||||
app->getLogger()->sync();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void handleSignal(int signal) {
|
|
||||||
// Throw so BugSplat can handle
|
|
||||||
throw(signal);
|
|
||||||
}
|
|
||||||
|
|
||||||
void __cdecl handlePureVirtualCall() {
|
|
||||||
qWarning() << "Pure virtual function call detected";
|
|
||||||
printStackTrace(2);
|
|
||||||
// Throw so BugSplat can handle
|
|
||||||
throw("ERROR: Pure virtual call");
|
|
||||||
}
|
|
||||||
|
|
||||||
void handleInvalidParameter(const wchar_t * expression, const wchar_t * function, const wchar_t * file,
|
|
||||||
unsigned int line, uintptr_t pReserved ) {
|
|
||||||
// Throw so BugSplat can handle
|
|
||||||
throw("ERROR: Invalid parameter");
|
|
||||||
}
|
|
||||||
|
|
||||||
int handleNewError(size_t size) {
|
|
||||||
// Throw so BugSplat can handle
|
|
||||||
throw("ERROR: Errors calling new");
|
|
||||||
}
|
|
||||||
|
|
||||||
LPTOP_LEVEL_EXCEPTION_FILTER WINAPI noop_SetUnhandledExceptionFilter(LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
_purecall_handler __cdecl noop_set_purecall_handler(_purecall_handler pNew) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef HAS_BUGSPLAT
|
|
||||||
|
|
||||||
static const DWORD BUG_SPLAT_FLAGS = MDSF_PREVENTHIJACKING | MDSF_USEGUARDMEMORY;
|
|
||||||
|
|
||||||
CrashReporter::CrashReporter(QString bugSplatDatabase, QString bugSplatApplicationName, QString version)
|
|
||||||
: mpSender(qPrintable(bugSplatDatabase), qPrintable(bugSplatApplicationName), qPrintable(version), nullptr, BUG_SPLAT_FLAGS)
|
|
||||||
{
|
|
||||||
signal(SIGSEGV, handleSignal);
|
|
||||||
signal(SIGABRT, handleSignal);
|
|
||||||
_set_purecall_handler(handlePureVirtualCall);
|
|
||||||
_set_invalid_parameter_handler(handleInvalidParameter);
|
|
||||||
_set_new_mode(1);
|
|
||||||
_set_new_handler(handleNewError);
|
|
||||||
|
|
||||||
// Disable WER popup
|
|
||||||
//SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX);
|
|
||||||
//_set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
|
|
||||||
|
|
||||||
// QtWebEngineCore internally sets its own purecall handler, overriding our own error handling. This disables that.
|
|
||||||
if (!redirectLibraryFunctionToFunction("msvcr120.dll", "_set_purecall_handler", &noop_set_purecall_handler)) {
|
|
||||||
qWarning() << "Failed to patch _set_purecall_handler";
|
|
||||||
}
|
|
||||||
// Patch SetUnhandledExceptionFilter to keep the CRT from overriding our own error handling.
|
|
||||||
if (!redirectLibraryFunctionToFunction("kernel32.dll", "SetUnhandledExceptionFilter", &noop_SetUnhandledExceptionFilter)) {
|
|
||||||
qWarning() << "Failed to patch setUnhandledExceptionFilter";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#endif
|
|
|
@ -1,32 +0,0 @@
|
||||||
//
|
|
||||||
// CrashReporter.h
|
|
||||||
// interface/src
|
|
||||||
//
|
|
||||||
// Created by Ryan Huffman on 11 April 2016.
|
|
||||||
// Copyright 2016 High Fidelity, Inc.
|
|
||||||
//
|
|
||||||
// Distributed under the Apache License, Version 2.0.
|
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
|
||||||
//
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#ifndef hifi_CrashReporter_h
|
|
||||||
#define hifi_CrashReporter_h
|
|
||||||
|
|
||||||
#include <QString>
|
|
||||||
|
|
||||||
#ifdef HAS_BUGSPLAT
|
|
||||||
|
|
||||||
#include <BugSplat.h>
|
|
||||||
|
|
||||||
class CrashReporter {
|
|
||||||
public:
|
|
||||||
CrashReporter(QString bugSplatDatabase, QString bugSplatApplicationName, QString version);
|
|
||||||
|
|
||||||
MiniDmpSender mpSender;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // hifi_CrashReporter_h
|
|
|
@ -31,11 +31,6 @@
|
||||||
#include "UserActivityLogger.h"
|
#include "UserActivityLogger.h"
|
||||||
#include "MainWindow.h"
|
#include "MainWindow.h"
|
||||||
|
|
||||||
#ifdef HAS_BUGSPLAT
|
|
||||||
#include <BugSplat.h>
|
|
||||||
#include <CrashReporter.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
extern "C" {
|
extern "C" {
|
||||||
typedef int(__stdcall * CHECKMINSPECPROC) ();
|
typedef int(__stdcall * CHECKMINSPECPROC) ();
|
||||||
|
@ -43,11 +38,6 @@ extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int main(int argc, const char* argv[]) {
|
int main(int argc, const char* argv[]) {
|
||||||
#if HAS_BUGSPLAT
|
|
||||||
static QString BUG_SPLAT_DATABASE = "interface_alpha";
|
|
||||||
static QString BUG_SPLAT_APPLICATION_NAME = "Interface";
|
|
||||||
CrashReporter crashReporter { BUG_SPLAT_DATABASE, BUG_SPLAT_APPLICATION_NAME, BuildInfo::VERSION };
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef Q_OS_LINUX
|
#ifdef Q_OS_LINUX
|
||||||
QApplication::setAttribute(Qt::AA_DontUseNativeMenuBar);
|
QApplication::setAttribute(Qt::AA_DontUseNativeMenuBar);
|
||||||
|
@ -253,7 +243,6 @@ int main(int argc, const char* argv[]) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
// Setup local server
|
// Setup local server
|
||||||
QLocalServer server { &app };
|
QLocalServer server { &app };
|
||||||
|
|
||||||
|
@ -261,29 +250,8 @@ int main(int argc, const char* argv[]) {
|
||||||
server.removeServer(applicationName);
|
server.removeServer(applicationName);
|
||||||
server.listen(applicationName);
|
server.listen(applicationName);
|
||||||
|
|
||||||
QObject::connect(&server, &QLocalServer::newConnection, &app, &Application::handleLocalServerConnection, Qt::DirectConnection);
|
QObject::connect(&server, &QLocalServer::newConnection,
|
||||||
|
&app, &Application::handleLocalServerConnection, Qt::DirectConnection);
|
||||||
#ifdef HAS_BUGSPLAT
|
|
||||||
auto accountManager = DependencyManager::get<AccountManager>();
|
|
||||||
crashReporter.mpSender.setDefaultUserName(qPrintable(accountManager->getAccountInfo().getUsername()));
|
|
||||||
QObject::connect(accountManager.data(), &AccountManager::usernameChanged, &app, [&crashReporter](const QString& newUsername) {
|
|
||||||
crashReporter.mpSender.setDefaultUserName(qPrintable(newUsername));
|
|
||||||
});
|
|
||||||
|
|
||||||
// BugSplat WILL NOT work with file paths that do not use OS native separators.
|
|
||||||
auto logger = app.getLogger();
|
|
||||||
auto logPath = QDir::toNativeSeparators(logger->getFilename());
|
|
||||||
crashReporter.mpSender.sendAdditionalFile(qPrintable(logPath));
|
|
||||||
|
|
||||||
QMetaObject::Connection connection;
|
|
||||||
connection = QObject::connect(logger, &FileLogger::rollingLogFile, &app, [&crashReporter, &connection](QString newFilename) {
|
|
||||||
// We only want to add the first rolled log file (the "beginning" of the log) to BugSplat to ensure we don't exceed the 2MB
|
|
||||||
// zipped limit, so we disconnect here.
|
|
||||||
QObject::disconnect(connection);
|
|
||||||
auto rolledLogPath = QDir::toNativeSeparators(newFilename);
|
|
||||||
crashReporter.mpSender.sendAdditionalFile(qPrintable(rolledLogPath));
|
|
||||||
});
|
|
||||||
#endif
|
|
||||||
|
|
||||||
printSystemInformation();
|
printSystemInformation();
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue