2013-05-16 08:18:31 +02:00
|
|
|
/*
|
|
|
|
* =============================================================================
|
|
|
|
* Accelerator Extension
|
|
|
|
* Copyright (C) 2011 Asher Baker (asherkin). All rights reserved.
|
|
|
|
* =============================================================================
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify it under
|
|
|
|
* the terms of the GNU General Public License, version 3.0, as published by the
|
|
|
|
* Free Software Foundation.
|
|
|
|
*
|
|
|
|
* This program 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 General Public License for more
|
|
|
|
* details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License along with
|
|
|
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "extension.h"
|
|
|
|
|
|
|
|
#include <IWebternet.h>
|
|
|
|
#include "MemoryDownloader.h"
|
|
|
|
|
2013-05-18 01:46:46 +02:00
|
|
|
#if defined _LINUX
|
2013-05-16 08:18:31 +02:00
|
|
|
#include "client/linux/handler/exception_handler.h"
|
2015-10-23 13:10:09 +02:00
|
|
|
#include "common/linux/linux_libc_support.h"
|
2015-10-22 18:18:17 +02:00
|
|
|
#include "third_party/lss/linux_syscall_support.h"
|
2013-05-16 08:18:31 +02:00
|
|
|
|
|
|
|
#include <signal.h>
|
|
|
|
#include <dirent.h>
|
|
|
|
#include <unistd.h>
|
2013-05-18 01:46:46 +02:00
|
|
|
#elif defined _WINDOWS
|
|
|
|
#define _STDINT // ~.~
|
|
|
|
#include "client/windows/handler/exception_handler.h"
|
2014-11-08 02:45:19 +01:00
|
|
|
#else
|
|
|
|
#error Bad platform.
|
2013-05-18 01:46:46 +02:00
|
|
|
#endif
|
2013-05-16 08:18:31 +02:00
|
|
|
|
|
|
|
Accelerator g_accelerator;
|
|
|
|
SMEXT_LINK(&g_accelerator);
|
|
|
|
|
|
|
|
IWebternet *webternet;
|
2016-01-13 17:25:03 +01:00
|
|
|
IGameConfig *gameconfig;
|
|
|
|
|
|
|
|
typedef void (*GetSpew_t)(char *buffer, unsigned int length);
|
|
|
|
GetSpew_t GetSpew;
|
|
|
|
|
|
|
|
char spewBuffer[65536]; // Hi.
|
2013-05-16 08:18:31 +02:00
|
|
|
|
2016-01-14 12:18:10 +01:00
|
|
|
char dumpStoragePath[512];
|
|
|
|
char logPath[512];
|
|
|
|
|
2013-05-16 08:18:31 +02:00
|
|
|
google_breakpad::ExceptionHandler *handler = NULL;
|
|
|
|
|
2015-10-22 18:18:17 +02:00
|
|
|
struct PluginInfo {
|
2015-10-23 13:10:09 +02:00
|
|
|
unsigned int serial;
|
|
|
|
PluginStatus status;
|
|
|
|
char filename[256];
|
2015-10-22 18:18:17 +02:00
|
|
|
char name[256];
|
|
|
|
char author[256];
|
|
|
|
char description[256];
|
|
|
|
char version[256];
|
|
|
|
char url[256];
|
|
|
|
};
|
|
|
|
|
|
|
|
unsigned int plugin_count;
|
|
|
|
PluginInfo plugins[256];
|
|
|
|
|
2013-05-18 01:46:46 +02:00
|
|
|
#if defined _LINUX
|
2013-05-16 08:18:31 +02:00
|
|
|
void (*SignalHandler)(int, siginfo_t *, void *);
|
|
|
|
|
|
|
|
const int kExceptionSignals[] = {
|
|
|
|
SIGSEGV, SIGABRT, SIGFPE, SIGILL, SIGBUS
|
|
|
|
};
|
|
|
|
|
|
|
|
const int kNumHandledSignals = sizeof(kExceptionSignals) / sizeof(kExceptionSignals[0]);
|
|
|
|
|
|
|
|
static bool dumpCallback(const google_breakpad::MinidumpDescriptor& descriptor, void* context, bool succeeded)
|
|
|
|
{
|
2015-10-22 18:18:17 +02:00
|
|
|
//printf("Wrote minidump to: %s\n", descriptor.path());
|
|
|
|
|
2016-01-13 17:25:03 +01:00
|
|
|
if (succeeded) {
|
|
|
|
sys_write(STDOUT_FILENO, "Wrote minidump to: ", 19);
|
|
|
|
} else {
|
|
|
|
sys_write(STDOUT_FILENO, "Failed to write minidump to: ", 29);
|
|
|
|
}
|
|
|
|
|
2015-10-23 13:10:09 +02:00
|
|
|
sys_write(STDOUT_FILENO, descriptor.path(), my_strlen(descriptor.path()));
|
2015-10-22 18:18:17 +02:00
|
|
|
sys_write(STDOUT_FILENO, "\n", 1);
|
|
|
|
|
2016-01-13 17:25:03 +01:00
|
|
|
if (!succeeded) {
|
|
|
|
return succeeded;
|
|
|
|
}
|
|
|
|
|
2016-01-14 12:18:10 +01:00
|
|
|
my_strlcpy(dumpStoragePath, descriptor.path(), sizeof(dumpStoragePath));
|
|
|
|
my_strlcat(dumpStoragePath, ".txt", sizeof(dumpStoragePath));
|
2015-10-22 18:18:17 +02:00
|
|
|
|
2016-01-14 12:18:10 +01:00
|
|
|
int extra = sys_open(dumpStoragePath, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
|
2015-10-22 18:18:17 +02:00
|
|
|
if (extra == -1) {
|
|
|
|
sys_write(STDOUT_FILENO, "Failed to open metadata file!\n", 30);
|
|
|
|
return succeeded;
|
|
|
|
}
|
|
|
|
|
2016-01-13 17:25:03 +01:00
|
|
|
if (GetSpew) {
|
|
|
|
GetSpew(spewBuffer, sizeof(spewBuffer));
|
|
|
|
sys_write(extra, "-------- CONSOLE HISTORY BEGIN --------\n", 40);
|
|
|
|
sys_write(extra, spewBuffer, my_strlen(spewBuffer));
|
|
|
|
sys_write(extra, "-------- CONSOLE HISTORY END --------\n", 38);
|
|
|
|
}
|
|
|
|
|
2015-10-23 13:10:09 +02:00
|
|
|
char pis[64];
|
|
|
|
char pds[32];
|
2015-10-22 18:18:17 +02:00
|
|
|
for (unsigned i = 0; i < plugin_count; ++i) {
|
|
|
|
PluginInfo *p = &plugins[i];
|
|
|
|
if (p->serial == 0) continue;
|
2015-10-23 13:10:09 +02:00
|
|
|
my_uitos(pds, i, my_uint_len(i));
|
|
|
|
pds[my_uint_len(i)] = '\0';
|
|
|
|
my_strlcpy(pis, "plugin[", sizeof(pis));
|
|
|
|
my_strlcat(pis, pds, sizeof(pis));
|
|
|
|
my_strlcat(pis, "].", sizeof(pis));
|
|
|
|
sys_write(extra, pis, my_strlen(pis));
|
|
|
|
sys_write(extra, "filename=", 9);
|
|
|
|
sys_write(extra, p->filename, my_strlen(p->filename));
|
2015-10-22 18:18:17 +02:00
|
|
|
sys_write(extra, "\n", 1);
|
2015-10-23 13:10:09 +02:00
|
|
|
sys_write(extra, pis, my_strlen(pis));
|
|
|
|
sys_write(extra, "name=", 5);
|
|
|
|
sys_write(extra, p->name, my_strlen(p->name));
|
2015-10-22 18:18:17 +02:00
|
|
|
sys_write(extra, "\n", 1);
|
2015-10-23 13:10:09 +02:00
|
|
|
sys_write(extra, pis, my_strlen(pis));
|
|
|
|
sys_write(extra, "author=", 7);
|
|
|
|
sys_write(extra, p->author, my_strlen(p->author));
|
2015-10-22 18:18:17 +02:00
|
|
|
sys_write(extra, "\n", 1);
|
2015-10-23 13:10:09 +02:00
|
|
|
sys_write(extra, pis, my_strlen(pis));
|
|
|
|
sys_write(extra, "description=", 12);
|
|
|
|
sys_write(extra, p->description, my_strlen(p->description));
|
2015-10-22 18:18:17 +02:00
|
|
|
sys_write(extra, "\n", 1);
|
2015-10-23 13:10:09 +02:00
|
|
|
sys_write(extra, pis, my_strlen(pis));
|
|
|
|
sys_write(extra, "version=", 8);
|
|
|
|
sys_write(extra, p->version, my_strlen(p->version));
|
2015-10-22 18:18:17 +02:00
|
|
|
sys_write(extra, "\n", 1);
|
2015-10-23 13:10:09 +02:00
|
|
|
sys_write(extra, pis, my_strlen(pis));
|
|
|
|
sys_write(extra, "url=", 4);
|
|
|
|
sys_write(extra, p->url, my_strlen(p->url));
|
2015-10-22 18:18:17 +02:00
|
|
|
sys_write(extra, "\n", 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
sys_close(extra);
|
|
|
|
|
2013-05-16 08:18:31 +02:00
|
|
|
return succeeded;
|
|
|
|
}
|
|
|
|
|
|
|
|
void OnGameFrame(bool simulating)
|
|
|
|
{
|
|
|
|
bool weHaveBeenFuckedOver = false;
|
|
|
|
struct sigaction oact;
|
|
|
|
|
|
|
|
for (int i = 0; i < kNumHandledSignals; ++i) {
|
|
|
|
sigaction(kExceptionSignals[i], NULL, &oact);
|
|
|
|
|
|
|
|
if (oact.sa_sigaction != SignalHandler) {
|
|
|
|
weHaveBeenFuckedOver = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!weHaveBeenFuckedOver) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct sigaction act;
|
|
|
|
memset(&act, 0, sizeof(act));
|
|
|
|
sigemptyset(&act.sa_mask);
|
|
|
|
|
|
|
|
for (int i = 0; i < kNumHandledSignals; ++i) {
|
|
|
|
sigaddset(&act.sa_mask, kExceptionSignals[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
act.sa_sigaction = SignalHandler;
|
|
|
|
act.sa_flags = SA_ONSTACK | SA_SIGINFO;
|
|
|
|
|
|
|
|
for (int i = 0; i < kNumHandledSignals; ++i) {
|
|
|
|
sigaction(kExceptionSignals[i], &act, NULL);
|
|
|
|
}
|
|
|
|
}
|
2013-05-18 01:46:46 +02:00
|
|
|
#elif defined _WINDOWS
|
2014-11-08 03:00:40 +01:00
|
|
|
void *vectoredHandler = NULL;
|
|
|
|
|
2013-05-18 01:46:46 +02:00
|
|
|
LONG CALLBACK BreakpadVectoredHandler(_In_ PEXCEPTION_POINTERS ExceptionInfo)
|
|
|
|
{
|
2013-05-19 04:28:09 +02:00
|
|
|
switch (ExceptionInfo->ExceptionRecord->ExceptionCode)
|
2013-05-18 01:46:46 +02:00
|
|
|
{
|
2013-05-19 04:28:09 +02:00
|
|
|
case EXCEPTION_ACCESS_VIOLATION:
|
2015-02-14 04:36:17 +01:00
|
|
|
case EXCEPTION_INVALID_HANDLE:
|
2013-05-19 04:28:09 +02:00
|
|
|
case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
|
|
|
|
case EXCEPTION_DATATYPE_MISALIGNMENT:
|
|
|
|
case EXCEPTION_ILLEGAL_INSTRUCTION:
|
2014-10-31 23:42:09 +01:00
|
|
|
case EXCEPTION_INT_DIVIDE_BY_ZERO:
|
2013-05-19 04:28:09 +02:00
|
|
|
case EXCEPTION_STACK_OVERFLOW:
|
2015-02-14 16:58:07 +01:00
|
|
|
case 0xC0000409: // STATUS_STACK_BUFFER_OVERRUN
|
|
|
|
case 0xC0000374: // STATUS_HEAP_CORRUPTION
|
2013-05-19 04:28:09 +02:00
|
|
|
break;
|
2014-10-31 23:42:09 +01:00
|
|
|
case 0: // Valve use this for Sys_Error.
|
|
|
|
if ((ExceptionInfo->ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE) == 0)
|
|
|
|
return EXCEPTION_CONTINUE_SEARCH;
|
|
|
|
break;
|
2013-05-19 04:28:09 +02:00
|
|
|
default:
|
|
|
|
return EXCEPTION_CONTINUE_SEARCH;
|
2013-05-18 01:46:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (handler->WriteMinidumpForException(ExceptionInfo))
|
|
|
|
{
|
|
|
|
// Stop the handler thread from deadlocking us.
|
|
|
|
delete handler;
|
|
|
|
|
|
|
|
// Stop Valve's handler being called.
|
|
|
|
ExceptionInfo->ExceptionRecord->ExceptionCode = EXCEPTION_BREAKPOINT;
|
|
|
|
|
|
|
|
return EXCEPTION_EXECUTE_HANDLER;
|
|
|
|
} else {
|
|
|
|
return EXCEPTION_CONTINUE_SEARCH;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool dumpCallback(const wchar_t* dump_path,
|
|
|
|
const wchar_t* minidump_id,
|
|
|
|
void* context,
|
|
|
|
EXCEPTION_POINTERS* exinfo,
|
|
|
|
MDRawAssertionInfo* assertion,
|
|
|
|
bool succeeded)
|
|
|
|
{
|
2016-01-13 17:49:19 +01:00
|
|
|
if (!succeeded) {
|
|
|
|
printf("Failed to write minidump to: %ls\\%ls.dmp\n", dump_path, minidump_id);
|
|
|
|
return succeeded;
|
|
|
|
}
|
|
|
|
|
2013-05-18 01:46:46 +02:00
|
|
|
printf("Wrote minidump to: %ls\\%ls.dmp\n", dump_path, minidump_id);
|
2016-01-13 17:49:19 +01:00
|
|
|
|
2016-01-14 12:18:10 +01:00
|
|
|
sprintf(dumpStoragePath, "%ls\\%ls.txt", dump_path, minidump_id);
|
2016-01-13 17:49:19 +01:00
|
|
|
|
2016-01-14 12:18:10 +01:00
|
|
|
FILE *extra = fopen(dumpStoragePath, L"wb");
|
2016-01-13 17:49:19 +01:00
|
|
|
if (!extra) {
|
|
|
|
printf("Failed to open metadata file!\n");
|
|
|
|
return succeeded;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (GetSpew) {
|
|
|
|
GetSpew(spewBuffer, sizeof(spewBuffer));
|
|
|
|
fprintf(extra, "-------- CONSOLE HISTORY BEGIN --------\n%s-------- CONSOLE HISTORY END --------\n", spewBuffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
fclose(extra);
|
|
|
|
|
2013-05-18 01:46:46 +02:00
|
|
|
return succeeded;
|
|
|
|
}
|
2014-11-08 02:45:19 +01:00
|
|
|
#else
|
|
|
|
#error Bad platform.
|
2013-05-18 01:46:46 +02:00
|
|
|
#endif
|
2013-05-16 08:18:31 +02:00
|
|
|
|
2016-01-14 12:18:10 +01:00
|
|
|
bool UploadAndDeleteCrashDump(const char *path, char *response, int maxlen)
|
2013-05-16 08:18:31 +02:00
|
|
|
{
|
|
|
|
IWebForm *form = webternet->CreateForm();
|
|
|
|
|
|
|
|
form->AddString("UserID", g_pSM->GetCoreConfigValue("MinidumpAccount"));
|
2014-11-08 03:04:17 +01:00
|
|
|
form->AddString("GameDirectory", g_pSM->GetGameFolderName());
|
2014-11-08 02:50:04 +01:00
|
|
|
form->AddString("ExtensionVersion", SMEXT_CONF_VERSION);
|
2013-05-16 08:18:31 +02:00
|
|
|
|
|
|
|
form->AddFile("upload_file_minidump", path);
|
|
|
|
|
2015-10-22 18:18:17 +02:00
|
|
|
char metapath[512];
|
2016-01-14 12:18:10 +01:00
|
|
|
g_pSM->Format(metapath, sizeof(metapath), "%s.txt", path);
|
2015-10-22 18:18:17 +02:00
|
|
|
if (libsys->PathExists(metapath)) {
|
|
|
|
form->AddFile("upload_file_metadata", metapath);
|
|
|
|
}
|
|
|
|
|
2013-05-16 08:18:31 +02:00
|
|
|
MemoryDownloader data;
|
|
|
|
IWebTransfer *xfer = webternet->CreateSession();
|
|
|
|
xfer->SetFailOnHTTPError(true);
|
|
|
|
|
2016-01-14 12:18:10 +01:00
|
|
|
bool uploaded = xfer->PostAndDownload("http://crash.limetech.org/submit", form, &data, NULL);
|
|
|
|
|
|
|
|
if (response) {
|
|
|
|
if (uploaded) {
|
|
|
|
g_pSM->Format(response, maxlen, "%s", data.GetBuffer());
|
|
|
|
} else {
|
|
|
|
g_pSM->Format(response, maxlen, "%s (%d)", xfer->LastErrorMessage(), xfer->LastErrorCode());
|
|
|
|
}
|
2013-05-16 08:18:31 +02:00
|
|
|
}
|
2015-10-23 13:11:16 +02:00
|
|
|
|
|
|
|
if (libsys->PathExists(metapath)) {
|
|
|
|
unlink(metapath);
|
|
|
|
}
|
2016-01-14 12:18:10 +01:00
|
|
|
|
|
|
|
unlink(path);
|
|
|
|
|
|
|
|
return uploaded;
|
2013-05-16 08:18:31 +02:00
|
|
|
}
|
|
|
|
|
2016-01-14 12:18:10 +01:00
|
|
|
class UploadThread: public IThread
|
2013-05-16 08:18:31 +02:00
|
|
|
{
|
2016-01-14 12:18:10 +01:00
|
|
|
void RunThread(IThreadHandle *pHandle) {
|
|
|
|
rootconsole->ConsolePrint("Accelerator upload thread started.");
|
2016-01-13 18:37:20 +01:00
|
|
|
|
2016-01-14 12:18:10 +01:00
|
|
|
FILE *log = fopen(logPath, "a");
|
|
|
|
if (!log) {
|
|
|
|
g_pSM->LogError(myself, "Failed to open Accelerator log file: %s", logPath);
|
|
|
|
}
|
2013-05-16 08:18:31 +02:00
|
|
|
|
2016-01-14 12:18:10 +01:00
|
|
|
IDirectory *dumps = libsys->OpenDirectory(dumpStoragePath);
|
2013-05-16 08:18:31 +02:00
|
|
|
|
2016-01-14 12:18:10 +01:00
|
|
|
int count = 0;
|
|
|
|
int failed = 0;
|
|
|
|
char path[512];
|
|
|
|
char response[512];
|
|
|
|
|
|
|
|
while (dumps->MoreFiles()) {
|
|
|
|
if (!dumps->IsEntryFile()) {
|
|
|
|
dumps->NextEntry();
|
|
|
|
continue;
|
|
|
|
}
|
2015-10-22 18:18:17 +02:00
|
|
|
|
2016-01-14 12:18:10 +01:00
|
|
|
const char *name = dumps->GetEntryName();
|
|
|
|
|
|
|
|
int namelen = strlen(name);
|
|
|
|
if (namelen < 4 || strcmp(&name[namelen-4], ".dmp") != 0) {
|
|
|
|
dumps->NextEntry();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_pSM->Format(path, sizeof(path), "%s/%s", dumpStoragePath, name);
|
|
|
|
bool uploaded = UploadAndDeleteCrashDump(path, response, sizeof(response));
|
|
|
|
|
|
|
|
if (uploaded) {
|
|
|
|
count++;
|
|
|
|
g_pSM->LogError(myself, "Accelerator uploaded crash dump: %s", response);
|
|
|
|
if (log) fprintf(log, "Uploaded crash dump: %s\n", response);
|
|
|
|
} else {
|
|
|
|
failed++;
|
|
|
|
g_pSM->LogError(myself, "Accelerator failed to upload crash dump: %s", response);
|
|
|
|
if (log) fprintf(log, "Failed to upload crash dump: %s\n", response);
|
|
|
|
}
|
2015-10-22 18:18:17 +02:00
|
|
|
|
|
|
|
dumps->NextEntry();
|
|
|
|
}
|
|
|
|
|
2016-01-14 12:18:10 +01:00
|
|
|
libsys->CloseDirectory(dumps);
|
|
|
|
|
|
|
|
if (log) {
|
|
|
|
fclose(log);
|
2014-11-08 02:45:19 +01:00
|
|
|
}
|
2013-05-18 01:46:46 +02:00
|
|
|
|
2016-01-14 12:18:10 +01:00
|
|
|
rootconsole->ConsolePrint("Accelerator upload thread finished. (%d uploaded, %d failed)", count, failed);
|
2013-05-16 08:18:31 +02:00
|
|
|
}
|
|
|
|
|
2016-01-14 12:18:10 +01:00
|
|
|
void OnTerminate(IThreadHandle *pHandle, bool cancel) {
|
|
|
|
rootconsole->ConsolePrint("Accelerator upload thread terminated. (canceled = %s)", (cancel ? "true" : "false"));
|
2014-11-08 02:45:19 +01:00
|
|
|
}
|
2013-05-16 08:18:31 +02:00
|
|
|
|
2016-01-13 18:37:20 +01:00
|
|
|
} uploadThread;
|
|
|
|
|
2013-05-16 08:18:31 +02:00
|
|
|
bool Accelerator::SDK_OnLoad(char *error, size_t maxlength, bool late)
|
|
|
|
{
|
|
|
|
sharesys->AddDependency(myself, "webternet.ext", true, true);
|
|
|
|
SM_GET_IFACE(WEBTERNET, webternet);
|
|
|
|
|
2016-01-14 12:18:10 +01:00
|
|
|
g_pSM->BuildPath(Path_SM, dumpStoragePath, sizeof(dumpStoragePath), "data/dumps");
|
2013-05-16 08:18:31 +02:00
|
|
|
|
2016-01-14 12:18:10 +01:00
|
|
|
if (!libsys->IsPathDirectory(dumpStoragePath))
|
2013-05-17 15:48:52 +02:00
|
|
|
{
|
2016-01-14 12:18:10 +01:00
|
|
|
if (!libsys->CreateFolder(dumpStoragePath))
|
2013-05-17 15:48:52 +02:00
|
|
|
{
|
|
|
|
if (error)
|
2016-01-14 12:18:10 +01:00
|
|
|
g_pSM->Format(error, maxlength, "%s didn't exist and we couldn't create it :(", dumpStoragePath);
|
2013-05-17 15:48:52 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-14 12:18:10 +01:00
|
|
|
g_pSM->BuildPath(Path_SM, logPath, sizeof(logPath), "logs/accelerator.log");
|
|
|
|
|
2016-01-13 18:37:20 +01:00
|
|
|
threader->MakeThread(&uploadThread);
|
|
|
|
|
2016-01-13 17:25:03 +01:00
|
|
|
if (!gameconfs->LoadGameConfigFile("accelerator.games", &gameconfig, error, maxlength)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!gameconfig->GetMemSig("GetSpew", (void **)&GetSpew)) {
|
|
|
|
smutils->LogError(myself, "WARNING: GetSpew not found in gamedata, console output will not be included in crash reports.");
|
|
|
|
} else if (!GetSpew) {
|
|
|
|
smutils->LogError(myself, "WARNING: Sigscan for GetSpew failed, console output will not be included in crash reports.");
|
|
|
|
}
|
|
|
|
|
2013-05-18 01:46:46 +02:00
|
|
|
#if defined _LINUX
|
2016-01-14 12:18:10 +01:00
|
|
|
google_breakpad::MinidumpDescriptor descriptor(dumpStoragePath);
|
2013-05-16 08:18:31 +02:00
|
|
|
handler = new google_breakpad::ExceptionHandler(descriptor, NULL, dumpCallback, NULL, true, -1);
|
|
|
|
|
|
|
|
struct sigaction oact;
|
|
|
|
sigaction(SIGSEGV, NULL, &oact);
|
|
|
|
SignalHandler = oact.sa_sigaction;
|
2013-05-18 01:46:46 +02:00
|
|
|
|
2013-05-16 08:18:31 +02:00
|
|
|
g_pSM->AddGameFrameHook(OnGameFrame);
|
2013-05-18 01:46:46 +02:00
|
|
|
#elif defined _WINDOWS
|
2016-01-14 12:18:10 +01:00
|
|
|
wchar_t *buf = new wchar_t[sizeof(dumpStoragePath)];
|
|
|
|
size_t num_chars = mbstowcs(buf, dumpStoragePath, sizeof(dumpStoragePath));
|
2013-05-18 01:46:46 +02:00
|
|
|
|
|
|
|
handler = new google_breakpad::ExceptionHandler(std::wstring(buf, num_chars), NULL, dumpCallback, NULL, google_breakpad::ExceptionHandler::HANDLER_ALL);
|
|
|
|
|
2014-11-08 03:00:40 +01:00
|
|
|
vectoredHandler = AddVectoredExceptionHandler(0, BreakpadVectoredHandler);
|
2013-05-18 01:46:46 +02:00
|
|
|
|
|
|
|
delete buf;
|
2014-11-08 02:45:19 +01:00
|
|
|
#else
|
|
|
|
#error Bad platform.
|
2013-05-18 01:46:46 +02:00
|
|
|
#endif
|
|
|
|
|
2015-10-22 18:18:17 +02:00
|
|
|
IPluginIterator *i = plsys->GetPluginIterator();
|
|
|
|
while (i->MorePlugins()) {
|
|
|
|
IPlugin *p = i->GetPlugin();
|
|
|
|
const sm_plugininfo_t *pmi = p->GetPublicInfo();
|
|
|
|
PluginInfo *pi = &plugins[plugin_count++];
|
|
|
|
|
|
|
|
pi->serial = p->GetSerial();
|
|
|
|
pi->status = p->GetStatus();
|
|
|
|
|
|
|
|
strncpy(pi->filename, p->GetFilename(), sizeof(pi->filename) - 1);
|
|
|
|
|
|
|
|
strncpy(pi->name, pmi->name, sizeof(pi->name) - 1);
|
|
|
|
strncpy(pi->author, pmi->author, sizeof(pi->author) - 1);
|
|
|
|
strncpy(pi->description, pmi->description, sizeof(pi->description) - 1);
|
|
|
|
strncpy(pi->version, pmi->version, sizeof(pi->version) - 1);
|
|
|
|
strncpy(pi->url, pmi->url, sizeof(pi->url) - 1);
|
|
|
|
|
|
|
|
i->NextPlugin();
|
|
|
|
}
|
|
|
|
delete i;
|
|
|
|
|
2013-05-16 08:18:31 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Accelerator::SDK_OnUnload()
|
|
|
|
{
|
2013-05-18 01:46:46 +02:00
|
|
|
#if defined _LINUX
|
2013-05-16 08:18:31 +02:00
|
|
|
g_pSM->RemoveGameFrameHook(OnGameFrame);
|
2013-05-18 01:46:46 +02:00
|
|
|
#elif defined _WINDOWS
|
2014-11-08 03:00:40 +01:00
|
|
|
if (vectoredHandler) {
|
|
|
|
RemoveVectoredExceptionHandler(vectoredHandler);
|
|
|
|
}
|
2014-11-08 02:45:19 +01:00
|
|
|
#else
|
|
|
|
#error Bad platform.
|
2013-05-18 01:46:46 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
delete handler;
|
2013-05-16 08:18:31 +02:00
|
|
|
}
|
|
|
|
|